Skip to content

Commit ea63691

Browse files
committed
- reuse inmemory fsp for inmemory log fsp
- rename keyvalue and indexeddb log fsp to file fsp - create indexeddb outside the provider and pass it
1 parent 98b3c0b commit ea63691

5 files changed

Lines changed: 134 additions & 146 deletions

File tree

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { KeyValueFileSystemProvider } from 'vs/platform/files/common/keyValueFileSystemProvider';
7+
import * as browser from 'vs/base/browser/browser';
8+
9+
export function openDatabase(name: string, version: number, stores: string[]): Promise<IDBDatabase | null> {
10+
if (browser.isEdge) {
11+
return Promise.resolve(null);
12+
}
13+
return new Promise((c, e) => {
14+
const request = window.indexedDB.open(name, version);
15+
request.onerror = (err) => e(request.error);
16+
request.onsuccess = () => {
17+
const db = request.result;
18+
for (const store of stores) {
19+
if (!db.objectStoreNames.contains(store)) {
20+
console.error(`Error while creating indexedDB. Could not create ${store} object store`);
21+
c(null);
22+
return;
23+
}
24+
}
25+
c(db);
26+
};
27+
request.onupgradeneeded = () => {
28+
const db = request.result;
29+
for (const store of stores) {
30+
if (!db.objectStoreNames.contains(store)) {
31+
db.createObjectStore(store);
32+
}
33+
}
34+
};
35+
});
36+
}
37+
38+
export class IndexedDBFileSystemProvider extends KeyValueFileSystemProvider {
39+
40+
constructor(scheme: string, private readonly database: IDBDatabase, private readonly store: string) {
41+
super(scheme);
42+
}
43+
44+
protected async getAllKeys(): Promise<string[]> {
45+
return new Promise(async (c, e) => {
46+
const transaction = this.database.transaction([this.store]);
47+
const objectStore = transaction.objectStore(this.store);
48+
const request = objectStore.getAllKeys();
49+
request.onerror = () => e(request.error);
50+
request.onsuccess = () => c(<string[]>request.result);
51+
});
52+
}
53+
54+
protected hasKey(key: string): Promise<boolean> {
55+
return new Promise<boolean>(async (c, e) => {
56+
const transaction = this.database.transaction([this.store]);
57+
const objectStore = transaction.objectStore(this.store);
58+
const request = objectStore.getKey(key);
59+
request.onerror = () => e(request.error);
60+
request.onsuccess = () => {
61+
c(!!request.result);
62+
};
63+
});
64+
}
65+
66+
protected getValue(key: string): Promise<string> {
67+
return new Promise(async (c, e) => {
68+
const transaction = this.database.transaction([this.store]);
69+
const objectStore = transaction.objectStore(this.store);
70+
const request = objectStore.get(key);
71+
request.onerror = () => e(request.error);
72+
request.onsuccess = () => c(request.result || '');
73+
});
74+
}
75+
76+
protected setValue(key: string, value: string): Promise<void> {
77+
return new Promise(async (c, e) => {
78+
const transaction = this.database.transaction([this.store], 'readwrite');
79+
const objectStore = transaction.objectStore(this.store);
80+
const request = objectStore.put(value, key);
81+
request.onerror = () => e(request.error);
82+
request.onsuccess = () => c();
83+
});
84+
}
85+
86+
protected deleteKey(key: string): Promise<void> {
87+
return new Promise(async (c, e) => {
88+
const transaction = this.database.transaction([this.store], 'readwrite');
89+
const objectStore = transaction.objectStore(this.store);
90+
const request = objectStore.delete(key);
91+
request.onerror = () => e(request.error);
92+
request.onsuccess = () => c();
93+
});
94+
}
95+
}

