@fnndsc/cumin 3.16.1 → 3.17.0
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/cache/index.d.ts +4 -3
- package/dist/cache/index.js +13 -1
- package/dist/cache/index.js.map +1 -1
- package/dist/cache/listCache.d.ts +37 -12
- package/dist/cache/listCache.js +88 -21
- package/dist/cache/listCache.js.map +1 -1
- package/dist/cache/listingInvalidation.d.ts +47 -0
- package/dist/cache/listingInvalidation.js +170 -0
- package/dist/cache/listingInvalidation.js.map +1 -0
- package/dist/cache/procCache.d.ts +105 -18
- package/dist/cache/procCache.js +155 -11
- package/dist/cache/procCache.js.map +1 -1
- package/dist/chrisapi/contract.d.ts +2 -0
- package/dist/chrisapi/contract.js.map +1 -1
- package/dist/context/chrisContext.d.ts +23 -1
- package/dist/context/chrisContext.js +41 -2
- package/dist/context/chrisContext.js.map +1 -1
- package/dist/feeds/chrisFeed.d.ts +19 -0
- package/dist/feeds/chrisFeed.js +66 -0
- package/dist/feeds/chrisFeed.js.map +1 -1
- package/dist/io/chrisIO.d.ts +16 -3
- package/dist/io/chrisIO.js +77 -5
- package/dist/io/chrisIO.js.map +1 -1
- package/package.json +1 -1
package/dist/cache/index.d.ts
CHANGED
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
|
-
export { ListCache, listCache_get } from './listCache.js';
|
|
6
|
+
export { ListCache, listCache_get, LIST_CACHE_SIGNAL_BACKED_TTL_MS, LIST_CACHE_SIGNAL_FREE_TTL_MS, LIST_CACHE_PLUGIN_INDEX_TTL_MS, LIST_CACHE_MAX_ENTRIES, } from './listCache.js';
|
|
7
7
|
export type { CacheStats, CacheResult, CacheOptions, ListCacheSnapshot, ListCacheEntrySnapshot } from './listCache.js';
|
|
8
8
|
export { listCheckpointPath_get, listCheckpoint_restore, listCheckpoint_save, listCheckpoint_watch, } from './listCheckpoint.js';
|
|
9
9
|
export type { ListCheckpointRestoreResult } from './listCheckpoint.js';
|
|
10
|
-
export {
|
|
11
|
-
export
|
|
10
|
+
export { listingsForFeeds_note, listingsForFeeds_drop, listingsForRoster_note, listingInvalidation_flush, listingInvalidation_reset, LISTING_INVALIDATION_WINDOW_MS, } from './listingInvalidation.js';
|
|
11
|
+
export { ProcCache, procCache_get, status_isTerminal, feed_isActive, feedTopology_changed, PROC_TERMINAL_STATUSES, PROC_ARRIVAL_TTL_MS } from './procCache.js';
|
|
12
|
+
export type { RosterFolders, ProcInstance, ProcFeed, ProcFeedScopeCounts, ProcWarmupProgress, ProcFeedLoadProgress, ProcCacheState, ProcCacheLifecycle, ProcCacheSnapshot, ProcFeedSnapshot, ProcCacheChange, ProcCacheListener, } from './procCache.js';
|
|
12
13
|
export type { ProcPromptState, ProcPromptProgress } from '@fnndsc/menu';
|
|
13
14
|
export { procCheckpointPath_get, procCheckpointDir_get, procCheckpoint_restore, procCheckpoint_save, procCheckpointFeed_save, procCheckpointRoster_save, procCheckpoint_watch, } from './procCheckpoint.js';
|
|
14
15
|
export type { ProcCheckpointRestoreResult } from './procCheckpoint.js';
|
package/dist/cache/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.procCheckpoint_watch = exports.procCheckpointRoster_save = exports.procCheckpointFeed_save = exports.procCheckpoint_save = exports.procCheckpoint_restore = exports.procCheckpointDir_get = exports.procCheckpointPath_get = exports.PROC_TERMINAL_STATUSES = exports.feedTopology_changed = exports.feed_isActive = exports.status_isTerminal = exports.procCache_get = exports.ProcCache = exports.listCheckpoint_watch = exports.listCheckpoint_save = exports.listCheckpoint_restore = exports.listCheckpointPath_get = exports.listCache_get = exports.ListCache = void 0;
|
|
3
|
+
exports.procCheckpoint_watch = exports.procCheckpointRoster_save = exports.procCheckpointFeed_save = exports.procCheckpoint_save = exports.procCheckpoint_restore = exports.procCheckpointDir_get = exports.procCheckpointPath_get = exports.PROC_ARRIVAL_TTL_MS = exports.PROC_TERMINAL_STATUSES = exports.feedTopology_changed = exports.feed_isActive = exports.status_isTerminal = exports.procCache_get = exports.ProcCache = exports.LISTING_INVALIDATION_WINDOW_MS = exports.listingInvalidation_reset = exports.listingInvalidation_flush = exports.listingsForRoster_note = exports.listingsForFeeds_drop = exports.listingsForFeeds_note = exports.listCheckpoint_watch = exports.listCheckpoint_save = exports.listCheckpoint_restore = exports.listCheckpointPath_get = exports.LIST_CACHE_MAX_ENTRIES = exports.LIST_CACHE_PLUGIN_INDEX_TTL_MS = exports.LIST_CACHE_SIGNAL_FREE_TTL_MS = exports.LIST_CACHE_SIGNAL_BACKED_TTL_MS = exports.listCache_get = exports.ListCache = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* @file Cache module exports.
|
|
6
6
|
*
|
|
@@ -9,11 +9,22 @@ exports.procCheckpoint_watch = exports.procCheckpointRoster_save = exports.procC
|
|
|
9
9
|
var listCache_js_1 = require("./listCache.js");
|
|
10
10
|
Object.defineProperty(exports, "ListCache", { enumerable: true, get: function () { return listCache_js_1.ListCache; } });
|
|
11
11
|
Object.defineProperty(exports, "listCache_get", { enumerable: true, get: function () { return listCache_js_1.listCache_get; } });
|
|
12
|
+
Object.defineProperty(exports, "LIST_CACHE_SIGNAL_BACKED_TTL_MS", { enumerable: true, get: function () { return listCache_js_1.LIST_CACHE_SIGNAL_BACKED_TTL_MS; } });
|
|
13
|
+
Object.defineProperty(exports, "LIST_CACHE_SIGNAL_FREE_TTL_MS", { enumerable: true, get: function () { return listCache_js_1.LIST_CACHE_SIGNAL_FREE_TTL_MS; } });
|
|
14
|
+
Object.defineProperty(exports, "LIST_CACHE_PLUGIN_INDEX_TTL_MS", { enumerable: true, get: function () { return listCache_js_1.LIST_CACHE_PLUGIN_INDEX_TTL_MS; } });
|
|
15
|
+
Object.defineProperty(exports, "LIST_CACHE_MAX_ENTRIES", { enumerable: true, get: function () { return listCache_js_1.LIST_CACHE_MAX_ENTRIES; } });
|
|
12
16
|
var listCheckpoint_js_1 = require("./listCheckpoint.js");
|
|
13
17
|
Object.defineProperty(exports, "listCheckpointPath_get", { enumerable: true, get: function () { return listCheckpoint_js_1.listCheckpointPath_get; } });
|
|
14
18
|
Object.defineProperty(exports, "listCheckpoint_restore", { enumerable: true, get: function () { return listCheckpoint_js_1.listCheckpoint_restore; } });
|
|
15
19
|
Object.defineProperty(exports, "listCheckpoint_save", { enumerable: true, get: function () { return listCheckpoint_js_1.listCheckpoint_save; } });
|
|
16
20
|
Object.defineProperty(exports, "listCheckpoint_watch", { enumerable: true, get: function () { return listCheckpoint_js_1.listCheckpoint_watch; } });
|
|
21
|
+
var listingInvalidation_js_1 = require("./listingInvalidation.js");
|
|
22
|
+
Object.defineProperty(exports, "listingsForFeeds_note", { enumerable: true, get: function () { return listingInvalidation_js_1.listingsForFeeds_note; } });
|
|
23
|
+
Object.defineProperty(exports, "listingsForFeeds_drop", { enumerable: true, get: function () { return listingInvalidation_js_1.listingsForFeeds_drop; } });
|
|
24
|
+
Object.defineProperty(exports, "listingsForRoster_note", { enumerable: true, get: function () { return listingInvalidation_js_1.listingsForRoster_note; } });
|
|
25
|
+
Object.defineProperty(exports, "listingInvalidation_flush", { enumerable: true, get: function () { return listingInvalidation_js_1.listingInvalidation_flush; } });
|
|
26
|
+
Object.defineProperty(exports, "listingInvalidation_reset", { enumerable: true, get: function () { return listingInvalidation_js_1.listingInvalidation_reset; } });
|
|
27
|
+
Object.defineProperty(exports, "LISTING_INVALIDATION_WINDOW_MS", { enumerable: true, get: function () { return listingInvalidation_js_1.LISTING_INVALIDATION_WINDOW_MS; } });
|
|
17
28
|
var procCache_js_1 = require("./procCache.js");
|
|
18
29
|
Object.defineProperty(exports, "ProcCache", { enumerable: true, get: function () { return procCache_js_1.ProcCache; } });
|
|
19
30
|
Object.defineProperty(exports, "procCache_get", { enumerable: true, get: function () { return procCache_js_1.procCache_get; } });
|
|
@@ -21,6 +32,7 @@ Object.defineProperty(exports, "status_isTerminal", { enumerable: true, get: fun
|
|
|
21
32
|
Object.defineProperty(exports, "feed_isActive", { enumerable: true, get: function () { return procCache_js_1.feed_isActive; } });
|
|
22
33
|
Object.defineProperty(exports, "feedTopology_changed", { enumerable: true, get: function () { return procCache_js_1.feedTopology_changed; } });
|
|
23
34
|
Object.defineProperty(exports, "PROC_TERMINAL_STATUSES", { enumerable: true, get: function () { return procCache_js_1.PROC_TERMINAL_STATUSES; } });
|
|
35
|
+
Object.defineProperty(exports, "PROC_ARRIVAL_TTL_MS", { enumerable: true, get: function () { return procCache_js_1.PROC_ARRIVAL_TTL_MS; } });
|
|
24
36
|
var procCheckpoint_js_1 = require("./procCheckpoint.js");
|
|
25
37
|
Object.defineProperty(exports, "procCheckpointPath_get", { enumerable: true, get: function () { return procCheckpoint_js_1.procCheckpointPath_get; } });
|
|
26
38
|
Object.defineProperty(exports, "procCheckpointDir_get", { enumerable: true, get: function () { return procCheckpoint_js_1.procCheckpointDir_get; } });
|
package/dist/cache/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cache/index.ts"],"names":[],"mappings":";;;AAAA;;;;GAIG;AACH,+
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cache/index.ts"],"names":[],"mappings":";;;AAAA;;;;GAIG;AACH,+CAOwB;AANtB,yGAAA,SAAS,OAAA;AACT,6GAAA,aAAa,OAAA;AACb,+HAAA,+BAA+B,OAAA;AAC/B,6HAAA,6BAA6B,OAAA;AAC7B,8HAAA,8BAA8B,OAAA;AAC9B,sHAAA,sBAAsB,OAAA;AAGxB,yDAK6B;AAJ3B,2HAAA,sBAAsB,OAAA;AACtB,2HAAA,sBAAsB,OAAA;AACtB,wHAAA,mBAAmB,OAAA;AACnB,yHAAA,oBAAoB,OAAA;AAGtB,mEAOkC;AANhC,+HAAA,qBAAqB,OAAA;AACrB,+HAAA,qBAAqB,OAAA;AACrB,gIAAA,sBAAsB,OAAA;AACtB,mIAAA,yBAAyB,OAAA;AACzB,mIAAA,yBAAyB,OAAA;AACzB,wIAAA,8BAA8B,OAAA;AAEhC,+CAA+J;AAAtJ,yGAAA,SAAS,OAAA;AAAE,6GAAA,aAAa,OAAA;AAAE,iHAAA,iBAAiB,OAAA;AAAE,6GAAA,aAAa,OAAA;AAAE,oHAAA,oBAAoB,OAAA;AAAE,sHAAA,sBAAsB,OAAA;AAAE,mHAAA,mBAAmB,OAAA;AA0BtI,yDAQ6B;AAP3B,2HAAA,sBAAsB,OAAA;AACtB,0HAAA,qBAAqB,OAAA;AACrB,2HAAA,sBAAsB,OAAA;AACtB,wHAAA,mBAAmB,OAAA;AACnB,4HAAA,uBAAuB,OAAA;AACvB,8HAAA,yBAAyB,OAAA;AACzB,yHAAA,oBAAoB,OAAA"}
|
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Lifetime for a path `/proc` reports movement on.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
4
|
+
* Long by design: arrivals, departures and job completions mark these
|
|
5
|
+
* dirty as they happen, so the clock is a backstop against a missed
|
|
6
|
+
* notification rather than the mechanism.
|
|
7
|
+
*/
|
|
8
|
+
export declare const LIST_CACHE_SIGNAL_BACKED_TTL_MS: number;
|
|
9
|
+
/** Lifetime for a path nothing reports movement on. */
|
|
10
|
+
export declare const LIST_CACHE_SIGNAL_FREE_TTL_MS: number;
|
|
11
|
+
/**
|
|
12
|
+
* Lifetime for the plugin and pipeline indexes.
|
|
12
13
|
*
|
|
13
|
-
*
|
|
14
|
+
* Registration is an administrative act on a CUBE, not something a
|
|
15
|
+
* session causes, and it happens on a scale of months.
|
|
14
16
|
*/
|
|
17
|
+
export declare const LIST_CACHE_PLUGIN_INDEX_TTL_MS: number;
|
|
18
|
+
/** How many path listings the cache retains before evicting the oldest. */
|
|
19
|
+
export declare const LIST_CACHE_MAX_ENTRIES: number;
|
|
15
20
|
/**
|
|
16
21
|
* Result returned by cache_get with freshness information.
|
|
17
22
|
*/
|
|
@@ -69,6 +74,8 @@ export interface CacheStats {
|
|
|
69
74
|
entries: number;
|
|
70
75
|
/** Estimated total memory usage in bytes. */
|
|
71
76
|
totalSize: number;
|
|
77
|
+
/** Age of the oldest retained entry in milliseconds, or null when empty. */
|
|
78
|
+
oldestAge: number | null;
|
|
72
79
|
}
|
|
73
80
|
/**
|
|
74
81
|
* Singleton cache for directory listings with TTL and dirty tracking.
|
|
@@ -112,10 +119,19 @@ export declare class ListCache {
|
|
|
112
119
|
private cache;
|
|
113
120
|
/** Maximum cache entries (LRU eviction). */
|
|
114
121
|
private maxEntries;
|
|
115
|
-
/**
|
|
122
|
+
/** Lifetime for a path no configured prefix covers. */
|
|
116
123
|
private defaultTTL;
|
|
117
|
-
/**
|
|
124
|
+
/**
|
|
125
|
+
* Prefix-keyed lifetimes, longest prefix winning.
|
|
126
|
+
*
|
|
127
|
+
* A path is governed by a signal or by a clock, never argued over by
|
|
128
|
+
* both. Where `/proc` reports movement, the clock is only a backstop
|
|
129
|
+
* against a missed notification and can be long. Where nothing reports,
|
|
130
|
+
* a guess is all that is available and it stays short.
|
|
131
|
+
*/
|
|
118
132
|
private ttlConfig;
|
|
133
|
+
/** Whether this session has already reported that the cache filled. */
|
|
134
|
+
private evictionReported;
|
|
119
135
|
/** Cache statistics. */
|
|
120
136
|
private stats;
|
|
121
137
|
/** Listeners told after any mutation a persister would want to see. */
|
|
@@ -170,6 +186,15 @@ export declare class ListCache {
|
|
|
170
186
|
* @param options - Optional TTL and dirty flag.
|
|
171
187
|
*/
|
|
172
188
|
cache_set<T = unknown>(path: string, data: T, options?: CacheOptions): void;
|
|
189
|
+
/**
|
|
190
|
+
* Every path the cache currently holds.
|
|
191
|
+
*
|
|
192
|
+
* Returned as a snapshot so a caller may mark or invalidate while
|
|
193
|
+
* iterating without mutating the map underneath itself.
|
|
194
|
+
*
|
|
195
|
+
* @returns The cached paths, least recently used first.
|
|
196
|
+
*/
|
|
197
|
+
paths_get(): string[];
|
|
173
198
|
/**
|
|
174
199
|
* Marks a cached path as dirty (needs refresh).
|
|
175
200
|
* Used when local mutations might have changed the data.
|
package/dist/cache/listCache.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ListCache = exports.LIST_CACHE_MAX_ENTRIES = exports.LIST_CACHE_PLUGIN_INDEX_TTL_MS = exports.LIST_CACHE_SIGNAL_FREE_TTL_MS = exports.LIST_CACHE_SIGNAL_BACKED_TTL_MS = void 0;
|
|
4
|
+
exports.listCache_get = listCache_get;
|
|
2
5
|
/**
|
|
3
6
|
* @file Enhanced Directory Listing Cache with TTL and dirty tracking.
|
|
4
7
|
*
|
|
@@ -13,9 +16,26 @@
|
|
|
13
16
|
*
|
|
14
17
|
* @module
|
|
15
18
|
*/
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
const errorStack_1 = require("../error/errorStack");
|
|
20
|
+
/**
|
|
21
|
+
* Lifetime for a path `/proc` reports movement on.
|
|
22
|
+
*
|
|
23
|
+
* Long by design: arrivals, departures and job completions mark these
|
|
24
|
+
* dirty as they happen, so the clock is a backstop against a missed
|
|
25
|
+
* notification rather than the mechanism.
|
|
26
|
+
*/
|
|
27
|
+
exports.LIST_CACHE_SIGNAL_BACKED_TTL_MS = 60 * 60 * 1000;
|
|
28
|
+
/** Lifetime for a path nothing reports movement on. */
|
|
29
|
+
exports.LIST_CACHE_SIGNAL_FREE_TTL_MS = 3 * 60 * 1000;
|
|
30
|
+
/**
|
|
31
|
+
* Lifetime for the plugin and pipeline indexes.
|
|
32
|
+
*
|
|
33
|
+
* Registration is an administrative act on a CUBE, not something a
|
|
34
|
+
* session causes, and it happens on a scale of months.
|
|
35
|
+
*/
|
|
36
|
+
exports.LIST_CACHE_PLUGIN_INDEX_TTL_MS = 24 * 60 * 60 * 1000;
|
|
37
|
+
/** How many path listings the cache retains before evicting the oldest. */
|
|
38
|
+
exports.LIST_CACHE_MAX_ENTRIES = 500;
|
|
19
39
|
/**
|
|
20
40
|
* Singleton cache for directory listings with TTL and dirty tracking.
|
|
21
41
|
*
|
|
@@ -109,16 +129,33 @@ class ListCache {
|
|
|
109
129
|
/** Cache storage: path → entry. */
|
|
110
130
|
this.cache = new Map();
|
|
111
131
|
/** Maximum cache entries (LRU eviction). */
|
|
112
|
-
this.maxEntries =
|
|
113
|
-
/**
|
|
114
|
-
this.defaultTTL =
|
|
115
|
-
/**
|
|
132
|
+
this.maxEntries = exports.LIST_CACHE_MAX_ENTRIES;
|
|
133
|
+
/** Lifetime for a path no configured prefix covers. */
|
|
134
|
+
this.defaultTTL = exports.LIST_CACHE_SIGNAL_FREE_TTL_MS;
|
|
135
|
+
/**
|
|
136
|
+
* Prefix-keyed lifetimes, longest prefix winning.
|
|
137
|
+
*
|
|
138
|
+
* A path is governed by a signal or by a clock, never argued over by
|
|
139
|
+
* both. Where `/proc` reports movement, the clock is only a backstop
|
|
140
|
+
* against a missed notification and can be long. Where nothing reports,
|
|
141
|
+
* a guess is all that is available and it stays short.
|
|
142
|
+
*/
|
|
116
143
|
this.ttlConfig = new Map([
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
['/
|
|
120
|
-
['/
|
|
144
|
+
// Signal-covered: the roster and job-completion notifications decide
|
|
145
|
+
// when these go stale (see listing_dirtyByFeed).
|
|
146
|
+
['/home', exports.LIST_CACHE_SIGNAL_BACKED_TTL_MS],
|
|
147
|
+
['/SHARED', exports.LIST_CACHE_SIGNAL_BACKED_TTL_MS],
|
|
148
|
+
['/PUBLIC', exports.LIST_CACHE_SIGNAL_BACKED_TTL_MS],
|
|
149
|
+
// Signal-free: nothing reports movement, so a clock is the only option.
|
|
150
|
+
// Plugin registration is an administrative act on a scale of months,
|
|
151
|
+
// so a day is closer to true than an hour; `refresh` is the escape
|
|
152
|
+
// hatch when an operator knows a plugin was just registered.
|
|
153
|
+
['/bin', exports.LIST_CACHE_PLUGIN_INDEX_TTL_MS],
|
|
154
|
+
['/usr/share', exports.LIST_CACHE_PLUGIN_INDEX_TTL_MS],
|
|
155
|
+
['/PIPELINES', exports.LIST_CACHE_PLUGIN_INDEX_TTL_MS],
|
|
121
156
|
]);
|
|
157
|
+
/** Whether this session has already reported that the cache filled. */
|
|
158
|
+
this.evictionReported = false;
|
|
122
159
|
/** Cache statistics. */
|
|
123
160
|
this.stats = {
|
|
124
161
|
hits: 0,
|
|
@@ -189,6 +226,17 @@ class ListCache {
|
|
|
189
226
|
this.evict_lru();
|
|
190
227
|
this.change_emit();
|
|
191
228
|
}
|
|
229
|
+
/**
|
|
230
|
+
* Every path the cache currently holds.
|
|
231
|
+
*
|
|
232
|
+
* Returned as a snapshot so a caller may mark or invalidate while
|
|
233
|
+
* iterating without mutating the map underneath itself.
|
|
234
|
+
*
|
|
235
|
+
* @returns The cached paths, least recently used first.
|
|
236
|
+
*/
|
|
237
|
+
paths_get() {
|
|
238
|
+
return Array.from(this.cache.keys());
|
|
239
|
+
}
|
|
192
240
|
/**
|
|
193
241
|
* Marks a cached path as dirty (needs refresh).
|
|
194
242
|
* Used when local mutations might have changed the data.
|
|
@@ -270,18 +318,23 @@ class ListCache {
|
|
|
270
318
|
* @returns TTL in milliseconds.
|
|
271
319
|
*/
|
|
272
320
|
ttl_get(path) {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
321
|
+
const exact = this.ttlConfig.get(path);
|
|
322
|
+
if (exact !== undefined)
|
|
323
|
+
return exact;
|
|
324
|
+
// Longest matching prefix wins, so a deeper entry can override a
|
|
325
|
+
// shallower one. Matching is on whole segments: `/bindings` must not
|
|
326
|
+
// inherit `/bin`'s lifetime.
|
|
327
|
+
let bestLength = -1;
|
|
328
|
+
let bestTTL = this.defaultTTL;
|
|
329
|
+
for (const [prefix, ttl] of this.ttlConfig) {
|
|
330
|
+
if (!path.startsWith(prefix + '/'))
|
|
331
|
+
continue;
|
|
332
|
+
if (prefix.length > bestLength) {
|
|
333
|
+
bestLength = prefix.length;
|
|
334
|
+
bestTTL = ttl;
|
|
282
335
|
}
|
|
283
336
|
}
|
|
284
|
-
return
|
|
337
|
+
return bestTTL;
|
|
285
338
|
}
|
|
286
339
|
/**
|
|
287
340
|
* Evicts oldest entries if cache exceeds max size.
|
|
@@ -292,6 +345,14 @@ class ListCache {
|
|
|
292
345
|
if (oldestKey !== undefined) {
|
|
293
346
|
this.cache.delete(oldestKey);
|
|
294
347
|
this.stats.evictions++;
|
|
348
|
+
// An eviction is not an error, but it is worth knowing about: the
|
|
349
|
+
// dropped listing also leaves the checkpoint, so a restart comes
|
|
350
|
+
// back thinner than the session that wrote it. Said once, because
|
|
351
|
+
// a session that crosses the cap will cross it repeatedly.
|
|
352
|
+
if (!this.evictionReported) {
|
|
353
|
+
this.evictionReported = true;
|
|
354
|
+
errorStack_1.errorStack.stack_push('warning', `listing cache is full at ${this.maxEntries} paths; the least recently used listings are being dropped and will not survive to the next session`);
|
|
355
|
+
}
|
|
295
356
|
}
|
|
296
357
|
else {
|
|
297
358
|
break; // Should never happen, but safety check
|
|
@@ -305,9 +366,13 @@ class ListCache {
|
|
|
305
366
|
*/
|
|
306
367
|
stats_get() {
|
|
307
368
|
let totalSize = 0;
|
|
369
|
+
let oldestTimestamp = null;
|
|
308
370
|
for (const entry of this.cache.values()) {
|
|
309
371
|
// Rough estimate: JSON string length
|
|
310
372
|
totalSize += JSON.stringify(entry.data).length;
|
|
373
|
+
if (oldestTimestamp === null || entry.timestamp < oldestTimestamp) {
|
|
374
|
+
oldestTimestamp = entry.timestamp;
|
|
375
|
+
}
|
|
311
376
|
}
|
|
312
377
|
return {
|
|
313
378
|
hits: this.stats.hits,
|
|
@@ -316,6 +381,7 @@ class ListCache {
|
|
|
316
381
|
evictions: this.stats.evictions,
|
|
317
382
|
entries: this.cache.size,
|
|
318
383
|
totalSize,
|
|
384
|
+
oldestAge: oldestTimestamp === null ? null : Date.now() - oldestTimestamp,
|
|
319
385
|
};
|
|
320
386
|
}
|
|
321
387
|
/**
|
|
@@ -327,6 +393,7 @@ class ListCache {
|
|
|
327
393
|
this.stats.misses = 0;
|
|
328
394
|
this.stats.staleHits = 0;
|
|
329
395
|
this.stats.evictions = 0;
|
|
396
|
+
this.evictionReported = false;
|
|
330
397
|
}
|
|
331
398
|
}
|
|
332
399
|
exports.ListCache = ListCache;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"listCache.js","sourceRoot":"","sources":["../../src/cache/listCache.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"listCache.js","sourceRoot":"","sources":["../../src/cache/listCache.ts"],"names":[],"mappings":";;;AA6gBA,sCAEC;AA/gBD;;;;;;;;;;;;;GAaG;AACH,oDAAiD;AAEjD;;;;;;GAMG;AACU,QAAA,+BAA+B,GAAW,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAEtE,uDAAuD;AAC1C,QAAA,6BAA6B,GAAW,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AAEnE;;;;;GAKG;AACU,QAAA,8BAA8B,GAAW,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAE1E,2EAA2E;AAC9D,QAAA,sBAAsB,GAAW,GAAG,CAAC;AA6FlD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAa,SAAS;IAgDpB;;;;;;OAMG;IACH,kBAAkB,CAAC,QAAoB;QACrC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,GAAS,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1D,CAAC;IAEO,WAAW;QACjB,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS;YAAE,QAAQ,EAAE,CAAC;IACpD,CAAC;IAED;;;;OAIG;IACH,eAAe;QACb,MAAM,OAAO,GAA6B,EAAE,CAAC;QAC7C,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACvC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;QAC3G,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,CAAC;IACrB,CAAC;IAED;;;;;;;;OAQG;IACH,gBAAgB,CAAC,QAA2B;QAC1C,MAAM,IAAI,GAAqC,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnE,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACnB,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;YACrC,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;gBAAE,SAAS;YACnC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;QACnH,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI;YAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC9D,IAAI,CAAC,SAAS,EAAE,CAAC;QACjB,IAAI,CAAC,WAAW,EAAE,CAAC;IACrB,CAAC;IAED;;OAEG;IACH;QAlGA,mCAAmC;QAC3B,UAAK,GAAqC,IAAI,GAAG,EAAE,CAAC;QAE5D,4CAA4C;QACpC,eAAU,GAAW,8BAAsB,CAAC;QAEpD,uDAAuD;QAC/C,eAAU,GAAW,qCAA6B,CAAC;QAE3D;;;;;;;WAOG;QACK,cAAS,GAAwB,IAAI,GAAG,CAAC;YAC/C,qEAAqE;YACrE,iDAAiD;YACjD,CAAC,OAAO,EAAE,uCAA+B,CAAC;YAC1C,CAAC,SAAS,EAAE,uCAA+B,CAAC;YAC5C,CAAC,SAAS,EAAE,uCAA+B,CAAC;YAC5C,wEAAwE;YACxE,qEAAqE;YACrE,mEAAmE;YACnE,6DAA6D;YAC7D,CAAC,MAAM,EAAE,sCAA8B,CAAC;YACxC,CAAC,YAAY,EAAE,sCAA8B,CAAC;YAC9C,CAAC,YAAY,EAAE,sCAA8B,CAAC;SAC/C,CAAC,CAAC;QAEH,uEAAuE;QAC/D,qBAAgB,GAAY,KAAK,CAAC;QAE1C,wBAAwB;QAChB,UAAK,GAAG;YACd,IAAI,EAAE,CAAC;YACP,MAAM,EAAE,CAAC;YACT,SAAS,EAAE,CAAC;YACZ,SAAS,EAAE,CAAC;SACb,CAAC;QACF,uEAAuE;QAC/D,cAAS,GAAoB,IAAI,GAAG,EAAE,CAAC;IAuDxB,CAAC;IAExB;;;;OAIG;IACH,MAAM,CAAC,YAAY;QACjB,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC;YACxB,SAAS,CAAC,QAAQ,GAAG,IAAI,SAAS,EAAE,CAAC;QACvC,CAAC;QACD,OAAO,SAAS,CAAC,QAAQ,CAAC;IAC5B,CAAC;IAED;;;;;OAKG;IACH,SAAS,CAAc,IAAY;QACjC,MAAM,KAAK,GAAoC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAEpE,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;YACpB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,2CAA2C;QAC3C,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACxB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAE5B,sBAAsB;QACtB,MAAM,GAAG,GAAW,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,CAAC;QACjD,MAAM,KAAK,GAAY,CAAC,KAAK,CAAC,KAAK,IAAI,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC;QAEvD,IAAI,KAAK,EAAE,CAAC;YACV,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACpB,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;QACzB,CAAC;QAED,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAS,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;IAC/C,CAAC;IAED;;;;;;OAMG;IACH,SAAS,CAAc,IAAY,EAAE,IAAO,EAAE,OAAsB;QAClE,mDAAmD;QACnD,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;QAED,MAAM,GAAG,GAAW,OAAO,EAAE,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAEvD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE;YACnB,IAAI;YACJ,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,KAAK,EAAE,OAAO,EAAE,KAAK,IAAI,KAAK;YAC9B,GAAG;SACJ,CAAC,CAAC;QAEH,6BAA6B;QAC7B,IAAI,CAAC,SAAS,EAAE,CAAC;QACjB,IAAI,CAAC,WAAW,EAAE,CAAC;IACrB,CAAC;IAED;;;;;;;OAOG;IACH,SAAS;QACP,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IACvC,CAAC;IAED;;;;;OAKG;IACH,eAAe,CAAC,IAAY;QAC1B,MAAM,KAAK,GAAoC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACpE,IAAI,KAAK,EAAE,CAAC;YACV,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC;YACnB,IAAI,CAAC,WAAW,EAAE,CAAC;QACrB,CAAC;IACH,CAAC;IAED;;;;;;OAMG;IACH,YAAY,CAAc,IAAY,EAAE,OAAuB;QAC7D,MAAM,KAAK,GAAoC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACpE,IAAI,KAAK,EAAE,CAAC;YACV,KAAK,CAAC,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,IAAS,CAAC,CAAC;YACtC,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAE,kBAAkB;YACjD,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAY,qBAAqB;YACrD,IAAI,CAAC,WAAW,EAAE,CAAC;QACrB,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,gBAAgB,CAAC,IAAa;QAC5B,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACrB,CAAC;QACD,IAAI,CAAC,WAAW,EAAE,CAAC;IACrB,CAAC;IAED;;;;;;;;;OASG;IACH,oBAAoB,CAAC,IAAY;QAC/B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACxB,MAAM,MAAM,GAAW,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC;QAC9D,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;YACpC,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC3B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;QACD,IAAI,CAAC,WAAW,EAAE,CAAC;IACrB,CAAC;IAED;;;;;OAKG;IACH,UAAU,CAAC,OAAe;QACxB,qDAAqD;QACrD,oDAAoD;IACtD,CAAC;IAED;;;;;OAKG;IACK,OAAO,CAAC,IAAY;QAC1B,MAAM,KAAK,GAAuB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC3D,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC;QAEtC,iEAAiE;QACjE,qEAAqE;QACrE,6BAA6B;QAC7B,IAAI,UAAU,GAAW,CAAC,CAAC,CAAC;QAC5B,IAAI,OAAO,GAAW,IAAI,CAAC,UAAU,CAAC;QACtC,KAAK,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YAC3C,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,GAAG,CAAC;gBAAE,SAAS;YAC7C,IAAI,MAAM,CAAC,MAAM,GAAG,UAAU,EAAE,CAAC;gBAC/B,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC;gBAC3B,OAAO,GAAG,GAAG,CAAC;YAChB,CAAC;QACH,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;OAEG;IACK,SAAS;QACf,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;YACzC,MAAM,SAAS,GAAuB,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;YACrE,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;gBAC5B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;gBAC7B,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;gBACvB,kEAAkE;gBAClE,iEAAiE;gBACjE,kEAAkE;gBAClE,2DAA2D;gBAC3D,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC;oBAC3B,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;oBAC7B,uBAAU,CAAC,UAAU,CACnB,SAAS,EACT,4BAA4B,IAAI,CAAC,UAAU,qGAAqG,CACjJ,CAAC;gBACJ,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAE,wCAAwC;YAClD,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,SAAS;QACP,IAAI,SAAS,GAAW,CAAC,CAAC;QAC1B,IAAI,eAAe,GAAkB,IAAI,CAAC;QAC1C,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YACxC,qCAAqC;YACrC,SAAS,IAAI,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;YAC/C,IAAI,eAAe,KAAK,IAAI,IAAI,KAAK,CAAC,SAAS,GAAG,eAAe,EAAE,CAAC;gBAClE,eAAe,GAAG,KAAK,CAAC,SAAS,CAAC;YACpC,CAAC;QACH,CAAC;QAED,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI;YACrB,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM;YACzB,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS;YAC/B,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS;YAC/B,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI;YACxB,SAAS;YACT,SAAS,EAAE,eAAe,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,eAAe;SAC1E,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,WAAW;QACT,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC;QACpB,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;QACtB,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC;IAChC,CAAC;CACF;AAhWD,8BAgWC;AAED;;;;GAIG;AACH,SAAgB,aAAa;IAC3B,OAAO,SAAS,CAAC,YAAY,EAAE,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How long feed movement collects before the cache is walked.
|
|
3
|
+
*
|
|
4
|
+
* Short on purpose: the whole point is that the mark beats the operator's
|
|
5
|
+
* next listing of that folder.
|
|
6
|
+
*/
|
|
7
|
+
export declare const LISTING_INVALIDATION_WINDOW_MS: number;
|
|
8
|
+
/**
|
|
9
|
+
* Notes that a feed's contents moved, so its cached folder listings are
|
|
10
|
+
* behind. Call when a job crosses into a terminal state — that is when
|
|
11
|
+
* output becomes visible.
|
|
12
|
+
*
|
|
13
|
+
* @param feedIDs - Feeds whose contents changed.
|
|
14
|
+
*/
|
|
15
|
+
export declare function listingsForFeeds_note(feedIDs: readonly number[]): void;
|
|
16
|
+
/**
|
|
17
|
+
* Notes that feeds arrived in, or vanished from, a parent folder.
|
|
18
|
+
*
|
|
19
|
+
* An arrival changes the *parent* listing rather than anything inside the
|
|
20
|
+
* feed, which is why this takes the folders as well: a feed shared to this
|
|
21
|
+
* identity adds a row to a folder that may itself be perfectly fresh.
|
|
22
|
+
*
|
|
23
|
+
* @param feedIDs - Feeds that arrived or departed.
|
|
24
|
+
* @param parentPaths - Folder listings whose membership therefore changed.
|
|
25
|
+
*/
|
|
26
|
+
export declare function listingsForRoster_note(feedIDs: readonly number[], parentPaths: readonly string[]): void;
|
|
27
|
+
/**
|
|
28
|
+
* Removes every cached listing belonging to feeds that are gone.
|
|
29
|
+
*
|
|
30
|
+
* A departure is not staleness. A feed this identity can no longer see has
|
|
31
|
+
* no contents to serve, and dirty entries are still served while they
|
|
32
|
+
* refresh, so marking one would keep showing a tree that has been taken
|
|
33
|
+
* away. This deletes instead, and does so at once rather than on the
|
|
34
|
+
* window, because there is nothing to race.
|
|
35
|
+
*
|
|
36
|
+
* @param feedIDs - Feeds that vanished from the roster.
|
|
37
|
+
* @returns The cache paths removed.
|
|
38
|
+
*/
|
|
39
|
+
export declare function listingsForFeeds_drop(feedIDs: readonly number[]): string[];
|
|
40
|
+
/**
|
|
41
|
+
* Applies any pending movement at once, without waiting for the window.
|
|
42
|
+
*
|
|
43
|
+
* @returns The cache paths marked dirty.
|
|
44
|
+
*/
|
|
45
|
+
export declare function listingInvalidation_flush(): string[];
|
|
46
|
+
/** Discards pending movement without applying it (tests, cache reset). */
|
|
47
|
+
export declare function listingInvalidation_reset(): void;
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LISTING_INVALIDATION_WINDOW_MS = void 0;
|
|
4
|
+
exports.listingsForFeeds_note = listingsForFeeds_note;
|
|
5
|
+
exports.listingsForRoster_note = listingsForRoster_note;
|
|
6
|
+
exports.listingsForFeeds_drop = listingsForFeeds_drop;
|
|
7
|
+
exports.listingInvalidation_flush = listingInvalidation_flush;
|
|
8
|
+
exports.listingInvalidation_reset = listingInvalidation_reset;
|
|
9
|
+
/**
|
|
10
|
+
* @file Feed movement invalidates the folder listings it touched.
|
|
11
|
+
*
|
|
12
|
+
* The listing cache used to decide staleness with a clock that had no
|
|
13
|
+
* relationship to when anything changed, while `/proc` — in the same
|
|
14
|
+
* process — knew and said nothing. This is the wire between them.
|
|
15
|
+
*
|
|
16
|
+
* Two rules govern what happens on the far end:
|
|
17
|
+
*
|
|
18
|
+
* - **Your own act deletes; someone else's act dirties.** A mutation
|
|
19
|
+
* (rm, mv, cp, upload) removes the entry, because showing a file you
|
|
20
|
+
* just deleted is incoherent. A job's output or a colleague's share is
|
|
21
|
+
* not wrong, merely behind, so the entry is marked dirty and served at
|
|
22
|
+
* once while it refreshes behind.
|
|
23
|
+
* - **Movement coalesces.** A feed completing a fan-out stage lands many
|
|
24
|
+
* terminal transitions in the same second; they collapse into one pass
|
|
25
|
+
* over the cache keys.
|
|
26
|
+
*
|
|
27
|
+
* Nothing here subscribes to the process cache's change stream. That
|
|
28
|
+
* stream fires on every instance add and status observation, so indexing
|
|
29
|
+
* one large feed emits tens of thousands of events, none of which mean a
|
|
30
|
+
* file appeared. Movement is pushed from the two places that know.
|
|
31
|
+
*
|
|
32
|
+
* @module
|
|
33
|
+
*/
|
|
34
|
+
const listCache_1 = require("./listCache");
|
|
35
|
+
const chrisPath_1 = require("../path/chrisPath");
|
|
36
|
+
/**
|
|
37
|
+
* How long feed movement collects before the cache is walked.
|
|
38
|
+
*
|
|
39
|
+
* Short on purpose: the whole point is that the mark beats the operator's
|
|
40
|
+
* next listing of that folder.
|
|
41
|
+
*/
|
|
42
|
+
exports.LISTING_INVALIDATION_WINDOW_MS = 1500;
|
|
43
|
+
/** Feed ids whose listings are waiting to be marked. */
|
|
44
|
+
const pendingFeeds = new Set();
|
|
45
|
+
/** Parent folders waiting to be marked, from arrivals and departures. */
|
|
46
|
+
const pendingParents = new Set();
|
|
47
|
+
/** The open coalescing window, or null when nothing is pending. */
|
|
48
|
+
let windowTimer = null;
|
|
49
|
+
/**
|
|
50
|
+
* Marks every cached listing belonging to the given feeds, and any parent
|
|
51
|
+
* folders queued alongside them.
|
|
52
|
+
*
|
|
53
|
+
* @returns The cache paths marked dirty.
|
|
54
|
+
*/
|
|
55
|
+
function pending_flush() {
|
|
56
|
+
const feeds = new Set(pendingFeeds);
|
|
57
|
+
const parents = new Set(pendingParents);
|
|
58
|
+
pendingFeeds.clear();
|
|
59
|
+
pendingParents.clear();
|
|
60
|
+
windowTimer = null;
|
|
61
|
+
if (feeds.size === 0 && parents.size === 0)
|
|
62
|
+
return [];
|
|
63
|
+
// Only paths the cache still holds are considered, so a listing dropped
|
|
64
|
+
// between the note and the flush leaves nothing behind to mark.
|
|
65
|
+
const cache = (0, listCache_1.listCache_get)();
|
|
66
|
+
const marked = [];
|
|
67
|
+
for (const path of cache.paths_get()) {
|
|
68
|
+
const feedID = (0, chrisPath_1.path_extractFeedID)(path);
|
|
69
|
+
const isFeedPath = feedID !== null && feeds.has(feedID);
|
|
70
|
+
if (!isFeedPath && !parents.has(path))
|
|
71
|
+
continue;
|
|
72
|
+
cache.cache_markDirty(path);
|
|
73
|
+
marked.push(path);
|
|
74
|
+
}
|
|
75
|
+
return marked;
|
|
76
|
+
}
|
|
77
|
+
/** Opens the coalescing window if one is not already running. */
|
|
78
|
+
function window_open() {
|
|
79
|
+
if (windowTimer !== null)
|
|
80
|
+
return;
|
|
81
|
+
windowTimer = setTimeout(() => { pending_flush(); }, exports.LISTING_INVALIDATION_WINDOW_MS);
|
|
82
|
+
// A pending mark must never hold a process open on its own.
|
|
83
|
+
windowTimer.unref?.();
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Notes that a feed's contents moved, so its cached folder listings are
|
|
87
|
+
* behind. Call when a job crosses into a terminal state — that is when
|
|
88
|
+
* output becomes visible.
|
|
89
|
+
*
|
|
90
|
+
* @param feedIDs - Feeds whose contents changed.
|
|
91
|
+
*/
|
|
92
|
+
function listingsForFeeds_note(feedIDs) {
|
|
93
|
+
if (feedIDs.length === 0)
|
|
94
|
+
return;
|
|
95
|
+
for (const feedID of feedIDs)
|
|
96
|
+
pendingFeeds.add(feedID);
|
|
97
|
+
window_open();
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Notes that feeds arrived in, or vanished from, a parent folder.
|
|
101
|
+
*
|
|
102
|
+
* An arrival changes the *parent* listing rather than anything inside the
|
|
103
|
+
* feed, which is why this takes the folders as well: a feed shared to this
|
|
104
|
+
* identity adds a row to a folder that may itself be perfectly fresh.
|
|
105
|
+
*
|
|
106
|
+
* @param feedIDs - Feeds that arrived or departed.
|
|
107
|
+
* @param parentPaths - Folder listings whose membership therefore changed.
|
|
108
|
+
*/
|
|
109
|
+
function listingsForRoster_note(feedIDs, parentPaths) {
|
|
110
|
+
if (feedIDs.length === 0 && parentPaths.length === 0)
|
|
111
|
+
return;
|
|
112
|
+
for (const feedID of feedIDs)
|
|
113
|
+
pendingFeeds.add(feedID);
|
|
114
|
+
for (const path of parentPaths)
|
|
115
|
+
pendingParents.add(path);
|
|
116
|
+
window_open();
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Removes every cached listing belonging to feeds that are gone.
|
|
120
|
+
*
|
|
121
|
+
* A departure is not staleness. A feed this identity can no longer see has
|
|
122
|
+
* no contents to serve, and dirty entries are still served while they
|
|
123
|
+
* refresh, so marking one would keep showing a tree that has been taken
|
|
124
|
+
* away. This deletes instead, and does so at once rather than on the
|
|
125
|
+
* window, because there is nothing to race.
|
|
126
|
+
*
|
|
127
|
+
* @param feedIDs - Feeds that vanished from the roster.
|
|
128
|
+
* @returns The cache paths removed.
|
|
129
|
+
*/
|
|
130
|
+
function listingsForFeeds_drop(feedIDs) {
|
|
131
|
+
if (feedIDs.length === 0)
|
|
132
|
+
return [];
|
|
133
|
+
const gone = new Set(feedIDs);
|
|
134
|
+
const cache = (0, listCache_1.listCache_get)();
|
|
135
|
+
const removed = [];
|
|
136
|
+
for (const path of cache.paths_get()) {
|
|
137
|
+
const feedID = (0, chrisPath_1.path_extractFeedID)(path);
|
|
138
|
+
if (feedID === null || !gone.has(feedID))
|
|
139
|
+
continue;
|
|
140
|
+
cache.cache_invalidate(path);
|
|
141
|
+
removed.push(path);
|
|
142
|
+
}
|
|
143
|
+
// A feed that left must not be resurrected by movement noted before it
|
|
144
|
+
// went; drop it from anything still pending.
|
|
145
|
+
for (const feedID of feedIDs)
|
|
146
|
+
pendingFeeds.delete(feedID);
|
|
147
|
+
return removed;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Applies any pending movement at once, without waiting for the window.
|
|
151
|
+
*
|
|
152
|
+
* @returns The cache paths marked dirty.
|
|
153
|
+
*/
|
|
154
|
+
function listingInvalidation_flush() {
|
|
155
|
+
if (windowTimer !== null) {
|
|
156
|
+
clearTimeout(windowTimer);
|
|
157
|
+
windowTimer = null;
|
|
158
|
+
}
|
|
159
|
+
return pending_flush();
|
|
160
|
+
}
|
|
161
|
+
/** Discards pending movement without applying it (tests, cache reset). */
|
|
162
|
+
function listingInvalidation_reset() {
|
|
163
|
+
if (windowTimer !== null) {
|
|
164
|
+
clearTimeout(windowTimer);
|
|
165
|
+
windowTimer = null;
|
|
166
|
+
}
|
|
167
|
+
pendingFeeds.clear();
|
|
168
|
+
pendingParents.clear();
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=listingInvalidation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"listingInvalidation.js","sourceRoot":"","sources":["../../src/cache/listingInvalidation.ts"],"names":[],"mappings":"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"}
|