HDFS-16434. Add opname to read/write lock for remaining operations (#3915)

This commit is contained in:
litao 2022-03-25 19:19:01 +08:00 committed by GitHub
parent ffa0eab488
commit 565e848d88
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 66 additions and 52 deletions

View File

@ -383,7 +383,7 @@ public class DelegationTokenSecretManager
namesystem.logUpdateMasterKey(key); namesystem.logUpdateMasterKey(key);
} }
} finally { } finally {
namesystem.readUnlock(); namesystem.readUnlock("logUpdateMasterKey");
} }
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
// AbstractDelegationTokenManager may crash if an exception is thrown. // AbstractDelegationTokenManager may crash if an exception is thrown.
@ -412,7 +412,7 @@ public class DelegationTokenSecretManager
namesystem.logExpireDelegationToken(dtId); namesystem.logExpireDelegationToken(dtId);
} }
} finally { } finally {
namesystem.readUnlock(); namesystem.readUnlock("logExpireToken");
} }
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
// AbstractDelegationTokenManager may crash if an exception is thrown. // AbstractDelegationTokenManager may crash if an exception is thrown.

View File

@ -2017,7 +2017,7 @@ public class BlockManager implements BlockStatsMXBean {
blocksToReconstruct = neededReconstruction blocksToReconstruct = neededReconstruction
.chooseLowRedundancyBlocks(blocksToProcess, reset); .chooseLowRedundancyBlocks(blocksToProcess, reset);
} finally { } finally {
namesystem.writeUnlock(); namesystem.writeUnlock("computeBlockReconstructionWork");
} }
return computeReconstructionWorkForBlocks(blocksToReconstruct); return computeReconstructionWorkForBlocks(blocksToReconstruct);
} }
@ -2051,7 +2051,7 @@ public class BlockManager implements BlockStatsMXBean {
} }
} }
} finally { } finally {
namesystem.writeUnlock(); namesystem.writeUnlock("computeReconstructionWorkForBlocks");
} }
// Step 2: choose target nodes for each reconstruction task // Step 2: choose target nodes for each reconstruction task
@ -2092,7 +2092,7 @@ public class BlockManager implements BlockStatsMXBean {
} }
} }
} finally { } finally {
namesystem.writeUnlock(); namesystem.writeUnlock("computeReconstructionWorkForBlocks");
} }
if (blockLog.isDebugEnabled()) { if (blockLog.isDebugEnabled()) {
@ -2577,7 +2577,7 @@ public class BlockManager implements BlockStatsMXBean {
} }
} }
} finally { } finally {
namesystem.writeUnlock(); namesystem.writeUnlock("processPendingReconstructions");
} }
/* If we know the target datanodes where the replication timedout, /* If we know the target datanodes where the replication timedout,
* we could invoke decBlocksScheduled() on it. Its ok for now. * we could invoke decBlocksScheduled() on it. Its ok for now.
@ -2826,7 +2826,7 @@ public class BlockManager implements BlockStatsMXBean {
storageInfo.receivedBlockReport(); storageInfo.receivedBlockReport();
} finally { } finally {
endTime = Time.monotonicNow(); endTime = Time.monotonicNow();
namesystem.writeUnlock(); namesystem.writeUnlock("processReport");
} }
if(blockLog.isDebugEnabled()) { if(blockLog.isDebugEnabled()) {
@ -2870,7 +2870,7 @@ public class BlockManager implements BlockStatsMXBean {
context.getTotalRpcs(), Long.toHexString(context.getReportId())); context.getTotalRpcs(), Long.toHexString(context.getReportId()));
} }
} finally { } finally {
namesystem.writeUnlock(); namesystem.writeUnlock("removeBRLeaseIfNeeded");
} }
} }
@ -2908,7 +2908,7 @@ public class BlockManager implements BlockStatsMXBean {
postponedMisreplicatedBlocks.addAll(rescannedMisreplicatedBlocks); postponedMisreplicatedBlocks.addAll(rescannedMisreplicatedBlocks);
rescannedMisreplicatedBlocks.clear(); rescannedMisreplicatedBlocks.clear();
long endSize = postponedMisreplicatedBlocks.size(); long endSize = postponedMisreplicatedBlocks.size();
namesystem.writeUnlock(); namesystem.writeUnlock("rescanPostponedMisreplicatedBlocks");
LOG.info("Rescan of postponedMisreplicatedBlocks completed in {}" + LOG.info("Rescan of postponedMisreplicatedBlocks completed in {}" +
" msecs. {} blocks are left. {} blocks were removed.", " msecs. {} blocks are left. {} blocks were removed.",
(Time.monotonicNow() - startTime), endSize, (startSize - endSize)); (Time.monotonicNow() - startTime), endSize, (startSize - endSize));
@ -3775,7 +3775,7 @@ public class BlockManager implements BlockStatsMXBean {
break; break;
} }
} finally { } finally {
namesystem.writeUnlock(); namesystem.writeUnlock("processMisReplicatesAsync");
// Make sure it is out of the write lock for sufficiently long time. // Make sure it is out of the write lock for sufficiently long time.
Thread.sleep(sleepDuration); Thread.sleep(sleepDuration);
} }
@ -3830,7 +3830,7 @@ public class BlockManager implements BlockStatsMXBean {
"Re-scanned block {}, result is {}", blk, r); "Re-scanned block {}, result is {}", blk, r);
} }
} finally { } finally {
namesystem.writeUnlock(); namesystem.writeUnlock("processMisReplicatedBlocks");
} }
} }
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
@ -4553,7 +4553,7 @@ public class BlockManager implements BlockStatsMXBean {
// testPlacementWithLocalRackNodesDecommissioned, it is not protected by // testPlacementWithLocalRackNodesDecommissioned, it is not protected by
// lock, only when called by DatanodeManager.refreshNodes have writeLock // lock, only when called by DatanodeManager.refreshNodes have writeLock
if (namesystem.hasWriteLock()) { if (namesystem.hasWriteLock()) {
namesystem.writeUnlock(); namesystem.writeUnlock("processExtraRedundancyBlocksOnInService");
try { try {
Thread.sleep(1); Thread.sleep(1);
} catch (InterruptedException e) { } catch (InterruptedException e) {
@ -4685,7 +4685,7 @@ public class BlockManager implements BlockStatsMXBean {
repl.outOfServiceReplicas(), oldExpectedReplicas); repl.outOfServiceReplicas(), oldExpectedReplicas);
} }
} finally { } finally {
namesystem.writeUnlock(); namesystem.writeUnlock("updateNeededReconstructions");
} }
} }
@ -4742,7 +4742,7 @@ public class BlockManager implements BlockStatsMXBean {
return 0; return 0;
} }
} finally { } finally {
namesystem.writeUnlock(); namesystem.writeUnlock("invalidateWorkForOneNode");
} }
blockLog.debug("BLOCK* {}: ask {} to delete {}", getClass().getSimpleName(), blockLog.debug("BLOCK* {}: ask {} to delete {}", getClass().getSimpleName(),
dn, toInvalidate); dn, toInvalidate);
@ -4974,7 +4974,7 @@ public class BlockManager implements BlockStatsMXBean {
} }
} }
} finally { } finally {
namesystem.writeUnlock(); namesystem.writeUnlock("markedDeleteBlockScrubberThread");
} }
} }
} }
@ -5092,7 +5092,7 @@ public class BlockManager implements BlockStatsMXBean {
this.updateState(); this.updateState();
this.scheduledReplicationBlocksCount = workFound; this.scheduledReplicationBlocksCount = workFound;
} finally { } finally {
namesystem.writeUnlock(); namesystem.writeUnlock("computeDatanodeWork");
} }
workFound += this.computeInvalidateWork(nodesToProcess); workFound += this.computeInvalidateWork(nodesToProcess);
return workFound; return workFound;
@ -5332,7 +5332,7 @@ public class BlockManager implements BlockStatsMXBean {
action = queue.poll(); action = queue.poll();
} while (action != null); } while (action != null);
} finally { } finally {
namesystem.writeUnlock(); namesystem.writeUnlock("processQueue");
metrics.addBlockOpsBatched(processed - 1); metrics.addBlockOpsBatched(processed - 1);
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {

View File

@ -670,7 +670,7 @@ class BlockManagerSafeMode {
break; break;
} }
} finally { } finally {
namesystem.writeUnlock(); namesystem.writeUnlock("leaveSafeMode");
} }
try { try {

View File

@ -302,7 +302,7 @@ public class CacheReplicationMonitor extends Thread implements Closeable {
rescanCachedBlockMap(); rescanCachedBlockMap();
blockManager.getDatanodeManager().resetLastCachingDirectiveSentTime(); blockManager.getDatanodeManager().resetLastCachingDirectiveSentTime();
} finally { } finally {
namesystem.writeUnlock(); namesystem.writeUnlock("cacheReplicationMonitorRescan");
} }
} }

View File

@ -215,7 +215,7 @@ public class DatanodeAdminBackoffMonitor extends DatanodeAdminMonitorBase
processPendingNodes(); processPendingNodes();
} finally { } finally {
namesystem.writeUnlock(); namesystem.writeUnlock("DatanodeAdminMonitorV2Thread");
} }
// After processing the above, various parts of the check() method will // After processing the above, various parts of the check() method will
// take and drop the read / write lock as needed. Aside from the // take and drop the read / write lock as needed. Aside from the
@ -345,12 +345,12 @@ public class DatanodeAdminBackoffMonitor extends DatanodeAdminMonitorBase
// which added the node to the cancelled list. Therefore expired // which added the node to the cancelled list. Therefore expired
// maintenance nodes do not need to be added to the toRemove list. // maintenance nodes do not need to be added to the toRemove list.
dnAdmin.stopMaintenance(dn); dnAdmin.stopMaintenance(dn);
namesystem.writeUnlock(); namesystem.writeUnlock("processMaintenanceNodes");
namesystem.writeLock(); namesystem.writeLock();
} }
} }
} finally { } finally {
namesystem.writeUnlock(); namesystem.writeUnlock("processMaintenanceNodes");
} }
} }
@ -409,7 +409,7 @@ public class DatanodeAdminBackoffMonitor extends DatanodeAdminMonitorBase
} }
} }
} finally { } finally {
namesystem.writeUnlock(); namesystem.writeUnlock("processCompletedNodes");
} }
} }
@ -531,7 +531,7 @@ public class DatanodeAdminBackoffMonitor extends DatanodeAdminMonitorBase
// replication // replication
if (blocksProcessed >= blocksPerLock) { if (blocksProcessed >= blocksPerLock) {
blocksProcessed = 0; blocksProcessed = 0;
namesystem.writeUnlock(); namesystem.writeUnlock("moveBlocksToPending");
namesystem.writeLock(); namesystem.writeLock();
} }
blocksProcessed++; blocksProcessed++;
@ -553,7 +553,7 @@ public class DatanodeAdminBackoffMonitor extends DatanodeAdminMonitorBase
} }
} }
} finally { } finally {
namesystem.writeUnlock(); namesystem.writeUnlock("moveBlocksToPending");
} }
LOG.debug("{} blocks are now pending replication", pendingCount); LOG.debug("{} blocks are now pending replication", pendingCount);
} }
@ -637,7 +637,7 @@ public class DatanodeAdminBackoffMonitor extends DatanodeAdminMonitorBase
try { try {
storage = dn.getStorageInfos(); storage = dn.getStorageInfos();
} finally { } finally {
namesystem.readUnlock(); namesystem.readUnlock("scanDatanodeStorage");
} }
for (DatanodeStorageInfo s : storage) { for (DatanodeStorageInfo s : storage) {
@ -667,7 +667,7 @@ public class DatanodeAdminBackoffMonitor extends DatanodeAdminMonitorBase
numBlocksChecked++; numBlocksChecked++;
} }
} finally { } finally {
namesystem.readUnlock(); namesystem.readUnlock("scanDatanodeStorage");
} }
} }
} }
@ -722,7 +722,7 @@ public class DatanodeAdminBackoffMonitor extends DatanodeAdminMonitorBase
suspectBlocks.getOutOfServiceBlockCount()); suspectBlocks.getOutOfServiceBlockCount());
} }
} finally { } finally {
namesystem.writeUnlock(); namesystem.writeUnlock("processPendingReplication");
} }
} }

View File

@ -158,7 +158,7 @@ public class DatanodeAdminDefaultMonitor extends DatanodeAdminMonitorBase
LOG.warn("DatanodeAdminMonitor caught exception when processing node.", LOG.warn("DatanodeAdminMonitor caught exception when processing node.",
e); e);
} finally { } finally {
namesystem.writeUnlock(); namesystem.writeUnlock("DatanodeAdminMonitorThread");
} }
if (numBlocksChecked + numNodesChecked > 0) { if (numBlocksChecked + numNodesChecked > 0) {
LOG.info("Checked {} blocks and {} nodes this tick. {} nodes are now " + LOG.info("Checked {} blocks and {} nodes this tick. {} nodes are now " +
@ -373,7 +373,7 @@ public class DatanodeAdminDefaultMonitor extends DatanodeAdminMonitorBase
// lock. // lock.
// Yielding is required in case of block number is greater than the // Yielding is required in case of block number is greater than the
// configured per-iteration-limit. // configured per-iteration-limit.
namesystem.writeUnlock(); namesystem.writeUnlock("processBlocksInternal");
try { try {
LOG.debug("Yielded lock during decommission/maintenance check"); LOG.debug("Yielded lock during decommission/maintenance check");
Thread.sleep(0, 500); Thread.sleep(0, 500);

View File

@ -852,7 +852,7 @@ public class DatanodeManager {
+ node + " does not exist"); + node + " does not exist");
} }
} finally { } finally {
namesystem.writeUnlock(); namesystem.writeUnlock("removeDatanode");
} }
} }
@ -1296,7 +1296,7 @@ public class DatanodeManager {
refreshDatanodes(); refreshDatanodes();
countSoftwareVersions(); countSoftwareVersions();
} finally { } finally {
namesystem.writeUnlock(); namesystem.writeUnlock("refreshNodes");
} }
} }

View File

@ -503,7 +503,7 @@ class HeartbeatManager implements DatanodeStatistics {
try { try {
dm.removeDeadDatanode(dead, !dead.isMaintenance()); dm.removeDeadDatanode(dead, !dead.isMaintenance());
} finally { } finally {
namesystem.writeUnlock(); namesystem.writeUnlock("removeDeadDatanode");
} }
} }
if (failedStorage != null) { if (failedStorage != null) {
@ -512,7 +512,7 @@ class HeartbeatManager implements DatanodeStatistics {
try { try {
blockManager.removeBlocksAssociatedTo(failedStorage); blockManager.removeBlocksAssociatedTo(failedStorage);
} finally { } finally {
namesystem.writeUnlock(); namesystem.writeUnlock("removeBlocksAssociatedTo");
} }
} }
} }

View File

@ -222,7 +222,7 @@ public class BackupImage extends FSImage {
try { try {
getNamesystem().dir.updateCountForQuota(); getNamesystem().dir.updateCountForQuota();
} finally { } finally {
getNamesystem().writeUnlock(); getNamesystem().writeUnlock("applyEdits");
} }
} finally { } finally {
backupInputStream.clear(); backupInputStream.clear();

View File

@ -250,7 +250,7 @@ class Checkpointer extends Daemon {
sig.mostRecentCheckpointTxId); sig.mostRecentCheckpointTxId);
bnImage.reloadFromImageFile(file, backupNode.getNamesystem()); bnImage.reloadFromImageFile(file, backupNode.getNamesystem());
} finally { } finally {
backupNode.namesystem.writeUnlock(); backupNode.namesystem.writeUnlock("doCheckpointByBackupNode");
} }
} }
rollForwardByApplyingLogs(manifest, bnImage, backupNode.getNamesystem()); rollForwardByApplyingLogs(manifest, bnImage, backupNode.getNamesystem());

View File

@ -192,7 +192,7 @@ public class EncryptionZoneManager {
try { try {
iip = dir.resolvePath(pc, zone, DirOp.READ); iip = dir.resolvePath(pc, zone, DirOp.READ);
} finally { } finally {
dir.getFSNamesystem().readUnlock(); dir.getFSNamesystem().readUnlock("pauseForTestingAfterNthCheckpoint");
} }
reencryptionHandler reencryptionHandler
.pauseForTestingAfterNthCheckpoint(iip.getLastINode().getId(), count); .pauseForTestingAfterNthCheckpoint(iip.getLastINode().getId(), count);
@ -224,7 +224,7 @@ public class EncryptionZoneManager {
return getReencryptionStatus().getZoneStatus(inode.getId()); return getReencryptionStatus().getZoneStatus(inode.getId());
} finally { } finally {
dir.readUnlock(); dir.readUnlock();
dir.getFSNamesystem().readUnlock(); dir.getFSNamesystem().readUnlock("getZoneStatus");
} }
} }
@ -285,7 +285,7 @@ public class EncryptionZoneManager {
try { try {
reencryptionHandler.stopThreads(); reencryptionHandler.stopThreads();
} finally { } finally {
dir.getFSNamesystem().writeUnlock(); dir.getFSNamesystem().writeUnlock("stopReencryptThread");
} }
if (reencryptHandlerExecutor != null) { if (reencryptHandlerExecutor != null) {
reencryptHandlerExecutor.shutdownNow(); reencryptHandlerExecutor.shutdownNow();

View File

@ -656,7 +656,7 @@ final class FSDirEncryptionZoneOp {
Preconditions.checkNotNull(ezKeyName); Preconditions.checkNotNull(ezKeyName);
// Generate EDEK while not holding the fsn lock. // Generate EDEK while not holding the fsn lock.
fsn.writeUnlock(); fsn.writeUnlock("getEncryptionKeyInfo");
try { try {
EncryptionFaultInjector.getInstance().startFileBeforeGenerateKey(); EncryptionFaultInjector.getInstance().startFileBeforeGenerateKey();
return new EncryptionKeyInfo(protocolVersion, suite, ezKeyName, return new EncryptionKeyInfo(protocolVersion, suite, ezKeyName,
@ -733,7 +733,7 @@ final class FSDirEncryptionZoneOp {
dir.ezManager.checkEncryptionZoneRoot(iip.getLastINode(), zone); dir.ezManager.checkEncryptionZoneRoot(iip.getLastINode(), zone);
return dir.ezManager.getKeyName(iip); return dir.ezManager.getKeyName(iip);
} finally { } finally {
dir.getFSNamesystem().readUnlock(); dir.getFSNamesystem().readUnlock("getKeyNameForZone");
} }
} }
} }

View File

@ -1798,6 +1798,7 @@ public class FSNamesystem implements Namesystem, FSNamesystemMBean,
this.fsLock.readUnlock(); this.fsLock.readUnlock();
} }
@Override
public void readUnlock(String opName) { public void readUnlock(String opName) {
this.fsLock.readUnlock(opName); this.fsLock.readUnlock(opName);
} }
@ -1822,6 +1823,7 @@ public class FSNamesystem implements Namesystem, FSNamesystemMBean,
this.fsLock.writeUnlock(); this.fsLock.writeUnlock();
} }
@Override
public void writeUnlock(String opName) { public void writeUnlock(String opName) {
this.fsLock.writeUnlock(opName); this.fsLock.writeUnlock(opName);
} }

View File

@ -243,7 +243,7 @@ public class FsImageValidation {
loader.load(fsImageFile, false); loader.load(fsImageFile, false);
} finally { } finally {
namesystem.getFSDirectory().writeUnlock(); namesystem.getFSDirectory().writeUnlock();
namesystem.writeUnlock(); namesystem.writeUnlock("loadImage");
} }
} }
t.cancel(); t.cancel();

View File

@ -2090,7 +2090,7 @@ public class NameNode extends ReconfigurableBase implements
@Override @Override
public void writeUnlock() { public void writeUnlock() {
namesystem.unlockRetryCache(); namesystem.unlockRetryCache();
namesystem.writeUnlock(); namesystem.writeUnlock("HAState");
} }
/** Check if an operation of given category is allowed */ /** Check if an operation of given category is allowed */
@ -2254,7 +2254,7 @@ public class NameNode extends ReconfigurableBase implements
throw new ReconfigurationException(property, newVal, getConf().get( throw new ReconfigurationException(property, newVal, getConf().get(
property), e); property), e);
} finally { } finally {
namesystem.writeUnlock(); namesystem.writeUnlock("reconfReplicationParameters");
} }
} }
@ -2291,7 +2291,7 @@ public class NameNode extends ReconfigurableBase implements
throw new ReconfigurationException(property, newVal, getConf().get( throw new ReconfigurationException(property, newVal, getConf().get(
property), nfe); property), nfe);
} finally { } finally {
namesystem.writeUnlock(); namesystem.writeUnlock("reconfHeartbeatInterval");
LOG.info("RECONFIGURE* changed heartbeatInterval to " LOG.info("RECONFIGURE* changed heartbeatInterval to "
+ datanodeManager.getHeartbeatInterval()); + datanodeManager.getHeartbeatInterval());
} }
@ -2315,7 +2315,7 @@ public class NameNode extends ReconfigurableBase implements
throw new ReconfigurationException(property, newVal, getConf().get( throw new ReconfigurationException(property, newVal, getConf().get(
property), nfe); property), nfe);
} finally { } finally {
namesystem.writeUnlock(); namesystem.writeUnlock("reconfHeartbeatRecheckInterval");
LOG.info("RECONFIGURE* changed heartbeatRecheckInterval to " LOG.info("RECONFIGURE* changed heartbeatRecheckInterval to "
+ datanodeManager.getHeartbeatRecheckInterval()); + datanodeManager.getHeartbeatRecheckInterval());
} }
@ -2434,7 +2434,7 @@ public class NameNode extends ReconfigurableBase implements
throw new ReconfigurationException(property, newVal, getConf().get( throw new ReconfigurationException(property, newVal, getConf().get(
property), e); property), e);
} finally { } finally {
namesystem.writeUnlock(); namesystem.writeUnlock("reconfigureSlowNodesParameters");
} }
} }
@ -2454,7 +2454,7 @@ public class NameNode extends ReconfigurableBase implements
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
throw new ReconfigurationException(property, newVal, getConf().get(property), e); throw new ReconfigurationException(property, newVal, getConf().get(property), e);
} finally { } finally {
namesystem.writeUnlock(); namesystem.writeUnlock("reconfigureBlockInvalidateLimit");
} }
} }

