Skip to content

Commit 89befc3

Browse files
committed
Do one capability update at a time.
1 parent 3124f72 commit 89befc3

1 file changed

Lines changed: 9 additions & 2 deletions

File tree

rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/capabilities/CapabilityRegistration.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ public class CapabilityRegistration {
7575
private final Set<AbstractDynamicCapability<?>> staticCapabilities;
7676

7777
private final AtomicReference<Collection<ICapabilityParams>> lastParams = new AtomicReference<>(Collections.emptyList());
78+
private final AtomicReference<CompletableFuture<Void>> currentUpdate;
79+
7880
// Map of method names with current registration values
7981
private final Map<String, Registration> currentRegistrations = new ConcurrentHashMap<>();
8082

@@ -87,6 +89,7 @@ public CapabilityRegistration(LanguageClient client, Executor exec, ClientCapabi
8789
this.client = client;
8890
this.exec = exec;
8991
this.noop = CompletableFutureUtils.completedFuture(null, exec);
92+
this.currentUpdate = new AtomicReference<>(noop);
9093

9194
// Check whether to register capabilities dynamically or statically
9295
var dynamicCaps = new HashSet<AbstractDynamicCapability<?>>();
@@ -120,16 +123,19 @@ public void registerStaticCapabilities(ServerCapabilities result) {
120123
* @return A future that completes with a boolean that is false when any registration failed, and true otherwise.
121124
*/
122125
public CompletableFuture<Void> update(Collection<ICapabilityParams> languages) {
123-
logger.debug("Updating {} dynamic capabilities for {} languages", dynamicCapabilities.size(), languages.size());
124126
// Copy the contributions so we know we are looking at a stable collection of elements.
125-
126127
/*
127128
*VERY IMPORTANT* Setting the atomic reference from the thread that called us.
128129
We need to be sure that the `lastContributions` reference actually points to the most recently known contributions.
129130
Therefore, we need to set this reference before delegating any work to futures, where we lose guaranteed execution order.
130131
Additionally, this function should be called from a thread pool with predictable execution order.
131132
*/
132133
lastParams.set(List.copyOf(languages));
134+
return currentUpdate.updateAndGet(current -> current.thenComposeAsync(v -> doUpdate(languages), exec));
135+
}
136+
137+
private CompletableFuture<Void> doUpdate(Collection<ICapabilityParams> languages) {
138+
logger.debug("Updating {} dynamic capabilities for {} languages", dynamicCapabilities.size(), languages.size());
133139
return CompletableFutureUtils.reduce(dynamicCapabilities.stream().map(this::updateRegistration), exec)
134140
.thenAccept(_v -> logger.debug("Done updating dynamic capabilities"));
135141
}
@@ -200,6 +206,7 @@ private <T> CompletableFuture<Void> updateRegistration(AbstractDynamicCapability
200206
result = register(registration, existingRegistration);
201207
}
202208

209+
// TODO Check/Fix that if one capability fails, the rest are still registered
203210
return result.handle((_v, t) -> {
204211
if (t != null) {
205212
// An error occurred. Inform the user and do not recurse.

0 commit comments

Comments
 (0)