Skip to content

Commit

Permalink
HBASE-27905 Directly schedule procedures that do not need to acquire …
Browse files Browse the repository at this point in the history
…locks
  • Loading branch information
huiruan committed Jun 4, 2023
1 parent 7b571ca commit 867c44c
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,10 @@ protected boolean waitInitialized(TEnvironment env) {
return false;
}

public boolean needLock() {
return true;
}

/**
* The user should override this method if they need a lock on an Entity. A lock can be anything,
* and it is up to the implementor. The Procedure Framework will call this method just before it
Expand Down Expand Up @@ -974,6 +978,9 @@ final LockState doAcquireLock(TEnvironment env, ProcedureStore store) {
if (waitInitialized(env)) {
return LockState.LOCK_EVENT_WAIT;
}
if (!needLock()) {
return LockState.LOCK_ACQUIRED;
}
if (lockedWhenLoading) {
// reset it so we will not consider it anymore
lockedWhenLoading = false;
Expand All @@ -1000,6 +1007,10 @@ final LockState doAcquireLock(TEnvironment env, ProcedureStore store) {
* Internal method called by the ProcedureExecutor that starts the user-level code releaseLock().
*/
final void doReleaseLock(TEnvironment env, ProcedureStore store) {
if (!needLock()) {
return;
}

locked = false;
// persist that we have released the lock. This must be done before we actually release the
// lock. Another procedure may take this lock immediately after we release the lock, and if we
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,19 +149,22 @@ private <T extends Comparable<T>> void doAdd(FairQueue<T> fairq, Queue<T> queue,
Procedure<?> proc, boolean addFront) {
queue.add(proc, addFront);
// For the following conditions, we will put the queue back into execution
// 1. The procedure has already held the lock, or the lock has been restored when restarting,
// 1. The procedure does not need any lock at all.
// 2. The procedure has already held the lock, or the lock has been restored when restarting,
// which means it can be executed immediately.
// 2. The exclusive lock for this queue has not been held.
// 3. The given procedure has the exclusive lock permission for this queue.
// 3. The exclusive lock for this queue has not been held.
// 4. The given procedure has the exclusive lock permission for this queue.
Supplier<String> reason = null;
if (proc.hasLock()) {
if (!proc.needLock()) {
reason = () -> proc + " does not need any lock";
} else if (proc.needLock() && proc.hasLock()) {
reason = () -> proc + " has lock";
} else if (proc.isLockedWhenLoading()) {
reason = () -> proc + " restores lock when restarting";
} else if (!queue.getLockStatus().hasExclusiveLock()) {
reason = () -> "the exclusive lock is not held by anyone when adding " + proc;
} else if (queue.getLockStatus().hasLockAccess(proc)) {
reason = () -> proc + " has the excusive lock access";
reason = () -> proc + " has the exclusive lock access";
}
if (reason != null) {
addToRunQueue(fairq, queue, reason);
Expand Down Expand Up @@ -219,6 +222,9 @@ private <T extends Comparable<T>> Procedure<?> doPoll(final FairQueue<T> fairq)
// procedures, then we give up and remove the queue from run queue.
for (int i = 0, n = rq.size(); i < n; i++) {
Procedure<?> proc = rq.poll();
if (!proc.needLock()) {
return proc;
}
if (isLockReady(proc, rq)) {
// the queue is empty, remove from run queue
if (rq.isEmpty()) {
Expand Down Expand Up @@ -368,6 +374,13 @@ private static <T extends Comparable<T>> void addToRunQueue(FairQueue<T> fairq,

private static <T extends Comparable<T>> void removeFromRunQueue(FairQueue<T> fairq,
Queue<T> queue, Supplier<String> reason) {
if (hasNoLockNeededProcedure(queue)) {
if (LOG.isTraceEnabled()) {
LOG.trace("DO NOT remove {} from run queue because There are still procedures in the "
+ "queue that do not need to acquire locks", queue);
}
return;
}
if (LOG.isTraceEnabled()) {
LOG.trace("Remove {} from run queue because: {}", queue, reason.get());
}
Expand All @@ -376,6 +389,19 @@ private static <T extends Comparable<T>> void removeFromRunQueue(FairQueue<T> fa
}
}

private static <T extends Comparable<T>> boolean hasNoLockNeededProcedure(Queue<T> q) {
boolean ret = false;
// TODO: Iterate Queue in a more efficient way ?
for (int i = 0, n = q.size(); i < n; i++) {
Procedure<?> proc = q.poll();
if (!proc.needLock()) {
ret = true;
}
q.add(proc, false);
}
return ret;
}

// ============================================================================
// Table Queue Lookup Helpers
// ============================================================================
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1200,4 +1200,28 @@ public void testAcquireSharedLockWhileParentHoldingExclusiveLock() {
queue.wakeRegion(proc, regionInfo);
queue.wakeTableExclusiveLock(parentProc, tableName);
}

@Test
public void testDirectlyScheduleProcedureThatDoesNotNeedLock() {
TableName tableName = TableName.valueOf(name.getMethodName());
TestTableProcedure xLockNeededProc =
new TestTableProcedure(1, tableName, TableOperationType.DELETE);
TestTableProcedure noLockNeededProc =
new TestTableProcedure(2, tableName, TableOperationType.READ) {
@Override
public boolean needLock() {
return false;
}
};
queue.addBack(xLockNeededProc);
queue.addBack(noLockNeededProc);

assertSame(xLockNeededProc, queue.poll());
assertEquals(1, queue.size());

// now the table exclusive lock has been acquired
assertFalse(queue.waitTableExclusiveLock(xLockNeededProc, tableName));

assertSame(noLockNeededProc, queue.poll());
}
}

0 comments on commit 867c44c

Please sign in to comment.