Skip to content

Commit 4745ae6

Browse files
committed
perf - make resolving untitled workspaces async (microsoft#16381)
1 parent 835ace5 commit 4745ae6

File tree

5 files changed

+62
-39
lines changed

5 files changed

+62
-39
lines changed

src/main.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,7 @@ perf.mark('code/willStartCrashReporter');
5656
// * --disable-crash-reporter command line parameter is not set
5757
//
5858
// Disable crash reporting in all other cases.
59-
if (args['crash-reporter-directory'] ||
60-
(argvConfig['enable-crash-reporter'] && !args['disable-crash-reporter'])) {
59+
if (args['crash-reporter-directory'] || (argvConfig['enable-crash-reporter'] && !args['disable-crash-reporter'])) {
6160
configureCrashReporter();
6261
}
6362
perf.mark('code/didStartCrashReporter');

src/vs/code/electron-main/app.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ import { ExtensionsProfileScannerService, IExtensionsProfileScannerService } fro
109109
import { IExtensionsScannerService } from 'vs/platform/extensionManagement/common/extensionsScannerService';
110110
import { ExtensionsScannerService } from 'vs/platform/extensionManagement/node/extensionsScannerService';
111111
import { UserDataTransientProfilesHandler } from 'vs/platform/userDataProfile/electron-main/userDataTransientProfilesHandler';
112-
import { RunOnceScheduler, runWhenIdle } from 'vs/base/common/async';
112+
import { Promises, RunOnceScheduler, runWhenIdle } from 'vs/base/common/async';
113113
import { IUserDataProfile } from 'vs/platform/userDataProfile/common/userDataProfile';
114114

115115
/**
@@ -632,7 +632,8 @@ export class CodeApplication extends Disposable {
632632
services.set(IWindowsMainService, new SyncDescriptor(WindowsMainService, [machineId, this.userEnv], false));
633633

634634
// Dialogs
635-
services.set(IDialogMainService, new SyncDescriptor(DialogMainService, undefined, true));
635+
const dialogMainService = new DialogMainService(this.logService);
636+
services.set(IDialogMainService, dialogMainService);
636637

637638
// Launch
638639
services.set(ILaunchMainService, new SyncDescriptor(LaunchMainService, undefined, false /* proxied to other processes */));
@@ -659,10 +660,6 @@ export class CodeApplication extends Disposable {
659660
// Webview Manager
660661
services.set(IWebviewManagerService, new SyncDescriptor(WebviewMainService));
661662

662-
// Workspaces
663-
services.set(IWorkspacesService, new SyncDescriptor(WorkspacesMainService, undefined, false /* proxied to other processes */));
664-
services.set(IWorkspacesManagementMainService, new SyncDescriptor(WorkspacesManagementMainService, undefined, true));
665-
services.set(IWorkspacesHistoryMainService, new SyncDescriptor(WorkspacesHistoryMainService, undefined, false));
666663

667664
// Menubar
668665
services.set(IMenubarMainService, new SyncDescriptor(MenubarMainService));
@@ -690,6 +687,12 @@ export class CodeApplication extends Disposable {
690687
const backupMainService = new BackupMainService(this.environmentMainService, this.configurationService, this.logService, this.stateMainService);
691688
services.set(IBackupMainService, backupMainService);
692689

690+
// Workspaces
691+
const workspacesManagementMainService = new WorkspacesManagementMainService(this.environmentMainService, this.logService, this.userDataProfilesMainService, backupMainService, dialogMainService, this.productService);
692+
services.set(IWorkspacesManagementMainService, workspacesManagementMainService);
693+
services.set(IWorkspacesService, new SyncDescriptor(WorkspacesMainService, undefined, false /* proxied to other processes */));
694+
services.set(IWorkspacesHistoryMainService, new SyncDescriptor(WorkspacesHistoryMainService, undefined, false));
695+
693696
// URL handling
694697
services.set(IURLService, new SyncDescriptor(NativeURLService, undefined, false /* proxied to other processes */));
695698

@@ -712,7 +715,10 @@ export class CodeApplication extends Disposable {
712715
services.set(IExtensionsScannerService, new SyncDescriptor(ExtensionsScannerService, undefined, true));
713716

714717
// Init services that require it
715-
await backupMainService.initialize();
718+
await Promises.settled([
719+
backupMainService.initialize(),
720+
workspacesManagementMainService.initialize()
721+
]);
716722

717723
return this.mainInstantiationService.createChild(services);
718724
}

src/vs/platform/windows/electron-main/windowsMainService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
332332
if (openConfig.initialStartup) {
333333

334334
// Untitled workspaces are always restored
335-
untitledWorkspacesToRestore.push(...this.workspacesManagementMainService.getUntitledWorkspacesSync());
335+
untitledWorkspacesToRestore.push(...this.workspacesManagementMainService.getUntitledWorkspaces());
336336
workspacesToOpen.push(...untitledWorkspacesToRestore);
337337

338338
// Empty windows with backups are always restored

src/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts

Lines changed: 40 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { dirname, join } from 'vs/base/common/path';
1414
import { basename, extUriBiasedIgnorePathCase, joinPath, originalFSPath } from 'vs/base/common/resources';
1515
import { withNullAsUndefined } from 'vs/base/common/types';
1616
import { URI } from 'vs/base/common/uri';
17-
import { Promises, readdirSync, rimrafSync, writeFileSync } from 'vs/base/node/pfs';
17+
import { Promises, rimrafSync, writeFileSync } from 'vs/base/node/pfs';
1818
import { localize } from 'vs/nls';
1919
import { IBackupMainService } from 'vs/platform/backup/electron-main/backup';
2020
import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogMainService';
@@ -51,7 +51,7 @@ export interface IWorkspacesManagementMainService {
5151
deleteUntitledWorkspace(workspace: IWorkspaceIdentifier): Promise<void>;
5252
deleteUntitledWorkspaceSync(workspace: IWorkspaceIdentifier): void;
5353

54-
getUntitledWorkspacesSync(): IUntitledWorkspaceInfo[];
54+
getUntitledWorkspaces(): IUntitledWorkspaceInfo[];
5555
isUntitledWorkspace(workspace: IWorkspaceIdentifier): boolean;
5656

5757
resolveLocalWorkspaceSync(path: URI): IResolvedWorkspace | undefined;
@@ -64,14 +64,16 @@ export class WorkspacesManagementMainService extends Disposable implements IWork
6464

6565
declare readonly _serviceBrand: undefined;
6666

67-
private readonly untitledWorkspacesHome = this.environmentMainService.untitledWorkspacesHome; // local URI that contains all untitled workspaces
68-
6967
private readonly _onDidDeleteUntitledWorkspace = this._register(new Emitter<IWorkspaceIdentifier>());
7068
readonly onDidDeleteUntitledWorkspace: Event<IWorkspaceIdentifier> = this._onDidDeleteUntitledWorkspace.event;
7169

7270
private readonly _onDidEnterWorkspace = this._register(new Emitter<IWorkspaceEnteredEvent>());
7371
readonly onDidEnterWorkspace: Event<IWorkspaceEnteredEvent> = this._onDidEnterWorkspace.event;
7472

73+
private readonly untitledWorkspacesHome = this.environmentMainService.untitledWorkspacesHome; // local URI that contains all untitled workspaces
74+
75+
private untitledWorkspaces: IUntitledWorkspaceInfo[] = [];
76+
7577
constructor(
7678
@IEnvironmentMainService private readonly environmentMainService: IEnvironmentMainService,
7779
@ILogService private readonly logService: ILogService,
@@ -83,6 +85,30 @@ export class WorkspacesManagementMainService extends Disposable implements IWork
8385
super();
8486
}
8587

88+
async initialize(): Promise<void> {
89+
90+
// Reset
91+
this.untitledWorkspaces = [];
92+
93+
// Resolve untitled workspaces
94+
try {
95+
const untitledWorkspacePaths = (await Promises.readdir(this.untitledWorkspacesHome.fsPath)).map(folder => joinPath(this.untitledWorkspacesHome, folder, UNTITLED_WORKSPACE_NAME));
96+
for (const untitledWorkspacePath of untitledWorkspacePaths) {
97+
const workspace = getWorkspaceIdentifier(untitledWorkspacePath);
98+
const resolvedWorkspace = await this.resolveLocalWorkspace(untitledWorkspacePath);
99+
if (!resolvedWorkspace) {
100+
await this.deleteUntitledWorkspace(workspace);
101+
} else {
102+
this.untitledWorkspaces.push({ workspace, remoteAuthority: resolvedWorkspace.remoteAuthority });
103+
}
104+
}
105+
} catch (error) {
106+
if (error.code !== 'ENOENT') {
107+
this.logService.warn(`Unable to read folders in ${this.untitledWorkspacesHome} (${error}).`);
108+
}
109+
}
110+
}
111+
86112
resolveLocalWorkspaceSync(uri: URI): IResolvedWorkspace | undefined {
87113
return this.doResolveLocalWorkspace(uri, path => readFileSync(path, 'utf8'));
88114
}
@@ -158,6 +184,8 @@ export class WorkspacesManagementMainService extends Disposable implements IWork
158184
await Promises.mkdir(dirname(configPath), { recursive: true });
159185
await Promises.writeFile(configPath, JSON.stringify(storedWorkspace, null, '\t'));
160186

187+
this.untitledWorkspaces.push({ workspace, remoteAuthority });
188+
161189
return workspace;
162190
}
163191

@@ -168,6 +196,8 @@ export class WorkspacesManagementMainService extends Disposable implements IWork
168196
mkdirSync(dirname(configPath), { recursive: true });
169197
writeFileSync(configPath, JSON.stringify(storedWorkspace, null, '\t'));
170198

199+
this.untitledWorkspaces.push({ workspace, remoteAuthority });
200+
171201
return workspace;
172202
}
173203

@@ -204,8 +234,8 @@ export class WorkspacesManagementMainService extends Disposable implements IWork
204234
// Delete from disk
205235
this.doDeleteUntitledWorkspaceSync(workspace);
206236

237+
// unset workspace from profiles
207238
if (this.userDataProfilesMainService.isEnabled()) {
208-
// unset workspace from profiles
209239
this.userDataProfilesMainService.unsetWorkspace(workspace);
210240
}
211241

@@ -229,31 +259,16 @@ export class WorkspacesManagementMainService extends Disposable implements IWork
229259
if (existsSync(workspaceStoragePath)) {
230260
writeFileSync(join(workspaceStoragePath, 'obsolete'), '');
231261
}
262+
263+
// Remove from list
264+
this.untitledWorkspaces = this.untitledWorkspaces.filter(untitledWorkspace => untitledWorkspace.workspace.id !== workspace.id);
232265
} catch (error) {
233266
this.logService.warn(`Unable to delete untitled workspace ${configPath} (${error}).`);
234267
}
235268
}
236269

