@cloudbitmaps/core 0.20.0 → 0.22.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 +101 -5
- package/dist/{chunk-YSC7NJWV.js → chunk-OSU7W2Y3.js} +811 -164
- package/dist/chunk-OSU7W2Y3.js.map +7 -0
- package/dist/core/audit.d.ts +12 -2
- package/dist/core/bit-route.d.ts +9 -1
- package/dist/core/blob.d.ts +12 -1
- package/dist/core/codec.d.ts +1 -1
- package/dist/core/combine-expr.d.ts +10 -8
- package/dist/core/combine-feed.d.ts +12 -18
- package/dist/core/combine-many.d.ts +29 -22
- package/dist/core/concurrency.d.ts +8 -0
- package/dist/core/consistency.d.ts +69 -17
- package/dist/core/crbm/reader.d.ts +52 -6
- package/dist/core/crbm-storage-source.d.ts +65 -452
- package/dist/core/crypto.d.ts +6 -1
- package/dist/core/determinism.d.ts +2 -1
- package/dist/core/engine.d.ts +222 -33
- package/dist/core/erase-id.d.ts +60 -15
- package/dist/core/erasure.d.ts +5 -4
- package/dist/core/errors.d.ts +61 -11
- package/dist/core/leases.d.ts +4 -3
- package/dist/core/load.d.ts +58 -45
- package/dist/core/lru.d.ts +2 -15
- package/dist/core/metrics.d.ts +5 -3
- package/dist/core/pinned-storage-source.d.ts +4 -4
- package/dist/core/ports.d.ts +96 -22
- package/dist/core/registry-scan.d.ts +0 -7
- package/dist/core/retention-sweep.d.ts +70 -66
- package/dist/core/retention.d.ts +2 -2
- package/dist/core/retry.d.ts +15 -18
- package/dist/core/rollback.d.ts +61 -31
- package/dist/core/validate.d.ts +2 -0
- package/dist/driver-kit.d.ts +11 -2
- package/dist/driver-kit.js +84 -16
- package/dist/driver-kit.js.map +3 -3
- package/dist/drivers/_shared/bytes.d.ts +6 -0
- package/dist/drivers/_shared/faults.d.ts +15 -0
- package/dist/drivers/_shared/object-keys.d.ts +18 -0
- package/dist/drivers/_shared/object-registry-keys.d.ts +0 -2
- package/dist/drivers/_shared/object-registry.d.ts +2 -0
- package/dist/drivers/_shared/options.d.ts +19 -0
- package/dist/drivers/backends.d.ts +2 -0
- package/dist/drivers/crypto.d.ts +1 -1
- package/dist/export/index.d.ts +9 -8
- package/dist/index.d.ts +11 -10
- package/dist/index.js +4202 -2833
- package/dist/index.js.map +4 -4
- package/package.json +7 -2
- package/dist/chunk-YSC7NJWV.js.map +0 -7
- package/dist/core/chunk-checks.d.ts +0 -34
- package/dist/core/chunk-stream.d.ts +0 -22
- package/dist/core/chunk-window.d.ts +0 -30
- package/dist/core/combine-ledger.d.ts +0 -43
- package/dist/core/crbm/crc32c.d.ts +0 -10
- package/dist/core/crbm/fingerprint.d.ts +0 -18
- package/dist/core/crbm/format.d.ts +0 -151
- package/dist/core/crbm/frame.d.ts +0 -10
- package/dist/core/crbm/plan-reads.d.ts +0 -44
- package/dist/core/crbm/varint.d.ts +0 -13
- package/dist/core/crbm/writer.d.ts +0 -68
- package/dist/core/due-index.d.ts +0 -53
- package/dist/core/generation-gc.d.ts +0 -179
- package/dist/core/item-pull.d.ts +0 -29
- package/dist/core/kept-generations.d.ts +0 -40
- package/dist/core/metadata.d.ts +0 -42
- package/dist/core/reader-defaults.d.ts +0 -29
- package/dist/core/summary.d.ts +0 -78
- package/dist/core/token.d.ts +0 -41
- package/dist/drivers/_shared/entropy.d.ts +0 -5
- package/dist/drivers/_shared/registry.d.ts +0 -104
- package/dist/drivers/localfs/exact-case.d.ts +0 -37
- package/dist/drivers/localfs/fs-util.d.ts +0 -33
- package/dist/drivers/localfs/paths.d.ts +0 -40
- package/dist/drivers/localfs/registry.d.ts +0 -44
- package/dist/drivers/localfs/storage.d.ts +0 -21
- package/dist/drivers/memory.d.ts +0 -61
- package/dist/testing/fuzz-core.d.ts +0 -15
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* An ordered window of reads: up to `max` reads open ahead of the one being consumed, handed back in key order.
|
|
3
|
-
* With `ramp`, the window opens 1, 2, 4 … wide (or at `rampStart`, then doubling) up to `max` instead of `max` at once, so a consumer that stops
|
|
4
|
-
* after a few chunks has fetched a handful, not a full window.
|
|
5
|
-
*
|
|
6
|
-
* `T` is whatever one read yields (a decoded chunk, or the raw bytes of one). Each read is wrapped to resolve and
|
|
7
|
-
* never reject, so a read nobody consumes (the consumer stopped, or an earlier chunk failed) cannot raise an
|
|
8
|
-
* unhandled rejection; its error surfaces from {@link take} only if the consumer reaches that chunk. Memory is
|
|
9
|
-
* bounded by the window: at most `max` results are held ahead.
|
|
10
|
-
*
|
|
11
|
-
* Internal to core: not exported from any entry point.
|
|
12
|
-
*/
|
|
13
|
-
export declare class ChunkWindow<T> {
|
|
14
|
-
private readonly keys;
|
|
15
|
-
private readonly fetch;
|
|
16
|
-
private readonly max;
|
|
17
|
-
private readonly ramp;
|
|
18
|
-
/** With `ramp`, the width the window opens at (default 1). */
|
|
19
|
-
private readonly rampStart;
|
|
20
|
-
private readonly open;
|
|
21
|
-
private launched;
|
|
22
|
-
private taken;
|
|
23
|
-
constructor(keys: readonly number[], fetch: (chunkKey: number) => Promise<T>, max: number, ramp: boolean,
|
|
24
|
-
/** With `ramp`, the width the window opens at (default 1). */
|
|
25
|
-
rampStart?: number);
|
|
26
|
-
/** Resolves once every read launched and not yet taken has settled; it never rejects, as the reads never do. */
|
|
27
|
-
settle(): Promise<void>;
|
|
28
|
-
/** The next read's result in key order, or the error that read raised. */
|
|
29
|
-
take(): Promise<T>;
|
|
30
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The resident-bytes ledger of a batch combine. Pure: no I/O, time or randomness.
|
|
3
|
-
*
|
|
4
|
-
* It counts what is **resident**, not what a bitmap serializes to: a native bitmap costs a fixed amount over its
|
|
5
|
-
* serialized bytes, so a million small chunks hold far more than their serialized size says. Measured on the shipped
|
|
6
|
-
* codec with one bitmap per chunk, the cost over serialized size was about 440 bytes for a chunk of up to 50 ids,
|
|
7
|
-
* rising to about 1,700 bytes around 3,000 ids (an array container's spare capacity) and falling to about 300 bytes for
|
|
8
|
-
* a bitset. {@link residentBytes} is a model that stays above every measured point.
|
|
9
|
-
*/
|
|
10
|
-
/**
|
|
11
|
-
* The fixed resident cost of one native bitmap beyond its serialized bytes. Measured on the shipped codec, over 50,000
|
|
12
|
-
* bitmaps of one chunk each, it was 430 to 450 bytes for a chunk of up to 50 ids on macOS (arm64) and 357 to 373 on Linux
|
|
13
|
-
* (arm64, glibc 2.36), and 279 to 433 for a bitset; the constant sits above the highest of those.
|
|
14
|
-
*/
|
|
15
|
-
export declare const RESIDENT_BITMAP_OVERHEAD = 512;
|
|
16
|
-
/** An upper bound on the serialized size of a chunk of `cardinality` ids: an array container, capped at a bitset. */
|
|
17
|
-
export declare function serializedBound(cardinality: number): number;
|
|
18
|
-
/** The resident bytes of one bitmap whose serialized size is `serialized`: above every measured point. */
|
|
19
|
-
export declare function residentBytes(serialized: number): number;
|
|
20
|
-
/** The resident bytes of one chunk of at most `cardinality` ids. */
|
|
21
|
-
export declare function residentBound(cardinality: number): number;
|
|
22
|
-
/**
|
|
23
|
-
* A byte budget with a high-water mark. Everything the pass keeps resident is charged to it and released when it is
|
|
24
|
-
* let go, so `used` is the pass's own count of what it holds, and `maxBufferedBytes` is a bound on it.
|
|
25
|
-
*/
|
|
26
|
-
export declare class ResidentLedger {
|
|
27
|
-
readonly limit: number;
|
|
28
|
-
private held;
|
|
29
|
-
private peak;
|
|
30
|
-
constructor(limit: number);
|
|
31
|
-
get used(): number;
|
|
32
|
-
get highWater(): number;
|
|
33
|
-
/** Bytes still free. */
|
|
34
|
-
get room(): number;
|
|
35
|
-
/** Charge `bytes` if they fit. */
|
|
36
|
-
tryCharge(bytes: number): boolean;
|
|
37
|
-
/**
|
|
38
|
-
* Charge `bytes`, asking `makeRoom` to free some while they do not fit. `makeRoom` releases what it frees (through
|
|
39
|
-
* {@link release}) and answers whether it freed anything; the charge is refused when it cannot.
|
|
40
|
-
*/
|
|
41
|
-
reserve(bytes: number, makeRoom: () => boolean): boolean;
|
|
42
|
-
release(bytes: number): void;
|
|
43
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CRC32C (Castagnoli, polynomial 0x1EDC6F41) — the pre-deserialize integrity screen for `.crbm`
|
|
3
|
-
* payloads, index, and footer.
|
|
4
|
-
*
|
|
5
|
-
* Pure TypeScript, table-driven: `core/` may not import `crypto`/`node:crypto` (the determinism lint
|
|
6
|
-
* enforces it), and a from-scratch implementation is what the cross-language golden corpus will be pinned
|
|
7
|
-
* against. CRC32C (not CRC32) is the locked choice — it matches the hardware-accelerated checksum used
|
|
8
|
-
* by SSE/iSCSI/Btrfs, and it is the algorithm the `.crbm` format locks in.
|
|
9
|
-
*/
|
|
10
|
-
export declare function crc32c(bytes: Uint8Array, seed?: number): number;
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/** What names an object: its size, then its footer's CRC. One spelling, for an open reader and a footer read alone. */
|
|
2
|
-
export declare const sizePart: (size: number) => string;
|
|
3
|
-
/** An object's fingerprint, from its size and its footer's CRC (see `CrbmReader.fingerprint`). */
|
|
4
|
-
export declare const fingerprintFor: (size: number, footerCrc: number) => string;
|
|
5
|
-
/**
|
|
6
|
-
* A fingerprint taken apart, or `undefined` for text that is not one an object can have: a size that is a safe integer
|
|
7
|
-
* no smaller than a `.crbm` preamble and footer, and a footer CRC that fits in 32 bits. For a row's summary, which
|
|
8
|
-
* names its object by it and reports the size from it.
|
|
9
|
-
*/
|
|
10
|
-
export declare function fingerprintParts(fingerprint: unknown): {
|
|
11
|
-
readonly size: number;
|
|
12
|
-
readonly footerCrc: number;
|
|
13
|
-
} | undefined;
|
|
14
|
-
/**
|
|
15
|
-
* A fingerprint spelled short, for a key a read builds on every chunk: its size and its footer's CRC in base 36,
|
|
16
|
-
* `<size>.<crc>`. Two compact spellings are equal exactly when the fingerprints are.
|
|
17
|
-
*/
|
|
18
|
-
export declare function compactFingerprint(fingerprint: string): string;
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Frozen `.crbm` v1 layout constants (format 1.0, with its optional extension block).
|
|
3
|
-
*
|
|
4
|
-
* These byte widths/offsets are pinned by the golden corpus and must never change for v1 —
|
|
5
|
-
* a new layout is a new format version. All multi-byte integers are little-endian (v1 fixes LE).
|
|
6
|
-
*/
|
|
7
|
-
import { FOOTER_BYTES, PREAMBLE_BYTES } from './frame.js';
|
|
8
|
-
/** 4-byte magic at both file ends: "CRBM". */
|
|
9
|
-
export declare const MAGIC: Uint8Array<ArrayBuffer>;
|
|
10
|
-
export declare const VERSION_MAJOR = 1;
|
|
11
|
-
export declare const VERSION_MINOR = 0;
|
|
12
|
-
export { FOOTER_BYTES, PREAMBLE_BYTES };
|
|
13
|
-
/** Payloads begin immediately after the preamble. */
|
|
14
|
-
export declare const PAYLOAD_START = 8;
|
|
15
|
-
/** Byte offsets of each field within the 104-byte footer. */
|
|
16
|
-
export declare const FOOTER: {
|
|
17
|
-
readonly indexOffset: 0;
|
|
18
|
-
readonly indexLength: 8;
|
|
19
|
-
readonly indexCrc32c: 16;
|
|
20
|
-
readonly flags: 20;
|
|
21
|
-
readonly payloadCodecId: 24;
|
|
22
|
-
readonly elementWidth: 26;
|
|
23
|
-
readonly containerCodec: 27;
|
|
24
|
-
readonly versionMajor: 28;
|
|
25
|
-
readonly versionMinor: 29;
|
|
26
|
-
readonly reserved2: 30;
|
|
27
|
-
readonly generation: 32;
|
|
28
|
-
readonly indexNonce: 40;
|
|
29
|
-
readonly indexTag: 52;
|
|
30
|
-
readonly keyId: 68;
|
|
31
|
-
readonly chunkCount: 84;
|
|
32
|
-
readonly totalCardinality: 88;
|
|
33
|
-
readonly footerCrc32c: 96;
|
|
34
|
-
readonly endMagic: 100;
|
|
35
|
-
};
|
|
36
|
-
/** Footer bytes covered by `footer_crc32c` (everything before the CRC field). */
|
|
37
|
-
export declare const FOOTER_CRC_COVERAGE: 96;
|
|
38
|
-
/** `flags` bit positions. */
|
|
39
|
-
export declare const FLAG_ENCRYPTED: number;
|
|
40
|
-
export declare const FLAG_INDEX_COMPRESSED: number;
|
|
41
|
-
export declare const FLAG_LITTLE_ENDIAN: number;
|
|
42
|
-
/**
|
|
43
|
-
* The object carries an extension block just before its index (a generation's metadata). Set only when there is
|
|
44
|
-
* something to put in it, so an object without metadata is the same bytes as before the block existed; a reader that
|
|
45
|
-
* does not know the bit refuses the object rather than reading past what it cannot see.
|
|
46
|
-
*/
|
|
47
|
-
export declare const FLAG_EXTENSION: number;
|
|
48
|
-
/** Flag bits a v1 reader understands; any bit outside this mask is an unsupported feature. */
|
|
49
|
-
export declare const KNOWN_FLAGS: number;
|
|
50
|
-
/**
|
|
51
|
-
* Default element width: 32-bit ids (the u32 member space). `64` is the *reserved* escape above the
|
|
52
|
-
* ~4.29 B-ids/segment u32 ceiling; a v1 (32-bit) reader must **reject** a 64-bit generation rather than feed
|
|
53
|
-
* it to the 32-bit deserializer (which would mis-count fleet-wide). A future 64-bit generation is therefore a
|
|
54
|
-
* **major**-version bump (auto-rejected by old readers), never a silent minor one — see
|
|
55
|
-
* {@link CrbmReader.open} validates this.
|
|
56
|
-
*/
|
|
57
|
-
export declare const ELEMENT_WIDTH_32 = 32;
|
|
58
|
-
/**
|
|
59
|
-
* **Which codec produced the chunk payloads.** Recorded in the footer, validated on read.
|
|
60
|
-
*
|
|
61
|
-
* `.crbm` is a shared container: the index, the CRC32Cs, the AEAD framing and the generation model are all
|
|
62
|
-
* codec-independent, and **only the chunk payload bytes belong to a flavor** (hence *Chunked Remote BitMap* —
|
|
63
|
-
* see the `.crbm` format section of the API reference). This field is what lets one container hold either, the same way ZIP tags each member
|
|
64
|
-
* with a compression method.
|
|
65
|
-
*
|
|
66
|
-
* **A codec id, not a roaring-specific one.** A second codec is genuinely expected — `soaring` is a planned
|
|
67
|
-
* Roaring *variant*, so its serialized bytes are unlikely to be roaring-portable, and it lands *after* the `1.0`
|
|
68
|
-
* format freeze. A field frozen under a codec-specific meaning could not be reinterpreted later without a major
|
|
69
|
-
* format version.
|
|
70
|
-
*
|
|
71
|
-
* **Ids are permanent once published.** Add to {@link KNOWN_PAYLOAD_CODEC_IDS} when a codec ships; never
|
|
72
|
-
* reuse or renumber. Ids are deliberately *not* pre-allocated for codecs that do not exist — a reserved number
|
|
73
|
-
* for an unbuilt codec is a guess about a format nobody has designed.
|
|
74
|
-
*/
|
|
75
|
-
export declare const PAYLOAD_CODEC_ROARING_PORTABLE = 1;
|
|
76
|
-
/**
|
|
77
|
-
* Every payload codec id this reader can decode.
|
|
78
|
-
*
|
|
79
|
-
* The reader validates membership rather than equality with a single constant. That is the whole point of an
|
|
80
|
-
* id registry: an unknown id is rejected with a typed error naming it, so an old reader meeting a
|
|
81
|
-
* future-codec generation **fails closed** — the correct direction, and the reason a store built on one codec
|
|
82
|
-
* can never silently misread another's bytes as its own. (The homogeneity contract means one store is one
|
|
83
|
-
* codec, so meeting a foreign generation implies misconfiguration, and a loud rejection is exactly what you
|
|
84
|
-
* want there.)
|
|
85
|
-
*/
|
|
86
|
-
export declare const KNOWN_PAYLOAD_CODEC_IDS: ReadonlySet<number>;
|
|
87
|
-
/**
|
|
88
|
-
* The only container codec v1 defines: `0` = none (payloads are stored as the portable roaring serialization
|
|
89
|
-
* with no extra container-level transform). A non-zero codec is a future format feature; a v1 reader rejects
|
|
90
|
-
* it ({@link UnsupportedError}) rather than mis-decode. Stamped by the writer, validated by the reader.
|
|
91
|
-
*/
|
|
92
|
-
export declare const CONTAINER_CODEC_NONE = 0;
|
|
93
|
-
/**
|
|
94
|
-
* Default speculative-tail-read size. The spec's worst-case index (a full 16-bit span) is ~400–650 KB,
|
|
95
|
-
* so 256 KB collapses the read to a single GET for the vast majority of real (sparse/medium) segments;
|
|
96
|
-
* only near-full-span segments take the documented second GET.
|
|
97
|
-
*/
|
|
98
|
-
export declare const DEFAULT_TAIL_BYTES: number;
|
|
99
|
-
/**
|
|
100
|
-
* Hard cap on the index region a reader will fetch/parse from one (untrusted) object. The index is read
|
|
101
|
-
* whole on the cheap `open()`/`count()` path, so it must be bounded before allocation — generously
|
|
102
|
-
* above the ~650 KB full-span worst case, well below a denial-of-wallet allocation.
|
|
103
|
-
*/
|
|
104
|
-
export declare const DEFAULT_MAX_INDEX_BYTES: number;
|
|
105
|
-
/**
|
|
106
|
-
* Largest serialized bitmap the engine decodes (1 MiB, per chunk). A well-formed 16-bit chunk serializes to at most
|
|
107
|
-
* about 8.2 KiB, so no legitimate chunk is near it; both the read engine and the erase path decode under this one cap.
|
|
108
|
-
*/
|
|
109
|
-
export declare const DEFAULT_MAX_BITMAP_BYTES: number;
|
|
110
|
-
/** A chunk's cardinality is in `[1, 65536]` (empty chunks are never written). */
|
|
111
|
-
export declare const MAX_CHUNK_CARDINALITY = 65536;
|
|
112
|
-
/**
|
|
113
|
-
* The extension block, present when the footer sets {@link FLAG_EXTENSION}: `section* ‖ u32 sectionsLength ‖ u32
|
|
114
|
-
* crc32c ‖ "CRBX"`, between the last payload and the index, so the index starts right after it. A reader finds it from
|
|
115
|
-
* `indexOffset`: the trailer is the {@link EXT_TRAILER_BYTES} bytes before the index, and the CRC32C covers the sections
|
|
116
|
-
* and the length field. Each section is `u8 type ‖ u32 length ‖ bytes`, in strictly ascending type order; a reader
|
|
117
|
-
* skips a type it does not know, so a section must be safe to ignore.
|
|
118
|
-
*/
|
|
119
|
-
export declare const EXT_MAGIC: Uint8Array<ArrayBuffer>;
|
|
120
|
-
/** The trailer: the sections' length (u32), their CRC32C (u32) and {@link EXT_MAGIC}. */
|
|
121
|
-
export declare const EXT_TRAILER_BYTES = 12;
|
|
122
|
-
/** A section's header: its type (u8) and its length (u32). */
|
|
123
|
-
export declare const EXT_SECTION_HEADER_BYTES = 5;
|
|
124
|
-
/**
|
|
125
|
-
* Cap on the sections of one block, in bytes. A reader refuses a larger block from its trailer alone, before it reads
|
|
126
|
-
* any sections beyond what it already holds (the read that brings the index may already hold up to this much before
|
|
127
|
-
* it), and a writer of any 1.x minor keeps within it, so a later section type stays readable by this reader.
|
|
128
|
-
*/
|
|
129
|
-
export declare const MAX_EXT_BYTES: number;
|
|
130
|
-
/**
|
|
131
|
-
* Section type 1: the generation's metadata, its canonical JSON in UTF-8. On an encrypted object the section is
|
|
132
|
-
* `nonce ‖ ciphertext ‖ tag`, sealed under the segment's key with the metadata scope of the associated data.
|
|
133
|
-
* Type 0 is not a section type: a reader refuses it.
|
|
134
|
-
*/
|
|
135
|
-
export declare const EXT_SECTION_METADATA = 1;
|
|
136
|
-
/** Fixed width of a per-chunk CRC32C field in the index (high-entropy → not varint). */
|
|
137
|
-
export declare const CRC32C_BYTES = 4;
|
|
138
|
-
/**
|
|
139
|
-
* v1 AEAD framing sizes (AES-256-GCM), fixed by the format exactly like the payload codec id — a
|
|
140
|
-
* different cipher is a new format version. An encrypted chunk payload is stored as `nonce ‖ ciphertext ‖ tag`;
|
|
141
|
-
* the encrypted **index**'s nonce/tag live in the footer's reserved `indexNonce`/`indexTag` slots. Matches
|
|
142
|
-
* {@link FOOTER.indexNonce} (12 B) and {@link FOOTER.indexTag} (16 B).
|
|
143
|
-
*/
|
|
144
|
-
export declare const AEAD_NONCE_BYTES = 12;
|
|
145
|
-
export declare const AEAD_TAG_BYTES = 16;
|
|
146
|
-
/**
|
|
147
|
-
* Hard cap on one encrypted chunk's stored payload (a cleartext one is capped at the decode cap): the decode cap plus the AEAD framing, so an
|
|
148
|
-
* entry the engine would refuse to decode is refused when the object is opened, before any payload is read. No writer
|
|
149
|
-
* exceeds it: a stored payload is a serialized 16-bit chunk (at most about 8.2 KiB) plus, when encrypted, that framing.
|
|
150
|
-
*/
|
|
151
|
-
export declare const DEFAULT_MAX_PAYLOAD_BYTES: number;
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The two widths every `.crbm` v1 object is framed by: its front preamble and its footer. Frozen with the rest of the
|
|
3
|
-
* layout in `format.ts`, which re-exports them. They live in a module of their own, with no imports, so that what needs
|
|
4
|
-
* only the smallest size an object can have (the registry's check of a summary's fingerprint) does not bring the
|
|
5
|
-
* format's other constants, or the reader, with it.
|
|
6
|
-
*/
|
|
7
|
-
/** Front preamble: magic(4) + version_major(1) + version_minor(1) + reserved(2). */
|
|
8
|
-
export declare const PREAMBLE_BYTES = 8;
|
|
9
|
-
/** Fixed footer size (v1.0). */
|
|
10
|
-
export declare const FOOTER_BYTES = 104;
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The most unneeded bytes one read may carry between two needed chunks: reading 256 KiB that nothing wants costs
|
|
3
|
-
* a few milliseconds of transfer, while the request it saves costs a round trip.
|
|
4
|
-
*/
|
|
5
|
-
export declare const MAX_COALESCE_GAP_BYTES: number;
|
|
6
|
-
/**
|
|
7
|
-
* The most bytes one read may span, unless it holds a single chunk. It equals the decode cap, so a window of
|
|
8
|
-
* coalesced reads holds the window's width times the per-chunk cap that bounds a window of single-chunk reads.
|
|
9
|
-
*/
|
|
10
|
-
export declare const MAX_COALESCED_READ_BYTES: number;
|
|
11
|
-
/**
|
|
12
|
-
* The default number of range reads a chunk stream holds ahead of its consumer, in flight or landed and not yet taken;
|
|
13
|
-
* the rest of the plan follows as the consumer takes them. A range is at most {@link MAX_COALESCED_READ_BYTES} unless
|
|
14
|
-
* it is one chunk, so a stream holds at most this many times the per-chunk decode cap, whatever the key list and the
|
|
15
|
-
* object: the memory bound a window of single-chunk reads has, and no more connections than it opens.
|
|
16
|
-
*/
|
|
17
|
-
export declare const MAX_RANGES_IN_FLIGHT = 32;
|
|
18
|
-
/** One needed chunk, as its index entry places it in the object. */
|
|
19
|
-
export interface ChunkExtent {
|
|
20
|
-
readonly key: number;
|
|
21
|
-
readonly offset: number;
|
|
22
|
-
readonly length: number;
|
|
23
|
-
}
|
|
24
|
-
/** One byte range to read, and the needed chunks inside it, in object order. */
|
|
25
|
-
export interface PlannedRead {
|
|
26
|
-
readonly offset: number;
|
|
27
|
-
readonly length: number;
|
|
28
|
-
readonly chunks: readonly ChunkExtent[];
|
|
29
|
-
}
|
|
30
|
-
/** The part of an object that holds chunk payloads: `[start, end)`. */
|
|
31
|
-
export interface ChunkRegion {
|
|
32
|
-
readonly start: number;
|
|
33
|
-
readonly end: number;
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Plan the reads for `extents`: the needed chunks of one object, ascending by offset (the index lists chunks in key
|
|
37
|
-
* order, which is object order), each at least a byte long, none overlapping another. The reads come back
|
|
38
|
-
* ascending and disjoint, each covering one or more of the chunks, every chunk in exactly one read.
|
|
39
|
-
*
|
|
40
|
-
* Throws {@link IntegrityError} for an extent that is not a pair of safe integers, or is outside `region`, or out of
|
|
41
|
-
* order, or overlapping the one before it:
|
|
42
|
-
* the index a plan is made from is untrusted bytes, and a read is never planned outside the chunk region.
|
|
43
|
-
*/
|
|
44
|
-
export declare function planChunkReads(extents: readonly ChunkExtent[], region: ChunkRegion): readonly PlannedRead[];
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/** Append the LEB128 encoding of a u32 `value` to `out`. */
|
|
2
|
-
export declare function writeVarint(out: number[], value: number): void;
|
|
3
|
-
export interface VarintRead {
|
|
4
|
-
readonly value: number;
|
|
5
|
-
/** Offset just past the bytes consumed. */
|
|
6
|
-
readonly next: number;
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* Decode a LEB128 varint from `bytes` starting at `offset`. Throws `IntegrityError` on a truncated or
|
|
10
|
-
* over-long (> 5-byte / > u32) encoding — the bytes are untrusted, so a malformed index must fail
|
|
11
|
-
* cleanly, never loop or overflow.
|
|
12
|
-
*/
|
|
13
|
-
export declare function readVarint(bytes: Uint8Array, offset: number): VarintRead;
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import type { CrbmCrypto } from '../crypto.js';
|
|
2
|
-
import type { GenerationMetadata } from '../ports.js';
|
|
3
|
-
import type { BlobSink } from '../blob.js';
|
|
4
|
-
export interface CrbmWriterOptions {
|
|
5
|
-
/** Self-describing generation number (also encoded in the object key). */
|
|
6
|
-
readonly generation: number;
|
|
7
|
-
/**
|
|
8
|
-
* Which codec produced the chunk payloads. Defaults to {@link PAYLOAD_CODEC_ROARING_PORTABLE}.
|
|
9
|
-
*
|
|
10
|
-
* A codec id rather than a roaring-specific one, because `.crbm` is a shared container and a second codec is
|
|
11
|
-
* expected before the format freezes.
|
|
12
|
-
*/
|
|
13
|
-
readonly payloadCodecId?: number;
|
|
14
|
-
readonly elementWidth?: number;
|
|
15
|
-
/** When set, payloads + index are AES-256-GCM-encrypted, bound to `(segment, generation, scope)` via AAD. */
|
|
16
|
-
readonly crypto?: CrbmCrypto;
|
|
17
|
-
/**
|
|
18
|
-
* The generation's metadata, checked against the metadata rules and copied as its canonical JSON when the writer
|
|
19
|
-
* is constructed, so a later change to the caller's object never reaches the object. A value that breaks a rule
|
|
20
|
-
* throws {@link ValidationError} from the constructor, before a byte is written. None, or the empty object, writes
|
|
21
|
-
* format 1.0.
|
|
22
|
-
*/
|
|
23
|
-
readonly metadata?: GenerationMetadata;
|
|
24
|
-
}
|
|
25
|
-
export declare class CrbmWriter {
|
|
26
|
-
private readonly sink;
|
|
27
|
-
private readonly options;
|
|
28
|
-
private readonly entries;
|
|
29
|
-
private offset;
|
|
30
|
-
private lastKey;
|
|
31
|
-
private totalCardinality;
|
|
32
|
-
private preambleWritten;
|
|
33
|
-
private finished;
|
|
34
|
-
/** The metadata's canonical JSON, copied at construction; `undefined` leaves the footer's extension flag clear. */
|
|
35
|
-
private readonly metadata;
|
|
36
|
-
/** Bytes written so far, the footer included once {@link finish} has run. */
|
|
37
|
-
private written;
|
|
38
|
-
private footerCrc32c;
|
|
39
|
-
constructor(sink: BlobSink, options: CrbmWriterOptions);
|
|
40
|
-
/**
|
|
41
|
-
* Append one chunk's payload (the roaring-serialized bytes) with its cardinality. `chunkKey` must be
|
|
42
|
-
* strictly greater than the previous one (ascending, no duplicates); `cardinality` is `[1, 65536]`.
|
|
43
|
-
*/
|
|
44
|
-
addChunk(chunkKey: number, payload: Uint8Array, cardinality: number): Promise<void>;
|
|
45
|
-
/**
|
|
46
|
-
* Write the extension block (when there is metadata), the index region and the fixed footer. After this the object
|
|
47
|
-
* is complete and immutable.
|
|
48
|
-
*/
|
|
49
|
-
finish(): Promise<void>;
|
|
50
|
-
/**
|
|
51
|
-
* The finished object's size and its footer's CRC: what names it, as a reader's fingerprint does. A writer that
|
|
52
|
-
* has to tell its own object from another stored later under the same key compares these with the object's
|
|
53
|
-
* footer. Throws before {@link finish}.
|
|
54
|
-
*/
|
|
55
|
-
get identity(): {
|
|
56
|
-
readonly size: number;
|
|
57
|
-
readonly footerCrc: number;
|
|
58
|
-
};
|
|
59
|
-
private ensurePreamble;
|
|
60
|
-
/**
|
|
61
|
-
* The extension block: one metadata section (`u8 type ‖ u32 length ‖ bytes`), then the trailer
|
|
62
|
-
* (`u32 sectionsLength ‖ u32 crc32c(sections ‖ sectionsLength) ‖ "CRBX"`). Encrypted, the section holds
|
|
63
|
-
* `nonce ‖ ciphertext ‖ tag`, sealed with the metadata scope of the associated data.
|
|
64
|
-
*/
|
|
65
|
-
private extensionBlock;
|
|
66
|
-
private encodeIndex;
|
|
67
|
-
private buildFooter;
|
|
68
|
-
}
|
package/dist/core/due-index.d.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { MAX_NAME_LENGTH } from './validate.js';
|
|
2
|
-
import type { RegistryRecord, SegmentRef } from './ports.js';
|
|
3
|
-
/** Bucket width. One day: small enough that a cycle reads little, coarse enough that the index stays tiny. */
|
|
4
|
-
export declare const DUE_BUCKET_MS = 86400000;
|
|
5
|
-
/**
|
|
6
|
-
* The name-length cap, and an index row encodes **both** of the original ref's parts into one name — so a ref
|
|
7
|
-
* whose encoding would exceed it is simply not indexed (see {@link canIndex}).
|
|
8
|
-
*
|
|
9
|
-
* Re-exported from the validator rather than restated. The two were separate constants with the same value
|
|
10
|
-
* until the validator started measuring the **encoded** length; `canIndex` went on counting raw characters and
|
|
11
|
-
* began answering `true` for refs the registry then refused, turning a documented graceful degradation into a
|
|
12
|
-
* guaranteed throw on the retention fast path.
|
|
13
|
-
*/
|
|
14
|
-
export { MAX_NAME_LENGTH };
|
|
15
|
-
/** Which bucket an expiry falls in. Total and reversible; no calendar, no timezone, no ambient time. */
|
|
16
|
-
export declare function dueBucket(expiresAt: number): number;
|
|
17
|
-
/** The namespace holding one bucket's pointers. */
|
|
18
|
-
export declare function dueNamespace(bucket: number): string;
|
|
19
|
-
/** Is this record a due-index pointer rather than a segment? */
|
|
20
|
-
export declare function isDueIndexRow(record: Pick<RegistryRecord, 'namespace'>): boolean;
|
|
21
|
-
/**
|
|
22
|
-
* Encode a ref into one index-row name, unambiguously.
|
|
23
|
-
*
|
|
24
|
-
* `${namespaceLength}.${namespace}${segment}` — a decimal length, a dot, then the two parts concatenated. The
|
|
25
|
-
* length prefix is what makes it reversible: a name may contain any character, the dot included, so no
|
|
26
|
-
* separator character could ever be unambiguous on its own. Reading the digits
|
|
27
|
-
* up to the first dot tells the parser exactly where the namespace ends.
|
|
28
|
-
*/
|
|
29
|
-
export declare function encodeDueName(ref: SegmentRef): string;
|
|
30
|
-
/**
|
|
31
|
-
* Can this ref be indexed at all? False when the encoded name would exceed the 256-character name cap —
|
|
32
|
-
* possible only for a ref whose namespace and segment are together near the limit.
|
|
33
|
-
*
|
|
34
|
-
* **Not indexable is not "not retired".** The repair scan still sees the segment's own row, so the consequence
|
|
35
|
-
* is that it expires on the repair cadence instead of the fast one. Callers must not treat `false` as an error.
|
|
36
|
-
*/
|
|
37
|
-
export declare function canIndex(ref: SegmentRef): boolean;
|
|
38
|
-
/** The registry ref of the pointer for `ref` in `bucket`. Throws if the ref cannot be encoded — check first. */
|
|
39
|
-
export declare function dueIndexRef(bucket: number, ref: SegmentRef): SegmentRef;
|
|
40
|
-
/**
|
|
41
|
-
* Recover the original ref from an index row's name. `null` for anything we did not write — a foreign row in
|
|
42
|
-
* the reserved namespace is ignored rather than acted upon.
|
|
43
|
-
*/
|
|
44
|
-
export declare function decodeDueName(name: string): SegmentRef | null;
|
|
45
|
-
/**
|
|
46
|
-
* Which buckets a cycle must read at `now`: everything from `since` up to and including the current one.
|
|
47
|
-
*
|
|
48
|
-
* Past buckets are included because a sweep that did not run — a scaled-to-zero worker, a failed deploy, a
|
|
49
|
-
* paused schedule — must not leave its buckets stranded. `lookbackBuckets` bounds how far back a first run
|
|
50
|
-
* reaches, so a long outage costs a bounded number of list calls per cycle rather than one per day since the
|
|
51
|
-
* epoch; anything older is the repair scan's job.
|
|
52
|
-
*/
|
|
53
|
-
export declare function dueBucketsAt(now: number, lookbackBuckets: number): number[];
|
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
import type { GenKey, IStorageDriver, IRegistryDriver, RegistryRecord, SegmentRef, Token } from './ports.js';
|
|
2
|
-
/** The two ports generation bookkeeping needs: the objects, and the pointer that says which one is current. */
|
|
3
|
-
export interface GenerationDeps {
|
|
4
|
-
readonly storage: IStorageDriver;
|
|
5
|
-
readonly registry: IRegistryDriver;
|
|
6
|
-
}
|
|
7
|
-
/**
|
|
8
|
-
* The generation number a writer should use for the segment's **next** object: one above the highest generation
|
|
9
|
-
* the registry points at *or* that is present in Storage — whichever is higher. The erasure rewrite numbers this
|
|
10
|
-
* way; a load numbers with {@link nextLoadGeneration}, which lists as this does when its existence check finds the
|
|
11
|
-
* number taken or cannot answer.
|
|
12
|
-
*
|
|
13
|
-
* Both are consulted because they can disagree. A load that wrote its object and crashed before publishing leaves
|
|
14
|
-
* an object *above* `currentGen`; a writer that consulted only the pointer would pick that same number and hit the
|
|
15
|
-
* write-once conflict on every retry. Skipping past it costs one `list` and keeps the retry trivial — the crashed
|
|
16
|
-
* object is an orphan {@link gcOrphanGenerations} collects once the pointer moves on. Reusing such an object
|
|
17
|
-
* instead of skipping it (verify-and-publish) is `load()`'s job, not a numbering helper's.
|
|
18
|
-
*
|
|
19
|
-
* A segment with no row and no objects starts at 0. An admin/write-path helper, never on the read path.
|
|
20
|
-
*/
|
|
21
|
-
export declare function nextGeneration(ref: SegmentRef, deps: GenerationDeps): Promise<number>;
|
|
22
|
-
/** The number a load takes, and whether one existence check proved it free (so nothing is above the pointer). */
|
|
23
|
-
export interface LoadNumber {
|
|
24
|
-
readonly generation: number;
|
|
25
|
-
/**
|
|
26
|
-
* `true` when the number is `currentGen + 1` and the check found no object holding it. Collection by name rests
|
|
27
|
-
* on it: the row named `generation - 1` as current, so every number the window evicts is below it, and nothing
|
|
28
|
-
* the listing would have kept is a name the pass takes. `false` when the listing numbered the load.
|
|
29
|
-
*/
|
|
30
|
-
readonly checked: boolean;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* The generation number a load takes, from the row it has already read: `currentGen + 1` (0 with no row or no
|
|
34
|
-
* pointer yet) when no object holds that number, which one existence check proves (a zero-byte `getTail`, one
|
|
35
|
-
* metadata request on every shipped driver); otherwise one above the pointer and above everything listed, as
|
|
36
|
-
* {@link nextGeneration} numbers. The check finding the number taken (a crashed load's orphan, the object of a
|
|
37
|
-
* load still in flight, or the generations a rollback left above the pointer) and the check failing in any way
|
|
38
|
-
* other than "not found" both take the listing, so the listing stays the authority whenever the check cannot
|
|
39
|
-
* prove the number free. A failed check falls back silently: nothing records it, and what it costs is the listing,
|
|
40
|
-
* one more PUT-class request on S3, so a fault that makes every check fail shows only in the bill.
|
|
41
|
-
*
|
|
42
|
-
* A load can therefore take a number **below** an object already in the bucket: an orphan at `currentGen + 2`
|
|
43
|
-
* with `currentGen + 1` free is numbered under, not past. That is as safe as a listing's number. A load never
|
|
44
|
-
* takes a number an object holds, and a put that races onto one fails write-once, so the load reports
|
|
45
|
-
* `superseded`. The orphan above stays unpublished; the load whose check meets it numbers past it by the listing,
|
|
46
|
-
* and collection takes it once a generation above it is current. Like a listing's, the number can be one whose
|
|
47
|
-
* object was deleted (an erasure removes the generations above a rolled-back pointer that held the id), which is
|
|
48
|
-
* why nothing identifies a generation by its number alone: the reader cache and the chunk cache key on the number and
|
|
49
|
-
* the row's `pointerId`, which every write that takes a number again renews, and an open of a row with a usable
|
|
50
|
-
* summary holds the object to the fingerprint the summary records; a pin keys on its object's fingerprint.
|
|
51
|
-
*/
|
|
52
|
-
export declare function nextLoadGeneration(ref: SegmentRef, deps: GenerationDeps, row: RegistryRecord | null): Promise<LoadNumber>;
|
|
53
|
-
/**
|
|
54
|
-
* How often a load that could collect by name lists instead: every generation divisible by this. A name-only pass
|
|
55
|
-
* takes the names its publish pushed out of the row's window and never looks at the rest, so what it misses (a crashed
|
|
56
|
-
* or refused load's object, a delete that failed, extras a fault left after a `keep` that shrank, an object a rollback
|
|
57
|
-
* or an erasure left stranded below the pointer) waits for a listing. The number is a generation's, not a clock's, so the choice needs
|
|
58
|
-
* no state and no time, and a segment that loads cleanly lists once in this many loads at most. The bound is in
|
|
59
|
-
* generation numbers: a rollback moves the pointer down, and the loads that then take the numbers above it count
|
|
60
|
-
* from there.
|
|
61
|
-
*/
|
|
62
|
-
export declare const LIST_COLLECTION_CADENCE = 16;
|
|
63
|
-
/**
|
|
64
|
-
* Garbage-collect superseded Storage generations for a segment: everything strictly below `currentGen`, keeping
|
|
65
|
-
* the most recent `keep` of them as a grace window, so a read still fetching from a just-superseded
|
|
66
|
-
* generation need not re-resolve mid-call (**invariant 4**). It is a window, not a lock: a read whose
|
|
67
|
-
* generation is swept anyway re-resolves and retries once rather than failing (see `withFreshSnapshot`), so
|
|
68
|
-
* `keep` trades storage for round trips. Generations ≥ `currentGen` are never touched. Returns the generations
|
|
69
|
-
* deleted.
|
|
70
|
-
*
|
|
71
|
-
* **Except on a `destroyed` segment, where EVERY generation is garbage** and the grace window is meaningless.
|
|
72
|
-
* A tombstoned segment resolves no generation for any reader, pinned or not — a pin cannot be taken on one, and
|
|
73
|
-
* a pin taken while it was still active re-checks the status on every open — and nothing else in the library
|
|
74
|
-
* would ever collect them, so without this those objects are billed forever.
|
|
75
|
-
*
|
|
76
|
-
* **Throws {@link WriteConflictError} when it cannot act on the row it read**: the row is gone when it is re-read,
|
|
77
|
-
* after the listing or before a delete; on an active segment, the pointer has fallen below the cutoff before a
|
|
78
|
-
* delete; on a `destroyed` segment, the row's token has changed. Not to be confused with the empty array it still
|
|
79
|
-
* returns when there was genuinely nothing to collect (no row at all, or no pointer yet), which is why an empty
|
|
80
|
-
* array is not a receipt. The row is read before the listing and acted on after it, so a name that was purged and
|
|
81
|
-
* re-created in that window is a *different* segment wearing the same name, and its live object must not be
|
|
82
|
-
* collected on the strength of the old row: on an active segment the lower of the two pointers is what keeps it
|
|
83
|
-
* safe, and on a `destroyed` one the token. Refusing is safe — the objects are not going anywhere and the next
|
|
84
|
-
* pass reads a consistent row — but it has to be **distinguishable** from "there was nothing to collect", which
|
|
85
|
-
* an empty array is not: `eraseIdFromSegment` reads the returned list as the physical half of its erasure
|
|
86
|
-
* receipt, and would otherwise report `erased: true` over bytes still in the bucket. Re-run it.
|
|
87
|
-
*
|
|
88
|
-
* That state is reachable in practice: a `dropSegment` whose Storage sweep threw part-way, or a load that had read
|
|
89
|
-
* the row before the tombstone landed, wrote its object afterwards, and stopped before its refusal deleted it. `dropSegment` re-sweeps
|
|
90
|
-
* and reports whatever it could not reclaim in `generationsRemaining`, but a drop that was never re-run leaves a
|
|
91
|
-
* residual, and this is what eventually collects it from the retention sweep.
|
|
92
|
-
*
|
|
93
|
-
* `keep: 0` is how a subject-erasure rewrite makes a bit **physically** gone on return: the generation that held
|
|
94
|
-
* it is collected the moment the rewrite is current. A live read still fetching from it heals forward to the
|
|
95
|
-
* rewrite, and a pin of it (`seg.pin()`) fails with `NotFoundError` for any chunk it has yet to read.
|
|
96
|
-
*/
|
|
97
|
-
export declare function gcOrphanGenerations(ref: SegmentRef, deps: GenerationDeps, options?: {
|
|
98
|
-
keep?: number;
|
|
99
|
-
}): Promise<number[]>;
|
|
100
|
-
/**
|
|
101
|
-
* What makes a collection spare leased generations: the clock that says whether a lease has ended. Only a load's
|
|
102
|
-
* collection passes one, and a load with no clock passes none: it cannot tell a live lease from an ended one, so it
|
|
103
|
-
* reads none. A pass without a guard never reads the row's leases, which is what keeps erasure, shred and drop deleting
|
|
104
|
-
* what a lease names.
|
|
105
|
-
*/
|
|
106
|
-
export interface LeaseGuard {
|
|
107
|
-
readonly now: () => number;
|
|
108
|
-
}
|
|
109
|
-
/** What a load's publish recorded in the row, as `publishGeneration` reports it. */
|
|
110
|
-
export interface PublishedKept {
|
|
111
|
-
/** The list the publish wrote, or `undefined` when it wrote none (the row then does not know which are kept). */
|
|
112
|
-
readonly list: readonly number[] | undefined;
|
|
113
|
-
/** The names the publish pushed out of the window, ascending. */
|
|
114
|
-
readonly evict: readonly number[];
|
|
115
|
-
/** The token of the row the publish wrote, when it is known: a write settled by reading the row has none. */
|
|
116
|
-
readonly token: Token | undefined;
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Collect after a load's publish. The row records the generations the load keeps, so the pass deletes by name what the
|
|
120
|
-
* publish pushed out of that window ({@link deleteEvicted}) and lists the segment ({@link gcOrphanGenerations}'s
|
|
121
|
-
* pass) only when it cannot rely on the row or must catch what a name does not:
|
|
122
|
-
*
|
|
123
|
-
* - the row recorded no list (a `keep` above {@link MAX_KEPT_GENERATIONS}, a row an earlier schema wrote, one a
|
|
124
|
-
* rollback or an erasure moved, or a publish whose write was settled by reading the row): the pass keeps the
|
|
125
|
-
* newest `keep` generations present below the pointer, and records them with one compare-and-swap, fenced on the
|
|
126
|
-
* publish's own token, so the next load collects by name;
|
|
127
|
-
* - the guard found the current generation's object gone, or, for a `keep` of 1 or more when the guard took the size
|
|
128
|
-
* from the row's summary and opened nothing, one zero-byte read of it does not find it (`proveCurrent`): the
|
|
129
|
-
* window then counts a generation that is not there, so the same pass keeps what is;
|
|
130
|
-
* - a number the listing chose (something sits above the pointer, or the existence check could not answer), a
|
|
131
|
-
* caller that asks for a listing, and every {@link LIST_COLLECTION_CADENCE}th generation: the pass deletes every
|
|
132
|
-
* generation below the pointer the row does not name, which collects what a name-only pass leaves.
|
|
133
|
-
*
|
|
134
|
-
* It makes no request when `keep` is at least the generation published, since no more generations than that exist
|
|
135
|
-
* below it. A load onto a `destroyed` row is refused at its publish and never reaches here; a drop that lands after
|
|
136
|
-
* the publish leaves this pass collecting the tombstone's generations, and the drop's own sweep takes the rest.
|
|
137
|
-
*
|
|
138
|
-
* The seed's compare-and-swap moves the row's token, so a derived writer in flight on the row (an erasure rewrite)
|
|
139
|
-
* meets a lost fence and re-derives: it happens once per row that recorded no list. A `WriteConflictError` from it is
|
|
140
|
-
* a lost race, and the load took effect, so it is not raised; the next load records the list. Any other fault is
|
|
141
|
-
* raised, as every fault of a collection after a landed publish is.
|
|
142
|
-
*/
|
|
143
|
-
export declare function collectAfterLoad(ref: SegmentRef, deps: GenerationDeps, options: {
|
|
144
|
-
generation: number;
|
|
145
|
-
keep: number;
|
|
146
|
-
/** The load's number was proved free by one existence check, and no caller asked for a listing. */
|
|
147
|
-
byName: boolean;
|
|
148
|
-
/** The guard opened the current generation's object and found it gone. */
|
|
149
|
-
currentGone?: boolean;
|
|
150
|
-
kept: PublishedKept | undefined;
|
|
151
|
-
/**
|
|
152
|
-
* The object the load's row named as current, which the caller did not open. Before it collects by name, the pass
|
|
153
|
-
* looks for this object with one zero-byte read, and lists instead unless that finds it: a name-only pass is
|
|
154
|
-
* safe only while the object the row named is in the bucket.
|
|
155
|
-
*/
|
|
156
|
-
proveCurrent?: GenKey;
|
|
157
|
-
/** Spare the generations the row's live leases hold. Absent, the pass ignores leases. */
|
|
158
|
-
leases?: LeaseGuard;
|
|
159
|
-
}): Promise<number[]>;
|
|
160
|
-
/**
|
|
161
|
-
* Delete, with no listing, the generations a publish of `generation` pushed out of its row's window, `evict`, taken
|
|
162
|
-
* from the list the publish was written against. Returns the names asked for, whether or not an object was there: a
|
|
163
|
-
* delete of an absent object succeeds on every backend and says nothing, so a generation a concurrent pass, an erasure
|
|
164
|
-
* or a lifecycle rule had already taken is listed all the same. A list is not a receipt (invariant 4), and neither is
|
|
165
|
-
* this.
|
|
166
|
-
*
|
|
167
|
-
* Each delete re-reads the row first (invariant 4) and stops the pass, deleting nothing more and raising nothing, unless
|
|
168
|
-
* the row still has a pointer at or above `generation` (a rollback, or a name purged and re-created with fewer loads,
|
|
169
|
-
* has moved it below: the publish already landed, nothing here protects it or needs the result), the name is below
|
|
170
|
-
* that pointer, and the row's own list is usable and does not name it. The last condition is what keeps a late delete
|
|
171
|
-
* from taking a generation that a later publish, after a rollback, put in the window. A pointer that has moved above
|
|
172
|
-
* `generation` does not stop it: a publish landing in the meantime leaves routine collection working. A fault, a
|
|
173
|
-
* registry read or a delete that throws, propagates, with the pointer at `generation`.
|
|
174
|
-
*/
|
|
175
|
-
export declare function deleteEvicted(ref: SegmentRef, deps: GenerationDeps, options: {
|
|
176
|
-
generation: number;
|
|
177
|
-
evict: readonly number[];
|
|
178
|
-
leases?: LeaseGuard;
|
|
179
|
-
}): Promise<number[]>;
|