src/vs/workbench/services/log/common/keyValueLogProvider.ts renamed to src/vs/platform/files/common/keyValueFileSystemProvider.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ import { IFileSystemProviderWithFileReadWriteCapability, FileSystemProviderCapab
88
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
99
import { Event, Emitter } from 'vs/base/common/event';
1010
import { VSBuffer } from 'vs/base/common/buffer';
11-
import { joinPath, extUri } from 'vs/base/common/resources';
11+
import { joinPath, extUri, dirname } from 'vs/base/common/resources';
1212
import { values } from 'vs/base/common/map';
1313
import { localize } from 'vs/nls';
1414

15-
export abstract class KeyValueLogProvider extends Disposable implements IFileSystemProviderWithFileReadWriteCapability {
15+
export abstract class KeyValueFileSystemProvider extends Disposable implements IFileSystemProviderWithFileReadWriteCapability {
1616

1717
readonly capabilities: FileSystemProviderCapabilities =
1818
FileSystemProviderCapabilities.FileReadWrite
@@ -23,6 +23,7 @@ export abstract class KeyValueLogProvider extends Disposable implements IFileSys
2323
readonly onDidChangeFile: Event<readonly IFileChange[]> = this._onDidChangeFile.event;
2424

2525
private readonly versions: Map<string, number> = new Map<string, number>();
26+
private readonly dirs: Set<string> = new Set<string>();
2627

2728
constructor(private readonly scheme: string) {
2829
super();
@@ -33,6 +34,18 @@ export abstract class KeyValueLogProvider extends Disposable implements IFileSys
3334
}
3435

3536
async mkdir(resource: URI): Promise<void> {
37+
const parentDir = dirname(resource).path;
38+
if (parentDir !== '/' && !this.dirs.has(parentDir)) {
39+
throw createFileSystemProviderError(localize('fileNotFound', "File not found"), FileSystemProviderErrorCode.FileNotFound);
40+
}
41+
const hasKey = await this.hasKey(resource.path);
42+
if (hasKey) {
43+
throw createFileSystemProviderError(localize('fileNotDirectory', "File is not a directory"), FileSystemProviderErrorCode.FileNotADirectory);
44+
}
45+
if (this.dirs.has(resource.path)) {
46+
throw createFileSystemProviderError(localize('flieExists', "File exists"), FileSystemProviderErrorCode.FileExists);
47+
}
48+
this.dirs.add(resource.path);
3649
}
3750

3851
async stat(resource: URI): Promise<IStat> {
@@ -55,6 +68,14 @@ export abstract class KeyValueLogProvider extends Disposable implements IFileSys
5568
size: 0
5669
};
5770
}
71+
if (this.dirs.has(resource.path)) {
72+
return {
73+
type: FileType.Directory,
74+
ctime: 0,
75+
mtime: 0,
76+
size: 0
77+
};
78+
}
5879
throw createFileSystemProviderError(localize('fileNotExists', "File does not exist"), FileSystemProviderErrorCode.FileNotFound);
5980
}
6081

src/vs/workbench/browser/web.main.ts

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -43,22 +43,31 @@ import { registerWindowDriver } from 'vs/platform/driver/browser/driver';
4343
import { BufferLogService } from 'vs/platform/log/common/bufferLog';
4444
import { FileLogService } from 'vs/platform/log/common/fileLogService';
4545
import { toLocalISOString } from 'vs/base/common/date';
46-
import { IndexedDBLogProvider } from 'vs/workbench/services/log/browser/indexedDBLogProvider';
47-
import { InMemoryLogProvider } from 'vs/workbench/services/log/common/inMemoryLogProvider';
4846
import { isWorkspaceToOpen, isFolderToOpen } from 'vs/platform/windows/common/windows';
4947
import { getWorkspaceIdentifier } from 'vs/workbench/services/workspaces/browser/workspaces';
5048
import { coalesce } from 'vs/base/common/arrays';
5149
import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFilesystemProvider';
5250
import { WebResourceIdentityService, IResourceIdentityService } from 'vs/platform/resource/common/resourceIdentityService';
5351
import { ICommandService } from 'vs/platform/commands/common/commands';
52+
import { IndexedDBFileSystemProvider, openDatabase as openIndexedDB } from 'vs/platform/files/browser/indexedDBFileSystemProvider';
53+
54+
const INDEXEDDB_VSCODE_DB = 'vscode-web-db';
55+
const INDEXEDDB_LOGS_OBJECT_STORE = 'vscode-logs-store';
5456

5557
class BrowserMain extends Disposable {
5658

59+
private readonly indexedDB: Promise<IDBDatabase | null>;
60+
5761
constructor(
5862
private readonly domElement: HTMLElement,
5963
private readonly configuration: IWorkbenchConstructionOptions
6064
) {
6165
super();
66+
this.indexedDB = openIndexedDB(INDEXEDDB_VSCODE_DB, 2, [INDEXEDDB_LOGS_OBJECT_STORE])
67+
.then(null, error => {
68+
console.error(error);
69+
return null;
70+
});
6271
}
6372

6473
async open(): Promise<IWorkbench> {
@@ -209,20 +218,12 @@ class BrowserMain extends Disposable {
209218

210219
// Logger
211220
(async () => {
212-
if (browser.isEdge) {
213-
fileService.registerProvider(logsPath.scheme, new InMemoryLogProvider(logsPath.scheme));
221+
const indexedDB = await this.indexedDB;
222+
if (indexedDB) {
223+
const indexedDBLogProvider = new IndexedDBFileSystemProvider(logsPath.scheme, indexedDB, INDEXEDDB_LOGS_OBJECT_STORE);
224+
fileService.registerProvider(logsPath.scheme, indexedDBLogProvider);
214225
} else {
215-
try {
216-
const indexedDBLogProvider = new IndexedDBLogProvider(logsPath.scheme);
217-
await indexedDBLogProvider.database;
218-
219-
fileService.registerProvider(logsPath.scheme, indexedDBLogProvider);
220-
} catch (error) {
221-
logService.info('Error while creating indexedDB log provider. Falling back to in-memory log provider.');
222-
logService.error(error);
223-
224-
fileService.registerProvider(logsPath.scheme, new InMemoryLogProvider(logsPath.scheme));
225-
}
226+
fileService.registerProvider(logsPath.scheme, new InMemoryFileSystemProvider());
226227
}
227228

228229
logService.logger = new MultiplexLogService(coalesce([

src/vs/workbench/services/log/browser/indexedDBLogProvider.ts

Lines changed: 0 additions & 96 deletions
This file was deleted.

src/vs/workbench/services/log/common/inMemoryLogProvider.ts

Lines changed: 0 additions & 33 deletions
This file was deleted.

0 commit comments

Comments
 (0)