@instantdb/core 0.22.97 → 0.22.98
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commonjs/Connection.js +50 -51
- package/dist/commonjs/Connection.js.map +1 -1
- package/dist/commonjs/InMemoryStorage.js +13 -32
- package/dist/commonjs/InMemoryStorage.js.map +1 -1
- package/dist/commonjs/IndexedDBStorage.js +193 -217
- package/dist/commonjs/IndexedDBStorage.js.map +1 -1
- package/dist/commonjs/InstantError.js +1 -0
- package/dist/commonjs/InstantError.js.map +1 -1
- package/dist/commonjs/Reactor.js +566 -610
- package/dist/commonjs/Reactor.js.map +1 -1
- package/dist/commonjs/StorageAPI.js +51 -70
- package/dist/commonjs/StorageAPI.js.map +1 -1
- package/dist/commonjs/SyncTable.js +68 -81
- package/dist/commonjs/SyncTable.js.map +1 -1
- package/dist/commonjs/WindowNetworkListener.js +2 -13
- package/dist/commonjs/WindowNetworkListener.js.map +1 -1
- package/dist/commonjs/__types__/fieldsTypeTest.js +8 -16
- package/dist/commonjs/__types__/fieldsTypeTest.js.map +1 -1
- package/dist/commonjs/__types__/useDatesTypeTest.js +3 -6
- package/dist/commonjs/__types__/useDatesTypeTest.js.map +1 -1
- package/dist/commonjs/authAPI.js +62 -79
- package/dist/commonjs/authAPI.js.map +1 -1
- package/dist/commonjs/createRouteHandler.js +5 -15
- package/dist/commonjs/createRouteHandler.js.map +1 -1
- package/dist/commonjs/datalog.js +1 -1
- package/dist/commonjs/datalog.js.map +1 -1
- package/dist/commonjs/devtool.js +26 -8
- package/dist/commonjs/devtool.js.map +1 -1
- package/dist/commonjs/framework.d.ts.map +1 -1
- package/dist/commonjs/framework.js +142 -152
- package/dist/commonjs/framework.js.map +1 -1
- package/dist/commonjs/index.js +204 -190
- package/dist/commonjs/index.js.map +1 -1
- package/dist/commonjs/instaml.js +44 -30
- package/dist/commonjs/instaml.js.map +1 -1
- package/dist/commonjs/instaql.js +25 -33
- package/dist/commonjs/instaql.js.map +1 -1
- package/dist/commonjs/parseSchemaFromJSON.js +6 -7
- package/dist/commonjs/parseSchemaFromJSON.js.map +1 -1
- package/dist/commonjs/presence.js +7 -8
- package/dist/commonjs/presence.js.map +1 -1
- package/dist/commonjs/queryValidation.js +1 -2
- package/dist/commonjs/queryValidation.js.map +1 -1
- package/dist/commonjs/schema.js +8 -6
- package/dist/commonjs/schema.js.map +1 -1
- package/dist/commonjs/schemaTypes.js +22 -3
- package/dist/commonjs/schemaTypes.js.map +1 -1
- package/dist/commonjs/store.js +29 -38
- package/dist/commonjs/store.js.map +1 -1
- package/dist/commonjs/transactionValidation.js +1 -2
- package/dist/commonjs/transactionValidation.js.map +1 -1
- package/dist/commonjs/utils/Deferred.js +3 -0
- package/dist/commonjs/utils/Deferred.js.map +1 -1
- package/dist/commonjs/utils/PersistedObject.js +216 -233
- package/dist/commonjs/utils/PersistedObject.js.map +1 -1
- package/dist/commonjs/utils/fetch.js +9 -19
- package/dist/commonjs/utils/fetch.js.map +1 -1
- package/dist/commonjs/utils/linkIndex.js +2 -4
- package/dist/commonjs/utils/linkIndex.js.map +1 -1
- package/dist/commonjs/utils/object.js +1 -1
- package/dist/commonjs/utils/object.js.map +1 -1
- package/dist/esm/Connection.js +50 -51
- package/dist/esm/Connection.js.map +1 -1
- package/dist/esm/InMemoryStorage.js +13 -32
- package/dist/esm/InMemoryStorage.js.map +1 -1
- package/dist/esm/IndexedDBStorage.js +193 -217
- package/dist/esm/IndexedDBStorage.js.map +1 -1
- package/dist/esm/InstantError.js +1 -0
- package/dist/esm/InstantError.js.map +1 -1
- package/dist/esm/Reactor.js +566 -610
- package/dist/esm/Reactor.js.map +1 -1
- package/dist/esm/StorageAPI.js +51 -70
- package/dist/esm/StorageAPI.js.map +1 -1
- package/dist/esm/SyncTable.js +68 -81
- package/dist/esm/SyncTable.js.map +1 -1
- package/dist/esm/WindowNetworkListener.js +2 -13
- package/dist/esm/WindowNetworkListener.js.map +1 -1
- package/dist/esm/__types__/fieldsTypeTest.js +8 -16
- package/dist/esm/__types__/fieldsTypeTest.js.map +1 -1
- package/dist/esm/__types__/useDatesTypeTest.js +3 -6
- package/dist/esm/__types__/useDatesTypeTest.js.map +1 -1
- package/dist/esm/authAPI.js +62 -79
- package/dist/esm/authAPI.js.map +1 -1
- package/dist/esm/createRouteHandler.js +5 -15
- package/dist/esm/createRouteHandler.js.map +1 -1
- package/dist/esm/datalog.js +1 -1
- package/dist/esm/datalog.js.map +1 -1
- package/dist/esm/devtool.js +26 -8
- package/dist/esm/devtool.js.map +1 -1
- package/dist/esm/framework.d.ts.map +1 -1
- package/dist/esm/framework.js +142 -152
- package/dist/esm/framework.js.map +1 -1
- package/dist/esm/index.js +204 -190
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/instaml.js +44 -30
- package/dist/esm/instaml.js.map +1 -1
- package/dist/esm/instaql.js +25 -33
- package/dist/esm/instaql.js.map +1 -1
- package/dist/esm/parseSchemaFromJSON.js +6 -7
- package/dist/esm/parseSchemaFromJSON.js.map +1 -1
- package/dist/esm/presence.js +7 -8
- package/dist/esm/presence.js.map +1 -1
- package/dist/esm/queryValidation.js +1 -2
- package/dist/esm/queryValidation.js.map +1 -1
- package/dist/esm/schema.js +8 -6
- package/dist/esm/schema.js.map +1 -1
- package/dist/esm/schemaTypes.js +22 -3
- package/dist/esm/schemaTypes.js.map +1 -1
- package/dist/esm/store.js +29 -38
- package/dist/esm/store.js.map +1 -1
- package/dist/esm/transactionValidation.js +1 -2
- package/dist/esm/transactionValidation.js.map +1 -1
- package/dist/esm/utils/Deferred.js +3 -0
- package/dist/esm/utils/Deferred.js.map +1 -1
- package/dist/esm/utils/PersistedObject.js +216 -233
- package/dist/esm/utils/PersistedObject.js.map +1 -1
- package/dist/esm/utils/fetch.js +9 -19
- package/dist/esm/utils/fetch.js.map +1 -1
- package/dist/esm/utils/linkIndex.js +2 -4
- package/dist/esm/utils/linkIndex.js.map +1 -1
- package/dist/esm/utils/object.js +1 -1
- package/dist/esm/utils/object.js.map +1 -1
- package/dist/standalone/index.js +2610 -2367
- package/dist/standalone/index.umd.cjs +3 -3
- package/package.json +2 -2
- package/src/framework.ts +0 -1
|
@@ -12,15 +12,6 @@
|
|
|
12
12
|
// Each PersistedObject provides it's own `onMerge`
|
|
13
13
|
// function to handle the merge of data from storage and memory
|
|
14
14
|
// on load
|
|
15
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
16
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
17
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
18
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
19
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
20
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
21
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
22
|
-
});
|
|
23
|
-
};
|
|
24
15
|
// Uses `requestIdleCallback` if available, otherwise calls the
|
|
25
16
|
// callback immediately
|
|
26
17
|
import { create } from 'mutative';
|
|
@@ -37,29 +28,40 @@ export class StorageInterface {
|
|
|
37
28
|
constructor(appId, storeName) { }
|
|
38
29
|
}
|
|
39
30
|
export class PersistedObject {
|
|
31
|
+
currentValue;
|
|
32
|
+
_subs = [];
|
|
33
|
+
_persister;
|
|
34
|
+
_merge;
|
|
35
|
+
serialize;
|
|
36
|
+
parse;
|
|
37
|
+
_saveThrottleMs;
|
|
38
|
+
_idleCallbackMaxWaitMs;
|
|
39
|
+
_nextSave = null;
|
|
40
|
+
_nextGc = null;
|
|
41
|
+
_pendingSaveKeys = new Set();
|
|
42
|
+
_loadedKeys = new Set();
|
|
43
|
+
_loadingKeys;
|
|
44
|
+
_objectSize;
|
|
45
|
+
_log;
|
|
46
|
+
onKeyLoaded;
|
|
47
|
+
_version = 0;
|
|
48
|
+
_meta = {
|
|
49
|
+
isLoading: true,
|
|
50
|
+
onLoadCbs: [],
|
|
51
|
+
value: null,
|
|
52
|
+
error: null,
|
|
53
|
+
attempts: 0,
|
|
54
|
+
};
|
|
55
|
+
_gcOpts;
|
|
40
56
|
constructor(opts) {
|
|
41
|
-
var _a, _b;
|
|
42
|
-
this._subs = [];
|
|
43
|
-
this._nextSave = null;
|
|
44
|
-
this._nextGc = null;
|
|
45
|
-
this._pendingSaveKeys = new Set();
|
|
46
|
-
this._loadedKeys = new Set();
|
|
47
|
-
this._version = 0;
|
|
48
|
-
this._meta = {
|
|
49
|
-
isLoading: true,
|
|
50
|
-
onLoadCbs: [],
|
|
51
|
-
value: null,
|
|
52
|
-
error: null,
|
|
53
|
-
attempts: 0,
|
|
54
|
-
};
|
|
55
57
|
this._persister = opts.persister;
|
|
56
58
|
this._merge = opts.merge;
|
|
57
59
|
this.serialize = opts.serialize;
|
|
58
60
|
this.parse = opts.parse;
|
|
59
61
|
this._objectSize = opts.objectSize;
|
|
60
62
|
this._log = opts.logger;
|
|
61
|
-
this._saveThrottleMs =
|
|
62
|
-
this._idleCallbackMaxWaitMs =
|
|
63
|
+
this._saveThrottleMs = opts.saveThrottleMs ?? 100;
|
|
64
|
+
this._idleCallbackMaxWaitMs = opts.idleCallbackMaxWaitMs ?? 1000;
|
|
63
65
|
this._gcOpts = opts.gc;
|
|
64
66
|
this.currentValue = {};
|
|
65
67
|
this._loadedKeys = new Set();
|
|
@@ -69,97 +71,85 @@ export class PersistedObject {
|
|
|
69
71
|
this._preloadEntries(opts.preloadEntryCount);
|
|
70
72
|
}
|
|
71
73
|
}
|
|
72
|
-
_initMeta() {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
74
|
+
async _initMeta() {
|
|
75
|
+
if (this._meta.loadingPromise) {
|
|
76
|
+
await this._meta.loadingPromise;
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
const p = this._persister.getItem(META_KEY);
|
|
80
|
+
this._meta.loadingPromise = p;
|
|
81
|
+
const v = await p;
|
|
82
|
+
this._meta.isLoading = false;
|
|
83
|
+
this._meta.error = null;
|
|
84
|
+
this._meta.loadingPromise = null;
|
|
85
|
+
this._meta.attempts = 0;
|
|
86
|
+
const existingObjects = this._meta.value?.objects ?? {};
|
|
87
|
+
const value = v ?? {};
|
|
88
|
+
const objects = value.objects ?? {};
|
|
89
|
+
// Merge the values from storage with in-memory values
|
|
90
|
+
this._meta.value = {
|
|
91
|
+
...value,
|
|
92
|
+
objects: { ...existingObjects, ...objects },
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
catch (e) {
|
|
96
|
+
this._meta.error = e;
|
|
97
|
+
this._meta.attempts++;
|
|
98
|
+
this._meta.loadingPromise = null;
|
|
99
|
+
}
|
|
98
100
|
}
|
|
99
|
-
_getMeta() {
|
|
100
|
-
|
|
101
|
-
if (this._meta.value) {
|
|
102
|
-
return this._meta.value;
|
|
103
|
-
}
|
|
104
|
-
if (this._meta.loadingPromise) {
|
|
105
|
-
yield this._meta.loadingPromise;
|
|
106
|
-
return this._meta.value;
|
|
107
|
-
}
|
|
108
|
-
this._initMeta();
|
|
109
|
-
yield this._meta.loadingPromise;
|
|
101
|
+
async _getMeta() {
|
|
102
|
+
if (this._meta.value) {
|
|
110
103
|
return this._meta.value;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
115
|
-
yield this._initMeta();
|
|
104
|
+
}
|
|
105
|
+
if (this._meta.loadingPromise) {
|
|
106
|
+
await this._meta.loadingPromise;
|
|
116
107
|
return this._meta.value;
|
|
117
|
-
}
|
|
108
|
+
}
|
|
109
|
+
this._initMeta();
|
|
110
|
+
await this._meta.loadingPromise;
|
|
111
|
+
return this._meta.value;
|
|
118
112
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
if (!meta)
|
|
123
|
-
return;
|
|
124
|
-
const entries = Object.entries(meta.objects);
|
|
125
|
-
entries.sort(([_k_a, a_meta], [_k_b, b_meta]) => {
|
|
126
|
-
return b_meta.updatedAt - a_meta.updatedAt;
|
|
127
|
-
});
|
|
128
|
-
for (const [k] of entries.slice(0, n)) {
|
|
129
|
-
this._loadKey(k);
|
|
130
|
-
}
|
|
131
|
-
});
|
|
113
|
+
async _refreshMeta() {
|
|
114
|
+
await this._initMeta();
|
|
115
|
+
return this._meta.value;
|
|
132
116
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const parsed = this.parse(key, data);
|
|
141
|
-
return parsed;
|
|
142
|
-
}
|
|
143
|
-
catch (e) {
|
|
144
|
-
console.error(`Unable to read from storage for key=${key}`, e);
|
|
145
|
-
return null;
|
|
146
|
-
}
|
|
117
|
+
async _preloadEntries(n) {
|
|
118
|
+
const meta = await this.waitForMetaToLoad();
|
|
119
|
+
if (!meta)
|
|
120
|
+
return;
|
|
121
|
+
const entries = Object.entries(meta.objects);
|
|
122
|
+
entries.sort(([_k_a, a_meta], [_k_b, b_meta]) => {
|
|
123
|
+
return b_meta.updatedAt - a_meta.updatedAt;
|
|
147
124
|
});
|
|
125
|
+
for (const [k] of entries.slice(0, n)) {
|
|
126
|
+
this._loadKey(k);
|
|
127
|
+
}
|
|
148
128
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
129
|
+
async _getFromStorage(key) {
|
|
130
|
+
try {
|
|
131
|
+
const data = await this._persister.getItem(key);
|
|
132
|
+
if (!data) {
|
|
133
|
+
return data;
|
|
153
134
|
}
|
|
154
|
-
|
|
135
|
+
const parsed = this.parse(key, data);
|
|
136
|
+
return parsed;
|
|
137
|
+
}
|
|
138
|
+
catch (e) {
|
|
139
|
+
console.error(`Unable to read from storage for key=${key}`, e);
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
async waitForKeyToLoad(k) {
|
|
144
|
+
if (this._loadedKeys.has(k)) {
|
|
155
145
|
return this.currentValue[k];
|
|
156
|
-
}
|
|
146
|
+
}
|
|
147
|
+
await (this._loadingKeys[k] || this._loadKey(k));
|
|
148
|
+
return this.currentValue[k];
|
|
157
149
|
}
|
|
158
150
|
// Used for tests
|
|
159
|
-
waitForMetaToLoad() {
|
|
160
|
-
return
|
|
161
|
-
return this._getMeta();
|
|
162
|
-
});
|
|
151
|
+
async waitForMetaToLoad() {
|
|
152
|
+
return this._getMeta();
|
|
163
153
|
}
|
|
164
154
|
// Unloads the key so that it can be garbage collected, but does not
|
|
165
155
|
// delete it. Removes the key from currentValue.
|
|
@@ -168,41 +158,38 @@ export class PersistedObject {
|
|
|
168
158
|
delete this._loadingKeys[k];
|
|
169
159
|
delete this.currentValue[k];
|
|
170
160
|
}
|
|
171
|
-
_loadKey(k) {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
this.currentValue[k] = merged;
|
|
184
|
-
}
|
|
161
|
+
async _loadKey(k) {
|
|
162
|
+
if (this._loadedKeys.has(k) || k in this._loadingKeys)
|
|
163
|
+
return;
|
|
164
|
+
const p = this._getFromStorage(k);
|
|
165
|
+
this._loadingKeys[k] = p;
|
|
166
|
+
const value = await p;
|
|
167
|
+
delete this._loadingKeys[k];
|
|
168
|
+
this._loadedKeys.add(k);
|
|
169
|
+
if (value) {
|
|
170
|
+
const merged = this._merge(k, value, this.currentValue[k]);
|
|
171
|
+
if (merged) {
|
|
172
|
+
this.currentValue[k] = merged;
|
|
185
173
|
}
|
|
186
|
-
|
|
187
|
-
|
|
174
|
+
}
|
|
175
|
+
this.onKeyLoaded && this.onKeyLoaded(k);
|
|
188
176
|
}
|
|
189
177
|
// Returns a promise with a number so that we can wait for flush
|
|
190
178
|
// to finish in the tests. The number is the number of operations
|
|
191
179
|
// it performed, but it's mostly there so that typescript will warn
|
|
192
180
|
// us if we forget to retun the promise from the function.
|
|
193
181
|
_writeToStorage(opts) {
|
|
194
|
-
var _a, _b;
|
|
195
182
|
const promises = [];
|
|
196
|
-
const skipGc = opts
|
|
183
|
+
const skipGc = opts?.skipGc;
|
|
197
184
|
if (this._meta.isLoading) {
|
|
198
185
|
// Wait for meta to load and try again, give it a delay so that
|
|
199
186
|
// we don't spend too much time retrying
|
|
200
187
|
const p = new Promise((resolve, reject) => {
|
|
201
|
-
var _a;
|
|
202
188
|
setTimeout(() => this._enqueuePersist(opts
|
|
203
|
-
?
|
|
189
|
+
? { ...opts, attempts: (opts.attempts || 0) + 1 }
|
|
190
|
+
: { attempts: 1 })
|
|
204
191
|
.then(resolve)
|
|
205
|
-
.catch(reject), 10 + (
|
|
192
|
+
.catch(reject), 10 + (opts?.attempts ?? 0) * 1000);
|
|
206
193
|
});
|
|
207
194
|
promises.push(p);
|
|
208
195
|
return Promise.all(promises).then((vs) => vs.reduce((acc, x) => acc + x, 0));
|
|
@@ -233,14 +220,14 @@ export class PersistedObject {
|
|
|
233
220
|
}
|
|
234
221
|
const keysToLoad = [];
|
|
235
222
|
const kvPairs = [[META_KEY, metaValue]];
|
|
236
|
-
const metaObjects =
|
|
223
|
+
const metaObjects = metaValue.objects ?? {};
|
|
237
224
|
metaValue.objects = metaObjects;
|
|
238
225
|
for (const k of keysToUpdate) {
|
|
239
226
|
if (this._loadedKeys.has(k)) {
|
|
240
227
|
const serializedV = this.serialize(k, this.currentValue[k]);
|
|
241
228
|
kvPairs.push([k, serializedV]);
|
|
242
229
|
const size = this._objectSize(serializedV);
|
|
243
|
-
const m =
|
|
230
|
+
const m = metaObjects[k] ?? {
|
|
244
231
|
createdAt: Date.now(),
|
|
245
232
|
updatedAt: Date.now(),
|
|
246
233
|
size,
|
|
@@ -271,119 +258,115 @@ export class PersistedObject {
|
|
|
271
258
|
return vs.reduce((acc, x) => acc + x, 0);
|
|
272
259
|
});
|
|
273
260
|
}
|
|
274
|
-
flush() {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
return p;
|
|
283
|
-
});
|
|
261
|
+
async flush() {
|
|
262
|
+
if (!this._nextSave) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
clearTimeout(this._nextSave);
|
|
266
|
+
this._nextSave = null;
|
|
267
|
+
const p = this._writeToStorage();
|
|
268
|
+
return p;
|
|
284
269
|
}
|
|
285
|
-
_gc() {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
continue;
|
|
323
|
-
}
|
|
324
|
-
this._log.info('Lost track of key in meta', key);
|
|
325
|
-
promises.push(this._persister.removeItem(key));
|
|
326
|
-
deets.removed.push(key);
|
|
327
|
-
deets.removedMissingCount++;
|
|
328
|
-
}
|
|
329
|
-
// Remove anything over the max age
|
|
330
|
-
const now = Date.now();
|
|
331
|
-
for (const [k, m] of Object.entries(meta.objects)) {
|
|
332
|
-
if (!sacredKeys.has(k) &&
|
|
333
|
-
m.updatedAt < now - this._gcOpts.maxAgeMs) {
|
|
334
|
-
promises.push(this._persister.removeItem(k));
|
|
335
|
-
delete meta.objects[k];
|
|
336
|
-
deets.removed.push(k);
|
|
337
|
-
deets.removedOldCount++;
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
// Keep queries under max queries
|
|
341
|
-
const maxEntries = Object.entries(meta.objects);
|
|
342
|
-
maxEntries.sort(([_k_a, a_meta], [_k_b, b_meta]) => {
|
|
343
|
-
return a_meta.updatedAt - b_meta.updatedAt;
|
|
344
|
-
});
|
|
345
|
-
const deletableMaxEntries = maxEntries.filter(([x]) => !sacredKeys.has(x));
|
|
346
|
-
if (maxEntries.length > this._gcOpts.maxEntries) {
|
|
347
|
-
for (const [k] of deletableMaxEntries.slice(0, maxEntries.length - this._gcOpts.maxEntries)) {
|
|
348
|
-
promises.push(this._persister.removeItem(k));
|
|
349
|
-
delete meta.objects[k];
|
|
350
|
-
deets.removed.push(k);
|
|
351
|
-
deets.removedThresholdCount++;
|
|
352
|
-
}
|
|
270
|
+
async _gc() {
|
|
271
|
+
if (!this._gcOpts) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
const keys = new Set(await this._persister.getAllKeys());
|
|
275
|
+
keys.delete(META_KEY);
|
|
276
|
+
// Keys we can't delete
|
|
277
|
+
const sacredKeys = new Set(Object.keys(this.currentValue));
|
|
278
|
+
for (const k of Object.keys(this._loadingKeys)) {
|
|
279
|
+
sacredKeys.add(k);
|
|
280
|
+
}
|
|
281
|
+
for (const k of this._loadedKeys) {
|
|
282
|
+
sacredKeys.add(k);
|
|
283
|
+
}
|
|
284
|
+
// Refresh meta from the store so that we're less likely to
|
|
285
|
+
// clobber data from other tabs
|
|
286
|
+
const meta = await this._refreshMeta();
|
|
287
|
+
if (!meta) {
|
|
288
|
+
this._log.info('Could not gc because we were not able to load meta');
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
const promises = [];
|
|
292
|
+
const deets = {
|
|
293
|
+
gcOpts: this._gcOpts,
|
|
294
|
+
keys,
|
|
295
|
+
sacredKeys,
|
|
296
|
+
removed: [],
|
|
297
|
+
metaRemoved: [],
|
|
298
|
+
removedMissingCount: 0,
|
|
299
|
+
removedOldCount: 0,
|
|
300
|
+
removedThresholdCount: 0,
|
|
301
|
+
removedSizeCount: 0,
|
|
302
|
+
};
|
|
303
|
+
// First, remove all keys we don't know about
|
|
304
|
+
for (const key of keys) {
|
|
305
|
+
if (sacredKeys.has(key) || key in meta.objects) {
|
|
306
|
+
continue;
|
|
353
307
|
}
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
currentSize > this._gcOpts.maxSize &&
|
|
365
|
-
deletableDelEntries.length) {
|
|
366
|
-
const [[k, m]] = deletableDelEntries.splice(0, 1);
|
|
367
|
-
currentSize -= m.size;
|
|
308
|
+
this._log.info('Lost track of key in meta', key);
|
|
309
|
+
promises.push(this._persister.removeItem(key));
|
|
310
|
+
deets.removed.push(key);
|
|
311
|
+
deets.removedMissingCount++;
|
|
312
|
+
}
|
|
313
|
+
// Remove anything over the max age
|
|
314
|
+
const now = Date.now();
|
|
315
|
+
for (const [k, m] of Object.entries(meta.objects)) {
|
|
316
|
+
if (!sacredKeys.has(k) &&
|
|
317
|
+
m.updatedAt < now - this._gcOpts.maxAgeMs) {
|
|
368
318
|
promises.push(this._persister.removeItem(k));
|
|
369
319
|
delete meta.objects[k];
|
|
370
320
|
deets.removed.push(k);
|
|
371
|
-
deets.
|
|
321
|
+
deets.removedOldCount++;
|
|
372
322
|
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
323
|
+
}
|
|
324
|
+
// Keep queries under max queries
|
|
325
|
+
const maxEntries = Object.entries(meta.objects);
|
|
326
|
+
maxEntries.sort(([_k_a, a_meta], [_k_b, b_meta]) => {
|
|
327
|
+
return a_meta.updatedAt - b_meta.updatedAt;
|
|
328
|
+
});
|
|
329
|
+
const deletableMaxEntries = maxEntries.filter(([x]) => !sacredKeys.has(x));
|
|
330
|
+
if (maxEntries.length > this._gcOpts.maxEntries) {
|
|
331
|
+
for (const [k] of deletableMaxEntries.slice(0, maxEntries.length - this._gcOpts.maxEntries)) {
|
|
332
|
+
promises.push(this._persister.removeItem(k));
|
|
333
|
+
delete meta.objects[k];
|
|
334
|
+
deets.removed.push(k);
|
|
335
|
+
deets.removedThresholdCount++;
|
|
382
336
|
}
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
337
|
+
}
|
|
338
|
+
// Remove oldest entries until we are under max size
|
|
339
|
+
const delEntries = Object.entries(meta.objects);
|
|
340
|
+
delEntries.sort(([_k_a, a_meta], [_k_b, b_meta]) => {
|
|
341
|
+
return a_meta.updatedAt - b_meta.updatedAt;
|
|
386
342
|
});
|
|
343
|
+
const deletableDelEntries = delEntries.filter(([x]) => !sacredKeys.has(x));
|
|
344
|
+
let currentSize = delEntries.reduce((acc, [_k, m]) => {
|
|
345
|
+
return acc + m.size;
|
|
346
|
+
}, 0);
|
|
347
|
+
while (currentSize > 0 &&
|
|
348
|
+
currentSize > this._gcOpts.maxSize &&
|
|
349
|
+
deletableDelEntries.length) {
|
|
350
|
+
const [[k, m]] = deletableDelEntries.splice(0, 1);
|
|
351
|
+
currentSize -= m.size;
|
|
352
|
+
promises.push(this._persister.removeItem(k));
|
|
353
|
+
delete meta.objects[k];
|
|
354
|
+
deets.removed.push(k);
|
|
355
|
+
deets.removedSizeCount++;
|
|
356
|
+
}
|
|
357
|
+
// Update meta to remove keys that are no longer in the store
|
|
358
|
+
for (const k of Object.keys(meta.objects)) {
|
|
359
|
+
if (!keys.has(k) && !sacredKeys.has(k)) {
|
|
360
|
+
delete meta.objects[k];
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
if (deets.removed.length || deets.metaRemoved.length) {
|
|
364
|
+
// Trigger a flush of the meta
|
|
365
|
+
promises.push(this._enqueuePersist({ skipGc: true }));
|
|
366
|
+
}
|
|
367
|
+
this._log.info('Completed GC', deets);
|
|
368
|
+
await Promise.all(promises);
|
|
369
|
+
return deets;
|
|
387
370
|
}
|
|
388
371
|
// Schedules a GC to run in one minute (unless it is already scheduled)
|
|
389
372
|
gc() {
|