Skip to content

Commit 986d53a

Browse files
committed
central: Avoid getting workspace writeLock in getWorkspace
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 <[email protected]>
1 parent 5005fc0 commit 986d53a

File tree

1 file changed

+45
-23
lines changed

1 file changed

+45
-23
lines changed

bndtools.core/src/bndtools/central/Central.java

Lines changed: 45 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -224,54 +224,76 @@ public static Workspace getWorkspace() throws Exception {
224224
throw new IllegalStateException("Central is not initialised");
225225
}
226226
final Workspace ws;
227-
java.util.function.Consumer<Workspace> resolve = null;
227+
Consumer<Workspace> afterLock = null;
228228
synchronized (workspace) {
229229
if (workspace.peek() == null) { // No workspace has been created
230230
ws = workspace.get();
231231
// Resolve with new workspace
232-
resolve = tryResolve(anyWorkspaceDeferred);
232+
afterLock = tryResolve(anyWorkspaceDeferred);
233233
if (!ws.isDefaultWorkspace()) {
234-
resolve = resolve.andThen(tryResolve(cnfWorkspaceDeferred));
234+
afterLock = afterLock.andThen(tryResolve(cnfWorkspaceDeferred));
235235
}
236236
} else {
237237
ws = workspace.get();
238238
// get the parent directory of the "cnf" project, if there is
239239
// one
240240
File workspaceDirectory = getWorkspaceDirectory();
241-
// Check to see if we need to convert it...
241+
// Check to see if we need to adjust it...
242242
if (workspaceDirectory != null && !workspaceDirectory.equals(ws.getBase())) {
243243
// There is a "cnf" project and the current workspace is
244244
// not the same as the directory the cnf project is in,
245245
// so switch the workspace to the directory
246-
ws.writeLocked(() -> {
247-
ws.setFileSystem(workspaceDirectory, Workspace.CNFDIR);
248-
ws.forceRefresh();
249-
ws.refresh();
250-
ws.refreshProjects();
251-
return null;
252-
});
253-
resolve = tryResolve(cnfWorkspaceDeferred);
246+
afterLock = Central::adjustWorkspace;
254247
} else if (workspaceDirectory == null && !ws.isDefaultWorkspace()) {
255248
// There is no "cnf" project and the current workspace is
256249
// not the default, so switch the workspace to the default
257-
cnfWorkspaceDeferred = promiseFactory().deferred();
258-
ws.writeLocked(() -> {
259-
ws.setFileSystem(Workspace.BND_DEFAULT_WS, Workspace.CNFDIR);
260-
ws.forceRefresh();
261-
ws.refresh();
262-
ws.refreshProjects();
263-
return null;
264-
});
250+
afterLock = Central::adjustWorkspace;
265251
}
266252
}
267253
}
268-
if (resolve != null) { // resolve deferred if requested
269-
resolve.accept(ws);
254+
if (afterLock != null) { // perform after lock action
255+
afterLock.accept(ws);
270256
}
271257
return ws;
272258
}
273259

274-
private static <T> java.util.function.Consumer<T> tryResolve(Deferred<T> deferred) {
260+
private static void adjustWorkspace(Workspace ws) throws Exception {
261+
// Get write lock on another thread
262+
promiseFactory().submit(() -> {
263+
Consumer<Workspace> afterLock = ws.writeLocked(() -> {
264+
// get the parent directory of the "cnf" project, if there is
265+
// one
266+
File workspaceDirectory = getWorkspaceDirectory();
267+
// Check to see if we need to convert it...
268+
if (workspaceDirectory != null && !workspaceDirectory.equals(ws.getBase())) {
269+
// There is a "cnf" project and the current workspace is
270+
// not the same as the directory the cnf project is in,
271+
// so switch the workspace to the directory
272+
ws.setFileSystem(workspaceDirectory, Workspace.CNFDIR);
273+
ws.forceRefresh();
274+
ws.refresh();
275+
ws.refreshProjects();
276+
return tryResolve(cnfWorkspaceDeferred);
277+
} else if (workspaceDirectory == null && !ws.isDefaultWorkspace()) {
278+
// There is no "cnf" project and the current workspace is
279+
// not the default, so switch the workspace to the default
280+
cnfWorkspaceDeferred = promiseFactory().deferred();
281+
ws.setFileSystem(Workspace.BND_DEFAULT_WS, Workspace.CNFDIR);
282+
ws.forceRefresh();
283+
ws.refresh();
284+
ws.refreshProjects();
285+
return null;
286+
}
287+
return null;
288+
});
289+
if (afterLock != null) { // perform after lock action
290+
afterLock.accept(ws);
291+
}
292+
return ws;
293+
});
294+
}
295+
296+
private static <T> Consumer<T> tryResolve(Deferred<T> deferred) {
275297
return value -> {
276298
try {
277299
deferred.resolve(value);

0 commit comments

Comments
 (0)