Skip to content

Commit 624cf6d

Browse files
committed
Make the debounce time of publish diagnostic job adaptive
Signed-off-by: Sheng Chen <[email protected]>
1 parent 30e4958 commit 624cf6d

File tree

2 files changed

+72
-17
lines changed

2 files changed

+72
-17
lines changed

org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/BaseDocumentLifeCycleHandler.java

+51-5
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import org.eclipse.core.runtime.Status;
4040
import org.eclipse.core.runtime.SubMonitor;
4141
import org.eclipse.core.runtime.jobs.ISchedulingRule;
42+
import org.eclipse.core.runtime.jobs.Job;
4243
import org.eclipse.core.runtime.jobs.MultiRule;
4344
import org.eclipse.jdt.core.IBuffer;
4445
import org.eclipse.jdt.core.ICompilationUnit;
@@ -92,12 +93,23 @@ public abstract class BaseDocumentLifeCycleHandler {
9293
*/
9394
private static final long DOCUMENT_LIFECYCLE_MAX_DEBOUNCE = 400; /*ms*/
9495

96+
/**
97+
* The min & init value of adaptive debounce time for publish diagnostic job.
98+
*/
99+
private static final long PUBLISH_DIAGNOSTICS_MIN_DEBOUNCE = 400; /*ms*/
100+
101+
/**
102+
* The max value of adaptive debounce time for publish diagnostic job.
103+
*/
104+
private static final long PUBLISH_DIAGNOSTICS_MAX_DEBOUNCE = 3000; /*ms*/
105+
95106
private CoreASTProvider sharedASTProvider;
96107
private WorkspaceJob validationTimer;
97108
private WorkspaceJob publishDiagnosticsJob;
98109
private Set<ICompilationUnit> toReconcile = new HashSet<>();
99110
private Map<String, Integer> documentVersions = new HashMap<>();
100-
private MovingAverage movingAverage = new MovingAverage(DOCUMENT_LIFECYCLE_MAX_DEBOUNCE);
111+
private MovingAverage movingAverageForValidation = new MovingAverage(DOCUMENT_LIFECYCLE_MAX_DEBOUNCE);
112+
private MovingAverage movingAverageForDiagnostics = new MovingAverage(PUBLISH_DIAGNOSTICS_MIN_DEBOUNCE);
101113

102114
public BaseDocumentLifeCycleHandler(boolean delayValidation) {
103115
this.sharedASTProvider = CoreASTProvider.getInstance();
@@ -107,7 +119,7 @@ public BaseDocumentLifeCycleHandler(boolean delayValidation) {
107119
public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException {
108120
long start = System.currentTimeMillis();
109121
IStatus status = performValidation(monitor);
110-
movingAverage.update(System.currentTimeMillis() - start);
122+
movingAverageForValidation.update(System.currentTimeMillis() - start);
111123
return status;
112124
}
113125

@@ -156,7 +168,18 @@ protected void triggerValidation(ICompilationUnit cu, long delay) throws JavaMod
156168
}
157169

158170
private long getDocumentLifecycleDelay() {
159-
return Math.min(DOCUMENT_LIFECYCLE_MAX_DEBOUNCE, Math.round(1.5 * movingAverage.value));
171+
return Math.min(DOCUMENT_LIFECYCLE_MAX_DEBOUNCE, Math.round(1.5 * movingAverageForValidation.value));
172+
}
173+
174+
/**
175+
* @return the delay time of the publish diagnostics job. The value ranges in
176+
* ({@link #PUBLISH_DIAGNOSTICS_MIN_DEBOUNCE}, {@link #PUBLISH_DIAGNOSTICS_MAX_DEBOUNCE}) ms.
177+
*/
178+
private long getPublishDiagnosticsDelay() {
179+
return Math.min(
180+
Math.max(PUBLISH_DIAGNOSTICS_MIN_DEBOUNCE, Math.round(1.5 * movingAverageForDiagnostics.value)),
181+
PUBLISH_DIAGNOSTICS_MAX_DEBOUNCE
182+
);
160183
}
161184

162185
private ISchedulingRule getRule(Set<ICompilationUnit> units) {
@@ -209,7 +232,7 @@ private IStatus performValidation(IProgressMonitor monitor) throws JavaModelExce
209232
if (monitor.isCanceled()) {
210233
return Status.CANCEL_STATUS;
211234
}
212-
publishDiagnosticsJob.schedule(400);
235+
schedulePublishDiagnosticJob();
213236
} else {
214237
return publishDiagnostics(new NullProgressMonitor());
215238
}
@@ -280,6 +303,26 @@ public IProblemRequestor getProblemRequestor(ICompilationUnit workingCopy) {
280303
unit.reconcile(ICompilationUnit.NO_AST, flags, wcOwner, monitor);
281304
}
282305

306+
/**
307+
* Cancel the publish diagnostic job when it's <code>Job.WAITING</code> or <code>Job.SLEEPING</code>.
308+
* Do nothing for other job states.
309+
* @return <code>true</code> if the job is cancelled, otherwise return <code>false</code>
310+
*/
311+
public boolean cancelPublishDiagnosticJob() {
312+
if (publishDiagnosticsJob.getState() == Job.WAITING || publishDiagnosticsJob.getState() == Job.SLEEPING) {
313+
publishDiagnosticsJob.cancel();
314+
return true;
315+
}
316+
return false;
317+
}
318+
319+
/**
320+
* Schedule the publish diagnostic job.
321+
*/
322+
public void schedulePublishDiagnosticJob() {
323+
publishDiagnosticsJob.schedule(getPublishDiagnosticsDelay());
324+
}
325+
283326
public void didClose(DidCloseTextDocumentParams params) {
284327
documentVersions.remove(params.getTextDocument().getUri());
285328
ISchedulingRule rule = JDTUtils.getRule(params.getTextDocument().getUri());
@@ -652,7 +695,10 @@ private PublishDiagnosticJob(ISchedulingRule rule) {
652695

653696
@Override
654697
public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException {
655-
return publishDiagnostics(monitor);
698+
long start = System.currentTimeMillis();
699+
IStatus status = publishDiagnostics(monitor);
700+
movingAverageForDiagnostics.update(System.currentTimeMillis() - start);
701+
return status;
656702
}
657703

658704
/* (non-Javadoc)

org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/JDTLanguageServer.java

+21-12
Original file line numberDiff line numberDiff line change
@@ -572,20 +572,29 @@ public CompletableFuture<Object> executeCommand(ExecuteCommandParams params) {
572572
@Override
573573
public CompletableFuture<Either<List<CompletionItem>, CompletionList>> completion(CompletionParams position) {
574574
logInfo(">> document/completion");
575-
CompletionHandler handler = new CompletionHandler(preferenceManager);
576-
final IProgressMonitor[] monitors = new IProgressMonitor[1];
577-
CompletableFuture<Either<List<CompletionItem>, CompletionList>> result = computeAsync((monitor) -> {
578-
monitors[0] = monitor;
579-
if (Boolean.getBoolean(JAVA_LSP_JOIN_ON_COMPLETION)) {
580-
waitForLifecycleJobs(monitor);
575+
// postpone the publish diagnostic jobs during completion since the job will lock the whole workspace.
576+
boolean cancelled = documentLifeCycleHandler.cancelPublishDiagnosticJob();
577+
try {
578+
CompletionHandler handler = new CompletionHandler(preferenceManager);
579+
final IProgressMonitor[] monitors = new IProgressMonitor[1];
580+
CompletableFuture<Either<List<CompletionItem>, CompletionList>> result = computeAsync((monitor) -> {
581+
monitors[0] = monitor;
582+
if (Boolean.getBoolean(JAVA_LSP_JOIN_ON_COMPLETION)) {
583+
waitForLifecycleJobs(monitor);
584+
}
585+
return handler.completion(position, monitor);
586+
});
587+
result.join();
588+
if (monitors[0].isCanceled()) {
589+
result.cancel(true);
590+
}
591+
return result;
592+
} finally {
593+
if (cancelled) {
594+
documentLifeCycleHandler.schedulePublishDiagnosticJob();
581595
}
582-
return handler.completion(position, monitor);
583-
});
584-
result.join();
585-
if (monitors[0].isCanceled()) {
586-
result.cancel(true);
587596
}
588-
return result;
597+
589598
}
590599

591600
/* (non-Javadoc)

0 commit comments

Comments
 (0)