/**
* 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.hdfs.server.namenode;
/**
*
* This class provides locking mechanism that allows for concurrent reads.
*
* In addition, it provides an upgradeable read lock, that can be acquired
* by a single thread. It blocks any writes, but does not block other
* ordinary readers, unless the lock is upgraded.
*
* upgradeableReadLock is mutualy exclusive with another upgradeable read lock,
* which guarantees that the upgrade will succeed. It's also mutualy aclusive
* with the read lock. It's mutually exlusive with a read lock, only when
* upgraded.
*
* Usage:
*
* 1. similarly for readLock()
* writeLock();
* try{
* ...
* } finally {
* writeUnlock();
* }
*
* 2.
* upgradeableReadLock();
* try{
* ..
* ..
* upgradeLock();
* ..
* downgradeLock();
* ..
* upgradeLock();
* ..
* downgradeLock();
* } finally {
* upgradeableReadUnlock();
* }
*
*/
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class FSNamesystemLock {
private ReentrantReadWriteLock lock1;
private ReentrantReadWriteLock lock2;
private boolean hasRwLock;
FSNamesystemLock(boolean hasRwLock) {
this.hasRwLock = hasRwLock;
this.lock1 = new ReentrantReadWriteLock();
this.lock2 = new ReentrantReadWriteLock();
}
FSNamesystemLock() {
this(true);
}
/**
* Acquire read lock.
*/
void readLock() {
if (this.hasRwLock) {
this.lock2.readLock().lock();
} else {
writeLock();
}
}
/**
* Release read lock.
*/
void readUnlock() {
if (this.hasRwLock) {
this.lock2.readLock().unlock();
} else {
writeUnlock();
}
}
/**
* Acquire full write lock.
*/
void writeLock() {
this.lock1.writeLock().lock();
this.lock2.writeLock().lock();
}
/**
* Release full write lock.
*/
void writeUnlock() {
this.lock2.writeLock().unlock();
this.lock1.writeLock().unlock();
}
boolean hasWriteLock() {
// it's enough to say if the readLock.writelock is acquired
// as it's only acquired by writeLock or by upgrade
return this.lock2.isWriteLockedByCurrentThread();
}
/**
* Acquire the upgradeable lock.
*/
void upgradeableReadLock() {
this.lock1.writeLock().lock();
}
/**
* Downgrade if necessary.
* Release the upgradeable lock.
*/
void upgradeableReadUnlock() {
// we need to check if it was upgraded
if (lock2.isWriteLockedByCurrentThread()) {
this.lock2.writeLock().unlock();
}
this.lock1.writeLock().unlock();
}
/**
* Upgrade the upgradeable lock.
* Upgrading should only be used after acquiring
* the upgradeable lock.
*/
void upgradeLock() {
this.lock2.writeLock().lock();
}
/**
* Downgrade the upgradeable lock.
* Downgrading should not be used in "finally"
* Downgrade will fail if the lock has not been upgraded.
*/
void downgradeLock() {
this.lock2.writeLock().unlock();
}
}