blob: f3ed2c31303c08c01146cf38ce47f97c9d59b77a [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.ozone.om.multitenant;
import com.google.common.base.Preconditions;
import org.apache.hadoop.ozone.om.exceptions.OMException;
import org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.StampedLock;
import static org.apache.hadoop.ozone.OzoneConsts.OZONE_TENANT_AUTHORIZER_LOCK_WAIT_MILLIS;
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.INTERNAL_ERROR;
/**
* Implementation of {@link AuthorizerLock}.
*/
public class AuthorizerLockImpl implements AuthorizerLock {
public static final Logger LOG =
LoggerFactory.getLogger(AuthorizerLockImpl.class);
private final StampedLock authorizerStampedLock = new StampedLock();
// No need to use atomic here as both fields can only be updated after
// authorizer write lock is acquired.
private long omRequestWriteLockStamp = 0L;
private long omRequestWriteLockHolderTid = 0L;
@Override
public long tryReadLock(long timeout) throws InterruptedException {
if (LOG.isDebugEnabled()) {
LOG.debug("Trying to acquire authorizer read lock from thread {}",
Thread.currentThread().getId());
}
return authorizerStampedLock.tryReadLock(timeout, TimeUnit.MILLISECONDS);
}
/**
* Release read lock on the authorizer.
* This is only used by BG sync at the moment.
*/
@Override
public void unlockRead(long stamp) {
if (LOG.isDebugEnabled()) {
LOG.debug("Releasing authorizer read lock from thread {} with stamp {}",
Thread.currentThread().getId(), stamp);
}
authorizerStampedLock.unlockRead(stamp);
}
@Override
public long tryReadLockThrowOnTimeout() throws IOException {
long stamp;
try {
stamp = tryReadLock(OZONE_TENANT_AUTHORIZER_LOCK_WAIT_MILLIS);
} catch (InterruptedException e) {
throw new OMException(e, INTERNAL_ERROR);
}
if (stamp == 0L) {
throw new OMException("Timed out acquiring authorizer read lock."
+ " Another multi-tenancy request is in-progress. Try again later",
ResultCodes.TIMEOUT);
} else if (LOG.isDebugEnabled()) {
LOG.debug("Acquired authorizer read lock from thread {} with stamp {}",
Thread.currentThread().getId(), stamp);
}
return stamp;
}
@Override
public long tryWriteLock(long timeout) throws InterruptedException {
if (LOG.isDebugEnabled()) {
LOG.debug("Trying to acquire authorizer write lock from thread {}",
Thread.currentThread().getId());
}
return authorizerStampedLock.tryWriteLock(timeout, TimeUnit.MILLISECONDS);
}
/**
* Release read lock on the authorizer.
* This is used by both BG sync and tenant requests.
*/
@Override
public void unlockWrite(long stamp) {
if (LOG.isDebugEnabled()) {
LOG.debug("Releasing authorizer write lock from thread {} with stamp {}",
Thread.currentThread().getId(), stamp);
}
authorizerStampedLock.unlockWrite(stamp);
}
@Override
public long tryWriteLockThrowOnTimeout() throws IOException {
long stamp;
try {
stamp = tryWriteLock(OZONE_TENANT_AUTHORIZER_LOCK_WAIT_MILLIS);
} catch (InterruptedException e) {
throw new OMException(e, INTERNAL_ERROR);
}
if (stamp == 0L) {
throw new OMException("Timed out acquiring authorizer write lock. "
+ "Another multi-tenancy request is in-progress. Try again later",
ResultCodes.TIMEOUT);
} else if (LOG.isDebugEnabled()) {
LOG.debug("Acquired authorizer write lock from thread {} with stamp {}",
Thread.currentThread().getId(), stamp);
}
return stamp;
}
@Override
public void tryWriteLockInOMRequest() throws IOException {
long stamp = tryWriteLockThrowOnTimeout();
// Sanity check. Must not have held a write lock in a tenant OMRequest.
Preconditions.checkArgument(omRequestWriteLockStamp == 0L);
Preconditions.checkArgument(omRequestWriteLockHolderTid == 0L);
omRequestWriteLockStamp = stamp;
omRequestWriteLockHolderTid = Thread.currentThread().getId();
if (LOG.isDebugEnabled()) {
LOG.debug("Set omRequestWriteLockStamp to {}, "
+ "omRequestWriteLockHolderTid to {}",
omRequestWriteLockStamp, omRequestWriteLockHolderTid);
}
}
@Override
public void unlockWriteInOMRequest() {
if (omRequestWriteLockStamp == 0L) {
LOG.debug("Authorizer write lock is not held in this lock instance. "
+ "This OM might be follower, or leader changed. Ignored");
return;
}
final long stamp = omRequestWriteLockStamp;
// Reset the internal lock stamp record back to zero.
omRequestWriteLockStamp = 0L;
omRequestWriteLockHolderTid = 0L;
if (LOG.isDebugEnabled()) {
LOG.debug("Restored omRequestWriteLockStamp to {}, "
+ "omRequestWriteLockHolderTid to {}",
omRequestWriteLockStamp, omRequestWriteLockHolderTid);
}
unlockWrite(stamp);
}
@Override
public boolean isWriteLockHeldByCurrentThread() {
if (omRequestWriteLockHolderTid == 0L) {
LOG.debug("Write lock is not held by any OMRequest thread");
return false;
}
if (omRequestWriteLockHolderTid != Thread.currentThread().getId()) {
LOG.debug("Write lock is not held by current thread");
return false;
}
return true;
}
}