Skip to content

Commit 49cb181

Browse files
Ask to clean cache if a corrupted workspace cache is detected (#1011)
1 parent 54438d5 commit 49cb181

3 files changed

Lines changed: 61 additions & 2 deletions

File tree

src/daemon/index.ts

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import { promisify } from "util";
55
import * as vscode from "vscode";
6-
import { sendError } from "vscode-extension-telemetry-wrapper";
6+
import { sendError, sendInfo } from "vscode-extension-telemetry-wrapper";
77
import { LSDaemon } from "./daemon";
88

99
const delay = promisify(setTimeout);
@@ -25,12 +25,19 @@ async function checkJavaExtActivated(_context: vscode.ExtensionContext): Promise
2525
return false;
2626
}
2727

28+
vscode.workspace.onDidGrantWorkspaceTrust(() => {
29+
checkIfJavaServerCrashed(30 * 1000 /*ms*/);
30+
});
31+
2832
// wait javaExt to activate
2933
const timeout = 30 * 60 * 1000; // wait 30 min at most
3034
let count = 0;
3135
while(!javaExt.isActive && count < timeout) {
3236
await delay(1000);
3337
count += 1000;
38+
if (count % 10000 === 0) {
39+
checkIfJavaServerCrashed();
40+
}
3441
}
3542

3643
if (!javaExt.isActive) {
@@ -41,6 +48,10 @@ async function checkJavaExtActivated(_context: vscode.ExtensionContext): Promise
4148

4249
// on ServiceReady
4350
javaExt.exports.onDidServerModeChange(async (mode: string) => {
51+
if (mode === "Hybrid") { // begin to start standard language server
52+
checkIfJavaServerCrashed(30 * 1000 /*ms*/);
53+
}
54+
4455
if (mode === "Standard") {
4556
daemon.logWatcher.sendStartupMetadata("jdtls standard server ready");
4657

@@ -57,3 +68,35 @@ async function checkJavaExtActivated(_context: vscode.ExtensionContext): Promise
5768

5869
return true;
5970
}
71+
72+
let corruptedCacheDetected: boolean = false;
73+
async function checkIfJavaServerCrashed(wait: number = 0/*ms*/) {
74+
if (corruptedCacheDetected) {
75+
return;
76+
}
77+
78+
// wait Java Language Server to start
79+
if (wait) {
80+
await delay(wait);
81+
}
82+
83+
const corruptedCache = !await daemon.processWatcher.start() && await daemon.logWatcher.checkIfWorkspaceCorrupted();
84+
if (!corruptedCacheDetected && corruptedCache) {
85+
corruptedCacheDetected = true;
86+
sendInfo("", {
87+
name: "corrupted-cache",
88+
});
89+
const ans = await vscode.window.showErrorMessage("Java extension cannot start due to corrupted workspace cache, please try to clean the workspace.",
90+
"Clean and Restart", "Later");
91+
if (ans === "Clean and Restart") {
92+
sendInfo("", {
93+
name: "clean-cache-action",
94+
});
95+
vscode.commands.executeCommand("java.clean.workspace", true);
96+
} else {
97+
sendInfo("", {
98+
name: "clean-cache-cancel-action",
99+
});
100+
}
101+
}
102+
}

src/daemon/serverLog/logUtils.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ const MESSAGE_BUILD_JOBS_FINISHED = "!MESSAGE >> build jobs finished";
3939

4040
const STACK_INDICATOR = `${EOL}!STACK `;
4141
const MESSAGE_INDICATOR = `${EOL}!MESSAGE `;
42+
const CORRUPTED_WORKSPACE_INDICATOR = "Caused by: org.eclipse.core.internal.dtree.ObjectNotFoundException:";
4243

4344
export async function logsForLatestSession(logFilepath: string): Promise<string> {
4445
const content = await fs.promises.readFile(logFilepath, { encoding: 'utf-8' });
@@ -135,6 +136,12 @@ export function parseTimestamp(entry: string): LogEntry {
135136
}
136137
}
137138

139+
export function containsCorruptedException(log: string): boolean {
140+
const lines = log.split(`${EOL}`);
141+
const find = lines.find(line => line.startsWith(CORRUPTED_WORKSPACE_INDICATOR));
142+
return !!find;
143+
}
144+
138145
function getMessage(entry: string) {
139146
const start = entry.indexOf(MESSAGE_INDICATOR);
140147
if (start < 0) { return ""; }

src/daemon/serverLog/logWatcher.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import * as path from "path";
66
import * as vscode from "vscode";
77
import { sendInfo } from "vscode-extension-telemetry-wrapper";
88
import { LSDaemon } from "../daemon";
9-
import { collectErrors, collectErrorsSince, logsForLatestSession, sessionMetadata } from "./logUtils";
9+
import { collectErrors, collectErrorsSince, containsCorruptedException, logsForLatestSession, sessionMetadata } from "./logUtils";
1010
import { toElapsed } from "./utils";
1111
import { redact } from "./whitelist";
1212

@@ -122,4 +122,13 @@ export class LogWatcher {
122122
}
123123
}
124124
}
125+
126+
public async checkIfWorkspaceCorrupted(): Promise<boolean> {
127+
if (this.serverLogUri) {
128+
const logs = await logsForLatestSession(path.join(this.serverLogUri?.fsPath, ".log"));
129+
return containsCorruptedException(logs);
130+
}
131+
132+
return false;
133+
}
125134
}

0 commit comments

Comments
 (0)