@claudexor/journal 3.10.5 → 3.12.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/append-batch.d.ts +2 -0
- package/dist/append-batch.d.ts.map +1 -1
- package/dist/append-batch.js +4 -0
- package/dist/append-batch.js.map +1 -1
- package/dist/frame-codec.d.ts +54 -0
- package/dist/frame-codec.d.ts.map +1 -1
- package/dist/frame-codec.js +167 -87
- package/dist/frame-codec.js.map +1 -1
- package/dist/frame-reader.d.ts +30 -0
- package/dist/frame-reader.d.ts.map +1 -0
- package/dist/frame-reader.js +97 -0
- package/dist/frame-reader.js.map +1 -0
- package/dist/index.d.ts +34 -44
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +81 -156
- package/dist/index.js.map +1 -1
- package/dist/journal-background-compaction.d.ts +7 -2
- package/dist/journal-background-compaction.d.ts.map +1 -1
- package/dist/journal-background-compaction.js +79 -78
- package/dist/journal-background-compaction.js.map +1 -1
- package/dist/journal-compaction-chunks.d.ts +29 -0
- package/dist/journal-compaction-chunks.d.ts.map +1 -0
- package/dist/journal-compaction-chunks.js +112 -0
- package/dist/journal-compaction-chunks.js.map +1 -0
- package/dist/journal-compaction.d.ts +27 -5
- package/dist/journal-compaction.d.ts.map +1 -1
- package/dist/journal-compaction.js +22 -4
- package/dist/journal-compaction.js.map +1 -1
- package/dist/journal-core.d.ts +96 -0
- package/dist/journal-core.d.ts.map +1 -0
- package/dist/journal-core.js +173 -0
- package/dist/journal-core.js.map +1 -0
- package/dist/journal-files.d.ts +0 -1
- package/dist/journal-files.d.ts.map +1 -1
- package/dist/journal-files.js +0 -9
- package/dist/journal-files.js.map +1 -1
- package/dist/journal-fold.d.ts +47 -0
- package/dist/journal-fold.d.ts.map +1 -0
- package/dist/journal-fold.js +81 -0
- package/dist/journal-fold.js.map +1 -0
- package/dist/journal-recovery.d.ts +18 -6
- package/dist/journal-recovery.d.ts.map +1 -1
- package/dist/journal-recovery.js +46 -30
- package/dist/journal-recovery.js.map +1 -1
- package/dist/read-only-preparation.d.ts +7 -0
- package/dist/read-only-preparation.d.ts.map +1 -1
- package/dist/read-only-preparation.js +98 -41
- package/dist/read-only-preparation.js.map +1 -1
- package/package.json +2 -2
|
@@ -2,16 +2,14 @@ import { randomUUID } from "node:crypto";
|
|
|
2
2
|
import { constants } from "node:fs";
|
|
3
3
|
import { open, unlink } from "node:fs/promises";
|
|
4
4
|
import { join } from "node:path";
|
|
5
|
-
import { Readable, Writable } from "node:stream";
|
|
6
|
-
import { pipeline } from "node:stream/promises";
|
|
7
5
|
import { setImmediate } from "node:timers/promises";
|
|
8
|
-
import { createGzip } from "node:zlib";
|
|
9
6
|
import { encodeJournalPayload } from "./append-batch.js";
|
|
10
|
-
import { HASH_BYTES,
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
import { HASH_BYTES, ZERO_HASH, encodeFrame } from "./frame-codec.js";
|
|
8
|
+
import { STREAM_BATCH_BYTES, snapshotChunks } from "./journal-compaction-chunks.js";
|
|
9
|
+
import { capacityCapOf, declinedCompaction, isCompactionCapacityError, logicalRecord, } from "./journal-compaction.js";
|
|
10
|
+
import { foldStream } from "./journal-fold.js";
|
|
14
11
|
const COMPACTION_FILE_PREFIX = "journal-compaction-";
|
|
12
|
+
const FOLD_YIELD_EVERY = STREAM_BATCH_BYTES / 128;
|
|
15
13
|
/** The journal owns freshness and installation; this helper owns only its
|
|
16
14
|
* temporary file and immutable logical-record references. */
|
|
17
15
|
export async function prepareBackgroundCompaction(input) {
|
|
@@ -19,46 +17,74 @@ export async function prepareBackgroundCompaction(input) {
|
|
|
19
17
|
let path = null;
|
|
20
18
|
try {
|
|
21
19
|
await setImmediate(undefined, { signal: input.signal });
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
});
|
|
30
|
-
if (!snapshot || snapshot.frame.length >= input.prefix.knownFileBytes)
|
|
31
|
-
return null;
|
|
32
|
-
input.signal.throwIfAborted();
|
|
33
|
-
const records = [];
|
|
34
|
-
for (let index = 0; index < input.prefix.count; index += 1) {
|
|
35
|
-
records.push(compactedJournalRecord(input.entries[index], input.partition, input.epoch, index, snapshot.frameHash));
|
|
36
|
-
if ((index + 1) % (STREAM_BATCH_BYTES / 128) === 0)
|
|
37
|
-
await setImmediate(undefined, { signal: input.signal });
|
|
38
|
-
}
|
|
20
|
+
// The fold applies uniformly to the captured prefix: records retained at
|
|
21
|
+
// replay and unfolded appends since are judged by the same policy.
|
|
22
|
+
const folded = input.fold
|
|
23
|
+
? await foldPrefix(input.entries, input.prefix.count, input.fold, input.signal)
|
|
24
|
+
: null;
|
|
25
|
+
const source = folded ? folded.retained : input.entries;
|
|
26
|
+
const count = folded ? folded.retained.length : input.prefix.count;
|
|
39
27
|
input.signal.throwIfAborted();
|
|
40
28
|
path = join(input.stagingDir, `${COMPACTION_FILE_PREFIX}${randomUUID()}.compact`);
|
|
41
29
|
handle = await open(path, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL, 0o600);
|
|
42
|
-
await writeBytes(handle, snapshot.frame, input.signal);
|
|
43
30
|
const candidate = {
|
|
44
31
|
path,
|
|
45
|
-
records,
|
|
32
|
+
records: [],
|
|
46
33
|
epoch: input.epoch,
|
|
47
34
|
nextSeq: input.prefix.nextSeq,
|
|
48
|
-
previousFrameHash:
|
|
49
|
-
knownFileBytes:
|
|
35
|
+
previousFrameHash: ZERO_HASH,
|
|
36
|
+
knownFileBytes: 0,
|
|
50
37
|
receipt: {
|
|
51
38
|
beforeBytes: input.prefix.knownFileBytes,
|
|
52
|
-
afterBytes:
|
|
53
|
-
records:
|
|
39
|
+
afterBytes: 0,
|
|
40
|
+
records: 0,
|
|
41
|
+
retainedCount: count,
|
|
42
|
+
retiredCount: folded?.retiredCount ?? 0,
|
|
43
|
+
retiredBytes: folded?.retiredBytes ?? 0,
|
|
54
44
|
},
|
|
55
45
|
};
|
|
46
|
+
const chunks = snapshotChunks({
|
|
47
|
+
partition: input.partition,
|
|
48
|
+
epoch: input.epoch,
|
|
49
|
+
time: input.time,
|
|
50
|
+
records: source,
|
|
51
|
+
count,
|
|
52
|
+
endSeq: input.prefix.nextSeq - 1,
|
|
53
|
+
signal: input.signal,
|
|
54
|
+
});
|
|
55
|
+
for await (const chunk of chunks) {
|
|
56
|
+
await writeBytes(handle, chunk.frame, input.signal);
|
|
57
|
+
for (let index = 0; index < chunk.count; index += 1) {
|
|
58
|
+
const record = source[chunk.firstIndex + index];
|
|
59
|
+
candidate.records.push({
|
|
60
|
+
partition: input.partition,
|
|
61
|
+
epoch: input.epoch,
|
|
62
|
+
seq: record.seq,
|
|
63
|
+
previousFrameHash: index === 0 ? chunk.header.previousFrameHash : chunk.frameHash,
|
|
64
|
+
frameHash: chunk.frameHash,
|
|
65
|
+
time: record.time,
|
|
66
|
+
type: record.type,
|
|
67
|
+
payload: record.payload,
|
|
68
|
+
byteOffset: candidate.knownFileBytes,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
candidate.previousFrameHash = chunk.frameHash;
|
|
72
|
+
candidate.knownFileBytes += chunk.frame.length;
|
|
73
|
+
}
|
|
74
|
+
if (candidate.knownFileBytes >= input.prefix.knownFileBytes) {
|
|
75
|
+
return declinedCompaction("no_reclaim", {
|
|
76
|
+
compressedBytes: candidate.knownFileBytes,
|
|
77
|
+
cap: input.prefix.knownFileBytes,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
let consumed = input.prefix.count;
|
|
56
81
|
for (;;) {
|
|
57
82
|
input.signal.throwIfAborted();
|
|
58
83
|
// appendBatch publishes its entries/counters together, after ACK. Capture
|
|
59
84
|
// only complete batches, even when encoding yields partway through one.
|
|
60
85
|
const boundary = input.current();
|
|
61
|
-
await appendTail(handle, candidate, input.entries, boundary.count, input.signal);
|
|
86
|
+
await appendTail(handle, candidate, input.entries, consumed, boundary.count, input.signal);
|
|
87
|
+
consumed = boundary.count;
|
|
62
88
|
await handle.sync();
|
|
63
89
|
input.signal.throwIfAborted();
|
|
64
90
|
if (!sameBoundary(boundary, input.current()))
|
|
@@ -69,6 +95,7 @@ export async function prepareBackgroundCompaction(input) {
|
|
|
69
95
|
handle = null;
|
|
70
96
|
input.signal.throwIfAborted();
|
|
71
97
|
candidate.receipt = {
|
|
98
|
+
...candidate.receipt,
|
|
72
99
|
beforeBytes: boundary.knownFileBytes,
|
|
73
100
|
afterBytes: candidate.knownFileBytes,
|
|
74
101
|
records: candidate.records.length,
|
|
@@ -80,11 +107,13 @@ export async function prepareBackgroundCompaction(input) {
|
|
|
80
107
|
}
|
|
81
108
|
}
|
|
82
109
|
catch (error) {
|
|
83
|
-
if (
|
|
84
|
-
(error === input.signal.reason ||
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
110
|
+
if (input.signal.aborted &&
|
|
111
|
+
(error === input.signal.reason || (error instanceof Error && error.name === "AbortError")))
|
|
112
|
+
return declinedCompaction("aborted");
|
|
113
|
+
if (isCompactionCapacityError(error)) {
|
|
114
|
+
const cap = capacityCapOf(error);
|
|
115
|
+
return declinedCompaction("capacity", cap === undefined ? {} : { cap });
|
|
116
|
+
}
|
|
88
117
|
throw error;
|
|
89
118
|
}
|
|
90
119
|
finally {
|
|
@@ -106,47 +135,24 @@ export function sameBoundary(a, b) {
|
|
|
106
135
|
a.previousFrameHash === b.previousFrameHash &&
|
|
107
136
|
a.knownFileBytes === b.knownFileBytes);
|
|
108
137
|
}
|
|
109
|
-
async function
|
|
110
|
-
const
|
|
111
|
-
let compressedBytes = 0;
|
|
112
|
-
await pipeline(Readable.from(serializeRecords(entries, count, signal), {
|
|
113
|
-
objectMode: false,
|
|
114
|
-
highWaterMark: STREAM_BATCH_BYTES,
|
|
115
|
-
}), createGzip(), new Writable({
|
|
116
|
-
write(chunk, _encoding, done) {
|
|
117
|
-
compressedBytes += chunk.length;
|
|
118
|
-
if (compressedBytes > MAX_PAYLOAD_BYTES)
|
|
119
|
-
return done(capacityError("compressed bytes"));
|
|
120
|
-
chunks.push(chunk);
|
|
121
|
-
done();
|
|
122
|
-
},
|
|
123
|
-
}), { signal });
|
|
124
|
-
return Buffer.concat(chunks, compressedBytes);
|
|
125
|
-
}
|
|
126
|
-
async function* serializeRecords(entries, count, signal) {
|
|
127
|
-
let totalBytes = 2; // brackets
|
|
128
|
-
let batchBytes = 0;
|
|
129
|
-
yield "[";
|
|
138
|
+
async function foldPrefix(entries, count, fold, signal) {
|
|
139
|
+
const sink = foldStream(fold);
|
|
130
140
|
for (let index = 0; index < count; index += 1) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
batchBytes += bytes;
|
|
141
|
-
if (batchBytes >= STREAM_BATCH_BYTES) {
|
|
141
|
+
const record = entries[index];
|
|
142
|
+
sink.push(record, {
|
|
143
|
+
seq: record.seq,
|
|
144
|
+
type: record.type,
|
|
145
|
+
time: record.time,
|
|
146
|
+
payload: record.payload,
|
|
147
|
+
byteLength: Buffer.byteLength(JSON.stringify(logicalRecord(record)), "utf8"),
|
|
148
|
+
});
|
|
149
|
+
if ((index + 1) % FOLD_YIELD_EVERY === 0)
|
|
142
150
|
await setImmediate(undefined, { signal });
|
|
143
|
-
batchBytes = 0;
|
|
144
|
-
}
|
|
145
151
|
}
|
|
146
|
-
|
|
152
|
+
return sink.finish();
|
|
147
153
|
}
|
|
148
|
-
async function appendTail(handle, candidate, entries,
|
|
149
|
-
for (let index =
|
|
154
|
+
async function appendTail(handle, candidate, entries, from, to, signal) {
|
|
155
|
+
for (let index = from; index < to; index += 1) {
|
|
150
156
|
signal.throwIfAborted();
|
|
151
157
|
const record = entries[index];
|
|
152
158
|
const header = {
|
|
@@ -181,9 +187,4 @@ async function writeBytes(handle, bytes, signal) {
|
|
|
181
187
|
offset += bytesWritten;
|
|
182
188
|
}
|
|
183
189
|
}
|
|
184
|
-
function capacityError(kind) {
|
|
185
|
-
return Object.assign(new Error(`journal compaction exceeds the existing ${kind} cap`), {
|
|
186
|
-
code: "journal_compaction_capacity",
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
190
|
//# sourceMappingURL=journal-background-compaction.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"journal-background-compaction.js","sourceRoot":"","sources":["../src/journal-background-compaction.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAmB,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"journal-background-compaction.js","sourceRoot":"","sources":["../src/journal-background-compaction.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type FrameHeader, type JournalRecord } from "./frame-codec.js";
|
|
2
|
+
export declare const STREAM_BATCH_BYTES: number;
|
|
3
|
+
export interface SnapshotChunk {
|
|
4
|
+
frame: Buffer;
|
|
5
|
+
frameHash: string;
|
|
6
|
+
header: FrameHeader;
|
|
7
|
+
/** Index into the retained source of this chunk's first record. */
|
|
8
|
+
firstIndex: number;
|
|
9
|
+
count: number;
|
|
10
|
+
}
|
|
11
|
+
/** Emit the seq-preserving chain of `journal.compacted_snapshot` frames that
|
|
12
|
+
* covers logical sequence numbers `1..endSeq` and holds exactly the retained
|
|
13
|
+
* records `[0, count)` in seq order. Every record keeps its original `seq`; a
|
|
14
|
+
* chunk's header names the first sequence it covers and its `logicalSpan`
|
|
15
|
+
* runs up to the next chunk's first retained record (or `endSeq`), so the
|
|
16
|
+
* dropped numbers are accounted for without a record. Chunks are cut by
|
|
17
|
+
* logical bytes so the compressed base64 envelope fits one frame; a single
|
|
18
|
+
* record larger than the cut point becomes its own chunk, and only the
|
|
19
|
+
* compressed-output and envelope caps can refuse it. */
|
|
20
|
+
export declare function snapshotChunks(input: {
|
|
21
|
+
partition: string;
|
|
22
|
+
epoch: string;
|
|
23
|
+
time: string;
|
|
24
|
+
records: readonly JournalRecord[];
|
|
25
|
+
count: number;
|
|
26
|
+
endSeq: number;
|
|
27
|
+
signal: AbortSignal;
|
|
28
|
+
}): AsyncGenerator<SnapshotChunk>;
|
|
29
|
+
//# sourceMappingURL=journal-compaction-chunks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"journal-compaction-chunks.d.ts","sourceRoot":"","sources":["../src/journal-compaction-chunks.ts"],"names":[],"mappings":"AAKA,OAAO,EASL,KAAK,WAAW,EAChB,KAAK,aAAa,EACnB,MAAM,kBAAkB,CAAC;AAI1B,eAAO,MAAM,kBAAkB,QAAY,CAAC;AAE5C,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,WAAW,CAAC;IACpB,mEAAmE;IACnE,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;wDAQwD;AACxD,wBAAuB,cAAc,CAAC,KAAK,EAAE;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,SAAS,aAAa,EAAE,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,WAAW,CAAC;CACrB,GAAG,cAAc,CAAC,aAAa,CAAC,CA0BhC"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { Readable, Writable } from "node:stream";
|
|
2
|
+
import { pipeline } from "node:stream/promises";
|
|
3
|
+
import { setImmediate } from "node:timers/promises";
|
|
4
|
+
import { createGzip } from "node:zlib";
|
|
5
|
+
import { encodeJournalPayload } from "./append-batch.js";
|
|
6
|
+
import { COMPACTED_SNAPSHOT, HASH_BYTES, MAX_PAYLOAD_BYTES, SNAPSHOT_CHUNK_LOGICAL_BYTES, ZERO_HASH, encodeFrame, } from "./frame-codec.js";
|
|
7
|
+
import { capacityError } from "./journal-compaction.js";
|
|
8
|
+
// A working batch, never a history retention limit or a user setting.
|
|
9
|
+
export const STREAM_BATCH_BYTES = 64 * 1024;
|
|
10
|
+
/** Emit the seq-preserving chain of `journal.compacted_snapshot` frames that
|
|
11
|
+
* covers logical sequence numbers `1..endSeq` and holds exactly the retained
|
|
12
|
+
* records `[0, count)` in seq order. Every record keeps its original `seq`; a
|
|
13
|
+
* chunk's header names the first sequence it covers and its `logicalSpan`
|
|
14
|
+
* runs up to the next chunk's first retained record (or `endSeq`), so the
|
|
15
|
+
* dropped numbers are accounted for without a record. Chunks are cut by
|
|
16
|
+
* logical bytes so the compressed base64 envelope fits one frame; a single
|
|
17
|
+
* record larger than the cut point becomes its own chunk, and only the
|
|
18
|
+
* compressed-output and envelope caps can refuse it. */
|
|
19
|
+
export async function* snapshotChunks(input) {
|
|
20
|
+
const limit = SNAPSHOT_CHUNK_LOGICAL_BYTES;
|
|
21
|
+
const cursor = { index: 0, pending: null };
|
|
22
|
+
let coverStart = 1;
|
|
23
|
+
let previousFrameHash = ZERO_HASH;
|
|
24
|
+
do {
|
|
25
|
+
const firstIndex = cursor.index;
|
|
26
|
+
const compressed = await compressChunk(serializeChunk(input, cursor, limit), input.signal);
|
|
27
|
+
const count = cursor.index - firstIndex;
|
|
28
|
+
const coverEnd = cursor.index < input.count ? input.records[cursor.index].seq - 1 : input.endSeq;
|
|
29
|
+
const header = {
|
|
30
|
+
partition: input.partition,
|
|
31
|
+
epoch: input.epoch,
|
|
32
|
+
seq: coverStart,
|
|
33
|
+
previousFrameHash,
|
|
34
|
+
time: input.time,
|
|
35
|
+
type: COMPACTED_SNAPSHOT,
|
|
36
|
+
logicalSpan: coverEnd - coverStart + 1,
|
|
37
|
+
};
|
|
38
|
+
const frame = encodeFrame(header, encodeSnapshotPayload(count, compressed));
|
|
39
|
+
const frameHash = frame.subarray(frame.length - HASH_BYTES).toString("hex");
|
|
40
|
+
yield { frame, frameHash, header, firstIndex, count };
|
|
41
|
+
previousFrameHash = frameHash;
|
|
42
|
+
coverStart = coverEnd + 1;
|
|
43
|
+
} while (cursor.index < input.count);
|
|
44
|
+
}
|
|
45
|
+
function encodeSnapshotPayload(count, compressed) {
|
|
46
|
+
const payload = {
|
|
47
|
+
version: 1,
|
|
48
|
+
count,
|
|
49
|
+
encoding: "gzip-base64",
|
|
50
|
+
data: compressed.toString("base64"),
|
|
51
|
+
};
|
|
52
|
+
const bytes = encodeJournalPayload(payload);
|
|
53
|
+
if (bytes.length > MAX_PAYLOAD_BYTES)
|
|
54
|
+
throw capacityError("envelope", MAX_PAYLOAD_BYTES);
|
|
55
|
+
return bytes;
|
|
56
|
+
}
|
|
57
|
+
/** One chunk's JSON array, record by record. Stops before the record that
|
|
58
|
+
* would push a non-empty chunk past `limit`, leaving it pending for the next
|
|
59
|
+
* chunk; the first record of a chunk is always taken, whatever its size. */
|
|
60
|
+
async function* serializeChunk(input, cursor, limit) {
|
|
61
|
+
let totalBytes = 2; // brackets
|
|
62
|
+
let batchBytes = 0;
|
|
63
|
+
let emitted = 0;
|
|
64
|
+
yield "[";
|
|
65
|
+
while (cursor.index < input.count) {
|
|
66
|
+
input.signal.throwIfAborted();
|
|
67
|
+
const next = cursor.pending ?? serializeRecord(input.records[cursor.index]);
|
|
68
|
+
const bytes = next.bytes + (emitted === 0 ? 0 : 1);
|
|
69
|
+
if (emitted > 0 && totalBytes + bytes > limit) {
|
|
70
|
+
cursor.pending = next;
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
cursor.pending = null;
|
|
74
|
+
cursor.index += 1;
|
|
75
|
+
totalBytes += bytes;
|
|
76
|
+
if (emitted > 0)
|
|
77
|
+
yield ",";
|
|
78
|
+
yield next.json;
|
|
79
|
+
emitted += 1;
|
|
80
|
+
batchBytes += bytes;
|
|
81
|
+
if (batchBytes >= STREAM_BATCH_BYTES) {
|
|
82
|
+
await setImmediate(undefined, { signal: input.signal });
|
|
83
|
+
batchBytes = 0;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
yield "]";
|
|
87
|
+
}
|
|
88
|
+
function serializeRecord(record) {
|
|
89
|
+
const logical = {
|
|
90
|
+
seq: record.seq,
|
|
91
|
+
time: record.time,
|
|
92
|
+
type: record.type,
|
|
93
|
+
payload: record.payload,
|
|
94
|
+
};
|
|
95
|
+
const json = JSON.stringify(logical);
|
|
96
|
+
return { json, bytes: Buffer.byteLength(json, "utf8") };
|
|
97
|
+
}
|
|
98
|
+
async function compressChunk(source, signal) {
|
|
99
|
+
const chunks = [];
|
|
100
|
+
let compressedBytes = 0;
|
|
101
|
+
await pipeline(Readable.from(source, { objectMode: false, highWaterMark: STREAM_BATCH_BYTES }), createGzip(), new Writable({
|
|
102
|
+
write(chunk, _encoding, done) {
|
|
103
|
+
compressedBytes += chunk.length;
|
|
104
|
+
if (compressedBytes > MAX_PAYLOAD_BYTES)
|
|
105
|
+
return done(capacityError("compressed bytes", MAX_PAYLOAD_BYTES));
|
|
106
|
+
chunks.push(chunk);
|
|
107
|
+
done();
|
|
108
|
+
},
|
|
109
|
+
}), { signal });
|
|
110
|
+
return Buffer.concat(chunks, compressedBytes);
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=journal-compaction-chunks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"journal-compaction-chunks.js","sourceRoot":"","sources":["../src/journal-compaction-chunks.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +1,30 @@
|
|
|
1
1
|
import { type CompactedRecord, type JournalRecord } from "./frame-codec.js";
|
|
2
|
+
export interface JournalCompactionReceipt {
|
|
3
|
+
beforeBytes: number;
|
|
4
|
+
afterBytes: number;
|
|
5
|
+
/** Records in the installed file: the retained prefix plus the caught-up tail. */
|
|
6
|
+
records: number;
|
|
7
|
+
retainedCount: number;
|
|
8
|
+
retiredCount: number;
|
|
9
|
+
/** Serialized logical bytes of the retired records (informational; the daemon
|
|
10
|
+
* reports it as `journal.records_retired`). */
|
|
11
|
+
retiredBytes: number;
|
|
12
|
+
}
|
|
13
|
+
export type JournalCompactionDeclineReason = "aborted" | "below_threshold" | "empty" | "capacity" | "no_reclaim";
|
|
14
|
+
/** A declined maintenance pass leaves the original file untouched. */
|
|
15
|
+
export interface JournalCompactionDeclined {
|
|
16
|
+
declined: true;
|
|
17
|
+
reason: JournalCompactionDeclineReason;
|
|
18
|
+
compressedBytes?: number;
|
|
19
|
+
/** The cap that fired: the frame payload cap for `capacity`, the current
|
|
20
|
+
* file size for `no_reclaim`. */
|
|
21
|
+
cap?: number;
|
|
22
|
+
}
|
|
23
|
+
export type JournalCompactionOutcome = JournalCompactionReceipt | JournalCompactionDeclined;
|
|
24
|
+
export declare function declinedCompaction(reason: JournalCompactionDeclineReason, detail?: Omit<JournalCompactionDeclined, "declined" | "reason">): JournalCompactionDeclined;
|
|
2
25
|
export interface JournalCompactionResult {
|
|
3
26
|
path: string;
|
|
4
|
-
receipt:
|
|
5
|
-
beforeBytes: number;
|
|
6
|
-
afterBytes: number;
|
|
7
|
-
records: number;
|
|
8
|
-
};
|
|
27
|
+
receipt: JournalCompactionReceipt;
|
|
9
28
|
records: JournalRecord[];
|
|
10
29
|
epoch: string;
|
|
11
30
|
nextSeq: number;
|
|
@@ -33,5 +52,8 @@ export declare function encodeCompactionSnapshot(input: {
|
|
|
33
52
|
frameHash: string;
|
|
34
53
|
} | null;
|
|
35
54
|
export declare function compactedJournalRecord(record: CompactedRecord, partition: string, epoch: string, index: number, frameHash: string, payload?: unknown): JournalRecord;
|
|
55
|
+
/** A typed capacity refusal names the cap that actually fired. */
|
|
56
|
+
export declare function capacityError(kind: string, cap: number): Error;
|
|
57
|
+
export declare function capacityCapOf(error: unknown): number | undefined;
|
|
36
58
|
export declare function isCompactionCapacityError(error: unknown): boolean;
|
|
37
59
|
//# sourceMappingURL=journal-compaction.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"journal-compaction.d.ts","sourceRoot":"","sources":["../src/journal-compaction.ts"],"names":[],"mappings":"AAIA,OAAO,EAOL,KAAK,eAAe,EAGpB,KAAK,aAAa,EACnB,MAAM,kBAAkB,CAAC;AAG1B,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"journal-compaction.d.ts","sourceRoot":"","sources":["../src/journal-compaction.ts"],"names":[],"mappings":"AAIA,OAAO,EAOL,KAAK,eAAe,EAGpB,KAAK,aAAa,EACnB,MAAM,kBAAkB,CAAC;AAG1B,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,kFAAkF;IAClF,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB;mDAC+C;IAC/C,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,8BAA8B,GACxC,SAAS,GAAG,iBAAiB,GAAG,OAAO,GAAG,UAAU,GAAG,YAAY,CAAC;AAEtE,sEAAsE;AACtE,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,IAAI,CAAC;IACf,MAAM,EAAE,8BAA8B,CAAC;IACvC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;qCACiC;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,wBAAwB,GAAG,wBAAwB,GAAG,yBAAyB,CAAC;AAE5F,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,8BAA8B,EACtC,MAAM,GAAE,IAAI,CAAC,yBAAyB,EAAE,UAAU,GAAG,QAAQ,CAAM,GAClE,yBAAyB,CAE3B;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,wBAAwB,CAAC;IAClC,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,iFAAiF;AACjF,wBAAgB,wBAAwB,CAAC,KAAK,EAAE;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,SAAS,aAAa,EAAE,CAAC;IAClC,cAAc,EAAE,MAAM,CAAC;IACvB,GAAG,EAAE,MAAM,IAAI,CAAC;CACjB,GAAG,uBAAuB,GAAG,IAAI,CAiFjC;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,eAAe,EAAE,OAAO,UAAiB,GAAG,eAAe,CAEhG;AAED,qFAAqF;AACrF,wBAAgB,wBAAwB,CAAC,KAAK,EAAE;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA6B9C;AAED,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,eAAe,EACvB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,OAAO,UAAiB,GACvB,aAAa,CAYf;AAED,kEAAkE;AAClE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,KAAK,CAK9D;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAOhE;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAgBjE"}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { closeSync, constants, openSync, rmSync } from "node:fs";
|
|
3
3
|
import { gzipSync } from "node:zlib";
|
|
4
|
-
import { encodeJournalPayload } from "./append-batch.js";
|
|
4
|
+
import { cloneJson, encodeJournalPayload } from "./append-batch.js";
|
|
5
5
|
import { COMPACTED_SNAPSHOT, HASH_BYTES, MAX_COMPACTED_LOGICAL_BYTES, MAX_PAYLOAD_BYTES, ZERO_HASH, encodeFrame, } from "./frame-codec.js";
|
|
6
6
|
import { appendAndSync } from "./journal-files.js";
|
|
7
|
+
export function declinedCompaction(reason, detail = {}) {
|
|
8
|
+
return { declined: true, reason, ...detail };
|
|
9
|
+
}
|
|
7
10
|
/** Prepare a fsynced candidate. Only DurableJournal installs canonical bytes. */
|
|
8
11
|
export function prepareJournalCompaction(input) {
|
|
9
12
|
if (input.entries.length === 0)
|
|
@@ -81,6 +84,9 @@ export function prepareJournalCompaction(input) {
|
|
|
81
84
|
beforeBytes: input.knownFileBytes,
|
|
82
85
|
afterBytes: frame.length,
|
|
83
86
|
records: logical.length,
|
|
87
|
+
retainedCount: logical.length,
|
|
88
|
+
retiredCount: 0,
|
|
89
|
+
retiredBytes: 0,
|
|
84
90
|
},
|
|
85
91
|
records,
|
|
86
92
|
epoch,
|
|
@@ -140,6 +146,21 @@ export function compactedJournalRecord(record, partition, epoch, index, frameHas
|
|
|
140
146
|
byteOffset: 0,
|
|
141
147
|
};
|
|
142
148
|
}
|
|
149
|
+
/** A typed capacity refusal names the cap that actually fired. */
|
|
150
|
+
export function capacityError(kind, cap) {
|
|
151
|
+
return Object.assign(new Error(`journal compaction exceeds the existing ${kind} cap`), {
|
|
152
|
+
code: "journal_compaction_capacity",
|
|
153
|
+
cap,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
export function capacityCapOf(error) {
|
|
157
|
+
return typeof error === "object" &&
|
|
158
|
+
error !== null &&
|
|
159
|
+
"cap" in error &&
|
|
160
|
+
typeof error.cap === "number"
|
|
161
|
+
? error.cap
|
|
162
|
+
: undefined;
|
|
163
|
+
}
|
|
143
164
|
export function isCompactionCapacityError(error) {
|
|
144
165
|
if (error instanceof RangeError &&
|
|
145
166
|
(error.message === "Invalid string length" ||
|
|
@@ -153,7 +174,4 @@ export function isCompactionCapacityError(error) {
|
|
|
153
174
|
error.code === "ERR_STRING_TOO_LONG" ||
|
|
154
175
|
error.code === "journal_compaction_capacity"));
|
|
155
176
|
}
|
|
156
|
-
function cloneJson(value) {
|
|
157
|
-
return JSON.parse(JSON.stringify(value));
|
|
158
|
-
}
|
|
159
177
|
//# sourceMappingURL=journal-compaction.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"journal-compaction.js","sourceRoot":"","sources":["../src/journal-compaction.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"journal-compaction.js","sourceRoot":"","sources":["../src/journal-compaction.ts"],"names":[],"mappings":"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"}
|