@bradensbay/globals-core 0.2.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/README.md +69 -0
- package/dist/src/allocator.d.ts +78 -0
- package/dist/src/allocator.d.ts.map +1 -0
- package/dist/src/allocator.js +211 -0
- package/dist/src/allocator.js.map +1 -0
- package/dist/src/arena.d.ts +81 -0
- package/dist/src/arena.d.ts.map +1 -0
- package/dist/src/arena.js +224 -0
- package/dist/src/arena.js.map +1 -0
- package/dist/src/checksum.d.ts +5 -0
- package/dist/src/checksum.d.ts.map +1 -0
- package/dist/src/checksum.js +35 -0
- package/dist/src/checksum.js.map +1 -0
- package/dist/src/draft.d.ts +48 -0
- package/dist/src/draft.d.ts.map +1 -0
- package/dist/src/draft.js +427 -0
- package/dist/src/draft.js.map +1 -0
- package/dist/src/errors.d.ts +56 -0
- package/dist/src/errors.d.ts.map +1 -0
- package/dist/src/errors.js +69 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/external.d.ts +52 -0
- package/dist/src/external.d.ts.map +1 -0
- package/dist/src/external.js +68 -0
- package/dist/src/external.js.map +1 -0
- package/dist/src/hamt.d.ts +87 -0
- package/dist/src/hamt.d.ts.map +1 -0
- package/dist/src/hamt.js +643 -0
- package/dist/src/hamt.js.map +1 -0
- package/dist/src/history.d.ts +45 -0
- package/dist/src/history.d.ts.map +1 -0
- package/dist/src/history.js +49 -0
- package/dist/src/history.js.map +1 -0
- package/dist/src/index.d.ts +55 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +38 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/inspect.d.ts +74 -0
- package/dist/src/inspect.d.ts.map +1 -0
- package/dist/src/inspect.js +127 -0
- package/dist/src/inspect.js.map +1 -0
- package/dist/src/layout.d.ts +130 -0
- package/dist/src/layout.d.ts.map +1 -0
- package/dist/src/layout.js +149 -0
- package/dist/src/layout.js.map +1 -0
- package/dist/src/liveness.d.ts +48 -0
- package/dist/src/liveness.d.ts.map +1 -0
- package/dist/src/liveness.js +92 -0
- package/dist/src/liveness.js.map +1 -0
- package/dist/src/owner.d.ts +130 -0
- package/dist/src/owner.d.ts.map +1 -0
- package/dist/src/owner.js +368 -0
- package/dist/src/owner.js.map +1 -0
- package/dist/src/reader.d.ts +122 -0
- package/dist/src/reader.d.ts.map +1 -0
- package/dist/src/reader.js +325 -0
- package/dist/src/reader.js.map +1 -0
- package/dist/src/readers.d.ts +60 -0
- package/dist/src/readers.d.ts.map +1 -0
- package/dist/src/readers.js +122 -0
- package/dist/src/readers.js.map +1 -0
- package/dist/src/retained.d.ts +39 -0
- package/dist/src/retained.d.ts.map +1 -0
- package/dist/src/retained.js +99 -0
- package/dist/src/retained.js.map +1 -0
- package/dist/src/schema.d.ts +82 -0
- package/dist/src/schema.d.ts.map +1 -0
- package/dist/src/schema.js +18 -0
- package/dist/src/schema.js.map +1 -0
- package/dist/src/store.d.ts +83 -0
- package/dist/src/store.d.ts.map +1 -0
- package/dist/src/store.js +127 -0
- package/dist/src/store.js.map +1 -0
- package/dist/src/strings.d.ts +37 -0
- package/dist/src/strings.d.ts.map +1 -0
- package/dist/src/strings.js +144 -0
- package/dist/src/strings.js.map +1 -0
- package/dist/src/tags.d.ts +47 -0
- package/dist/src/tags.d.ts.map +1 -0
- package/dist/src/tags.js +53 -0
- package/dist/src/tags.js.map +1 -0
- package/dist/src/values.d.ts +90 -0
- package/dist/src/values.d.ts.map +1 -0
- package/dist/src/values.js +458 -0
- package/dist/src/values.js.map +1 -0
- package/dist/src/vector.d.ts +64 -0
- package/dist/src/vector.d.ts.map +1 -0
- package/dist/src/vector.js +387 -0
- package/dist/src/vector.js.map +1 -0
- package/dist/src/verify.d.ts +38 -0
- package/dist/src/verify.d.ts.map +1 -0
- package/dist/src/verify.js +179 -0
- package/dist/src/verify.js.map +1 -0
- package/dist/src/view.d.ts +66 -0
- package/dist/src/view.d.ts.map +1 -0
- package/dist/src/view.js +278 -0
- package/dist/src/view.js.map +1 -0
- package/package.json +28 -0
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
import { SharedArena } from "./arena.js";
|
|
2
|
+
import { Allocator } from "./allocator.js";
|
|
3
|
+
import { ReaderTable } from "./readers.js";
|
|
4
|
+
import { RetainedRing } from "./retained.js";
|
|
5
|
+
import { StringTable } from "./strings.js";
|
|
6
|
+
import { Header, VerifyMode } from "./layout.js";
|
|
7
|
+
import { publishChecksum } from "./verify.js";
|
|
8
|
+
import { collectBlocks, decodeValue, encodeValue, } from "./values.js";
|
|
9
|
+
import { createDraft, finalizeState } from "./draft.js";
|
|
10
|
+
import { Tag } from "./tags.js";
|
|
11
|
+
import { GlobalsError } from "./errors.js";
|
|
12
|
+
const DEFAULTS = {
|
|
13
|
+
byteLength: 1 << 20,
|
|
14
|
+
maxByteLength: 1 << 26,
|
|
15
|
+
maxReaders: 32,
|
|
16
|
+
retainedVersions: 64,
|
|
17
|
+
verify: VerifyMode.Header,
|
|
18
|
+
historyDepth: 0,
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* The sole writer.
|
|
22
|
+
*
|
|
23
|
+
* In Electron this runs in the hidden owner window. In tests it runs on the main thread of
|
|
24
|
+
* a plain Node process, which is exactly the point of keeping this package free of Electron
|
|
25
|
+
* imports.
|
|
26
|
+
*
|
|
27
|
+
* The single writer property is load bearing. It removes allocator locking, it makes the
|
|
28
|
+
* free lists safe to keep on the writer heap where no other window can corrupt them, and it
|
|
29
|
+
* makes the commit sequence a plain store rather than a contended compare and exchange.
|
|
30
|
+
*/
|
|
31
|
+
export class ArenaOwner {
|
|
32
|
+
arena;
|
|
33
|
+
#allocator;
|
|
34
|
+
#strings;
|
|
35
|
+
#readers;
|
|
36
|
+
#ring;
|
|
37
|
+
#versionId = 0;
|
|
38
|
+
#currentSlot = { tag: 0, payload: 0 };
|
|
39
|
+
/**
|
|
40
|
+
* The oldest version a reader may still decode. Monotonic: once memory below a version
|
|
41
|
+
* is freed, no later decision may lower the floor back over it.
|
|
42
|
+
*/
|
|
43
|
+
#reclaimFloor = 0;
|
|
44
|
+
#historyDepth = 0;
|
|
45
|
+
#verify = VerifyMode.Header;
|
|
46
|
+
/**
|
|
47
|
+
* Blocks that became unreachable when a version was superseded, keyed by the version
|
|
48
|
+
* that still referenced them. Insertion order is ascending by version, which the
|
|
49
|
+
* reclamation scan relies on.
|
|
50
|
+
*/
|
|
51
|
+
#garbage = new Map();
|
|
52
|
+
constructor(arena) {
|
|
53
|
+
this.arena = arena;
|
|
54
|
+
this.#allocator = new Allocator(arena, (minimum) => this.#growBuffer(minimum));
|
|
55
|
+
this.#strings = new StringTable(arena, this.#allocator);
|
|
56
|
+
this.#readers = new ReaderTable(arena);
|
|
57
|
+
this.#ring = new RetainedRing(arena);
|
|
58
|
+
}
|
|
59
|
+
/** Allocate and format a new arena. */
|
|
60
|
+
static create(options = {}) {
|
|
61
|
+
const settings = { ...DEFAULTS, ...options };
|
|
62
|
+
if (settings.maxByteLength < settings.byteLength) {
|
|
63
|
+
throw new GlobalsError("maxByteLength cannot be smaller than byteLength");
|
|
64
|
+
}
|
|
65
|
+
const buffer = new SharedArrayBuffer(settings.byteLength, {
|
|
66
|
+
maxByteLength: settings.maxByteLength,
|
|
67
|
+
});
|
|
68
|
+
const arena = SharedArena.format(buffer, {
|
|
69
|
+
maxReaders: settings.maxReaders,
|
|
70
|
+
retainedCapacity: settings.retainedVersions,
|
|
71
|
+
flags: settings.verify,
|
|
72
|
+
});
|
|
73
|
+
const owner = new ArenaOwner(arena);
|
|
74
|
+
owner.#historyDepth = Math.max(0, Math.min(settings.historyDepth, settings.retainedVersions - 1));
|
|
75
|
+
owner.#verify = settings.verify;
|
|
76
|
+
owner.commit(undefined);
|
|
77
|
+
return owner;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Adopt a buffer that a previous owner formatted. Bumps the owner generation so readers
|
|
81
|
+
* attached to the dead owner can detect the change.
|
|
82
|
+
*
|
|
83
|
+
* The free lists cannot be recovered, so an adopted arena starts with a bump pointer
|
|
84
|
+
* where the previous owner left it and no reusable blocks. That is acceptable because
|
|
85
|
+
* adoption follows an owner crash, which is rare and already costs a rehydrate.
|
|
86
|
+
*/
|
|
87
|
+
static adopt(buffer) {
|
|
88
|
+
const arena = SharedArena.attach(buffer);
|
|
89
|
+
arena.addHeader(Header.OwnerGeneration, 1);
|
|
90
|
+
const owner = new ArenaOwner(arena);
|
|
91
|
+
owner.#verify = (arena.loadHeader(Header.Flags) & 0b11);
|
|
92
|
+
owner.#versionId = arena.loadHeader(Header.VersionId);
|
|
93
|
+
owner.#reclaimFloor = arena.loadHeader(Header.ReclaimFloor);
|
|
94
|
+
owner.#currentSlot = {
|
|
95
|
+
tag: arena.loadHeader(Header.RootTag),
|
|
96
|
+
payload: arena.loadHeader(Header.RootPayload),
|
|
97
|
+
};
|
|
98
|
+
return owner;
|
|
99
|
+
}
|
|
100
|
+
get buffer() {
|
|
101
|
+
return this.arena.buffer;
|
|
102
|
+
}
|
|
103
|
+
get versionId() {
|
|
104
|
+
return this.#versionId;
|
|
105
|
+
}
|
|
106
|
+
get strings() {
|
|
107
|
+
return this.#strings;
|
|
108
|
+
}
|
|
109
|
+
get allocator() {
|
|
110
|
+
return this.#allocator;
|
|
111
|
+
}
|
|
112
|
+
get readers() {
|
|
113
|
+
return this.#readers;
|
|
114
|
+
}
|
|
115
|
+
get ring() {
|
|
116
|
+
return this.#ring;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Encode `value`, publish it as the new root, and reclaim what the previous version was
|
|
120
|
+
* keeping alive.
|
|
121
|
+
*
|
|
122
|
+
* The publication is a seqlock write. Readers never block on it: they observe an odd
|
|
123
|
+
* sequence, spin briefly, and retry. The window is a handful of stores wide.
|
|
124
|
+
*/
|
|
125
|
+
commit(value) {
|
|
126
|
+
const context = this.#newContext();
|
|
127
|
+
let slot;
|
|
128
|
+
try {
|
|
129
|
+
slot = encodeValue(context, value);
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
this.#rollback(context);
|
|
133
|
+
throw error;
|
|
134
|
+
}
|
|
135
|
+
// A wholesale replacement shares nothing with the previous version, so everything the
|
|
136
|
+
// old root reached is garbage once that version is unreadable.
|
|
137
|
+
const retired = collectBlocks(this.arena, this.#currentSlot, context.retired);
|
|
138
|
+
return this.#install(slot, retired);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Apply a recipe to a draft of the current state and commit the result.
|
|
142
|
+
*
|
|
143
|
+
* This is the path that makes retention affordable. Only the paths the recipe touched are
|
|
144
|
+
* rebuilt, so setting one field of a large object copies a handful of nodes rather than
|
|
145
|
+
* the tree.
|
|
146
|
+
*
|
|
147
|
+
* owner.update((draft) => {
|
|
148
|
+
* draft.users[3].name = "new name";
|
|
149
|
+
* });
|
|
150
|
+
*/
|
|
151
|
+
update(recipe) {
|
|
152
|
+
const context = this.#newContext();
|
|
153
|
+
const current = this.#currentSlot;
|
|
154
|
+
if (current.tag !== Tag.Object && current.tag !== Tag.Array) {
|
|
155
|
+
throw new GlobalsError("update needs an object or array root. Commit one first, or use commit to replace " +
|
|
156
|
+
"the root outright.");
|
|
157
|
+
}
|
|
158
|
+
let slot;
|
|
159
|
+
try {
|
|
160
|
+
const draft = createDraft(context, current);
|
|
161
|
+
recipe(draft.proxy);
|
|
162
|
+
slot = finalizeState(context, draft.state);
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
this.#rollback(context);
|
|
166
|
+
throw error;
|
|
167
|
+
}
|
|
168
|
+
if (slot.tag === current.tag && slot.payload === current.payload) {
|
|
169
|
+
// The recipe changed nothing. Publishing a version anyway would wake every window for
|
|
170
|
+
// no reason.
|
|
171
|
+
return this.#versionId;
|
|
172
|
+
}
|
|
173
|
+
return this.#install(slot, context.retired);
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* The current state as a detached plain value.
|
|
177
|
+
*
|
|
178
|
+
* The owner reads through this rather than through a reader, because it already knows the
|
|
179
|
+
* current root and does not need to pin anything: nothing can reclaim a version while the
|
|
180
|
+
* only writer is inside a synchronous method.
|
|
181
|
+
*/
|
|
182
|
+
readSnapshot() {
|
|
183
|
+
return decodeValue(this.arena, this.#currentSlot);
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Undo a commit that failed part way.
|
|
187
|
+
*
|
|
188
|
+
* Both lists matter. The allocated blocks are obvious. The interning journal is less so:
|
|
189
|
+
* strings are append only and never freed during normal operation, so without releasing
|
|
190
|
+
* the ones a rejected write created, a sequence of rejected writes would consume the arena
|
|
191
|
+
* permanently. A window that can request writes could then exhaust it with writes that
|
|
192
|
+
* were all refused.
|
|
193
|
+
*/
|
|
194
|
+
#rollback(context) {
|
|
195
|
+
for (const offset of context.allocated)
|
|
196
|
+
this.#allocator.free(offset);
|
|
197
|
+
this.#strings.forget(context.interned);
|
|
198
|
+
// Freeing returns the blocks to their size classes, which is not enough on its own: a
|
|
199
|
+
// write that filled the arena with small records leaves it unable to serve a larger
|
|
200
|
+
// request, because there is no coalescing. Rewinding the bump pointer past everything
|
|
201
|
+
// this commit allocated returns the arena to exactly where it was.
|
|
202
|
+
this.#allocator.rewindTo(context.bumpBefore);
|
|
203
|
+
}
|
|
204
|
+
#newContext() {
|
|
205
|
+
return {
|
|
206
|
+
arena: this.arena,
|
|
207
|
+
allocator: this.#allocator,
|
|
208
|
+
strings: this.#strings,
|
|
209
|
+
allocated: [],
|
|
210
|
+
retired: [],
|
|
211
|
+
interned: [],
|
|
212
|
+
bumpBefore: this.#allocator.stats().bumpPointer,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
#install(slot, retired) {
|
|
216
|
+
const previousVersion = this.#versionId;
|
|
217
|
+
const version = previousVersion + 1;
|
|
218
|
+
this.#evictForVersion(version);
|
|
219
|
+
this.#publish(version, slot);
|
|
220
|
+
if (previousVersion > 0 && retired.length > 0) {
|
|
221
|
+
const existing = this.#garbage.get(previousVersion);
|
|
222
|
+
if (existing)
|
|
223
|
+
existing.push(...retired);
|
|
224
|
+
else
|
|
225
|
+
this.#garbage.set(previousVersion, retired);
|
|
226
|
+
}
|
|
227
|
+
this.#currentSlot = slot;
|
|
228
|
+
this.#versionId = version;
|
|
229
|
+
this.arena.addHeader(Header.StatCommits, 1);
|
|
230
|
+
this.reclaim();
|
|
231
|
+
return version;
|
|
232
|
+
}
|
|
233
|
+
#publish(version, slot) {
|
|
234
|
+
const arena = this.arena;
|
|
235
|
+
// Odd sequence: a commit is in progress and readers must retry.
|
|
236
|
+
arena.addHeader(Header.Sequence, 1);
|
|
237
|
+
// The ring entry is written before the header so a reader that observes the new version
|
|
238
|
+
// can always find it live in the ring.
|
|
239
|
+
this.#ring.publish(version, slot.tag, slot.payload);
|
|
240
|
+
arena.storeHeader(Header.RootTag, slot.tag);
|
|
241
|
+
arena.storeHeader(Header.RootPayload, slot.payload);
|
|
242
|
+
arena.storeHeader(Header.VersionId, version);
|
|
243
|
+
// The checksum goes inside the seqlock too, so a reader that observes the new version
|
|
244
|
+
// always observes the checksum that matches it rather than the previous one.
|
|
245
|
+
publishChecksum(arena, slot, version, this.#verify);
|
|
246
|
+
// Even sequence: the root is stable again.
|
|
247
|
+
arena.addHeader(Header.Sequence, 1);
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Reclaim every version that no reader can still be pinned to.
|
|
251
|
+
*
|
|
252
|
+
* The order below is the whole correctness argument, so it is written out rather than
|
|
253
|
+
* left to be rediscovered:
|
|
254
|
+
*
|
|
255
|
+
* 1. Scan the reader table for the minimum pinned epoch.
|
|
256
|
+
* 2. Publish the resulting floor.
|
|
257
|
+
* 3. Scan again.
|
|
258
|
+
* 4. Free only below the minimum of the two scans.
|
|
259
|
+
*
|
|
260
|
+
* Step 3 is what closes the race. A reader that pinned between steps 1 and 2 is seen by
|
|
261
|
+
* the second scan. A reader that pinned after step 2 must load the floor after the store
|
|
262
|
+
* that published it, sees its version is below the floor, and retries. There is no
|
|
263
|
+
* interleaving in which a reader proceeds with a version this method then frees.
|
|
264
|
+
*/
|
|
265
|
+
reclaim() {
|
|
266
|
+
const firstScan = this.#readers.minimumPinnedEpoch();
|
|
267
|
+
// History, when it is switched on, holds versions alive that nothing is pinned to. It is
|
|
268
|
+
// a deliberate cost rather than a free feature: those versions keep their path copies.
|
|
269
|
+
const boundary = Math.min(firstScan, this.#versionId - this.#historyDepth);
|
|
270
|
+
this.#raiseFloor(Number.isFinite(boundary) ? boundary : 0);
|
|
271
|
+
const secondScan = this.#readers.minimumPinnedEpoch();
|
|
272
|
+
const safeBelow = Math.min(boundary, secondScan);
|
|
273
|
+
for (const [versionId, blocks] of this.#garbage) {
|
|
274
|
+
if (versionId >= safeBelow)
|
|
275
|
+
break;
|
|
276
|
+
for (const offset of blocks)
|
|
277
|
+
this.#allocator.free(offset);
|
|
278
|
+
this.#garbage.delete(versionId);
|
|
279
|
+
this.#ring.retire(versionId, false);
|
|
280
|
+
}
|
|
281
|
+
this.arena.storeHeader(Header.StatBytesLive, this.#allocator.stats().liveBytes);
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Raise the reclaim floor and publish it. Never lowers it: a reader that has been told a
|
|
285
|
+
* version is gone must not later be told it is available again, because the memory
|
|
286
|
+
* beneath it has already been handed to a different allocation.
|
|
287
|
+
*/
|
|
288
|
+
#raiseFloor(value) {
|
|
289
|
+
if (value <= this.#reclaimFloor)
|
|
290
|
+
return;
|
|
291
|
+
this.#reclaimFloor = value;
|
|
292
|
+
this.arena.storeHeader(Header.ReclaimFloor, value);
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* The ring slot a new version will occupy may still hold a live version. Free it, even if
|
|
296
|
+
* a reader is pinned to it.
|
|
297
|
+
*
|
|
298
|
+
* This is the bounded retention rule. The alternative is to let one frozen window grow
|
|
299
|
+
* the arena without limit, which turns a stuck renderer into an out of memory crash for
|
|
300
|
+
* the whole application. A reader that loses its version this way raises
|
|
301
|
+
* StaleSnapshotError on its next decode and reacquires, which is a recoverable outcome.
|
|
302
|
+
*/
|
|
303
|
+
#evictForVersion(version) {
|
|
304
|
+
const evicted = version - this.#ring.capacity;
|
|
305
|
+
if (evicted < 1)
|
|
306
|
+
return;
|
|
307
|
+
const minimumPinned = this.#readers.minimumPinnedEpoch();
|
|
308
|
+
if (minimumPinned <= evicted)
|
|
309
|
+
this.arena.addHeader(Header.StatForcedAdvances, 1);
|
|
310
|
+
// The floor rises before anything is freed. A reader that is part way through decoding
|
|
311
|
+
// one of these versions revalidates after its decode and sees the raised floor, so it
|
|
312
|
+
// reports a stale snapshot instead of returning a value read from reused memory. The
|
|
313
|
+
// reverse order loses that: the reader would decode recycled bytes and revalidate
|
|
314
|
+
// against a floor that had not moved yet.
|
|
315
|
+
this.#raiseFloor(evicted + 1);
|
|
316
|
+
for (const [versionId, blocks] of this.#garbage) {
|
|
317
|
+
if (versionId > evicted)
|
|
318
|
+
break;
|
|
319
|
+
for (const offset of blocks)
|
|
320
|
+
this.#allocator.free(offset);
|
|
321
|
+
this.#garbage.delete(versionId);
|
|
322
|
+
this.#ring.retire(versionId, versionId >= minimumPinned);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Grow the buffer. Every holder observes the new length, because a growable
|
|
327
|
+
* SharedArrayBuffer reserves its maximum at allocation and grow() only publishes more of
|
|
328
|
+
* it. Views made before the growth are refreshed lazily by SharedArena.
|
|
329
|
+
*/
|
|
330
|
+
#growBuffer(minimumBytes) {
|
|
331
|
+
const buffer = this.arena.buffer;
|
|
332
|
+
const maximum = buffer.maxByteLength ?? buffer.byteLength;
|
|
333
|
+
if (!buffer.growable || buffer.byteLength >= maximum)
|
|
334
|
+
return false;
|
|
335
|
+
const wanted = Math.min(maximum, Math.max(buffer.byteLength * 2, buffer.byteLength + minimumBytes));
|
|
336
|
+
if (wanted <= buffer.byteLength)
|
|
337
|
+
return false;
|
|
338
|
+
buffer.grow(wanted);
|
|
339
|
+
this.arena.refresh();
|
|
340
|
+
this.arena.storeHeader(Header.CapacityBytes, this.arena.byteLength);
|
|
341
|
+
return true;
|
|
342
|
+
}
|
|
343
|
+
/** Bump the owner heartbeat. Readers use it to detect an owner that has stopped. */
|
|
344
|
+
beat() {
|
|
345
|
+
this.arena.addHeader(Header.OwnerHeartbeat, 1);
|
|
346
|
+
}
|
|
347
|
+
stats() {
|
|
348
|
+
const allocator = this.#allocator.stats();
|
|
349
|
+
const minimum = this.#readers.minimumPinnedEpoch();
|
|
350
|
+
return {
|
|
351
|
+
versionId: this.#versionId,
|
|
352
|
+
commits: this.arena.loadHeader(Header.StatCommits),
|
|
353
|
+
forcedAdvances: this.arena.loadHeader(Header.StatForcedAdvances),
|
|
354
|
+
liveBytes: allocator.liveBytes,
|
|
355
|
+
bumpPointer: allocator.bumpPointer,
|
|
356
|
+
capacityBytes: allocator.capacityBytes,
|
|
357
|
+
freeListBytes: allocator.freeListBytes,
|
|
358
|
+
strandedBytes: this.#allocator.strandedBytes(),
|
|
359
|
+
internedStrings: this.#strings.size,
|
|
360
|
+
pendingGarbageVersions: this.#garbage.size,
|
|
361
|
+
historyDepth: this.#historyDepth,
|
|
362
|
+
reclaimFloor: this.arena.loadHeader(Header.ReclaimFloor),
|
|
363
|
+
claimedReaders: this.#readers.claimedSlots().length,
|
|
364
|
+
minimumPinnedEpoch: Number.isFinite(minimum) ? minimum : 0,
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
//# sourceMappingURL=owner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"owner.js","sourceRoot":"","sources":["../../src/owner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { SharedArena } from "./arena.js";
|
|
2
|
+
import { type Slot } from "./values.js";
|
|
3
|
+
export interface SnapshotInfo {
|
|
4
|
+
readonly versionId: number;
|
|
5
|
+
readonly ownerGeneration: number;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* A pinned version.
|
|
9
|
+
*
|
|
10
|
+
* Holding one guarantees the graph beneath it cannot change, because the writer never
|
|
11
|
+
* mutates a published node. It does not guarantee the version stays retained forever: past
|
|
12
|
+
* the retention cap the owner force advances, and the next decode raises
|
|
13
|
+
* StaleSnapshotError rather than reading recycled memory.
|
|
14
|
+
*/
|
|
15
|
+
export declare class Snapshot {
|
|
16
|
+
#private;
|
|
17
|
+
readonly versionId: number;
|
|
18
|
+
readonly ownerGeneration: number;
|
|
19
|
+
constructor(reader: ArenaReader, versionId: number, ownerGeneration: number, slot: Slot);
|
|
20
|
+
get released(): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* The root value. Synchronous, no await, no round trip. This is the whole product.
|
|
23
|
+
*
|
|
24
|
+
* Validated on both sides of the decode. The check before it rejects a version that is
|
|
25
|
+
* already gone. The check after it is the one that matters: the owner raises the reclaim
|
|
26
|
+
* floor before it frees anything, so a version that is still above the floor once the
|
|
27
|
+
* decode has finished cannot have been freed while the decode was running. Validating
|
|
28
|
+
* only beforehand leaves a window in which a forced reclaim recycles the block and the
|
|
29
|
+
* reader returns a well formed but wrong value, which the soak harness found in about two
|
|
30
|
+
* reads out of four million.
|
|
31
|
+
*/
|
|
32
|
+
get value(): unknown;
|
|
33
|
+
/**
|
|
34
|
+
* The whole version as a detached plain value, with no proxies and no arena references.
|
|
35
|
+
*
|
|
36
|
+
* Use it to hand state to something that has to own it, such as a serialiser or a worker.
|
|
37
|
+
* It costs a full decode, which is exactly what the lazy path exists to avoid, so it is a
|
|
38
|
+
* deliberate call rather than the default.
|
|
39
|
+
*/
|
|
40
|
+
toJSON(): unknown;
|
|
41
|
+
/**
|
|
42
|
+
* Read one path without building views for the nodes along it.
|
|
43
|
+
*
|
|
44
|
+
* The cheapest shape for a selector, and what the framework bindings use.
|
|
45
|
+
*/
|
|
46
|
+
get(path: readonly (string | number)[]): unknown;
|
|
47
|
+
/** The root slot, for callers decoding lazily rather than eagerly. */
|
|
48
|
+
get root(): Slot;
|
|
49
|
+
/**
|
|
50
|
+
* Prove this version is still retained. Two atomic loads and two comparisons, run on both
|
|
51
|
+
* sides of every decode. Cheap enough to sit on the read path, and the only thing standing
|
|
52
|
+
* between a stalled reader and freed memory.
|
|
53
|
+
*/
|
|
54
|
+
validate(): void;
|
|
55
|
+
/**
|
|
56
|
+
* True when this snapshot can still be decoded. Never throws, and never constructs an
|
|
57
|
+
* error object, because it runs twice per read and a try/catch around the throwing form
|
|
58
|
+
* kept the whole path out of the optimising compiler.
|
|
59
|
+
*/
|
|
60
|
+
isValid(): boolean;
|
|
61
|
+
release(): void;
|
|
62
|
+
}
|
|
63
|
+
export interface ReaderOptions {
|
|
64
|
+
/** Bump the heartbeat on every acquire so the owner can tell this reader is alive. */
|
|
65
|
+
heartbeat?: boolean;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* A reader.
|
|
69
|
+
*
|
|
70
|
+
* Attaching claims one slot in the reader table. Acquiring a snapshot is a seqlock read of
|
|
71
|
+
* the root, one atomic store to publish the pinned epoch, and one atomic load to confirm
|
|
72
|
+
* the version is above the reclaim floor. Nothing here blocks, allocates a promise, or
|
|
73
|
+
* sends a message.
|
|
74
|
+
*/
|
|
75
|
+
export declare class ArenaReader {
|
|
76
|
+
#private;
|
|
77
|
+
readonly arena: SharedArena;
|
|
78
|
+
readonly slot: number;
|
|
79
|
+
readonly generation: number;
|
|
80
|
+
private constructor();
|
|
81
|
+
static attach(buffer: SharedArrayBuffer, options?: ReaderOptions): ArenaReader;
|
|
82
|
+
get detached(): boolean;
|
|
83
|
+
reclaimFloor(): number;
|
|
84
|
+
ownerGeneration(): number;
|
|
85
|
+
/** The version the owner has currently published, without pinning it. */
|
|
86
|
+
publishedVersion(): number;
|
|
87
|
+
/**
|
|
88
|
+
* Acquire the current version and pin it.
|
|
89
|
+
*
|
|
90
|
+
* Returns the snapshot already held when the owner has not committed since, so a render
|
|
91
|
+
* loop that calls this every frame does not churn pins.
|
|
92
|
+
*/
|
|
93
|
+
acquire(): Snapshot;
|
|
94
|
+
/** Read the current root value. The synchronous read the whole library exists for. */
|
|
95
|
+
read(): unknown;
|
|
96
|
+
/**
|
|
97
|
+
* Pin a specific retained version rather than the current one.
|
|
98
|
+
*
|
|
99
|
+
* For debugging and time travel. It pins that version and everything after it against
|
|
100
|
+
* reclamation, so a snapshot obtained this way must be released. A render path should
|
|
101
|
+
* never use it.
|
|
102
|
+
*
|
|
103
|
+
* A reader owns one epoch slot, so this suspends the pin the render path was holding until
|
|
104
|
+
* the returned snapshot is released. A debug panel that browses history while a render
|
|
105
|
+
* reads should attach its own reader rather than share one, which costs a slot and keeps
|
|
106
|
+
* the two independent.
|
|
107
|
+
*/
|
|
108
|
+
acquireVersion(versionId: number): Snapshot;
|
|
109
|
+
/** Materialise a retained version, pinning it only for the duration of the read. */
|
|
110
|
+
readVersion(versionId: number): unknown;
|
|
111
|
+
releaseSnapshot(snapshot: Snapshot): void;
|
|
112
|
+
/** Release the pin and the reader slot. Always call this before dropping a reader. */
|
|
113
|
+
detach(): void;
|
|
114
|
+
stats(): {
|
|
115
|
+
slot: number;
|
|
116
|
+
generation: number;
|
|
117
|
+
pinnedEpoch: number;
|
|
118
|
+
publishedVersion: number;
|
|
119
|
+
reclaimFloor: number;
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=reader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reader.d.ts","sourceRoot":"","sources":["../../src/reader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAKzC,OAAO,EAAe,KAAK,IAAI,EAAE,MAAM,aAAa,CAAC;AAWrD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAED;;;;;;;GAOG;AACH,qBAAa,QAAQ;;IACnB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IAMjC,YAAY,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAKtF;IAED,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED;;;;;;;;;;OAUG;IACH,IAAI,KAAK,IAAI,OAAO,CAKnB;IAED;;;;;;OAMG;IACH,MAAM,IAAI,OAAO,CAKhB;IAED;;;;OAIG;IACH,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,GAAG,OAAO,CAK/C;IAmBD,sEAAsE;IACtE,IAAI,IAAI,IAAI,IAAI,CAGf;IAED;;;;OAIG;IACH,QAAQ,IAAI,IAAI,CAGf;IAED;;;;OAIG;IACH,OAAO,IAAI,OAAO,CAMjB;IAED,OAAO,IAAI,IAAI,CAId;CACF;AAED,MAAM,WAAW,aAAa;IAC5B,sFAAsF;IACtF,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,qBAAa,WAAW;;IACtB,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAgB5B,OAAO,eASN;IAED,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,iBAAiB,EAAE,OAAO,GAAE,aAAkB,GAAG,WAAW,CAEjF;IAED,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,YAAY,IAAI,MAAM,CAErB;IAED,eAAe,IAAI,MAAM,CAExB;IAED,yEAAyE;IACzE,gBAAgB,IAAI,MAAM,CAEzB;IAED;;;;;OAKG;IACH,OAAO,IAAI,QAAQ,CAwDlB;IAED,sFAAsF;IACtF,IAAI,IAAI,OAAO,CAEd;IAED;;;;;;;;;;;OAWG;IACH,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,QAAQ,CAsB1C;IAED,oFAAoF;IACpF,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAWtC;IAED,eAAe,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAcxC;IAED,sFAAsF;IACtF,MAAM,IAAI,IAAI,CAKb;IAED,KAAK,IAAI;QACP,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;QACpB,gBAAgB,EAAE,MAAM,CAAC;QACzB,YAAY,EAAE,MAAM,CAAC;KACtB,CAQA;CACF"}
|