View File

@ -350,7 +350,7 @@ public class ReencryptionHandler implements Runnable {
getReencryptionStatus().markZoneStarted(zoneId); getReencryptionStatus().markZoneStarted(zoneId);
resetSubmissionTracker(zoneId); resetSubmissionTracker(zoneId);
} finally { } finally {
dir.getFSNamesystem().readUnlock(); dir.getFSNamesystem().readUnlock("reEncryptThread");
} }
try { try {

View File

@ -1098,7 +1098,7 @@ public class SecondaryNameNode implements Runnable,
try { try {
dstImage.reloadFromImageFile(file, dstNamesystem); dstImage.reloadFromImageFile(file, dstNamesystem);
} finally { } finally {
dstNamesystem.writeUnlock(); dstNamesystem.writeUnlock("reloadFromImageFile");
} }
dstNamesystem.imageLoadComplete(); dstNamesystem.imageLoadComplete();
} }

View File

@ -385,7 +385,7 @@ public class EditLogTailer {
lastLoadedTxnId = image.getLastAppliedTxId(); lastLoadedTxnId = image.getLastAppliedTxId();
return editsLoaded; return editsLoaded;
} finally { } finally {
namesystem.writeUnlock(); namesystem.writeUnlock("doTailEdits");
} }
} }

