Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ protected static class FDBDirectoryLock extends Lock {
*/
private FDBRecordContext closingContext = null;
private final Object fileLockSetLock = new Object();
private boolean clearingLockNow = false;
private final Object clearingLockNowLock = new Object();

private FDBDirectoryLock(final AgilityContext agilityContext, final String lockName, byte[] fileLockKey, int timeWindowMilliseconds) {
this.agilityContext = agilityContext;
Expand Down Expand Up @@ -210,6 +212,17 @@ private void fileLockCheckNewLock(byte[] val, long nowMillis) {
}

private void fileLockClearFlushAndClose(boolean isRecovery) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It sounds like there are some concurrency challenges with FDBDirectoryLock, it would probably be good to add some tests that try to clear this lock concurrently.

if (clearingLockNow) {
// Here: this function is being called from too many paths. Until cleanup, this guard is here to avoid recursions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If indeed all that the synchronized block is trying to do is protect a boolean, then an AtomicBoolean can do the job. It seems as if we are not trying to create a totally exclusive code flow but just prevent "too many" runs of the same methods, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to AtomicBoolean.
The code supposed to prevent concurrent lock clears, which seems to be caused by concurrent, possibly recursive, calls to directory close.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had to undo the AtomicBoolean use as some tests were failing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious: Which tests failed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure, but it might have been testMultiClose.

return;
}
synchronized (clearingLockNowLock) {
// repeat under lock
if (clearingLockNow) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've only seen it for lazy instantiation, but would it be worth to duplicate this before the synchronized lock to avoid entering the Synchronized lock if already clearing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can either do that or remove the synchronized lock altogether (since our concern is recursion, the synchronized lock might be an overkill...)

return;
}
clearingLockNow = true;
}
Function<FDBRecordContext, CompletableFuture<Void>> fileLockFunc = aContext ->
aContext.ensureActive().get(fileLockKey)
.thenAccept(val -> {
Expand All @@ -224,6 +237,12 @@ private void fileLockClearFlushAndClose(boolean isRecovery) {
throw new AlreadyClosedException("FileLock: Expected to be locked during close.This=" + this + " existingUuid=" + existingUuid); // The string append methods should handle null arguments.
}
}
})
.whenComplete((res, err) -> {
synchronized (clearingLockNowLock) {
// clearing under lock to avoid spotbugsMain's "Inconsistent synchronization" issue.
clearingLockNow = false;
}
});

if (agilityContext.isClosed()) {
Expand Down
Loading