@cloudbitmaps/core 0.23.0 → 0.24.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 +0 -9
- package/dist/{chunk-MVUD4R72.js → chunk-2B2QF4FU.js} +6 -1
- package/dist/chunk-2B2QF4FU.js.map +7 -0
- package/dist/{chunk-7GT632UF.js → chunk-45ML6YU4.js} +2 -2
- package/dist/{chunk-CGILDXGP.js → chunk-BUDAVGBI.js} +2 -2
- package/dist/{chunk-GKHERVVQ.js → chunk-WPER7R2R.js} +2 -2
- package/dist/core/check.d.ts +2 -1
- package/dist/core/codec.d.ts +13 -3
- package/dist/core/cooperative.d.ts +8 -5
- package/dist/core/crbm/reader.d.ts +1 -1
- package/dist/core/engine.d.ts +1 -1
- package/dist/core/erase-id.d.ts +1 -1
- package/dist/core/load-input.d.ts +1 -1
- package/dist/core/load.d.ts +2 -2
- package/dist/driver-kit.js +3 -3
- package/dist/index.js +81 -24
- package/dist/index.js.map +2 -2
- package/dist/node.js +3 -3
- package/package.json +1 -2
- package/dist/chunk-MVUD4R72.js.map +0 -7
- /package/dist/{chunk-7GT632UF.js.map → chunk-45ML6YU4.js.map} +0 -0
- /package/dist/{chunk-CGILDXGP.js.map → chunk-BUDAVGBI.js.map} +0 -0
- /package/dist/{chunk-GKHERVVQ.js.map → chunk-WPER7R2R.js.map} +0 -0
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
requirePositiveInteger,
|
|
20
20
|
shown,
|
|
21
21
|
tailBytesFit
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-2B2QF4FU.js";
|
|
23
23
|
|
|
24
24
|
// src/drivers/_shared/options.ts
|
|
25
25
|
function checkNow(name, now) {
|
|
@@ -638,4 +638,4 @@ export {
|
|
|
638
638
|
namespaceKeyPart,
|
|
639
639
|
namespacePathPart
|
|
640
640
|
};
|
|
641
|
-
//# sourceMappingURL=chunk-
|
|
641
|
+
//# sourceMappingURL=chunk-45ML6YU4.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
requirePositiveInteger
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-2B2QF4FU.js";
|
|
4
4
|
|
|
5
5
|
// src/core/concurrency.ts
|
|
6
6
|
async function mapWithConcurrency(items, limit, fn) {
|
|
@@ -70,4 +70,4 @@ export {
|
|
|
70
70
|
mapWithConcurrency,
|
|
71
71
|
boundedAll
|
|
72
72
|
};
|
|
73
|
-
//# sourceMappingURL=chunk-
|
|
73
|
+
//# sourceMappingURL=chunk-BUDAVGBI.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ValidationError,
|
|
3
3
|
encodeNameForKey
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-2B2QF4FU.js";
|
|
5
5
|
|
|
6
6
|
// src/core/keys.ts
|
|
7
7
|
var FIELD = " ";
|
|
@@ -118,4 +118,4 @@ export {
|
|
|
118
118
|
BufferSink,
|
|
119
119
|
BufferReader
|
|
120
120
|
};
|
|
121
|
-
//# sourceMappingURL=chunk-
|
|
121
|
+
//# sourceMappingURL=chunk-WPER7R2R.js.map
|
package/dist/core/check.d.ts
CHANGED
|
@@ -33,7 +33,8 @@ export declare function requireFiniteNumber(value: unknown, bounds: {
|
|
|
33
33
|
/**
|
|
34
34
|
* Refuse an options bag that is not an object, or that holds a key not in `keys`, naming each such key and the keys it
|
|
35
35
|
* takes. `hint`, when given, ends the message, to point at where a likely mistake belongs (`an S3 client goes in
|
|
36
|
-
* \`client\``). Only the bag's own enumerable string keys are read
|
|
36
|
+
* \`client\``). Only the bag's own enumerable string keys are read, so a key inherited through a prototype is not
|
|
37
|
+
* checked.
|
|
37
38
|
*/
|
|
38
39
|
export declare function refuseUnknownOptions(name: string, options: unknown, keys: readonly string[], hint?: string): void;
|
|
39
40
|
/**
|
package/dist/core/codec.d.ts
CHANGED
|
@@ -54,7 +54,7 @@ export interface CodecBitmap {
|
|
|
54
54
|
toArray(): number[];
|
|
55
55
|
/**
|
|
56
56
|
* The set's values as one ascending `Uint32Array` the caller owns: what a batch read converts a chunk with, in one
|
|
57
|
-
*
|
|
57
|
+
* step instead of one iterator step per value.
|
|
58
58
|
*
|
|
59
59
|
* **Optional.** A codec without it is read through its iterator, which is correct and slower.
|
|
60
60
|
*
|
|
@@ -125,7 +125,7 @@ export interface EncodedChunk {
|
|
|
125
125
|
}
|
|
126
126
|
/**
|
|
127
127
|
* A pluggable bitmap codec — the factory the codec-agnostic engine constructs {@link CodecBitmap}s through.
|
|
128
|
-
* Implementations **must** size-cap before handing untrusted bytes to
|
|
128
|
+
* Implementations **must** size-cap before handing untrusted bytes to a decoder and use a safe
|
|
129
129
|
* (never a trusting/frozen) deserializer — hard invariant 5.
|
|
130
130
|
*/
|
|
131
131
|
export interface CodecInterface {
|
|
@@ -135,7 +135,7 @@ export interface CodecInterface {
|
|
|
135
135
|
fromValues(values: Iterable<number>): CodecBitmap;
|
|
136
136
|
/**
|
|
137
137
|
* Size-cap (`bytes.length <= maxBytes`) then portable-deserialize. Throws `IntegrityError` when the input
|
|
138
|
-
* exceeds the cap or fails to decode — the
|
|
138
|
+
* exceeds the cap or fails to decode — the decoder is never handed unbounded or unsafe-format input.
|
|
139
139
|
*
|
|
140
140
|
* "Fails to decode" includes bytes that are the right length and the wrong shape. A bitmap this returns must
|
|
141
141
|
* satisfy every invariant its own operations assume (for roaring: containers and values in order, runs
|
|
@@ -161,6 +161,16 @@ export interface CodecInterface {
|
|
|
161
161
|
* The answer is the whole check: an `owns` that answers `true` for anything lets any object through as a bitmap.
|
|
162
162
|
*/
|
|
163
163
|
owns?(bitmap: unknown): boolean;
|
|
164
|
+
/**
|
|
165
|
+
* Whether an intersect of three or more operands should meet each chunk's operands smallest-first (by `size`).
|
|
166
|
+
*
|
|
167
|
+
* **Optional, and off by default.** A codec whose combine cost depends on the order, because an early operand that is
|
|
168
|
+
* large and of one container kind makes the running result expensive, sets it; the engine then pays one `size` read per
|
|
169
|
+
* operand per chunk to put the sparsest first. A codec whose combines cost about the same in any order, or whose
|
|
170
|
+
* `size` is expensive to read, leaves it out and keeps the operand order it was given. The answer is the
|
|
171
|
+
* same either way.
|
|
172
|
+
*/
|
|
173
|
+
readonly intersectSmallestFirst?: boolean;
|
|
164
174
|
}
|
|
165
175
|
/**
|
|
166
176
|
* Resolve a codec that a **public core entry point** was given, failing fast when it is missing.
|
|
@@ -3,13 +3,16 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Everything this library does on the hot read path is small. Bulk-load is the exception: it is the one place
|
|
5
5
|
* where a single call legitimately occupies the CPU for hundreds of milliseconds, and Node has exactly one thread
|
|
6
|
-
* to occupy. Measured on
|
|
7
|
-
*
|
|
6
|
+
* to occupy. Measured on the native codec of 0.23.0 (every figure in this header is the native codec's, to be
|
|
7
|
+
* re-measured on the TypeScript codec), on a 1M-id load of 65,536 chunks onto in-memory storage, on a loaded Apple M3
|
|
8
|
+
* Pro: **518 ms wall, and 519 ms during which the event loop did not turn at all** (medians of 20 fresh-process
|
|
9
|
+
* runs). Wire that to a request handler and every other in-flight request on the instance — health
|
|
8
10
|
* checks included — waits out the whole load.
|
|
9
11
|
*
|
|
10
|
-
* The fix is not to make the work asynchronous. That was measured too,
|
|
11
|
-
* chunk's insert to the threadpool
|
|
12
|
-
* across ~62,000 chunks (636 ms versus 92 ms). The
|
|
12
|
+
* The fix is not to make the work asynchronous. That was measured too, on the native codec's threadpool insert, and
|
|
13
|
+
* it was a 7x *regression*: handing each chunk's insert to the threadpool cost ~9 µs of dispatch against ~1.5 µs of
|
|
14
|
+
* actual work once ids are spread across ~62,000 chunks (636 ms versus 92 ms). The TypeScript codec has no
|
|
15
|
+
* threadpool path. The work is genuinely CPU-bound and genuinely small per chunk;
|
|
13
16
|
* the only thing wrong with it is that it never stops to let anyone else go. So the fix is to keep the work
|
|
14
17
|
* synchronous and periodically hand the loop back.
|
|
15
18
|
*
|
|
@@ -179,7 +179,7 @@ export declare class CrbmReader {
|
|
|
179
179
|
has(chunkKey: number): boolean;
|
|
180
180
|
/**
|
|
181
181
|
* Range-GET one chunk's payload, verifying its CRC32C before returning. Returns `null` if the chunk is
|
|
182
|
-
* absent. Throws `IntegrityError` on a CRC mismatch (the bytes must never reach the
|
|
182
|
+
* absent. Throws `IntegrityError` on a CRC mismatch (the bytes must never reach the codec's
|
|
183
183
|
* deserializer). The returned bytes may be shared (a small generation's chunks are kept by the reader and handed out
|
|
184
184
|
* again), so callers must not change them.
|
|
185
185
|
*/
|
package/dist/core/engine.d.ts
CHANGED
|
@@ -401,7 +401,7 @@ export declare class SegmentEngine {
|
|
|
401
401
|
* The AND (or OR) of one chunk key across all operands, minus the excludes that hold it, or `null` if empty.
|
|
402
402
|
* Operand chunks are fetched **in parallel** (the spec's parallel byte-range reads).
|
|
403
403
|
*
|
|
404
|
-
* The accumulator is a **clone** of
|
|
404
|
+
* The accumulator is a **clone** of one operand's chunk (the first, or for a codec that asks the one with the fewest values), and that clone is load-bearing: every other
|
|
405
405
|
* bitmap here is the cached, shared Storage instance and must never be mutated, or the cache is poisoned for
|
|
406
406
|
* every later reader. The remaining operands and the excludes are only *read* by the in-place ops, so they are
|
|
407
407
|
* used as-is — one clone per key, not one per operand.
|
package/dist/core/erase-id.d.ts
CHANGED
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
* its number after the winner's object was already in the bucket. Up there nothing collects it, and it was derived
|
|
67
67
|
* from a generation the winner has replaced, so when the winner was another erasure it still holds the id that
|
|
68
68
|
* erasure has just reported gone. That object is deleted before this call returns, once its footer matches the
|
|
69
|
-
* rewrite's and a renewal of the row has refused every publish fenced on a row read before it, under the version the
|
|
69
|
+
* rewrite's (a read of it that faults is thrown instead, and the object stays) and a renewal of the row has refused every publish fenced on a row read before it, under the version the
|
|
70
70
|
* footer read reported, unless {@link DISCARD_ATTEMPTS} renewals lose to other writes (a load, a rollback, a
|
|
71
71
|
* retention write): then it is kept, and can hold the winner's id, until a later call takes it: any erasure that
|
|
72
72
|
* rewrites the segment (this one's re-run among them, while its id is still in the current generation) numbers above it
|
|
@@ -119,6 +119,6 @@ export declare function prepareLoadInput(input: LoadInput, codec: CodecInterface
|
|
|
119
119
|
* are copied first. An empty or detached buffer is the empty bitmap.
|
|
120
120
|
*
|
|
121
121
|
* @param what names the input in a refusal's message.
|
|
122
|
-
* @throws {ValidationError} for anything that is not such bytes; nothing reaches the codec's
|
|
122
|
+
* @throws {ValidationError} for anything that is not such bytes; nothing reaches the codec's decoder then.
|
|
123
123
|
*/
|
|
124
124
|
export declare function decodeSerialized(bytes: unknown, codec: CodecInterface, what?: string): CodecBitmap;
|
package/dist/core/load.d.ts
CHANGED
|
@@ -148,8 +148,8 @@ export interface LoadOptions {
|
|
|
148
148
|
* `ValidationError`, naming its position and never the id. The object is the same, byte for byte, as an unsorted load
|
|
149
149
|
* of the same ids writes under the same write identity.
|
|
150
150
|
*
|
|
151
|
-
* For ids only (an iterable or an async iterable): with `{ serialized }`, `{ bitmap }` or a
|
|
152
|
-
*
|
|
151
|
+
* For ids only (an iterable or an async iterable): with `{ serialized }`, `{ bitmap }` or a bitmap itself (an
|
|
152
|
+
* iterable with a `serialize` method, which a flavor loads as `{ bitmap }`), and on core's
|
|
153
153
|
* `loadSegmentChunks`, it throws `ValidationError`, as does a value that is not a boolean, before any request.
|
|
154
154
|
*
|
|
155
155
|
* The ids are read after the segment's row is read and judged, and after its number and key are settled, so a load
|
package/dist/driver-kit.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
mapWithConcurrency
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-BUDAVGBI.js";
|
|
4
4
|
import {
|
|
5
5
|
DEFAULT_NAMESPACE,
|
|
6
6
|
applyRegistryPatch,
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
validateNewRegistryRecord,
|
|
19
19
|
validateRegistryPatch,
|
|
20
20
|
webCryptoEntropy
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-45ML6YU4.js";
|
|
22
22
|
import {
|
|
23
23
|
CloudRoaringError,
|
|
24
24
|
IntegrityError,
|
|
@@ -45,7 +45,7 @@ import {
|
|
|
45
45
|
requireNonEmptyString,
|
|
46
46
|
unsettledConflict,
|
|
47
47
|
validateSegmentRef
|
|
48
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-2B2QF4FU.js";
|
|
49
49
|
|
|
50
50
|
// src/drivers/_shared/object-registry-keys.ts
|
|
51
51
|
var REGISTRY_SUFFIX = ".reg";
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
boundedAll,
|
|
3
3
|
mapWithConcurrency
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-BUDAVGBI.js";
|
|
5
5
|
import {
|
|
6
6
|
BufferReader,
|
|
7
7
|
KeptSegmentKeys,
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
segmentKey,
|
|
10
10
|
segmentPrefix,
|
|
11
11
|
shardOf
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-WPER7R2R.js";
|
|
13
13
|
import {
|
|
14
14
|
BudgetExceededError,
|
|
15
15
|
CHUNK_COUNT,
|
|
@@ -99,6 +99,7 @@ import {
|
|
|
99
99
|
rollbackKnown,
|
|
100
100
|
sameIncarnation,
|
|
101
101
|
sameKeys,
|
|
102
|
+
sameKnownGens,
|
|
102
103
|
sizeOfFingerprint,
|
|
103
104
|
sizePart,
|
|
104
105
|
splitId,
|
|
@@ -115,7 +116,7 @@ import {
|
|
|
115
116
|
validateUserRef,
|
|
116
117
|
windowOf,
|
|
117
118
|
withRetry
|
|
118
|
-
} from "./chunk-
|
|
119
|
+
} from "./chunk-2B2QF4FU.js";
|
|
119
120
|
|
|
120
121
|
// src/core/budget.ts
|
|
121
122
|
var DEFAULT_BUDGET = { maxRequests: 1e6 };
|
|
@@ -758,6 +759,23 @@ function chunkIds(chunk, chunkKey, w) {
|
|
|
758
759
|
for (let i = 0; i < rem.length; i++) rem[i] = base + (rem[i] & MAX_REMAINDER);
|
|
759
760
|
return rem;
|
|
760
761
|
}
|
|
762
|
+
function smallestFirst(chunks) {
|
|
763
|
+
const out = chunks.slice();
|
|
764
|
+
const sizes = out.map((c) => c.size);
|
|
765
|
+
for (let i = 1; i < out.length; i++) {
|
|
766
|
+
const c = out[i];
|
|
767
|
+
const size = sizes[i];
|
|
768
|
+
let j = i - 1;
|
|
769
|
+
while (j >= 0 && sizes[j] > size) {
|
|
770
|
+
out[j + 1] = out[j];
|
|
771
|
+
sizes[j + 1] = sizes[j];
|
|
772
|
+
j--;
|
|
773
|
+
}
|
|
774
|
+
out[j + 1] = c;
|
|
775
|
+
sizes[j + 1] = size;
|
|
776
|
+
}
|
|
777
|
+
return out;
|
|
778
|
+
}
|
|
761
779
|
function alignKeys(operands, mode) {
|
|
762
780
|
const candidates = [];
|
|
763
781
|
if (mode === "all") {
|
|
@@ -1504,7 +1522,7 @@ var SegmentEngine = class _SegmentEngine {
|
|
|
1504
1522
|
* The AND (or OR) of one chunk key across all operands, minus the excludes that hold it, or `null` if empty.
|
|
1505
1523
|
* Operand chunks are fetched **in parallel** (the spec's parallel byte-range reads).
|
|
1506
1524
|
*
|
|
1507
|
-
* The accumulator is a **clone** of
|
|
1525
|
+
* The accumulator is a **clone** of one operand's chunk (the first, or for a codec that asks the one with the fewest values), and that clone is load-bearing: every other
|
|
1508
1526
|
* bitmap here is the cached, shared Storage instance and must never be mutated, or the cache is poisoned for
|
|
1509
1527
|
* every later reader. The remaining operands and the excludes are only *read* by the in-place ops, so they are
|
|
1510
1528
|
* used as-is — one clone per key, not one per operand.
|
|
@@ -1518,10 +1536,11 @@ var SegmentEngine = class _SegmentEngine {
|
|
|
1518
1536
|
const fetched = await Promise.all(reads.map((op) => this.operandChunk(op, chunkKey, moves)));
|
|
1519
1537
|
const chunks = together ? fetched.slice(0, present.length) : fetched;
|
|
1520
1538
|
if (mode === "all" && chunks.some((c) => c === null)) return null;
|
|
1521
|
-
const
|
|
1539
|
+
const ordered = mode === "all" && chunks.length > 2 && this.codec.intersectSmallestFirst === true ? smallestFirst(chunks) : chunks;
|
|
1540
|
+
const first = ordered[0];
|
|
1522
1541
|
const acc = first ? first.clone() : this.codec.empty();
|
|
1523
|
-
for (let i = 1; i <
|
|
1524
|
-
const other =
|
|
1542
|
+
for (let i = 1; i < ordered.length; i++) {
|
|
1543
|
+
const other = ordered[i];
|
|
1525
1544
|
if (other === null || other === void 0) continue;
|
|
1526
1545
|
if (mode === "all") {
|
|
1527
1546
|
acc.andInPlace(other);
|
|
@@ -2301,6 +2320,22 @@ function requireCodec(codec, api) {
|
|
|
2301
2320
|
// src/export/index.ts
|
|
2302
2321
|
var UTF8 = new TextEncoder();
|
|
2303
2322
|
var DEFAULT_NDJSON_BATCH_BYTES = 64 * 1024;
|
|
2323
|
+
var EXPORT_BATCH = 1 << 16;
|
|
2324
|
+
async function addAll(bitmap, ids) {
|
|
2325
|
+
const batch = new Uint32Array(EXPORT_BATCH);
|
|
2326
|
+
let held = 0;
|
|
2327
|
+
let count = 0;
|
|
2328
|
+
for await (const id of ids) {
|
|
2329
|
+
batch[held++] = id;
|
|
2330
|
+
count += 1;
|
|
2331
|
+
if (held === EXPORT_BATCH) {
|
|
2332
|
+
bitmap.addMany(batch);
|
|
2333
|
+
held = 0;
|
|
2334
|
+
}
|
|
2335
|
+
}
|
|
2336
|
+
if (held > 0) bitmap.addMany(batch.subarray(0, held));
|
|
2337
|
+
return count;
|
|
2338
|
+
}
|
|
2304
2339
|
var errMessage = (err) => err instanceof Error ? err.message : String(err);
|
|
2305
2340
|
async function runExport(reader, registry, sink, options = {}) {
|
|
2306
2341
|
if (sink === null || typeof sink !== "object" || typeof sink.open !== "function") {
|
|
@@ -2360,10 +2395,7 @@ async function runExport(reader, registry, sink, options = {}) {
|
|
|
2360
2395
|
writer = await sink.open(ref, ext);
|
|
2361
2396
|
if (format === "roaring") {
|
|
2362
2397
|
const bm = requireCodec(options.codec, "runExport({ format: 'roaring' })").empty();
|
|
2363
|
-
|
|
2364
|
-
bm.add(id);
|
|
2365
|
-
count += 1;
|
|
2366
|
-
}
|
|
2398
|
+
count = await addAll(bm, ids);
|
|
2367
2399
|
if (count === 0 && await rowIsGone(ref)) return await skipGone(ref, writer);
|
|
2368
2400
|
const out = bm.serialize();
|
|
2369
2401
|
await writer.write(out);
|
|
@@ -2974,7 +3006,7 @@ var CrbmReader = class _CrbmReader {
|
|
|
2974
3006
|
}
|
|
2975
3007
|
/**
|
|
2976
3008
|
* Range-GET one chunk's payload, verifying its CRC32C before returning. Returns `null` if the chunk is
|
|
2977
|
-
* absent. Throws `IntegrityError` on a CRC mismatch (the bytes must never reach the
|
|
3009
|
+
* absent. Throws `IntegrityError` on a CRC mismatch (the bytes must never reach the codec's
|
|
2978
3010
|
* deserializer). The returned bytes may be shared (a small generation's chunks are kept by the reader and handed out
|
|
2979
3011
|
* again), so callers must not change them.
|
|
2980
3012
|
*/
|
|
@@ -3357,8 +3389,9 @@ async function provenObject(storage, key, fingerprint) {
|
|
|
3357
3389
|
version ??= tail.version;
|
|
3358
3390
|
});
|
|
3359
3391
|
return await CrbmReader.sameObject(blob, fingerprint) ? { version } : null;
|
|
3360
|
-
} catch {
|
|
3361
|
-
return null;
|
|
3392
|
+
} catch (err) {
|
|
3393
|
+
if (isNotFoundError(err)) return null;
|
|
3394
|
+
throw err;
|
|
3362
3395
|
}
|
|
3363
3396
|
}
|
|
3364
3397
|
function sameObjectUnder(storage, key, fingerprint) {
|
|
@@ -3409,12 +3442,7 @@ async function footerCrcUnder(storage, key) {
|
|
|
3409
3442
|
return (await readFooter(storageBlobReader(storage, key))).footerCrc;
|
|
3410
3443
|
}
|
|
3411
3444
|
async function provesOwnObject(storage, key, fingerprint) {
|
|
3412
|
-
|
|
3413
|
-
return await CrbmReader.sameObject(storageBlobReader(storage, key), fingerprint);
|
|
3414
|
-
} catch (err) {
|
|
3415
|
-
if (isNotFoundError(err)) return false;
|
|
3416
|
-
throw err;
|
|
3417
|
-
}
|
|
3445
|
+
return await provenObject(storage, key, fingerprint) !== null;
|
|
3418
3446
|
}
|
|
3419
3447
|
var openedVersions = /* @__PURE__ */ new WeakMap();
|
|
3420
3448
|
function openGenerationReader(storage, key, crypto, options = {}, named) {
|
|
@@ -7271,7 +7299,7 @@ var KeyBits = class {
|
|
|
7271
7299
|
};
|
|
7272
7300
|
|
|
7273
7301
|
// src/core/combine-ledger.ts
|
|
7274
|
-
var RESIDENT_BITMAP_OVERHEAD =
|
|
7302
|
+
var RESIDENT_BITMAP_OVERHEAD = 832;
|
|
7275
7303
|
var MAX_CHUNK_SERIALIZED = 8208;
|
|
7276
7304
|
function serializedBound(cardinality) {
|
|
7277
7305
|
return Math.min(2 * cardinality + 16, MAX_CHUNK_SERIALIZED);
|
|
@@ -7279,7 +7307,7 @@ function serializedBound(cardinality) {
|
|
|
7279
7307
|
var MAX_RESIDENT_DATA = 8800;
|
|
7280
7308
|
function residentBytes(serialized) {
|
|
7281
7309
|
return Math.ceil(
|
|
7282
|
-
RESIDENT_BITMAP_OVERHEAD + Math.min(1.6 * serialized, serialized +
|
|
7310
|
+
RESIDENT_BITMAP_OVERHEAD + Math.min(1.6 * serialized, serialized + 2200, MAX_RESIDENT_DATA)
|
|
7283
7311
|
);
|
|
7284
7312
|
}
|
|
7285
7313
|
function residentBound(cardinality) {
|
|
@@ -9681,7 +9709,8 @@ async function fence(c, plan) {
|
|
|
9681
9709
|
const ledger = usableKnownGens(row);
|
|
9682
9710
|
const doomed = doomedGenerations(c, plan, byName, ledger, pointer);
|
|
9683
9711
|
const named = ledger !== void 0 && ledger.some((e) => doomed.has(e.generation));
|
|
9684
|
-
const
|
|
9712
|
+
const sweepOwes = plan.sweeps && !named && row.pointerId === record.pointerId && sameKnownGens(row.knownGens, record.knownGens);
|
|
9713
|
+
const renew = byName.length > 0 || sweepOwes;
|
|
9685
9714
|
const renewedAfter = held && row.pointerId !== first.pointerId;
|
|
9686
9715
|
if (!named && (!renew || renewedAfter)) {
|
|
9687
9716
|
c.premise = row;
|
|
@@ -10039,6 +10068,34 @@ async function stage(c) {
|
|
|
10039
10068
|
throw err;
|
|
10040
10069
|
}
|
|
10041
10070
|
}
|
|
10071
|
+
async function provenOwn(c, key, fingerprint) {
|
|
10072
|
+
const { deps } = c;
|
|
10073
|
+
const retry = deps.readRetry;
|
|
10074
|
+
const base = retry?.isRetryable ?? isTransientError;
|
|
10075
|
+
let fault;
|
|
10076
|
+
try {
|
|
10077
|
+
return await retryRead(
|
|
10078
|
+
async () => {
|
|
10079
|
+
try {
|
|
10080
|
+
return await provenObject(deps.storage, key, fingerprint);
|
|
10081
|
+
} catch (err) {
|
|
10082
|
+
if (!isIntegrityError(err)) fault = err;
|
|
10083
|
+
throw err;
|
|
10084
|
+
}
|
|
10085
|
+
},
|
|
10086
|
+
retry === void 0 ? void 0 : {
|
|
10087
|
+
...retry,
|
|
10088
|
+
isRetryable: (err) => isIntegrityError(err) || base(err),
|
|
10089
|
+
onRetry: (info) => {
|
|
10090
|
+
if (!isIntegrityError(info.err)) retry.onRetry?.(info);
|
|
10091
|
+
}
|
|
10092
|
+
}
|
|
10093
|
+
);
|
|
10094
|
+
} catch (err) {
|
|
10095
|
+
if (isIntegrityError(err) && fault === void 0) return null;
|
|
10096
|
+
throw fault ?? err;
|
|
10097
|
+
}
|
|
10098
|
+
}
|
|
10042
10099
|
async function discardRefused(c, own) {
|
|
10043
10100
|
const { ref, deps, base, from } = c;
|
|
10044
10101
|
const key = { ...base, generation: own.generation };
|
|
@@ -10055,7 +10112,7 @@ async function discardRefused(c, own) {
|
|
|
10055
10112
|
}
|
|
10056
10113
|
if (row === null || row.status !== "active" || row.currentGen === null) return row;
|
|
10057
10114
|
if (row.currentGen <= from || row.currentGen >= own.generation) return row;
|
|
10058
|
-
const proven = await
|
|
10115
|
+
const proven = await provenOwn(c, key, own.fingerprint);
|
|
10059
10116
|
if (proven === null) return row;
|
|
10060
10117
|
const renewed = await renewal.renew(row);
|
|
10061
10118
|
if ("row" in renewed) {
|