237-
getUntitledWorkspacesSync(): IUntitledWorkspaceInfo[] {
238-
const untitledWorkspaces: IUntitledWorkspaceInfo[] = [];
239-
try {
240-
const untitledWorkspacePaths = readdirSync(this.untitledWorkspacesHome.fsPath).map(folder => joinPath(this.untitledWorkspacesHome, folder, UNTITLED_WORKSPACE_NAME));
241-
for (const untitledWorkspacePath of untitledWorkspacePaths) {
242-
const workspace = getWorkspaceIdentifier(untitledWorkspacePath);
243-
const resolvedWorkspace = this.resolveLocalWorkspaceSync(untitledWorkspacePath);
244-
if (!resolvedWorkspace) {
245-
this.doDeleteUntitledWorkspaceSync(workspace);
246-
} else {
247-
untitledWorkspaces.push({ workspace, remoteAuthority: resolvedWorkspace.remoteAuthority });
248-
}
249-
}
250-
} catch (error) {
251-
if (error.code !== 'ENOENT') {
252-
this.logService.warn(`Unable to read folders in ${this.untitledWorkspacesHome} (${error}).`);
253-
}
254-
}
255-
256-
return untitledWorkspaces;
270+
getUntitledWorkspaces(): IUntitledWorkspaceInfo[] {
271+
return this.untitledWorkspaces;
257272
}
258273

259274
async enterWorkspace(window: ICodeWindow, windows: ICodeWindow[], path: URI): Promise<IEnterWorkspaceResult | undefined> {

src/vs/platform/workspaces/test/electron-main/workspacesManagementMainService.test.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -412,19 +412,22 @@ flakySuite('WorkspacesManagementMainService', () => {
412412
service.deleteUntitledWorkspaceSync(workspace);
413413
});
414414

415-
test('getUntitledWorkspaceSync', async function () {
416-
let untitled = service.getUntitledWorkspacesSync();
415+
test('getUntitledWorkspace', async function () {
416+
await service.initialize();
417+
let untitled = service.getUntitledWorkspaces();
417418
assert.strictEqual(untitled.length, 0);
418419

419420
const untitledOne = await createUntitledWorkspace([cwd, tmpDir]);
420421
assert.ok(fs.existsSync(untitledOne.configPath.fsPath));
421422

422-
untitled = service.getUntitledWorkspacesSync();
423+
await service.initialize();
424+
untitled = service.getUntitledWorkspaces();
423425
assert.strictEqual(1, untitled.length);
424426
assert.strictEqual(untitledOne.id, untitled[0].workspace.id);
425427

426428
service.deleteUntitledWorkspaceSync(untitledOne);
427-
untitled = service.getUntitledWorkspacesSync();
429+
await service.initialize();
430+
untitled = service.getUntitledWorkspaces();
428431
assert.strictEqual(0, untitled.length);
429432
});
430433
});

0 commit comments

Comments
 (0)