Skip to content

Commit

Permalink
central: Avoid getting workspace writeLock in getWorkspace
Browse files Browse the repository at this point in the history
We move the code needing the writeLock into another thread.
getWorkspace is called from many places including places holding
the workspace readLock. So we move the code needing the writeLock
out of the caller's thread.

Fixes #5110

Signed-off-by: BJ Hargrave <bj@hargrave.dev>
  • Loading branch information
bjhargrave committed Feb 22, 2022
1 parent 5005fc0 commit 986d53a
Showing 1 changed file with 45 additions and 23 deletions.
68 changes: 45 additions & 23 deletions bndtools.core/src/bndtools/central/Central.java
Original file line number Diff line number Diff line change
Expand Up @@ -224,54 +224,76 @@ public static Workspace getWorkspace() throws Exception {
throw new IllegalStateException("Central is not initialised");
}
final Workspace ws;
java.util.function.Consumer<Workspace> resolve = null;
Consumer<Workspace> afterLock = null;
synchronized (workspace) {
if (workspace.peek() == null) { // No workspace has been created
ws = workspace.get();
// Resolve with new workspace
resolve = tryResolve(anyWorkspaceDeferred);
afterLock = tryResolve(anyWorkspaceDeferred);
if (!ws.isDefaultWorkspace()) {
resolve = resolve.andThen(tryResolve(cnfWorkspaceDeferred));
afterLock = afterLock.andThen(tryResolve(cnfWorkspaceDeferred));
}
} else {
ws = workspace.get();
// get the parent directory of the "cnf" project, if there is
// one
File workspaceDirectory = getWorkspaceDirectory();
// Check to see if we need to convert it...
// Check to see if we need to adjust it...
if (workspaceDirectory != null && !workspaceDirectory.equals(ws.getBase())) {
// There is a "cnf" project and the current workspace is
// not the same as the directory the cnf project is in,
// so switch the workspace to the directory
ws.writeLocked(() -> {
ws.setFileSystem(workspaceDirectory, Workspace.CNFDIR);
ws.forceRefresh();
ws.refresh();
ws.refreshProjects();
return null;
});
resolve = tryResolve(cnfWorkspaceDeferred);
afterLock = Central::adjustWorkspace;
} else if (workspaceDirectory == null && !ws.isDefaultWorkspace()) {
// There is no "cnf" project and the current workspace is
// not the default, so switch the workspace to the default
cnfWorkspaceDeferred = promiseFactory().deferred();
ws.writeLocked(() -> {
ws.setFileSystem(Workspace.BND_DEFAULT_WS, Workspace.CNFDIR);
ws.forceRefresh();
ws.refresh();
ws.refreshProjects();
return null;
});
afterLock = Central::adjustWorkspace;
}
}
}
if (resolve != null) { // resolve deferred if requested
resolve.accept(ws);
if (afterLock != null) { // perform after lock action
afterLock.accept(ws);
}
return ws;
}

private static <T> java.util.function.Consumer<T> tryResolve(Deferred<T> deferred) {
private static void adjustWorkspace(Workspace ws) throws Exception {
// Get write lock on another thread
promiseFactory().submit(() -> {
Consumer<Workspace> afterLock = ws.writeLocked(() -> {
// get the parent directory of the "cnf" project, if there is
// one
File workspaceDirectory = getWorkspaceDirectory();
// Check to see if we need to convert it...
if (workspaceDirectory != null && !workspaceDirectory.equals(ws.getBase())) {
// There is a "cnf" project and the current workspace is
// not the same as the directory the cnf project is in,
// so switch the workspace to the directory
ws.setFileSystem(workspaceDirectory, Workspace.CNFDIR);
ws.forceRefresh();
ws.refresh();
ws.refreshProjects();
return tryResolve(cnfWorkspaceDeferred);
} else if (workspaceDirectory == null && !ws.isDefaultWorkspace()) {
// There is no "cnf" project and the current workspace is
// not the default, so switch the workspace to the default
cnfWorkspaceDeferred = promiseFactory().deferred();
ws.setFileSystem(Workspace.BND_DEFAULT_WS, Workspace.CNFDIR);
ws.forceRefresh();
ws.refresh();
ws.refreshProjects();
return null;
}
return null;
});
if (afterLock != null) { // perform after lock action
afterLock.accept(ws);
}
return ws;
});
}

private static <T> Consumer<T> tryResolve(Deferred<T> deferred) {
return value -> {
try {
deferred.resolve(value);
Expand Down

0 comments on commit 986d53a

Please sign in to comment.