View File

@ -79,7 +79,7 @@ public class SnapshotDeletionGc {
LOG.error("Failed to chooseDeletedSnapshot", e); LOG.error("Failed to chooseDeletedSnapshot", e);
throw e; throw e;
} finally { } finally {
namesystem.readUnlock(); namesystem.readUnlock("gcDeletedSnapshot");
} }
if (deleted == null) { if (deleted == null) {
LOG.trace("{}: no snapshots are marked as deleted.", name); LOG.trace("{}: no snapshots are marked as deleted.", name);

View File

@ -28,6 +28,12 @@ public interface RwLock {
/** Release read lock. */ /** Release read lock. */
public void readUnlock(); public void readUnlock();
/**
* Release read lock with operation name.
* @param opName Option name.
*/
public void readUnlock(String opName);
/** Check if the current thread holds read lock. */ /** Check if the current thread holds read lock. */
public boolean hasReadLock(); public boolean hasReadLock();
@ -40,6 +46,12 @@ public interface RwLock {
/** Release write lock. */ /** Release write lock. */
public void writeUnlock(); public void writeUnlock();
/**
* Release write lock with operation name.
* @param opName Option name.
*/
public void writeUnlock(String opName);
/** Check if the current thread holds write lock. */ /** Check if the current thread holds write lock. */
public boolean hasWriteLock(); public boolean hasWriteLock();
} }