sliftutils 1.4.15 → 1.4.16
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/index.d.ts
CHANGED
|
@@ -944,6 +944,8 @@ declare module "sliftutils/storage/BulkDatabase2/BulkDatabaseBase" {
|
|
|
944
944
|
private automaticCompactionAllowed;
|
|
945
945
|
private overlay;
|
|
946
946
|
private streamTimes;
|
|
947
|
+
private columnCache;
|
|
948
|
+
private dataGen;
|
|
947
949
|
private streamRowsOnDisk;
|
|
948
950
|
private streamBytesOnDisk;
|
|
949
951
|
private streamFileName;
|
package/package.json
CHANGED
|
@@ -40,6 +40,8 @@ export declare class BulkDatabaseBase<T extends {
|
|
|
40
40
|
private automaticCompactionAllowed;
|
|
41
41
|
private overlay;
|
|
42
42
|
private streamTimes;
|
|
43
|
+
private columnCache;
|
|
44
|
+
private dataGen;
|
|
43
45
|
private streamRowsOnDisk;
|
|
44
46
|
private streamBytesOnDisk;
|
|
45
47
|
private streamFileName;
|
|
@@ -278,6 +278,17 @@ export class BulkDatabaseBase<T extends { key: string }> {
|
|
|
278
278
|
// overlay to decide whether an incoming remote write is actually newer than what we have.
|
|
279
279
|
private streamTimes = new Map<string, number>();
|
|
280
280
|
|
|
281
|
+
// Cache of fully-resolved (overlay-patched) column results, keyed by column name. The result only
|
|
282
|
+
// changes when the overlay mutates or the reader resets, so we keep it until then — repeat whole-column
|
|
283
|
+
// reads (common in a UI re-render) are then free, however large the column. Each cached array is frozen
|
|
284
|
+
// SHALLOWLY: Object.freeze locks the array itself (callers can't mutate a shared result) but never the
|
|
285
|
+
// element objects or their values, so typed-array column values keep their fast representation.
|
|
286
|
+
private columnCache = new Map<string, { key: string; value: unknown; time: number }[]>();
|
|
287
|
+
// Bumped on every overlay mutation / reader reset. An async column build captures it before its awaits
|
|
288
|
+
// and only caches its result if it hasn't changed since — so a write or reset mid-build (which clears
|
|
289
|
+
// the cache and may swap the reader) can never leave a stale entry behind.
|
|
290
|
+
private dataGen = 0;
|
|
291
|
+
|
|
281
292
|
// Approximate size of the tier-0 stream data on disk: set accurately from the last reader build, then
|
|
282
293
|
// kept current as each flush appends more. Drives the stream-fold trigger (see streamNeedsFold);
|
|
283
294
|
// reset on resetReader, since after a merge/reset the next reader build re-measures it.
|
|
@@ -304,6 +315,8 @@ export class BulkDatabaseBase<T extends { key: string }> {
|
|
|
304
315
|
}
|
|
305
316
|
|
|
306
317
|
private invalidateOverlay(key: string) {
|
|
318
|
+
this.dataGen++;
|
|
319
|
+
this.columnCache.clear();
|
|
307
320
|
this.deps.invalidate(key);
|
|
308
321
|
this.deps.invalidate(OVERLAY_SIGNAL);
|
|
309
322
|
}
|
|
@@ -435,6 +448,8 @@ export class BulkDatabaseBase<T extends { key: string }> {
|
|
|
435
448
|
this.baseFields.clear();
|
|
436
449
|
this.baseFieldsLoading.clear();
|
|
437
450
|
this.overlay.clear();
|
|
451
|
+
this.dataGen++;
|
|
452
|
+
this.columnCache.clear();
|
|
438
453
|
// The next reader build re-measures the stream; clear the estimate so a just-folded stream
|
|
439
454
|
// doesn't keep looking "heavy" and re-trigger a fold before then.
|
|
440
455
|
this.streamRowsOnDisk = 0;
|
|
@@ -1134,14 +1149,21 @@ export class BulkDatabaseBase<T extends { key: string }> {
|
|
|
1134
1149
|
|
|
1135
1150
|
public async getColumn<Column extends keyof T>(column: Column): Promise<{ key: string; value: T[Column]; time: number }[]> {
|
|
1136
1151
|
void this.syncSetup();
|
|
1152
|
+
const col = String(column);
|
|
1153
|
+
const cached = this.columnCache.get(col);
|
|
1154
|
+
if (cached) return cached as { key: string; value: T[Column]; time: number }[];
|
|
1155
|
+
const gen = this.dataGen;
|
|
1137
1156
|
let time = Date.now();
|
|
1138
1157
|
let reader = await this.reader();
|
|
1139
|
-
let base = await reader.getColumn(
|
|
1140
|
-
let result = this.patchColumn(base,
|
|
1158
|
+
let base = await reader.getColumn(col);
|
|
1159
|
+
let result = this.patchColumn(base, col) as { key: string; value: T[Column]; time: number }[];
|
|
1141
1160
|
time = Date.now() - time;
|
|
1142
1161
|
if (time > 50) {
|
|
1143
1162
|
console.log(`${blue(`${this.name}.getColumn(${JSON.stringify(column)})`)} took ${red(formatTime(time))} ${this.formatInfo(reader)}`);
|
|
1144
1163
|
}
|
|
1164
|
+
Object.freeze(result);
|
|
1165
|
+
// Only cache if no write/reset happened during the awaits above (else this result may be stale).
|
|
1166
|
+
if (this.dataGen === gen) this.columnCache.set(col, result);
|
|
1145
1167
|
return result;
|
|
1146
1168
|
}
|
|
1147
1169
|
|
|
@@ -1236,12 +1258,19 @@ export class BulkDatabaseBase<T extends { key: string }> {
|
|
|
1236
1258
|
// Observe the overlay-wide signal so we recompute once the base arrives or the overlay changes.
|
|
1237
1259
|
this.deps.observe(OVERLAY_SIGNAL);
|
|
1238
1260
|
let col = String(column);
|
|
1261
|
+
const cached = this.columnCache.get(col);
|
|
1262
|
+
if (cached) return cached as { key: string; value: T[Column]; time: number }[];
|
|
1239
1263
|
let base = this.baseColumns.get(col);
|
|
1240
1264
|
if (!base) {
|
|
1241
1265
|
this.ensureBaseColumn(col);
|
|
1242
1266
|
return undefined;
|
|
1243
1267
|
}
|
|
1244
|
-
|
|
1268
|
+
// Synchronous (no awaits) → reads the current overlay and caches it atomically; an observer re-runs
|
|
1269
|
+
// (and the cache is cleared) on any later change, so the frozen result is safe to share.
|
|
1270
|
+
let result = this.patchColumn(base, col) as { key: string; value: T[Column]; time: number }[];
|
|
1271
|
+
Object.freeze(result);
|
|
1272
|
+
this.columnCache.set(col, result);
|
|
1273
|
+
return result;
|
|
1245
1274
|
}
|
|
1246
1275
|
|
|
1247
1276
|
public async getColumnInfo() {
|