@cloudbitmaps/core 0.24.0 → 0.25.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/core/codec.d.ts +3 -3
- package/dist/core/cooperative.d.ts +1 -1
- package/dist/core/load-input.d.ts +9 -3
- package/dist/index.d.ts +2 -2
- package/dist/index.js +54 -58
- package/dist/index.js.map +2 -2
- package/dist/node.js.map +1 -1
- package/package.json +1 -1
package/dist/core/codec.d.ts
CHANGED
|
@@ -16,9 +16,9 @@
|
|
|
16
16
|
* different codecs, or a cached bitmap from codec A could reach codec B's in-place op. The `CloudRoaring` facade
|
|
17
17
|
* mints the cache per store, so this cannot arise in normal use.)
|
|
18
18
|
*
|
|
19
|
-
* **Interface surface = exactly what the engine needs**,
|
|
20
|
-
* (positional/
|
|
21
|
-
*
|
|
19
|
+
* **Interface surface = exactly what the engine needs**, and nothing a codec might one day offer: an operation the
|
|
20
|
+
* engine never calls (positional or rank/select access, say) is not on {@link CodecBitmap}, and a second codec that
|
|
21
|
+
* has such operations would carry them on its own value type. The one codec-linked concern
|
|
22
22
|
* this seam intentionally leaves in the format layer is the `.crbm` **payload codec id**
|
|
23
23
|
* (`PAYLOAD_CODEC_ROARING_PORTABLE` / `KNOWN_PAYLOAD_CODEC_IDS` in `crbm/format.ts`): it is stamped in the footer
|
|
24
24
|
* and validated on read, as membership of a registry rather than equality with one constant, so a codec-specific
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* the microtask queue drains to empty before the event loop advances a single phase. A loop awaiting them
|
|
23
23
|
* yields to other *microtasks* and to nothing else; no pending I/O callback runs. Measured: 555 ms of
|
|
24
24
|
* starvation against a 568 ms unyielded baseline **on the synthetic yield-primitive benchmark below** —
|
|
25
|
-
* a different, smaller workload than the
|
|
25
|
+
* a different, smaller workload than the 518 ms end-to-end load above, which is why the two baselines
|
|
26
26
|
* differ. The yield must be a **macrotask** — hence
|
|
27
27
|
* `Clock.yieldNow`, backed by `setImmediate` in production wiring.
|
|
28
28
|
* 2. **Yielding per unit of work costs more than the work.** The yield has to be periodic, and `everyN` has to be
|
|
@@ -115,10 +115,16 @@ export declare function prepareLoadInput(input: LoadInput, codec: CodecInterface
|
|
|
115
115
|
* input of a load goes through, and what a flavor offers its users to decode bytes they hold themselves.
|
|
116
116
|
*
|
|
117
117
|
* The bytes must be a `Uint8Array` (a Node `Buffer` is one), at most {@link MAX_SERIALIZED_LOAD_BYTES}, one whole
|
|
118
|
-
* bitmap and structurally sound. A view is read over the bytes it really holds, and
|
|
119
|
-
* are copied first. An empty or detached
|
|
118
|
+
* bitmap and structurally sound. A view is read over the bytes it really holds, once, and the size checks, the
|
|
119
|
+
* copy and the decode all use that one view. Bytes in a `SharedArrayBuffer` are copied first. An empty or detached
|
|
120
|
+
* buffer is the empty bitmap, unless `refuseEmpty` is set.
|
|
120
121
|
*
|
|
121
122
|
* @param what names the input in a refusal's message.
|
|
123
|
+
* @param options `maxBytes` lowers the size cap for this call (it cannot raise it); `refuseEmpty` refuses an empty or
|
|
124
|
+
* detached buffer, which is not a bitmap.
|
|
122
125
|
* @throws {ValidationError} for anything that is not such bytes; nothing reaches the codec's decoder then.
|
|
123
126
|
*/
|
|
124
|
-
export declare function decodeSerialized(bytes: unknown, codec: CodecInterface, what?: string
|
|
127
|
+
export declare function decodeSerialized(bytes: unknown, codec: CodecInterface, what?: string, options?: {
|
|
128
|
+
readonly maxBytes?: number;
|
|
129
|
+
readonly refuseEmpty?: boolean;
|
|
130
|
+
}): CodecBitmap;
|
package/dist/index.d.ts
CHANGED
|
@@ -24,7 +24,7 @@ export { BoundedLru } from './core/lru.js';
|
|
|
24
24
|
export { safeMetrics } from './core/metrics.js';
|
|
25
25
|
export { runExport } from './export/index.js';
|
|
26
26
|
export type { SegmentReader } from './export/index.js';
|
|
27
|
-
export { splitId } from './core/bit-route.js';
|
|
27
|
+
export { splitId, refusalOfId } from './core/bit-route.js';
|
|
28
28
|
export { mapWithConcurrency } from './core/concurrency.js';
|
|
29
29
|
export { resolveBudget, resolvePerOpBudget, checkBudget, collectWithinBudget } from './core/budget.js';
|
|
30
30
|
export { segmentExists, listSegments } from './core/discover.js';
|
|
@@ -43,7 +43,7 @@ export { compileCombineMany, rebindCombineMany, runCombineMany } from './core/co
|
|
|
43
43
|
export type { CombineManyDeps, CombineManyFeed, CombineManyOperand, CombineManyOutcome, CombineManyOutput, CombineManyRequest, CombineManyRun, CombineManyWrite, CompiledCombineMany, Expr, MaterializeManyFeedRecord, MaterializeManyOperandStats, MaterializeManyOutputStats, MaterializeManyStats, } from './core/combine-many.js';
|
|
44
44
|
export type { LoadDeps, LoadOptions, LoadGuard, GuardRefusal, LoadJudgement, LoadResult, LoadRefusal, } from './core/load.js';
|
|
45
45
|
export type { LoadInput, PortableBitmap } from './core/load-input.js';
|
|
46
|
-
export { decodeSerialized } from './core/load-input.js';
|
|
46
|
+
export { decodeSerialized, MAX_SERIALIZED_LOAD_BYTES } from './core/load-input.js';
|
|
47
47
|
export { listGenerations, rollbackSegment } from './core/rollback.js';
|
|
48
48
|
export type { GenerationListDeps, GenerationEntry, RollbackResult } from './core/rollback.js';
|
|
49
49
|
export { eraseIdFromSegment, findIdUnderTombstone } from './core/erase-id.js';
|
package/dist/index.js
CHANGED
|
@@ -183,7 +183,7 @@ async function refuseAbsent(op, candidates, limit, exists, nameOf) {
|
|
|
183
183
|
// src/core/chunk-checks.ts
|
|
184
184
|
function assertChunkKeyInRange(k) {
|
|
185
185
|
if (!Number.isInteger(k) || k < 0 || k >= CHUNK_COUNT) {
|
|
186
|
-
throw new IntegrityError(
|
|
186
|
+
throw new IntegrityError("a chunk key from a tier is out of range");
|
|
187
187
|
}
|
|
188
188
|
}
|
|
189
189
|
function assertChunkCardinalityInRange(c) {
|
|
@@ -206,22 +206,22 @@ function checkedChunkKeys(listed2) {
|
|
|
206
206
|
keys.sort((a, b) => a - b);
|
|
207
207
|
for (let i = 1; i < keys.length; i++) {
|
|
208
208
|
if (keys[i] === keys[i - 1]) {
|
|
209
|
-
throw new IntegrityError(
|
|
209
|
+
throw new IntegrityError("a chunk key from a tier is listed twice");
|
|
210
210
|
}
|
|
211
211
|
}
|
|
212
212
|
return keys;
|
|
213
213
|
}
|
|
214
|
-
function assertChunkPayloadInRange(bitmap
|
|
214
|
+
function assertChunkPayloadInRange(bitmap) {
|
|
215
215
|
const max = bitmap.maximum?.();
|
|
216
216
|
if (max !== void 0 && max > MAX_REMAINDER) {
|
|
217
217
|
throw new IntegrityError(
|
|
218
|
-
`chunk
|
|
218
|
+
`a chunk payload holds a value outside the 16-bit remainder range [0, ${MAX_REMAINDER}] (a container key other than 0) \u2014 the stored object is corrupt or was not written by this codec`
|
|
219
219
|
);
|
|
220
220
|
}
|
|
221
221
|
}
|
|
222
|
-
function decodeChunkBytes(codec, bytes,
|
|
222
|
+
function decodeChunkBytes(codec, bytes, maxBitmapBytes) {
|
|
223
223
|
const bitmap = codec.safeDeserialize(bytes, maxBitmapBytes);
|
|
224
|
-
assertChunkPayloadInRange(bitmap
|
|
224
|
+
assertChunkPayloadInRange(bitmap);
|
|
225
225
|
return bitmap;
|
|
226
226
|
}
|
|
227
227
|
|
|
@@ -238,12 +238,10 @@ var ChunkStream = class {
|
|
|
238
238
|
return this.iterator.next().then(
|
|
239
239
|
(step) => {
|
|
240
240
|
if (step.done === true) {
|
|
241
|
-
throw this.failure?.error ?? new IntegrityError(
|
|
241
|
+
throw this.failure?.error ?? new IntegrityError("chunk stream ended before a chunk it was opened over");
|
|
242
242
|
}
|
|
243
243
|
if (step.value.key !== key) {
|
|
244
|
-
throw new IntegrityError(
|
|
245
|
-
`chunk stream answered chunk ${step.value.key} where ${key} was due`
|
|
246
|
-
);
|
|
244
|
+
throw new IntegrityError("chunk stream answered a chunk other than the one due");
|
|
247
245
|
}
|
|
248
246
|
return step.value;
|
|
249
247
|
},
|
|
@@ -1201,9 +1199,7 @@ var SegmentEngine = class _SegmentEngine {
|
|
|
1201
1199
|
const expected = counts.get(chunkKey);
|
|
1202
1200
|
if (chunk === null || chunk.size !== expected) {
|
|
1203
1201
|
const got = chunk === null ? "no bytes" : `${chunk.size} ids`;
|
|
1204
|
-
throw new IntegrityError(
|
|
1205
|
-
`chunk ${chunkKey} holds ${got}, but the object's index says ${expected}`
|
|
1206
|
-
);
|
|
1202
|
+
throw new IntegrityError(`a chunk holds ${got}, but the object's index says ${expected}`);
|
|
1207
1203
|
}
|
|
1208
1204
|
return chunk.toUint32Array ? chunk.toUint32Array() : Uint32Array.from(chunk);
|
|
1209
1205
|
}
|
|
@@ -1871,7 +1867,7 @@ var SegmentEngine = class _SegmentEngine {
|
|
|
1871
1867
|
streamed.moves.moved = true;
|
|
1872
1868
|
}
|
|
1873
1869
|
if (read.bytes === null) return null;
|
|
1874
|
-
const bitmap = decodeChunkBytes(this.codec, read.bytes,
|
|
1870
|
+
const bitmap = decodeChunkBytes(this.codec, read.bytes, this.maxBitmapBytes);
|
|
1875
1871
|
if (this.cache && !streamed.invalidated && !this.scope.invalidatedSince(streamed.prefix, streamed.openedAt)) {
|
|
1876
1872
|
const version = this.streamedVersion(streamed.gen, read.version);
|
|
1877
1873
|
if (version !== null) {
|
|
@@ -2084,7 +2080,7 @@ var SegmentEngine = class _SegmentEngine {
|
|
|
2084
2080
|
}
|
|
2085
2081
|
}
|
|
2086
2082
|
if (!bytes) return null;
|
|
2087
|
-
const bitmap = decodeChunkBytes(this.codec, bytes,
|
|
2083
|
+
const bitmap = decodeChunkBytes(this.codec, bytes, this.maxBitmapBytes);
|
|
2088
2084
|
if (key !== "" && this.scope.isOpen(cacheKey, token)) this.cache?.set(key, bitmap);
|
|
2089
2085
|
return bitmap;
|
|
2090
2086
|
}
|
|
@@ -2545,7 +2541,7 @@ function* planChunkReads(extents, region) {
|
|
|
2545
2541
|
for (const extent of extents) {
|
|
2546
2542
|
const extentEnd = extent.offset + extent.length;
|
|
2547
2543
|
if (!(Number.isSafeInteger(extent.offset) && Number.isSafeInteger(extent.length) && extent.length >= 1 && extent.offset >= previousEnd && extentEnd <= region.end)) {
|
|
2548
|
-
throw crbmIntegrity(
|
|
2544
|
+
throw crbmIntegrity("a chunk is not inside the chunk region, in order");
|
|
2549
2545
|
}
|
|
2550
2546
|
previousEnd = extentEnd;
|
|
2551
2547
|
if (chunks.length > 0 && extent.offset - end <= MAX_COALESCE_GAP_BYTES && extentEnd - start <= MAX_COALESCED_READ_BYTES) {
|
|
@@ -2569,7 +2565,7 @@ function* planChunkReads(extents, region) {
|
|
|
2569
2565
|
var U32_CEIL = U32_MAX + 1;
|
|
2570
2566
|
function varintLength(value) {
|
|
2571
2567
|
if (!Number.isInteger(value) || value < 0 || value >= U32_CEIL) {
|
|
2572
|
-
throw new RangeError(
|
|
2568
|
+
throw new RangeError("varint value must be a u32");
|
|
2573
2569
|
}
|
|
2574
2570
|
if (value < 128) return 1;
|
|
2575
2571
|
if (value < 16384) return 2;
|
|
@@ -3016,7 +3012,7 @@ var CrbmReader = class _CrbmReader {
|
|
|
3016
3012
|
const offset = this.index.offsets[slot];
|
|
3017
3013
|
const length = this.index.lengths[slot];
|
|
3018
3014
|
if (offset < PAYLOAD_START || offset + length > this.objectSize - FOOTER_BYTES) {
|
|
3019
|
-
throw crbmIntegrity(`chunk ${
|
|
3015
|
+
throw crbmIntegrity(`chunk at position ${slot} payload out of bounds`);
|
|
3020
3016
|
}
|
|
3021
3017
|
const held = this.keptRange(offset, length);
|
|
3022
3018
|
return this.openChunk(slot, chunkKey, held ?? await this.blob.getRange(offset, length));
|
|
@@ -3043,11 +3039,11 @@ var CrbmReader = class _CrbmReader {
|
|
|
3043
3039
|
*/
|
|
3044
3040
|
openChunk(slot, chunkKey, bytes) {
|
|
3045
3041
|
if (crc32c(bytes) !== this.index.crcs[slot]) {
|
|
3046
|
-
throw crbmIntegrity(`chunk ${
|
|
3042
|
+
throw crbmIntegrity(`chunk at position ${slot} payload CRC mismatch`);
|
|
3047
3043
|
}
|
|
3048
3044
|
if (this.crypto === void 0) return bytes;
|
|
3049
3045
|
if (bytes.length < AEAD_NONCE_BYTES + AEAD_TAG_BYTES) {
|
|
3050
|
-
throw crbmIntegrity(`chunk ${
|
|
3046
|
+
throw crbmIntegrity(`chunk at position ${slot} encrypted payload too short`);
|
|
3051
3047
|
}
|
|
3052
3048
|
return this.crypto.aead.open(
|
|
3053
3049
|
{
|
|
@@ -3293,19 +3289,20 @@ function parseIndex(indexBytes, payloadEnd, maxPayloadBytes, minPayloadBytes = 1
|
|
|
3293
3289
|
const chunkKey = prevKey + keyDelta;
|
|
3294
3290
|
const offset = prevEnd + offDelta;
|
|
3295
3291
|
if (i > 0 && keyDelta === 0) {
|
|
3296
|
-
throw crbmIntegrity(`.crbm index
|
|
3292
|
+
throw crbmIntegrity(`.crbm index entry ${i} repeats a chunk key`);
|
|
3297
3293
|
}
|
|
3298
|
-
if (chunkKey > 65535)
|
|
3294
|
+
if (chunkKey > 65535)
|
|
3295
|
+
throw crbmIntegrity(`.crbm index entry ${i} has a chunk key out of range`);
|
|
3299
3296
|
if (len < minPayloadBytes || len > maxPayloadBytes) {
|
|
3300
3297
|
throw crbmIntegrity(
|
|
3301
|
-
`.crbm
|
|
3298
|
+
`.crbm index entry ${i} has a payload length ${len} invalid (most is ${maxPayloadBytes})`
|
|
3302
3299
|
);
|
|
3303
3300
|
}
|
|
3304
3301
|
if (card < 1 || card > MAX_CHUNK_CARDINALITY) {
|
|
3305
|
-
throw crbmIntegrity(`.crbm
|
|
3302
|
+
throw crbmIntegrity(`.crbm index entry ${i} has a cardinality ${card} invalid`);
|
|
3306
3303
|
}
|
|
3307
3304
|
if (offset + len > payloadEnd) {
|
|
3308
|
-
throw crbmIntegrity(`.crbm
|
|
3305
|
+
throw crbmIntegrity(`.crbm index entry ${i} has a payload out of bounds`);
|
|
3309
3306
|
}
|
|
3310
3307
|
keys[count] = chunkKey;
|
|
3311
3308
|
cardinalityMinusOne[count] = card - 1;
|
|
@@ -5070,11 +5067,11 @@ var PinnedStorageChunkSource = class {
|
|
|
5070
5067
|
constructor(inner, pins) {
|
|
5071
5068
|
this.inner = inner;
|
|
5072
5069
|
this.pins = pins;
|
|
5073
|
-
for (const [
|
|
5070
|
+
for (const [pinKey, pin] of pins) {
|
|
5074
5071
|
const held = pin;
|
|
5075
5072
|
if (held.generation !== null && (typeof held.version !== "string" || typeof held.fingerprint !== "string"))
|
|
5076
5073
|
throw new ValidationError(
|
|
5077
|
-
`pin for "${
|
|
5074
|
+
`pin for "${pinKey}" names generation ${held.generation} without its version and object fingerprint`
|
|
5078
5075
|
);
|
|
5079
5076
|
}
|
|
5080
5077
|
}
|
|
@@ -5275,14 +5272,15 @@ function plainView(bytes, what) {
|
|
|
5275
5272
|
}
|
|
5276
5273
|
return length === 0 ? new Uint8Array(0) : new Uint8Array(buffer, offset, length);
|
|
5277
5274
|
}
|
|
5278
|
-
var
|
|
5275
|
+
var plainByteLength = Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, "byteLength")?.get;
|
|
5276
|
+
var hasSharedMemory = typeof SharedArrayBuffer === "function";
|
|
5279
5277
|
function isShared(buffer) {
|
|
5280
|
-
if (
|
|
5278
|
+
if (!hasSharedMemory) return false;
|
|
5281
5279
|
try {
|
|
5282
|
-
|
|
5283
|
-
return true;
|
|
5284
|
-
} catch {
|
|
5280
|
+
plainByteLength.call(buffer);
|
|
5285
5281
|
return false;
|
|
5282
|
+
} catch {
|
|
5283
|
+
return true;
|
|
5286
5284
|
}
|
|
5287
5285
|
}
|
|
5288
5286
|
function overCap(what, length) {
|
|
@@ -5323,11 +5321,22 @@ function prepareLoadInput(input, codec) {
|
|
|
5323
5321
|
`a load takes ids (an iterable of integers), { serialized } or { bitmap }, as the only key; got an object with keys [${keys.join(", ")}]. Load options go in the next argument.`
|
|
5324
5322
|
);
|
|
5325
5323
|
}
|
|
5326
|
-
function decodeSerialized(bytes, codec, what = "the buffer") {
|
|
5324
|
+
function decodeSerialized(bytes, codec, what = "the buffer", options = {}) {
|
|
5327
5325
|
if (typeof bytes !== "object" || bytes === null || tagOf(bytes) !== "Uint8Array") {
|
|
5328
5326
|
throw new ValidationError(`${what} must be a Uint8Array of portable Roaring bytes`);
|
|
5329
5327
|
}
|
|
5330
5328
|
const view = plainView(bytes, what);
|
|
5329
|
+
if (view.byteLength === 0 && options.refuseEmpty === true) {
|
|
5330
|
+
throw new ValidationError(
|
|
5331
|
+
`${what} is empty or detached: an empty buffer is not a bitmap, and an empty bitmap is built without bytes`
|
|
5332
|
+
);
|
|
5333
|
+
}
|
|
5334
|
+
const { maxBytes } = options;
|
|
5335
|
+
if (maxBytes !== void 0 && maxBytes < MAX_SERIALIZED_LOAD_BYTES && view.byteLength > maxBytes) {
|
|
5336
|
+
throw new ValidationError(
|
|
5337
|
+
`${what} is ${view.byteLength} bytes, more than the ${maxBytes} this call allows (maxBytes)`
|
|
5338
|
+
);
|
|
5339
|
+
}
|
|
5331
5340
|
if (view.byteLength > MAX_SERIALIZED_LOAD_BYTES) throw overCap(what, view.byteLength);
|
|
5332
5341
|
const own = isShared(view.buffer) ? new Uint8Array(view) : view;
|
|
5333
5342
|
try {
|
|
@@ -5465,12 +5474,10 @@ var CrbmWriter = class {
|
|
|
5465
5474
|
async addChunk(chunkKey, payload, cardinality) {
|
|
5466
5475
|
if (this.finished) throw new ValidationError("CrbmWriter already finished");
|
|
5467
5476
|
if (!Number.isInteger(chunkKey) || chunkKey < 0 || chunkKey > 65535) {
|
|
5468
|
-
throw new ValidationError(
|
|
5477
|
+
throw new ValidationError("chunkKey must be a u16");
|
|
5469
5478
|
}
|
|
5470
5479
|
if (chunkKey <= this.lastKey) {
|
|
5471
|
-
throw new ValidationError(
|
|
5472
|
-
`chunkKey ${chunkKey} not strictly ascending (last ${this.lastKey})`
|
|
5473
|
-
);
|
|
5480
|
+
throw new ValidationError("chunkKey is not strictly ascending");
|
|
5474
5481
|
}
|
|
5475
5482
|
if (!Number.isInteger(cardinality) || cardinality < 1 || cardinality > MAX_CHUNK_CARDINALITY) {
|
|
5476
5483
|
throw new ValidationError(
|
|
@@ -6280,7 +6287,7 @@ async function collectChunks(input, codec, clock) {
|
|
|
6280
6287
|
throw new ValidationError("a chunk's key must be an integer in [0, 65535]");
|
|
6281
6288
|
}
|
|
6282
6289
|
if (chunkKey <= last) {
|
|
6283
|
-
throw new ValidationError(
|
|
6290
|
+
throw new ValidationError("a chunk's key does not ascend past the previous chunk's");
|
|
6284
6291
|
}
|
|
6285
6292
|
last = chunkKey;
|
|
6286
6293
|
const max = bitmap.maximum?.();
|
|
@@ -8671,7 +8678,7 @@ var Run = class {
|
|
|
8671
8678
|
failOperand(
|
|
8672
8679
|
c,
|
|
8673
8680
|
new IntegrityError(
|
|
8674
|
-
`operand "${c.op.spec.name}" lists chunk
|
|
8681
|
+
`operand "${c.op.spec.name}" lists a chunk its generation holds no bytes for`
|
|
8675
8682
|
),
|
|
8676
8683
|
victims ?? wanting(c)
|
|
8677
8684
|
);
|
|
@@ -8680,13 +8687,10 @@ var Run = class {
|
|
|
8680
8687
|
try {
|
|
8681
8688
|
const resident = residentBytes(bytes.length);
|
|
8682
8689
|
if (!this.ledger.reserve(resident, makeRoom)) {
|
|
8683
|
-
throw this.refuse(resident, `operand "${c.op.spec.name}" at
|
|
8690
|
+
throw this.refuse(resident, `operand "${c.op.spec.name}" at one of its chunks`);
|
|
8684
8691
|
}
|
|
8685
8692
|
held += resident;
|
|
8686
|
-
decoded.set(
|
|
8687
|
-
c.op.index,
|
|
8688
|
-
decodeChunkBytes(this.codec, bytes, key, this.maxBitmapBytes)
|
|
8689
|
-
);
|
|
8693
|
+
decoded.set(c.op.index, decodeChunkBytes(this.codec, bytes, this.maxBitmapBytes));
|
|
8690
8694
|
} catch (error) {
|
|
8691
8695
|
failOperand(c, error, victims ?? wanting(c));
|
|
8692
8696
|
}
|
|
@@ -9593,7 +9597,7 @@ async function holds(c, generation) {
|
|
|
9593
9597
|
}
|
|
9594
9598
|
throw err;
|
|
9595
9599
|
}
|
|
9596
|
-
return bytes !== null && codec
|
|
9600
|
+
return bytes !== null && decodeChunkBytes(codec, bytes, maxBytes).has(remainder);
|
|
9597
9601
|
} catch (err) {
|
|
9598
9602
|
if (isNotFoundError(err)) return null;
|
|
9599
9603
|
throw err;
|
|
@@ -10004,8 +10008,7 @@ async function stage(c) {
|
|
|
10004
10008
|
c.fromFingerprint = reader.fingerprint;
|
|
10005
10009
|
const bytes = await read(() => reader.getChunk(chunkKey));
|
|
10006
10010
|
if (bytes === null) return await notInCurrent(c);
|
|
10007
|
-
const target = codec
|
|
10008
|
-
assertRemaindersInRange(target, chunkKey);
|
|
10011
|
+
const target = decodeChunkBytes(codec, bytes, maxBytes);
|
|
10009
10012
|
if (!target.has(remainder)) return await notInCurrent(c);
|
|
10010
10013
|
target.remove(remainder);
|
|
10011
10014
|
assertRegistryCanWrite(deps.registry, "eraseIdFromSegment");
|
|
@@ -10291,26 +10294,17 @@ async function* rewrite(reader, chunkKey, replacement, codec, maxBytes, read) {
|
|
|
10291
10294
|
}
|
|
10292
10295
|
const item = await stream.next();
|
|
10293
10296
|
if (item.done === true || item.value.key !== k) {
|
|
10294
|
-
throw new IntegrityError(
|
|
10297
|
+
throw new IntegrityError("the chunk stream ended before a chunk the rewrite needs");
|
|
10295
10298
|
}
|
|
10296
10299
|
const bytes = item.value.bytes;
|
|
10297
10300
|
if (bytes === null) continue;
|
|
10298
|
-
const bitmap = codec
|
|
10299
|
-
assertRemaindersInRange(bitmap, k);
|
|
10301
|
+
const bitmap = decodeChunkBytes(codec, bytes, maxBytes);
|
|
10300
10302
|
yield { chunkKey: k, bitmap };
|
|
10301
10303
|
}
|
|
10302
10304
|
} finally {
|
|
10303
10305
|
await stream.return(void 0);
|
|
10304
10306
|
}
|
|
10305
10307
|
}
|
|
10306
|
-
function assertRemaindersInRange(bitmap, chunkKey) {
|
|
10307
|
-
const max = bitmap.maximum?.();
|
|
10308
|
-
if (max !== void 0 && max > MAX_REMAINDER) {
|
|
10309
|
-
throw new IntegrityError(
|
|
10310
|
-
`chunk ${chunkKey} payload holds value ${max}, outside the 16-bit remainder range [0, ${MAX_REMAINDER}] \u2014 the stored object is corrupt or was not written by this codec; refusing to carry it into a new generation`
|
|
10311
|
-
);
|
|
10312
|
-
}
|
|
10313
|
-
}
|
|
10314
10308
|
|
|
10315
10309
|
// src/core/cas-retry.ts
|
|
10316
10310
|
async function casRetry(deps, ref, plan, step) {
|
|
@@ -12104,6 +12098,7 @@ export {
|
|
|
12104
12098
|
LeaseLimitError,
|
|
12105
12099
|
MAX_LEASES_PER_SEGMENT,
|
|
12106
12100
|
MAX_LEASE_MS,
|
|
12101
|
+
MAX_SERIALIZED_LOAD_BYTES,
|
|
12107
12102
|
MIN_EXPIRES_AT_MS,
|
|
12108
12103
|
NOOP_METRICS,
|
|
12109
12104
|
NotFoundError,
|
|
@@ -12139,6 +12134,7 @@ export {
|
|
|
12139
12134
|
mapWithConcurrency,
|
|
12140
12135
|
readRetentionPolicy,
|
|
12141
12136
|
rebindCombineMany,
|
|
12137
|
+
refusalOfId,
|
|
12142
12138
|
refuseUnknownRefKeys,
|
|
12143
12139
|
releaseLease,
|
|
12144
12140
|
resolveBudget,
|