提交 f7adbed3 编写于 作者: B Benjamin Pasero

storage - switch to a workspace storage

上级 f41a6943
......@@ -15,7 +15,7 @@ import { startsWith } from 'vs/base/common/strings';
import { Action } from 'vs/base/common/actions';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { localize } from 'vs/nls';
import { mark } from 'vs/base/common/performance';
import { mark, getDuration } from 'vs/base/common/performance';
export class StorageService extends Disposable implements IStorageService {
_serviceBrand: any;
......@@ -169,13 +169,13 @@ export class StorageService extends Disposable implements IStorageService {
workspaceItemsParsed[key] = safeParse(value);
});
console.group(`Storage: Global (check: ${result[2]})`);
console.group(`Storage: Global (check: ${result[2]}, load: ${getDuration('willInitGlobalStorage', 'didInitGlobalStorage')})`);
console.table(globalItems);
console.groupEnd();
console.log(globalItemsParsed);
console.group(`Storage: Workspace (check: ${result[3]})`);
console.group(`Storage: Workspace (check: ${result[3]}, load: ${getDuration('willInitWorkspaceStorage', 'didInitWorkspaceStorage')})`);
console.table(workspaceItems);
console.groupEnd();
......@@ -245,40 +245,27 @@ export class DelegatingStorageService extends Disposable implements IStorageServ
}
get(key: string, scope: StorageScope, fallbackValue?: any): string {
const localStorageValue = this.storageLegacyService.get(key, this.convertScope(scope), fallbackValue);
const dbValue = this.storageService.get(key, scope, localStorageValue);
if (scope === StorageScope.WORKSPACE) {
return this.storageService.get(key, scope, fallbackValue);
}
return this.assertAndGet(key, scope, dbValue, localStorageValue);
return this.storageLegacyService.get(key, this.convertScope(scope), fallbackValue);
}
getBoolean(key: string, scope: StorageScope, fallbackValue?: boolean): boolean {
const localStorageValue = this.storageLegacyService.getBoolean(key, this.convertScope(scope), fallbackValue);
const dbValue = this.storageService.getBoolean(key, scope, localStorageValue);
if (scope === StorageScope.WORKSPACE) {
return this.storageService.getBoolean(key, scope, fallbackValue);
}
return this.assertAndGet(key, scope, dbValue, localStorageValue);
return this.storageLegacyService.getBoolean(key, this.convertScope(scope), fallbackValue);
}
getInteger(key: string, scope: StorageScope, fallbackValue?: number): number {
const localStorageValue = this.storageLegacyService.getInteger(key, this.convertScope(scope), fallbackValue);
const dbValue = this.storageService.getInteger(key, scope, localStorageValue);
return this.assertAndGet(key, scope, dbValue, localStorageValue);
}
private assertAndGet(key: string, scope: StorageScope, dbValue: any, localStorageValue: any): any {
if (scope === StorageScope.WORKSPACE) {
this.assertStorageValue(key, scope, dbValue, localStorageValue);
return dbValue;
return this.storageService.getInteger(key, scope, fallbackValue);
}
return localStorageValue;
}
private assertStorageValue(key: string, scope: StorageScope, dbValue: any, localStorageValue: any): void {
if (dbValue !== localStorageValue) {
this.logService.error(`Unexpected storage value (key: ${key}, scope: ${scope === StorageScope.GLOBAL ? 'global' : 'workspace'}), actual: ${dbValue}, expected: ${localStorageValue}`);
}
return this.storageLegacyService.getInteger(key, this.convertScope(scope), fallbackValue);
}
store(key: string, value: any, scope: StorageScope): void {
......
......@@ -16,7 +16,7 @@ import { IWorkspaceContextService, Workspace, WorkbenchState } from 'vs/platform
import { WorkspaceService, ISingleFolderWorkspaceInitializationPayload, IMultiFolderWorkspaceInitializationPayload, IEmptyWorkspaceInitializationPayload, IWorkspaceInitializationPayload } from 'vs/workbench/services/configuration/node/configurationService';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { stat } from 'vs/base/node/pfs';
import { stat, exists } from 'vs/base/node/pfs';
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
import * as gracefulFs from 'graceful-fs';
import { KeyboardMapperFactory } from 'vs/workbench/services/keybinding/electron-browser/keybindingService';
......@@ -43,8 +43,8 @@ import { RelayURLService } from 'vs/platform/url/common/urlService';
import { MenubarChannelClient } from 'vs/platform/menubar/node/menubarIpc';
import { IMenubarService } from 'vs/platform/menubar/common/menubar';
import { Schemas } from 'vs/base/common/network';
import { sanitizeFilePath } from 'vs/base/node/extfs';
import { basename } from 'path';
import { sanitizeFilePath, mkdirp } from 'vs/base/node/extfs';
import { basename, join } from 'path';
import { createHash } from 'crypto';
gracefulFs.gracefulify(fs); // enable gracefulFs
......@@ -101,46 +101,50 @@ function openWorkbench(configuration: IWindowConfiguration): Promise<void> {
// Resolve a workspace payload that we can get the workspace ID from
return createWorkspaceInitializationPayload(configuration, environmentService).then(payload => {
return Promise.all([
// Create and load workspace/configuration service
createWorkspaceService(payload, environmentService),
// Create and load storage service
createStorageService(environmentService, logService)
]).then(services => {
const workspaceService = services[0];
const storageLegacyService = createStorageLegacyService(workspaceService, environmentService);
const storageService = new DelegatingStorageService(services[1], storageLegacyService, logService);
return domContentLoaded().then(() => {
perf.mark('willStartWorkbench');
// Create Shell
const shell = new WorkbenchShell(document.body, {
contextService: workspaceService,
configurationService: workspaceService,
environmentService,
logService,
storageLegacyService,
storageService
}, mainServices, mainProcessClient, configuration);
// Gracefully Shutdown Storage
shell.onShutdown(event => {
event.join(storageService.close());
});
// Open Shell
shell.open();
// Inform user about loading issues from the loader
(<any>self).require.config({
onError: err => {
if (err.errorCode === 'load') {
shell.onUnexpectedError(new Error(nls.localize('loaderErrorNative', "Failed to load a required file. Please restart the application to try again. Details: {0}", JSON.stringify(err))));
// Prepare the workspace storage folder
return prepareWorkspaceStorageFolder(payload, environmentService).then(storagePath => {
return Promise.all([
// Create and load workspace/configuration service
createWorkspaceService(payload, environmentService),
// Create and load storage service
createStorageService(storagePath, environmentService, logService)
]).then(services => {
const workspaceService = services[0];
const storageLegacyService = createStorageLegacyService(workspaceService, environmentService);
const storageService = new DelegatingStorageService(services[1], storageLegacyService, logService);
return domContentLoaded().then(() => {
perf.mark('willStartWorkbench');
// Create Shell
const shell = new WorkbenchShell(document.body, {
contextService: workspaceService,
configurationService: workspaceService,
environmentService,
logService,
storageLegacyService,
storageService
}, mainServices, mainProcessClient, configuration);
// Gracefully Shutdown Storage
shell.onShutdown(event => {
event.join(storageService.close());
});
// Open Shell
shell.open();
// Inform user about loading issues from the loader
(<any>self).require.config({
onError: err => {
if (err.errorCode === 'load') {
shell.onUnexpectedError(new Error(nls.localize('loaderErrorNative', "Failed to load a required file. Please restart the application to try again. Details: {0}", JSON.stringify(err))));
}
}
}
});
});
});
});
......@@ -162,9 +166,14 @@ function createWorkspaceInitializationPayload(configuration: IWindowConfiguratio
return workspaceInitializationPayload.then(payload => {
// Fallback to empty workspace if we have no payload yet
// Fallback to empty workspace if we have no payload yet. We know the
// backupPath must be a unique path so we leverage its name as workspace ID
if (!payload) {
payload = { id: configuration.backupPath ? uri.from({ path: basename(configuration.backupPath), scheme: 'empty' }).toString() : '' } as IEmptyWorkspaceInitializationPayload;
if (!configuration.backupPath) {
return Promise.reject(new Error('Unexpected missing backupPath for empty window')); // should not happen in this case
}
payload = { id: basename(configuration.backupPath) } as IEmptyWorkspaceInitializationPayload;
}
return payload;
......@@ -188,6 +197,8 @@ function resolveSingleFolderWorkspaceInitializationPayload(folderUri: ISingleFol
}
}
// we use the ctime as extra salt to the ID so that we catch the case of a folder getting
// deleted and recreated. in that case we do not want to carry over previous state
return createHash('md5').update(folder.fsPath).update(ctime ? String(ctime) : '').digest('hex');
}
......@@ -217,14 +228,28 @@ function resolveSingleFolderWorkspaceInitializationPayload(folderUri: ISingleFol
});
}
function prepareWorkspaceStorageFolder(payload: IWorkspaceInitializationPayload, environmentService: IEnvironmentService): Thenable<string> {
// Workspace storage: scope by workspace identifier
const storagePath = join(environmentService.workspaceStorageHome, payload.id);
return exists(storagePath).then(exists => {
if (exists) {
return storagePath;
}
return mkdirp(storagePath).then(() => storagePath);
});
}
function createWorkspaceService(payload: IWorkspaceInitializationPayload, environmentService: IEnvironmentService): Promise<WorkspaceService> {
const workspaceService = new WorkspaceService(environmentService);
return workspaceService.initialize(payload).then(() => workspaceService, error => workspaceService);
}
function createStorageService(environmentService: IEnvironmentService, logService: ILogService): Promise<StorageService> {
const storageService = new StorageService(':memory:', logService, environmentService);
function createStorageService(workspaceStorageFolder: string, environmentService: IEnvironmentService, logService: ILogService): Promise<StorageService> {
const storageService = new StorageService(join(workspaceStorageFolder, 'storage.db'), logService, environmentService);
return storageService.init().then(() => storageService);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册