Skip to content

Commit 4192006

Browse files
authored
Merge pull request microsoft#152045 from microsoft/ben/151490
Profile support for global storage
2 parents 3d471d2 + ee1f284 commit 4192006

File tree

27 files changed

+751
-261
lines changed

27 files changed

+751
-261
lines changed

src/vs/base/browser/indexedDB.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export class IndexedDB {
2828
return new IndexedDB(database, name);
2929
}
3030

31-
static async openDatabase(name: string, version: number | undefined, stores: string[]): Promise<IDBDatabase> {
31+
private static async openDatabase(name: string, version: number | undefined, stores: string[]): Promise<IDBDatabase> {
3232
mark(`code/willOpenDatabase/${name}`);
3333
try {
3434
return await IndexedDB.doOpenDatabase(name, version, stores);

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ import { SharedProcess } from 'vs/platform/sharedProcess/electron-main/sharedPro
7070
import { ISignService } from 'vs/platform/sign/common/sign';
7171
import { IStateMainService } from 'vs/platform/state/electron-main/state';
7272
import { StorageDatabaseChannel } from 'vs/platform/storage/electron-main/storageIpc';
73-
import { GlobalStorageMainService, IGlobalStorageMainService, IStorageMainService, StorageMainService } from 'vs/platform/storage/electron-main/storageMainService';
73+
import { ApplicationStorageMainService, IApplicationStorageMainService, IStorageMainService, StorageMainService } from 'vs/platform/storage/electron-main/storageMainService';
7474
import { resolveCommonProperties } from 'vs/platform/telemetry/common/commonProperties';
7575
import { ITelemetryService, machineIdKey, TelemetryLevel } from 'vs/platform/telemetry/common/telemetry';
7676
import { TelemetryAppenderClient } from 'vs/platform/telemetry/common/telemetryIpc';
@@ -648,7 +648,7 @@ export class CodeApplication extends Disposable {
648648

649649
// Storage
650650
services.set(IStorageMainService, new SyncDescriptor(StorageMainService));
651-
services.set(IGlobalStorageMainService, new SyncDescriptor(GlobalStorageMainService));
651+
services.set(IApplicationStorageMainService, new SyncDescriptor(ApplicationStorageMainService));
652652

653653
// External terminal
654654
if (isWindows) {

src/vs/platform/externalServices/common/serviceMachineId.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { IFileService } from 'vs/platform/files/common/files';
1010
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
1111

1212
export async function getServiceMachineId(environmentService: IEnvironmentService, fileService: IFileService, storageService: IStorageService | undefined): Promise<string> {
13-
let uuid: string | null = storageService ? storageService.get('storage.serviceMachineId', StorageScope.GLOBAL) || null : null;
13+
let uuid: string | null = storageService ? storageService.get('storage.serviceMachineId', StorageScope.APPLICATION) || null : null;
1414
if (uuid) {
1515
return uuid;
1616
}
@@ -31,7 +31,7 @@ export async function getServiceMachineId(environmentService: IEnvironmentServic
3131
}
3232
}
3333
if (storageService) {
34-
storageService.store('storage.serviceMachineId', uuid, StorageScope.GLOBAL, StorageTarget.MACHINE);
34+
storageService.store('storage.serviceMachineId', uuid, StorageScope.APPLICATION, StorageTarget.MACHINE);
3535
}
3636
return uuid;
3737
}

src/vs/platform/notification/common/notification.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,16 @@ export enum NeverShowAgainScope {
4545
WORKSPACE,
4646

4747
/**
48-
* Will never show this notification on any workspace again.
48+
* Will never show this notification on any workspace of the same
49+
* profile again.
4950
*/
50-
GLOBAL
51+
GLOBAL,
52+
53+
/**
54+
* Will never show this notification on any workspace across all
55+
* profiles again.
56+
*/
57+
APPLICATION
5158
}
5259

5360
export interface INeverShowAgainOptions {
@@ -65,7 +72,8 @@ export interface INeverShowAgainOptions {
6572

6673
/**
6774
* Whether to persist the choice in the current workspace or for all workspaces. By
68-
* default it will be persisted for all workspaces (= `NeverShowAgainScope.GLOBAL`).
75+
* default it will be persisted for all workspaces across all profiles
76+
* (= `NeverShowAgainScope.APPLICATION`).
6977
*/
7078
readonly scope?: NeverShowAgainScope;
7179
}

src/vs/platform/storage/browser/storageService.ts

Lines changed: 68 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -12,76 +12,115 @@ import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'
1212
import { InMemoryStorageDatabase, isStorageItemsChangeEvent, IStorage, IStorageDatabase, IStorageItemsChangeEvent, IUpdateRequest, Storage } from 'vs/base/parts/storage/common/storage';
1313
import { ILogService } from 'vs/platform/log/common/log';
1414
import { AbstractStorageService, IS_NEW_KEY, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
15+
import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
1516
import { IAnyWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace';
1617

1718
export class BrowserStorageService extends AbstractStorageService {
1819

1920
private static BROWSER_DEFAULT_FLUSH_INTERVAL = 5 * 1000; // every 5s because async operations are not permitted on shutdown
2021

22+
private applicationStorage: IStorage | undefined;
2123
private globalStorage: IStorage | undefined;
2224
private workspaceStorage: IStorage | undefined;
2325

26+
private applicationStorageDatabase: IIndexedDBStorageDatabase | undefined;
2427
private globalStorageDatabase: IIndexedDBStorageDatabase | undefined;
2528
private workspaceStorageDatabase: IIndexedDBStorageDatabase | undefined;
2629

2730
get hasPendingUpdate(): boolean {
28-
return Boolean(this.globalStorageDatabase?.hasPendingUpdate || this.workspaceStorageDatabase?.hasPendingUpdate);
31+
return Boolean(
32+
this.applicationStorageDatabase?.hasPendingUpdate ||
33+
this.globalStorageDatabase?.hasPendingUpdate ||
34+
this.workspaceStorageDatabase?.hasPendingUpdate
35+
);
2936
}
3037

3138
constructor(
3239
private readonly payload: IAnyWorkspaceIdentifier,
33-
@ILogService private readonly logService: ILogService
40+
@ILogService private readonly logService: ILogService,
41+
@IUserDataProfilesService private readonly userDataProfileService: IUserDataProfilesService
3442
) {
3543
super({ flushInterval: BrowserStorageService.BROWSER_DEFAULT_FLUSH_INTERVAL });
3644
}
3745

3846
private getId(scope: StorageScope): string {
39-
return scope === StorageScope.GLOBAL ? 'global' : this.payload.id;
47+
switch (scope) {
48+
case StorageScope.APPLICATION:
49+
return 'global'; // use the default profile global DB for application scope
50+
case StorageScope.GLOBAL:
51+
if (this.userDataProfileService.currentProfile.isDefault) {
52+
return 'global'; // default profile DB has a fixed name for backwards compatibility
53+
} else {
54+
return `global-${this.userDataProfileService.currentProfile.id}`;
55+
}
56+
case StorageScope.WORKSPACE:
57+
return this.payload.id;
58+
}
4059
}
4160

4261
protected async doInitialize(): Promise<void> {
4362

4463
// Create Storage in Parallel
45-
const [workspaceStorageDatabase, globalStorageDatabase] = await Promises.settled([
46-
IndexedDBStorageDatabase.create({ id: this.getId(StorageScope.WORKSPACE) }, this.logService),
47-
IndexedDBStorageDatabase.create({ id: this.getId(StorageScope.GLOBAL), broadcastChanges: true /* only for global storage */ }, this.logService)
48-
]);
64+
const promises: Promise<IIndexedDBStorageDatabase>[] = [];
65+
promises.push(IndexedDBStorageDatabase.create({ id: this.getId(StorageScope.APPLICATION), broadcastChanges: true }, this.logService));
66+
promises.push(IndexedDBStorageDatabase.create({ id: this.getId(StorageScope.WORKSPACE) }, this.logService));
67+
if (!this.userDataProfileService.currentProfile.isDefault) {
68+
69+
// If we are in default profile, the global storage is
70+
// actually the same as application storage. As such we
71+
// avoid creating the storage library a second time on
72+
// the same DB.
73+
74+
promises.push(IndexedDBStorageDatabase.create({ id: this.getId(StorageScope.GLOBAL), broadcastChanges: true }, this.logService));
75+
}
76+
const [applicationStorageDatabase, workspaceStorageDatabase, globalStorageDatabase] = await Promises.settled(promises);
4977

5078
// Workspace Storage
5179
this.workspaceStorageDatabase = this._register(workspaceStorageDatabase);
5280
this.workspaceStorage = this._register(new Storage(this.workspaceStorageDatabase));
5381
this._register(this.workspaceStorage.onDidChangeStorage(key => this.emitDidChangeValue(StorageScope.WORKSPACE, key)));
5482

83+
// Application Storage
84+
this.applicationStorageDatabase = this._register(applicationStorageDatabase);
85+
this.applicationStorage = this._register(new Storage(this.applicationStorageDatabase));
86+
this._register(this.applicationStorage.onDidChangeStorage(key => this.emitDidChangeValue(StorageScope.APPLICATION, key)));
87+
5588
// Global Storage
56-
this.globalStorageDatabase = this._register(globalStorageDatabase);
57-
this.globalStorage = this._register(new Storage(this.globalStorageDatabase));
89+
if (globalStorageDatabase) {
90+
this.globalStorageDatabase = this._register(globalStorageDatabase);
91+
this.globalStorage = this._register(new Storage(this.globalStorageDatabase));
92+
} else {
93+
this.globalStorage = this.applicationStorage;
94+
}
5895
this._register(this.globalStorage.onDidChangeStorage(key => this.emitDidChangeValue(StorageScope.GLOBAL, key)));
5996

60-
// Init both
97+
// Init storages
6198
await Promises.settled([
6299
this.workspaceStorage.init(),
63-
this.globalStorage.init()
100+
this.globalStorage.init(),
101+
this.applicationStorage.init()
64102
]);
65103

66-
// Check to see if this is the first time we are "opening" the application
67-
const firstOpen = this.globalStorage.getBoolean(IS_NEW_KEY);
68-
if (firstOpen === undefined) {
69-
this.globalStorage.set(IS_NEW_KEY, true);
70-
} else if (firstOpen) {
71-
this.globalStorage.set(IS_NEW_KEY, false);
72-
}
73-
74-
// Check to see if this is the first time we are "opening" this workspace
75-
const firstWorkspaceOpen = this.workspaceStorage.getBoolean(IS_NEW_KEY);
76-
if (firstWorkspaceOpen === undefined) {
77-
this.workspaceStorage.set(IS_NEW_KEY, true);
78-
} else if (firstWorkspaceOpen) {
79-
this.workspaceStorage.set(IS_NEW_KEY, false);
104+
// Apply is-new markers
105+
for (const storage of [this.applicationStorage, this.globalStorage, this.workspaceStorage]) {
106+
const firstOpen = storage.getBoolean(IS_NEW_KEY);
107+
if (firstOpen === undefined) {
108+
storage.set(IS_NEW_KEY, true);
109+
} else if (firstOpen) {
110+
storage.set(IS_NEW_KEY, false);
111+
}
80112
}
81113
}
82114

83115
protected getStorage(scope: StorageScope): IStorage | undefined {
84-
return scope === StorageScope.GLOBAL ? this.globalStorage : this.workspaceStorage;
116+
switch (scope) {
117+
case StorageScope.APPLICATION:
118+
return this.applicationStorage;
119+
case StorageScope.GLOBAL:
120+
return this.globalStorage;
121+
default:
122+
return this.workspaceStorage;
123+
}
85124
}
86125

87126
protected getLogDetails(scope: StorageScope): string | undefined {
@@ -115,6 +154,7 @@ export class BrowserStorageService extends AbstractStorageService {
115154
// On all other browsers, we keep the databases opened because
116155
// we expect data to be written when the unload happens.
117156
if (isSafari) {
157+
this.applicationStorage?.close();
118158
this.globalStorageDatabase?.close();
119159
this.workspaceStorageDatabase?.close();
120160
}
@@ -127,7 +167,7 @@ export class BrowserStorageService extends AbstractStorageService {
127167
async clear(): Promise<void> {
128168

129169
// Clear key/values
130-
for (const scope of [StorageScope.GLOBAL, StorageScope.WORKSPACE]) {
170+
for (const scope of [StorageScope.APPLICATION, StorageScope.GLOBAL, StorageScope.WORKSPACE]) {
131171
for (const target of [StorageTarget.USER, StorageTarget.MACHINE]) {
132172
for (const key of this.keys(scope, target)) {
133173
this.remove(key, scope);
@@ -139,6 +179,7 @@ export class BrowserStorageService extends AbstractStorageService {
139179

140180
// Clear databases
141181
await Promises.settled([
182+
this.applicationStorageDatabase?.clear() ?? Promise.resolve(),
142183
this.globalStorageDatabase?.clear() ?? Promise.resolve(),
143184
this.workspaceStorageDatabase?.clear() ?? Promise.resolve()
144185
]);

0 commit comments

Comments
 (0)