@@ -12,76 +12,115 @@ import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'
12
12
import { InMemoryStorageDatabase , isStorageItemsChangeEvent , IStorage , IStorageDatabase , IStorageItemsChangeEvent , IUpdateRequest , Storage } from 'vs/base/parts/storage/common/storage' ;
13
13
import { ILogService } from 'vs/platform/log/common/log' ;
14
14
import { AbstractStorageService , IS_NEW_KEY , StorageScope , StorageTarget } from 'vs/platform/storage/common/storage' ;
15
+ import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile' ;
15
16
import { IAnyWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace' ;
16
17
17
18
export class BrowserStorageService extends AbstractStorageService {
18
19
19
20
private static BROWSER_DEFAULT_FLUSH_INTERVAL = 5 * 1000 ; // every 5s because async operations are not permitted on shutdown
20
21
22
+ private applicationStorage : IStorage | undefined ;
21
23
private globalStorage : IStorage | undefined ;
22
24
private workspaceStorage : IStorage | undefined ;
23
25
26
+ private applicationStorageDatabase : IIndexedDBStorageDatabase | undefined ;
24
27
private globalStorageDatabase : IIndexedDBStorageDatabase | undefined ;
25
28
private workspaceStorageDatabase : IIndexedDBStorageDatabase | undefined ;
26
29
27
30
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
+ ) ;
29
36
}
30
37
31
38
constructor (
32
39
private readonly payload : IAnyWorkspaceIdentifier ,
33
- @ILogService private readonly logService : ILogService
40
+ @ILogService private readonly logService : ILogService ,
41
+ @IUserDataProfilesService private readonly userDataProfileService : IUserDataProfilesService
34
42
) {
35
43
super ( { flushInterval : BrowserStorageService . BROWSER_DEFAULT_FLUSH_INTERVAL } ) ;
36
44
}
37
45
38
46
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
+ }
40
59
}
41
60
42
61
protected async doInitialize ( ) : Promise < void > {
43
62
44
63
// 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 ) ;
49
77
50
78
// Workspace Storage
51
79
this . workspaceStorageDatabase = this . _register ( workspaceStorageDatabase ) ;
52
80
this . workspaceStorage = this . _register ( new Storage ( this . workspaceStorageDatabase ) ) ;
53
81
this . _register ( this . workspaceStorage . onDidChangeStorage ( key => this . emitDidChangeValue ( StorageScope . WORKSPACE , key ) ) ) ;
54
82
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
+
55
88
// 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
+ }
58
95
this . _register ( this . globalStorage . onDidChangeStorage ( key => this . emitDidChangeValue ( StorageScope . GLOBAL , key ) ) ) ;
59
96
60
- // Init both
97
+ // Init storages
61
98
await Promises . settled ( [
62
99
this . workspaceStorage . init ( ) ,
63
- this . globalStorage . init ( )
100
+ this . globalStorage . init ( ) ,
101
+ this . applicationStorage . init ( )
64
102
] ) ;
65
103
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
+ }
80
112
}
81
113
}
82
114
83
115
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
+ }
85
124
}
86
125
87
126
protected getLogDetails ( scope : StorageScope ) : string | undefined {
@@ -115,6 +154,7 @@ export class BrowserStorageService extends AbstractStorageService {
115
154
// On all other browsers, we keep the databases opened because
116
155
// we expect data to be written when the unload happens.
117
156
if ( isSafari ) {
157
+ this . applicationStorage ?. close ( ) ;
118
158
this . globalStorageDatabase ?. close ( ) ;
119
159
this . workspaceStorageDatabase ?. close ( ) ;
120
160
}
@@ -127,7 +167,7 @@ export class BrowserStorageService extends AbstractStorageService {
127
167
async clear ( ) : Promise < void > {
128
168
129
169
// Clear key/values
130
- for ( const scope of [ StorageScope . GLOBAL , StorageScope . WORKSPACE ] ) {
170
+ for ( const scope of [ StorageScope . APPLICATION , StorageScope . GLOBAL , StorageScope . WORKSPACE ] ) {
131
171
for ( const target of [ StorageTarget . USER , StorageTarget . MACHINE ] ) {
132
172
for ( const key of this . keys ( scope , target ) ) {
133
173
this . remove ( key , scope ) ;
@@ -139,6 +179,7 @@ export class BrowserStorageService extends AbstractStorageService {
139
179
140
180
// Clear databases
141
181
await Promises . settled ( [
182
+ this . applicationStorageDatabase ?. clear ( ) ?? Promise . resolve ( ) ,
142
183
this . globalStorageDatabase ?. clear ( ) ?? Promise . resolve ( ) ,
143
184
this . workspaceStorageDatabase ?. clear ( ) ?? Promise . resolve ( )
144
185
] ) ;
0 commit comments