@Override public String toString() { return "exclusiveLockOwner=" + (hasExclusiveLock() ? getExclusiveLockProcIdOwner() : "NONE") + ", sharedLockCount=" + getSharedLockCount() + ", waitingProcCount=" + queue.size(); } }
public boolean tryExclusiveLock(Procedure<?> proc) { if (isLocked()) { return hasLockAccess(proc); } exclusiveLockOwnerProcedure = proc; return true; }
public SchemaLocking(Function<Long, Procedure<?>> procedureRetriever) { this.procedureRetriever = procedureRetriever; this.metaLock = new LockAndQueue(procedureRetriever); }
/** * @return whether we have succesfully acquired the shared lock. */ public boolean trySharedLock(Procedure<?> proc) { if (hasExclusiveLock() && !hasLockAccess(proc)) { return false; } // If no one holds the xlock, then we are free to hold the sharedLock // If the parent proc or we have already held the xlock, then we return true here as // xlock is more powerful then shared lock. sharedLock++; return true; }
@Test public void testHasLockAccess() { Map<Long, NoopProcedure<Void>> procMap = new HashMap<>(); for (long i = 1; i <= 10; i++) { NoopProcedure<Void> proc = new NoopProcedure<>(); proc.setProcId(i); if (i > 1) { proc.setParentProcId(i - 1); proc.setRootProcId(1); } procMap.put(i, proc); } LockAndQueue laq = new LockAndQueue(procMap::get); for (long i = 1; i <= 10; i++) { assertFalse(laq.hasLockAccess(procMap.get(i))); } for (long i = 1; i <= 10; i++) { NoopProcedure<Void> procHasLock = procMap.get(i); laq.tryExclusiveLock(procHasLock); for (long j = 1; j < i; j++) { assertFalse(laq.hasLockAccess(procMap.get(j))); } for (long j = i; j <= 10; j++) { assertTrue(laq.hasLockAccess(procMap.get(j))); } laq.releaseExclusiveLock(procHasLock); } } }
private LockedResource createLockedResource(LockedResourceType resourceType, String resourceName, LockAndQueue queue) { LockType lockType; Procedure<?> exclusiveLockOwnerProcedure; int sharedLockCount; if (queue.hasExclusiveLock()) { lockType = LockType.EXCLUSIVE; exclusiveLockOwnerProcedure = queue.getExclusiveLockOwnerProcedure(); sharedLockCount = 0; } else { lockType = LockType.SHARED; exclusiveLockOwnerProcedure = null; sharedLockCount = queue.getSharedLockCount(); } List<Procedure<?>> waitingProcedures = new ArrayList<>(); queue.filterWaitingQueue(p -> p instanceof LockProcedure) .forEachOrdered(waitingProcedures::add); return new LockedResource(resourceType, resourceName, lockType, exclusiveLockOwnerProcedure, sharedLockCount, waitingProcedures); }
@Override public String toString() { return "exclusiveLockOwner=" + (hasExclusiveLock()? getExclusiveLockProcIdOwner(): "NONE") + ", sharedLockCount=" + getSharedLockCount() + ", waitingProcCount=" + size(); } }
if (!regionLocks[i].tryExclusiveLock(procedure)) { LOG.info("Waiting on xlock for {} held by pid={}", procedure, regionLocks[i].getExclusiveLockProcIdOwner()); waitProcedure(regionLocks[i], procedure); hasLock = false; while (i-- > 0) { regionLocks[i].releaseExclusiveLock(procedure);
/** * @return whether we should wake the procedures waiting on the lock here. */ public boolean releaseSharedLock() { // hasExclusiveLock could be true, it usually means we acquire shared lock while we or our // parent have held the xlock. And since there is still an exclusive lock, we do not need to // wake any procedures. return --sharedLock == 0 && !hasExclusiveLock(); }
/** * Suspend the procedure if the specified namespace is already locked. * @see #wakeNamespaceExclusiveLock(Procedure,String) * @param procedure the procedure trying to acquire the lock * @param namespace Namespace to lock * @return true if the procedure has to wait for the namespace to be available */ public boolean waitNamespaceExclusiveLock(Procedure<?> procedure, String namespace) { schedLock(); try { final LockAndQueue systemNamespaceTableLock = locking.getTableLock(TableProcedureInterface.DUMMY_NAMESPACE_TABLE_NAME); if (!systemNamespaceTableLock.trySharedLock(procedure)) { waitProcedure(systemNamespaceTableLock, procedure); logLockedResource(LockedResourceType.TABLE, TableProcedureInterface.DUMMY_NAMESPACE_TABLE_NAME.getNameAsString()); return true; } final LockAndQueue namespaceLock = locking.getNamespaceLock(namespace); if (!namespaceLock.tryExclusiveLock(procedure)) { systemNamespaceTableLock.releaseSharedLock(); waitProcedure(namespaceLock, procedure); logLockedResource(LockedResourceType.NAMESPACE, namespace); return true; } return false; } finally { schedUnlock(); } }
/** * Try to acquire the exclusive lock on meta. * @see #wakeMetaExclusiveLock(Procedure) * @param procedure the procedure trying to acquire the lock * @return true if the procedure has to wait for meta to be available * @deprecated only used for {@link RecoverMetaProcedure}. Should be removed along with * {@link RecoverMetaProcedure}. */ @Deprecated public boolean waitMetaExclusiveLock(Procedure<?> procedure) { schedLock(); try { final LockAndQueue lock = locking.getMetaLock(); if (lock.tryExclusiveLock(procedure)) { removeFromRunQueue(metaRunQueue, getMetaQueue(), () -> procedure + " held exclusive lock"); return false; } waitProcedure(lock, procedure); logLockedResource(LockedResourceType.META, TableName.META_TABLE_NAME.getNameAsString()); return true; } finally { schedUnlock(); } }
if (regionLock.releaseExclusiveLock(procedure)) { if (!regionLock.isWaitingQueueEmpty()) { nextProcs[numProcs++] = regionLock.removeFirst(); } else { locking.removeRegionLock(regionInfo[i].getEncodedName());
private <T> void addToLockedResources(List<LockedResource> lockedResources, Map<T, LockAndQueue> locks, Function<T, String> keyTransformer, LockedResourceType resourcesType) { locks.entrySet().stream().filter(e -> e.getValue().isLocked()) .map(e -> createLockedResource(resourcesType, keyTransformer.apply(e.getKey()), e.getValue())) .forEachOrdered(lockedResources::add); }
/** * Wake the procedures waiting for the specified namespace * @see #waitNamespaceExclusiveLock(Procedure,String) * @param procedure the procedure releasing the lock * @param namespace the namespace that has the exclusive lock */ public void wakeNamespaceExclusiveLock(final Procedure<?> procedure, final String namespace) { schedLock(); try { final LockAndQueue namespaceLock = locking.getNamespaceLock(namespace); final LockAndQueue systemNamespaceTableLock = locking.getTableLock(TableProcedureInterface.DUMMY_NAMESPACE_TABLE_NAME); int waitingCount = 0; if (namespaceLock.releaseExclusiveLock(procedure)) { waitingCount += wakeWaitingProcedures(namespaceLock); } if (systemNamespaceTableLock.releaseSharedLock()) { addToRunQueue(tableRunQueue, getTableQueue(TableProcedureInterface.DUMMY_NAMESPACE_TABLE_NAME), () -> procedure + " released namespace exclusive lock"); waitingCount += wakeWaitingProcedures(systemNamespaceTableLock); } wakePollIfNeeded(waitingCount); } finally { schedUnlock(); } }
/** * Wake the procedures waiting for meta. * @see #waitMetaExclusiveLock(Procedure) * @param procedure the procedure releasing the lock * @deprecated only used for {@link RecoverMetaProcedure}. Should be removed along with * {@link RecoverMetaProcedure}. */ @Deprecated public void wakeMetaExclusiveLock(Procedure<?> procedure) { schedLock(); try { final LockAndQueue lock = locking.getMetaLock(); lock.releaseExclusiveLock(procedure); addToRunQueue(metaRunQueue, getMetaQueue(), () -> procedure + " released exclusive lock"); int waitingCount = wakeWaitingProcedures(lock); wakePollIfNeeded(waitingCount); } finally { schedUnlock(); } }
@Override public boolean isLockOwner(long procId) { return getExclusiveLockProcIdOwner() == procId; }
protected void waitProcedure(LockAndQueue lockAndQueue, final Procedure proc) { lockAndQueue.addLast(proc); }
@Test public void testHasLockAccess() { Map<Long, NoopProcedure<Void>> procMap = new HashMap<>(); for (long i = 1; i <= 10; i++) { NoopProcedure<Void> proc = new NoopProcedure<>(); proc.setProcId(i); if (i > 1) { proc.setParentProcId(i - 1); proc.setRootProcId(1); } procMap.put(i, proc); } LockAndQueue laq = new LockAndQueue(procMap::get); for (long i = 1; i <= 10; i++) { assertFalse(laq.hasLockAccess(procMap.get(i))); } for (long i = 1; i <= 10; i++) { NoopProcedure<Void> procHasLock = procMap.get(i); laq.tryExclusiveLock(procHasLock); for (long j = 1; j < i; j++) { assertFalse(laq.hasLockAccess(procMap.get(j))); } for (long j = i; j <= 10; j++) { assertTrue(laq.hasLockAccess(procMap.get(j))); } laq.releaseExclusiveLock(procHasLock); } } }
/** * @return whether we have succesfully acquired the shared lock. */ public boolean trySharedLock(Procedure<?> proc) { if (hasExclusiveLock() && !hasLockAccess(proc)) { return false; } // If no one holds the xlock, then we are free to hold the sharedLock // If the parent proc or we have already held the xlock, then we return true here as // xlock is more powerful then shared lock. sharedLock++; return true; }
/** * @return whether we should wake the procedures waiting on the lock here. */ public boolean releaseSharedLock() { // hasExclusiveLock could be true, it usually means we acquire shared lock while we or our // parent have held the xlock. And since there is still an exclusive lock, we do not need to // wake any procedures. return --sharedLock == 0 && !hasExclusiveLock(); }