mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-11 02:32:35 -05:00
Merge from vscode 5b9869eb02fa4c96205a74d05cad9164dfd06d60 (#5607)
This commit is contained in:
@@ -45,20 +45,21 @@ export class GlobalStorageDatabaseChannel extends Disposable implements IServerC
|
||||
this.whenReady = this.init();
|
||||
}
|
||||
|
||||
private init(): Promise<void> {
|
||||
return this.storageMainService.initialize().then(undefined, error => {
|
||||
private async init(): Promise<void> {
|
||||
try {
|
||||
await this.storageMainService.initialize();
|
||||
} catch (error) {
|
||||
onUnexpectedError(error);
|
||||
this.logService.error(error);
|
||||
}).then(() => {
|
||||
}
|
||||
|
||||
// Apply global telemetry values as part of the initialization
|
||||
// These are global across all windows and thereby should be
|
||||
// written from the main process once.
|
||||
this.initTelemetry();
|
||||
// Apply global telemetry values as part of the initialization
|
||||
// These are global across all windows and thereby should be
|
||||
// written from the main process once.
|
||||
this.initTelemetry();
|
||||
|
||||
// Setup storage change listeners
|
||||
this.registerListeners();
|
||||
});
|
||||
// Setup storage change listeners
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
private initTelemetry(): void {
|
||||
@@ -112,33 +113,39 @@ export class GlobalStorageDatabaseChannel extends Disposable implements IServerC
|
||||
throw new Error(`Event not found: ${event}`);
|
||||
}
|
||||
|
||||
call(_: unknown, command: string, arg?: any): Promise<any> {
|
||||
async call(_: unknown, command: string, arg?: any): Promise<any> {
|
||||
|
||||
// ensure to always wait for ready
|
||||
await this.whenReady;
|
||||
|
||||
// handle call
|
||||
switch (command) {
|
||||
case 'getItems': {
|
||||
return this.whenReady.then(() => mapToSerializable(this.storageMainService.items));
|
||||
return mapToSerializable(this.storageMainService.items);
|
||||
}
|
||||
|
||||
case 'updateItems': {
|
||||
return this.whenReady.then(() => {
|
||||
const items: ISerializableUpdateRequest = arg;
|
||||
if (items.insert) {
|
||||
for (const [key, value] of items.insert) {
|
||||
this.storageMainService.store(key, value);
|
||||
}
|
||||
const items: ISerializableUpdateRequest = arg;
|
||||
if (items.insert) {
|
||||
for (const [key, value] of items.insert) {
|
||||
this.storageMainService.store(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
if (items.delete) {
|
||||
items.delete.forEach(key => this.storageMainService.remove(key));
|
||||
}
|
||||
});
|
||||
if (items.delete) {
|
||||
items.delete.forEach(key => this.storageMainService.remove(key));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'checkIntegrity': {
|
||||
return this.whenReady.then(() => this.storageMainService.checkIntegrity(arg));
|
||||
return this.storageMainService.checkIntegrity(arg);
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`Call not found: ${command}`);
|
||||
default:
|
||||
throw new Error(`Call not found: ${command}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,8 +174,10 @@ export class GlobalStorageDatabaseChannelClient extends Disposable implements IS
|
||||
}
|
||||
}
|
||||
|
||||
getItems(): Promise<Map<string, string>> {
|
||||
return this.channel.call('getItems').then((data: Item[]) => serializableToMap(data));
|
||||
async getItems(): Promise<Map<string, string>> {
|
||||
const items: Item[] = await this.channel.call('getItems');
|
||||
|
||||
return serializableToMap(items);
|
||||
}
|
||||
|
||||
updateItems(request: IUpdateRequest): Promise<void> {
|
||||
|
||||
@@ -10,7 +10,6 @@ import { ILogService, LogLevel } from 'vs/platform/log/common/log';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IStorage, Storage, SQLiteStorageDatabase, ISQLiteStorageDatabaseLoggingOptions, InMemoryStorageDatabase } from 'vs/base/node/storage';
|
||||
import { join } from 'vs/base/common/path';
|
||||
import { exists } from 'vs/base/node/pfs';
|
||||
|
||||
export const IStorageMainService = createDecorator<IStorageMainService>('storageMainService');
|
||||
|
||||
@@ -121,25 +120,14 @@ export class StorageMainService extends Disposable implements IStorageMainServic
|
||||
}
|
||||
|
||||
private doInitialize(): Promise<void> {
|
||||
const useInMemoryStorage = this.storagePath === SQLiteStorageDatabase.IN_MEMORY_PATH;
|
||||
this.storage.dispose();
|
||||
this.storage = new Storage(new SQLiteStorageDatabase(this.storagePath, {
|
||||
logging: this.createLogginOptions()
|
||||
}));
|
||||
|
||||
let globalStorageExists: Promise<boolean>;
|
||||
if (useInMemoryStorage) {
|
||||
globalStorageExists = Promise.resolve(true);
|
||||
} else {
|
||||
globalStorageExists = exists(this.storagePath);
|
||||
}
|
||||
this._register(this.storage.onDidChangeStorage(key => this._onDidChangeStorage.fire({ key })));
|
||||
|
||||
return globalStorageExists.then(exists => {
|
||||
this.storage.dispose();
|
||||
this.storage = new Storage(new SQLiteStorageDatabase(this.storagePath, {
|
||||
logging: this.createLogginOptions()
|
||||
}));
|
||||
|
||||
this._register(this.storage.onDidChangeStorage(key => this._onDidChangeStorage.fire({ key })));
|
||||
|
||||
return this.storage.init();
|
||||
});
|
||||
return this.storage.init();
|
||||
}
|
||||
|
||||
get(key: string, fallbackValue: string): string;
|
||||
|
||||
@@ -62,38 +62,38 @@ export class StorageService extends Disposable implements IStorageService {
|
||||
return this.initializePromise;
|
||||
}
|
||||
|
||||
private doInitialize(payload: IWorkspaceInitializationPayload): Promise<void> {
|
||||
return Promise.all([
|
||||
private async doInitialize(payload: IWorkspaceInitializationPayload): Promise<void> {
|
||||
await Promise.all([
|
||||
this.initializeGlobalStorage(),
|
||||
this.initializeWorkspaceStorage(payload)
|
||||
]).then(() => undefined);
|
||||
]);
|
||||
}
|
||||
|
||||
private initializeGlobalStorage(): Promise<void> {
|
||||
return this.globalStorage.init();
|
||||
}
|
||||
|
||||
private initializeWorkspaceStorage(payload: IWorkspaceInitializationPayload): Promise<void> {
|
||||
private async initializeWorkspaceStorage(payload: IWorkspaceInitializationPayload): Promise<void> {
|
||||
|
||||
// Prepare workspace storage folder for DB
|
||||
return this.prepareWorkspaceStorageFolder(payload).then(result => {
|
||||
try {
|
||||
const result = await this.prepareWorkspaceStorageFolder(payload);
|
||||
|
||||
const useInMemoryStorage = !!this.environmentService.extensionTestsLocationURI; // no storage during extension tests!
|
||||
|
||||
// Create workspace storage and initalize
|
||||
mark('willInitWorkspaceStorage');
|
||||
return this.createWorkspaceStorage(useInMemoryStorage ? SQLiteStorageDatabase.IN_MEMORY_PATH : join(result.path, StorageService.WORKSPACE_STORAGE_NAME), result.wasCreated ? StorageHint.STORAGE_DOES_NOT_EXIST : undefined).init().then(() => {
|
||||
try {
|
||||
await this.createWorkspaceStorage(useInMemoryStorage ? SQLiteStorageDatabase.IN_MEMORY_PATH : join(result.path, StorageService.WORKSPACE_STORAGE_NAME), result.wasCreated ? StorageHint.STORAGE_DOES_NOT_EXIST : undefined).init();
|
||||
} finally {
|
||||
mark('didInitWorkspaceStorage');
|
||||
}, error => {
|
||||
mark('didInitWorkspaceStorage');
|
||||
|
||||
return Promise.reject(error);
|
||||
});
|
||||
}).then(undefined, error => {
|
||||
}
|
||||
} catch (error) {
|
||||
onUnexpectedError(error);
|
||||
|
||||
// Upon error, fallback to in-memory storage
|
||||
return this.createWorkspaceStorage(SQLiteStorageDatabase.IN_MEMORY_PATH).init();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private createWorkspaceStorage(workspaceStoragePath: string, hint?: StorageHint): IStorage {
|
||||
@@ -120,22 +120,20 @@ export class StorageService extends Disposable implements IStorageService {
|
||||
return join(this.environmentService.workspaceStorageHome, payload.id); // workspace home + workspace id;
|
||||
}
|
||||
|
||||
private prepareWorkspaceStorageFolder(payload: IWorkspaceInitializationPayload): Promise<{ path: string, wasCreated: boolean }> {
|
||||
private async prepareWorkspaceStorageFolder(payload: IWorkspaceInitializationPayload): Promise<{ path: string, wasCreated: boolean }> {
|
||||
const workspaceStorageFolderPath = this.getWorkspaceStorageFolderPath(payload);
|
||||
|
||||
return exists(workspaceStorageFolderPath).then<{ path: string, wasCreated: boolean }>(exists => {
|
||||
if (exists) {
|
||||
return { path: workspaceStorageFolderPath, wasCreated: false };
|
||||
}
|
||||
const storageExists = await exists(workspaceStorageFolderPath);
|
||||
if (storageExists) {
|
||||
return { path: workspaceStorageFolderPath, wasCreated: false };
|
||||
}
|
||||
|
||||
return mkdirp(workspaceStorageFolderPath).then(() => {
|
||||
await mkdirp(workspaceStorageFolderPath);
|
||||
|
||||
// Write metadata into folder
|
||||
this.ensureWorkspaceStorageFolderMeta(payload);
|
||||
// Write metadata into folder
|
||||
this.ensureWorkspaceStorageFolderMeta(payload);
|
||||
|
||||
return { path: workspaceStorageFolderPath, wasCreated: true };
|
||||
});
|
||||
});
|
||||
return { path: workspaceStorageFolderPath, wasCreated: true };
|
||||
}
|
||||
|
||||
private ensureWorkspaceStorageFolderMeta(payload: IWorkspaceInitializationPayload): void {
|
||||
@@ -148,13 +146,16 @@ export class StorageService extends Disposable implements IStorageService {
|
||||
|
||||
if (meta) {
|
||||
const workspaceStorageMetaPath = join(this.getWorkspaceStorageFolderPath(payload), StorageService.WORKSPACE_META_NAME);
|
||||
exists(workspaceStorageMetaPath).then(exists => {
|
||||
if (exists) {
|
||||
return undefined; // already existing
|
||||
(async function () {
|
||||
try {
|
||||
const storageExists = await exists(workspaceStorageMetaPath);
|
||||
if (!storageExists) {
|
||||
await writeFile(workspaceStorageMetaPath, JSON.stringify(meta, undefined, 2));
|
||||
}
|
||||
} catch (error) {
|
||||
onUnexpectedError(error);
|
||||
}
|
||||
|
||||
return writeFile(workspaceStorageMetaPath, JSON.stringify(meta, undefined, 2));
|
||||
}).then(undefined, error => onUnexpectedError(error));
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,16 +185,16 @@ export class StorageService extends Disposable implements IStorageService {
|
||||
this.getStorage(scope).delete(key);
|
||||
}
|
||||
|
||||
close(): Promise<void> {
|
||||
async close(): Promise<void> {
|
||||
|
||||
// Signal as event so that clients can still store data
|
||||
this._onWillSaveState.fire({ reason: WillSaveStateReason.SHUTDOWN });
|
||||
|
||||
// Do it
|
||||
return Promise.all([
|
||||
await Promise.all([
|
||||
this.globalStorage.close(),
|
||||
this.workspaceStorage.close()
|
||||
]).then(() => undefined);
|
||||
]);
|
||||
}
|
||||
|
||||
private getStorage(scope: StorageScope): IStorage {
|
||||
@@ -208,77 +209,75 @@ export class StorageService extends Disposable implements IStorageService {
|
||||
return scope === StorageScope.GLOBAL ? this.globalStorage.checkIntegrity(full) : this.workspaceStorage.checkIntegrity(full);
|
||||
}
|
||||
|
||||
logStorage(): Promise<void> {
|
||||
return Promise.all([
|
||||
async logStorage(): Promise<void> {
|
||||
const result = await Promise.all([
|
||||
this.globalStorage.items,
|
||||
this.workspaceStorage.items,
|
||||
this.globalStorage.checkIntegrity(true /* full */),
|
||||
this.workspaceStorage.checkIntegrity(true /* full */)
|
||||
]).then(result => {
|
||||
const safeParse = (value: string) => {
|
||||
try {
|
||||
return JSON.parse(value);
|
||||
} catch (error) {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
]);
|
||||
|
||||
const globalItems = new Map<string, string>();
|
||||
const globalItemsParsed = new Map<string, string>();
|
||||
result[0].forEach((value, key) => {
|
||||
globalItems.set(key, value);
|
||||
globalItemsParsed.set(key, safeParse(value));
|
||||
});
|
||||
const safeParse = (value: string) => {
|
||||
try {
|
||||
return JSON.parse(value);
|
||||
} catch (error) {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
const workspaceItems = new Map<string, string>();
|
||||
const workspaceItemsParsed = new Map<string, string>();
|
||||
result[1].forEach((value, key) => {
|
||||
workspaceItems.set(key, value);
|
||||
workspaceItemsParsed.set(key, safeParse(value));
|
||||
});
|
||||
|
||||
console.group(`Storage: Global (integrity: ${result[2]}, path: ${this.environmentService.globalStorageHome})`);
|
||||
let globalValues: { key: string, value: string }[] = [];
|
||||
globalItems.forEach((value, key) => {
|
||||
globalValues.push({ key, value });
|
||||
});
|
||||
console.table(globalValues);
|
||||
console.groupEnd();
|
||||
|
||||
console.log(globalItemsParsed);
|
||||
|
||||
console.group(`Storage: Workspace (integrity: ${result[3]}, load: ${getDuration('willInitWorkspaceStorage', 'didInitWorkspaceStorage')}, path: ${this.workspaceStoragePath})`);
|
||||
let workspaceValues: { key: string, value: string }[] = [];
|
||||
workspaceItems.forEach((value, key) => {
|
||||
workspaceValues.push({ key, value });
|
||||
});
|
||||
console.table(workspaceValues);
|
||||
console.groupEnd();
|
||||
|
||||
console.log(workspaceItemsParsed);
|
||||
const globalItems = new Map<string, string>();
|
||||
const globalItemsParsed = new Map<string, string>();
|
||||
result[0].forEach((value, key) => {
|
||||
globalItems.set(key, value);
|
||||
globalItemsParsed.set(key, safeParse(value));
|
||||
});
|
||||
|
||||
const workspaceItems = new Map<string, string>();
|
||||
const workspaceItemsParsed = new Map<string, string>();
|
||||
result[1].forEach((value, key) => {
|
||||
workspaceItems.set(key, value);
|
||||
workspaceItemsParsed.set(key, safeParse(value));
|
||||
});
|
||||
|
||||
console.group(`Storage: Global (integrity: ${result[2]}, path: ${this.environmentService.globalStorageHome})`);
|
||||
let globalValues: { key: string, value: string }[] = [];
|
||||
globalItems.forEach((value, key) => {
|
||||
globalValues.push({ key, value });
|
||||
});
|
||||
console.table(globalValues);
|
||||
console.groupEnd();
|
||||
|
||||
console.log(globalItemsParsed);
|
||||
|
||||
console.group(`Storage: Workspace (integrity: ${result[3]}, load: ${getDuration('willInitWorkspaceStorage', 'didInitWorkspaceStorage')}, path: ${this.workspaceStoragePath})`);
|
||||
let workspaceValues: { key: string, value: string }[] = [];
|
||||
workspaceItems.forEach((value, key) => {
|
||||
workspaceValues.push({ key, value });
|
||||
});
|
||||
console.table(workspaceValues);
|
||||
console.groupEnd();
|
||||
|
||||
console.log(workspaceItemsParsed);
|
||||
}
|
||||
|
||||
migrate(toWorkspace: IWorkspaceInitializationPayload): Promise<void> {
|
||||
async migrate(toWorkspace: IWorkspaceInitializationPayload): Promise<void> {
|
||||
if (this.workspaceStoragePath === SQLiteStorageDatabase.IN_MEMORY_PATH) {
|
||||
return Promise.resolve(); // no migration needed if running in memory
|
||||
}
|
||||
|
||||
// Close workspace DB to be able to copy
|
||||
return this.workspaceStorage.close().then(() => {
|
||||
await this.workspaceStorage.close();
|
||||
|
||||
// Prepare new workspace storage folder
|
||||
return this.prepareWorkspaceStorageFolder(toWorkspace).then(result => {
|
||||
const newWorkspaceStoragePath = join(result.path, StorageService.WORKSPACE_STORAGE_NAME);
|
||||
// Prepare new workspace storage folder
|
||||
const result = await this.prepareWorkspaceStorageFolder(toWorkspace);
|
||||
|
||||
// Copy current storage over to new workspace storage
|
||||
return copy(this.workspaceStoragePath, newWorkspaceStoragePath).then(() => {
|
||||
const newWorkspaceStoragePath = join(result.path, StorageService.WORKSPACE_STORAGE_NAME);
|
||||
|
||||
// Recreate and init workspace storage
|
||||
return this.createWorkspaceStorage(newWorkspaceStoragePath).init();
|
||||
});
|
||||
});
|
||||
});
|
||||
// Copy current storage over to new workspace storage
|
||||
await copy(this.workspaceStoragePath, newWorkspaceStoragePath);
|
||||
|
||||
// Recreate and init workspace storage
|
||||
return this.createWorkspaceStorage(newWorkspaceStoragePath).init();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user