@platformatic/sqlite-js-stream 0.0.0-stage → 0.1.1
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/CHANGELOG.md +40 -0
- package/LICENSE +202 -0
- package/NOTICE +22 -0
- package/README.md +482 -2
- package/dist/backends/file/index.d.ts +4 -0
- package/dist/backends/file/index.d.ts.map +1 -0
- package/dist/backends/file/index.js +3 -0
- package/dist/backends/file/leaser.d.ts +20 -0
- package/dist/backends/file/leaser.d.ts.map +1 -0
- package/dist/backends/file/leaser.js +123 -0
- package/dist/backends/file/replica-client.d.ts +38 -0
- package/dist/backends/file/replica-client.d.ts.map +1 -0
- package/dist/backends/file/replica-client.js +209 -0
- package/dist/db.d.ts +80 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +484 -0
- package/dist/errors.d.ts +42 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +66 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/leaser.d.ts +55 -0
- package/dist/leaser.d.ts.map +1 -0
- package/dist/leaser.js +60 -0
- package/dist/ltx/byte-reader.d.ts +18 -0
- package/dist/ltx/byte-reader.d.ts.map +1 -0
- package/dist/ltx/byte-reader.js +38 -0
- package/dist/ltx/bytes.d.ts +20 -0
- package/dist/ltx/bytes.d.ts.map +1 -0
- package/dist/ltx/bytes.js +69 -0
- package/dist/ltx/checksum.d.ts +20 -0
- package/dist/ltx/checksum.d.ts.map +1 -0
- package/dist/ltx/checksum.js +42 -0
- package/dist/ltx/compaction-level.d.ts +58 -0
- package/dist/ltx/compaction-level.d.ts.map +1 -0
- package/dist/ltx/compaction-level.js +115 -0
- package/dist/ltx/compactor.d.ts +33 -0
- package/dist/ltx/compactor.d.ts.map +1 -0
- package/dist/ltx/compactor.js +137 -0
- package/dist/ltx/constants.d.ts +49 -0
- package/dist/ltx/constants.d.ts.map +1 -0
- package/dist/ltx/constants.js +58 -0
- package/dist/ltx/crc64.d.ts +29 -0
- package/dist/ltx/crc64.d.ts.map +1 -0
- package/dist/ltx/crc64.js +57 -0
- package/dist/ltx/decoder.d.ts +55 -0
- package/dist/ltx/decoder.d.ts.map +1 -0
- package/dist/ltx/decoder.js +236 -0
- package/dist/ltx/encoder.d.ts +49 -0
- package/dist/ltx/encoder.d.ts.map +1 -0
- package/dist/ltx/encoder.js +159 -0
- package/dist/ltx/file-info.d.ts +24 -0
- package/dist/ltx/file-info.d.ts.map +1 -0
- package/dist/ltx/file-info.js +74 -0
- package/dist/ltx/filename.d.ts +13 -0
- package/dist/ltx/filename.d.ts.map +1 -0
- package/dist/ltx/filename.js +23 -0
- package/dist/ltx/header.d.ts +17 -0
- package/dist/ltx/header.d.ts.map +1 -0
- package/dist/ltx/header.js +115 -0
- package/dist/ltx/index.d.ts +24 -0
- package/dist/ltx/index.d.ts.map +1 -0
- package/dist/ltx/index.js +25 -0
- package/dist/ltx/lz4.d.ts +41 -0
- package/dist/ltx/lz4.d.ts.map +1 -0
- package/dist/ltx/lz4.js +264 -0
- package/dist/ltx/page-index.d.ts +26 -0
- package/dist/ltx/page-index.d.ts.map +1 -0
- package/dist/ltx/page-index.js +118 -0
- package/dist/ltx/page.d.ts +27 -0
- package/dist/ltx/page.d.ts.map +1 -0
- package/dist/ltx/page.js +66 -0
- package/dist/ltx/sink.d.ts +17 -0
- package/dist/ltx/sink.d.ts.map +1 -0
- package/dist/ltx/sink.js +21 -0
- package/dist/ltx/stream.d.ts +64 -0
- package/dist/ltx/stream.d.ts.map +1 -0
- package/dist/ltx/stream.js +248 -0
- package/dist/ltx/streaming-compactor.d.ts +34 -0
- package/dist/ltx/streaming-compactor.d.ts.map +1 -0
- package/dist/ltx/streaming-compactor.js +140 -0
- package/dist/ltx/trailer.d.ts +12 -0
- package/dist/ltx/trailer.d.ts.map +1 -0
- package/dist/ltx/trailer.js +47 -0
- package/dist/ltx/types.d.ts +79 -0
- package/dist/ltx/types.d.ts.map +1 -0
- package/dist/ltx/types.js +70 -0
- package/dist/replica-client.d.ts +92 -0
- package/dist/replica-client.d.ts.map +1 -0
- package/dist/replica-client.js +122 -0
- package/dist/replica-url.d.ts +20 -0
- package/dist/replica-url.d.ts.map +1 -0
- package/dist/replica-url.js +49 -0
- package/dist/replica.d.ts +379 -0
- package/dist/replica.d.ts.map +1 -0
- package/dist/replica.js +1253 -0
- package/dist/store.d.ts +34 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +60 -0
- package/dist/util/fs.d.ts +28 -0
- package/dist/util/fs.d.ts.map +1 -0
- package/dist/util/fs.js +73 -0
- package/dist/util/logger.d.ts +10 -0
- package/dist/util/logger.d.ts.map +1 -0
- package/dist/util/logger.js +7 -0
- package/dist/util/stream.d.ts +11 -0
- package/dist/util/stream.d.ts.map +1 -0
- package/dist/util/stream.js +25 -0
- package/dist/wal/checksum.d.ts +17 -0
- package/dist/wal/checksum.d.ts.map +1 -0
- package/dist/wal/checksum.js +30 -0
- package/dist/wal/constants.d.ts +8 -0
- package/dist/wal/constants.d.ts.map +1 -0
- package/dist/wal/constants.js +7 -0
- package/dist/wal/index.d.ts +5 -0
- package/dist/wal/index.d.ts.map +1 -0
- package/dist/wal/index.js +4 -0
- package/dist/wal/reader.d.ts +61 -0
- package/dist/wal/reader.d.ts.map +1 -0
- package/dist/wal/reader.js +207 -0
- package/package.json +68 -3
- package/src/backends/file/index.ts +3 -0
- package/src/backends/file/leaser.ts +145 -0
- package/src/backends/file/replica-client.ts +246 -0
- package/src/db.ts +553 -0
- package/src/errors.ts +74 -0
- package/src/index.ts +26 -0
- package/src/leaser.ts +86 -0
- package/src/ltx/byte-reader.ts +46 -0
- package/src/ltx/bytes.ts +87 -0
- package/src/ltx/checksum.ts +46 -0
- package/src/ltx/compaction-level.ts +135 -0
- package/src/ltx/compactor.ts +167 -0
- package/src/ltx/constants.ts +71 -0
- package/src/ltx/crc64.ts +65 -0
- package/src/ltx/decoder.ts +282 -0
- package/src/ltx/encoder.ts +200 -0
- package/src/ltx/file-info.ts +81 -0
- package/src/ltx/filename.ts +27 -0
- package/src/ltx/header.ts +126 -0
- package/src/ltx/index.ts +27 -0
- package/src/ltx/lz4.ts +279 -0
- package/src/ltx/page-index.ts +140 -0
- package/src/ltx/page.ts +80 -0
- package/src/ltx/sink.ts +33 -0
- package/src/ltx/stream.ts +286 -0
- package/src/ltx/streaming-compactor.ts +169 -0
- package/src/ltx/trailer.ts +58 -0
- package/src/ltx/types.ts +152 -0
- package/src/lz4js.d.ts +27 -0
- package/src/replica-client.ts +222 -0
- package/src/replica-url.ts +72 -0
- package/src/replica.ts +1480 -0
- package/src/store.ts +71 -0
- package/src/util/fs.ts +82 -0
- package/src/util/logger.ts +15 -0
- package/src/util/stream.ts +28 -0
- package/src/wal/checksum.ts +39 -0
- package/src/wal/constants.ts +10 -0
- package/src/wal/index.ts +5 -0
- package/src/wal/reader.ts +264 -0
package/dist/leaser.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Distributed leasing.
|
|
3
|
+
*
|
|
4
|
+
* When multiple replicas point at the same storage path, only one may be the
|
|
5
|
+
* active writer at a time. A `Leaser` acquires a lease on the replica's storage
|
|
6
|
+
* (a `lock.json` file / object); only the lease holder is the *primary* and may
|
|
7
|
+
* write. Other replicas become idle *followers* that poll until the lease is
|
|
8
|
+
* available.
|
|
9
|
+
*
|
|
10
|
+
* This mirrors litestream's `leaser.go`/`Lease` (a storage-agnostic interface)
|
|
11
|
+
* and `s3/leaser.go` (a conditional-write S3 implementation). Acquire uses
|
|
12
|
+
* `If-None-Match: *` when no lease exists and `If-Match: <etag>` (renew) or
|
|
13
|
+
* `If-Match: <etag>` (release) otherwise, so a stale writer can never clobber a
|
|
14
|
+
* live one.
|
|
15
|
+
*/
|
|
16
|
+
import { SqliteJsStreamError } from './errors.js';
|
|
17
|
+
/** A held lease. `etag` is the conditional-write token for renew/release. */
|
|
18
|
+
export declare class Lease {
|
|
19
|
+
generation: number;
|
|
20
|
+
expiresAt: number;
|
|
21
|
+
owner: string;
|
|
22
|
+
etag: string | null;
|
|
23
|
+
constructor(generation: number, expiresAt: number, owner: string, etag?: string | null);
|
|
24
|
+
/** IsExpired reports whether the lease has passed its expiration. */
|
|
25
|
+
isExpired(now?: number): boolean;
|
|
26
|
+
/** TTL returns the remaining time before expiration, in ms. */
|
|
27
|
+
ttl(now?: number): number;
|
|
28
|
+
}
|
|
29
|
+
/** The lease is already held by another owner. */
|
|
30
|
+
export declare class LeaseExistsError extends SqliteJsStreamError {
|
|
31
|
+
owner: string;
|
|
32
|
+
expiresAt: number;
|
|
33
|
+
constructor(owner: string, expiresAt: number);
|
|
34
|
+
}
|
|
35
|
+
/** The caller no longer holds the lease (lost it or never acquired it). */
|
|
36
|
+
export declare class ErrLeaseNotHeld extends SqliteJsStreamError {
|
|
37
|
+
constructor();
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Leaser acquires, renews, and releases a lease on a storage path. The
|
|
41
|
+
* implementation must use conditional writes so concurrent acquirers cannot
|
|
42
|
+
* both win.
|
|
43
|
+
*/
|
|
44
|
+
export interface Leaser {
|
|
45
|
+
/** Acquires the lease, throwing {@link LeaseExistsError} if held elsewhere. */
|
|
46
|
+
acquireLease(): Promise<Lease>;
|
|
47
|
+
/** Renews the lease, throwing {@link ErrLeaseNotHeld} if we lost it. */
|
|
48
|
+
renewLease(lease: Lease): Promise<Lease>;
|
|
49
|
+
/** Releases the lease, throwing {@link ErrLeaseNotHeld} if we lost it. */
|
|
50
|
+
releaseLease(lease: Lease): Promise<void>;
|
|
51
|
+
}
|
|
52
|
+
export declare const DefaultLeaseTTL = 30000;
|
|
53
|
+
export declare const DefaultLeasePath = "lock.json";
|
|
54
|
+
export declare const DefaultLeaseRenewalBuffer = 5000;
|
|
55
|
+
//# sourceMappingURL=leaser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"leaser.d.ts","sourceRoot":"","sources":["../src/leaser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAElD,6EAA6E;AAC7E,qBAAa,KAAK;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,IAAI,CAAQ;gBAEf,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,GAAG,IAAW;IAO5F,qEAAqE;IACrE,SAAS,CAAC,GAAG,SAAa,GAAG,OAAO;IAIpC,+DAA+D;IAC/D,GAAG,CAAC,GAAG,SAAa,GAAG,MAAM;CAG9B;AAED,kDAAkD;AAClD,qBAAa,gBAAiB,SAAQ,mBAAmB;IACvD,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;gBAEN,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;CAW7C;AAED,2EAA2E;AAC3E,qBAAa,eAAgB,SAAQ,mBAAmB;;CAKvD;AAED;;;;GAIG;AACH,MAAM,WAAW,MAAM;IACrB,+EAA+E;IAC/E,YAAY,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC;IAC/B,wEAAwE;IACxE,UAAU,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IACzC,0EAA0E;IAC1E,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3C;AAED,eAAO,MAAM,eAAe,QAAS,CAAC;AACtC,eAAO,MAAM,gBAAgB,cAAc,CAAC;AAC5C,eAAO,MAAM,yBAAyB,OAAQ,CAAC"}
|
package/dist/leaser.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Distributed leasing.
|
|
3
|
+
*
|
|
4
|
+
* When multiple replicas point at the same storage path, only one may be the
|
|
5
|
+
* active writer at a time. A `Leaser` acquires a lease on the replica's storage
|
|
6
|
+
* (a `lock.json` file / object); only the lease holder is the *primary* and may
|
|
7
|
+
* write. Other replicas become idle *followers* that poll until the lease is
|
|
8
|
+
* available.
|
|
9
|
+
*
|
|
10
|
+
* This mirrors litestream's `leaser.go`/`Lease` (a storage-agnostic interface)
|
|
11
|
+
* and `s3/leaser.go` (a conditional-write S3 implementation). Acquire uses
|
|
12
|
+
* `If-None-Match: *` when no lease exists and `If-Match: <etag>` (renew) or
|
|
13
|
+
* `If-Match: <etag>` (release) otherwise, so a stale writer can never clobber a
|
|
14
|
+
* live one.
|
|
15
|
+
*/
|
|
16
|
+
import { SqliteJsStreamError } from "./errors.js";
|
|
17
|
+
/** A held lease. `etag` is the conditional-write token for renew/release. */
|
|
18
|
+
export class Lease {
|
|
19
|
+
generation;
|
|
20
|
+
expiresAt; // ms since epoch
|
|
21
|
+
owner;
|
|
22
|
+
etag = null;
|
|
23
|
+
constructor(generation, expiresAt, owner, etag = null) {
|
|
24
|
+
this.generation = generation;
|
|
25
|
+
this.expiresAt = expiresAt;
|
|
26
|
+
this.owner = owner;
|
|
27
|
+
this.etag = etag;
|
|
28
|
+
}
|
|
29
|
+
/** IsExpired reports whether the lease has passed its expiration. */
|
|
30
|
+
isExpired(now = Date.now()) {
|
|
31
|
+
return now > this.expiresAt;
|
|
32
|
+
}
|
|
33
|
+
/** TTL returns the remaining time before expiration, in ms. */
|
|
34
|
+
ttl(now = Date.now()) {
|
|
35
|
+
return this.expiresAt - now;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** The lease is already held by another owner. */
|
|
39
|
+
export class LeaseExistsError extends SqliteJsStreamError {
|
|
40
|
+
owner;
|
|
41
|
+
expiresAt;
|
|
42
|
+
constructor(owner, expiresAt) {
|
|
43
|
+
super('ERR_LEASE_EXISTS', owner !== ''
|
|
44
|
+
? `lease already held by ${owner} until ${new Date(expiresAt).toISOString()}`
|
|
45
|
+
: `lease already held until ${new Date(expiresAt).toISOString()}`);
|
|
46
|
+
this.name = 'LeaseExistsError';
|
|
47
|
+
this.owner = owner;
|
|
48
|
+
this.expiresAt = expiresAt;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/** The caller no longer holds the lease (lost it or never acquired it). */
|
|
52
|
+
export class ErrLeaseNotHeld extends SqliteJsStreamError {
|
|
53
|
+
constructor() {
|
|
54
|
+
super('ERR_LEASE_NOT_HELD', 'lease not held');
|
|
55
|
+
this.name = 'ErrLeaseNotHeld';
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export const DefaultLeaseTTL = 30_000; // 30s
|
|
59
|
+
export const DefaultLeasePath = 'lock.json';
|
|
60
|
+
export const DefaultLeaseRenewalBuffer = 5_000; // renew before it expires
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A sequential byte reader over an in-memory buffer. Used by the LTX decoder
|
|
3
|
+
* to walk the page block, page index, and trailer while tracking position.
|
|
4
|
+
*/
|
|
5
|
+
export declare class ByteReader {
|
|
6
|
+
private buf;
|
|
7
|
+
pos: number;
|
|
8
|
+
constructor(buf: Uint8Array, start?: number);
|
|
9
|
+
get length(): number;
|
|
10
|
+
get remaining(): number;
|
|
11
|
+
/** Reads one byte, advancing the position. Throws on EOF. */
|
|
12
|
+
readByte(): number;
|
|
13
|
+
/** Reads exactly `n` bytes, advancing the position. Throws on short input. */
|
|
14
|
+
readFull(n: number): Uint8Array;
|
|
15
|
+
/** Returns a view of the bytes in [start, end) without moving the position. */
|
|
16
|
+
slice(start: number, end: number): Uint8Array;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=byte-reader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"byte-reader.d.ts","sourceRoot":"","sources":["../../src/ltx/byte-reader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,qBAAa,UAAU;IACrB,OAAO,CAAC,GAAG,CAAa;IACxB,GAAG,EAAE,MAAM,CAAC;gBAEA,GAAG,EAAE,UAAU,EAAE,KAAK,SAAI;IAKtC,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,6DAA6D;IAC7D,QAAQ,IAAI,MAAM;IAOlB,8EAA8E;IAC9E,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU;IAO/B,+EAA+E;IAC/E,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU;CAG9C"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A sequential byte reader over an in-memory buffer. Used by the LTX decoder
|
|
3
|
+
* to walk the page block, page index, and trailer while tracking position.
|
|
4
|
+
*/
|
|
5
|
+
import { assertFull } from "./bytes.js";
|
|
6
|
+
import { LTXFormatError } from "../errors.js";
|
|
7
|
+
export class ByteReader {
|
|
8
|
+
buf;
|
|
9
|
+
pos;
|
|
10
|
+
constructor(buf, start = 0) {
|
|
11
|
+
this.buf = buf;
|
|
12
|
+
this.pos = start;
|
|
13
|
+
}
|
|
14
|
+
get length() {
|
|
15
|
+
return this.buf.length;
|
|
16
|
+
}
|
|
17
|
+
get remaining() {
|
|
18
|
+
return this.buf.length - this.pos;
|
|
19
|
+
}
|
|
20
|
+
/** Reads one byte, advancing the position. Throws on EOF. */
|
|
21
|
+
readByte() {
|
|
22
|
+
if (this.pos >= this.buf.length) {
|
|
23
|
+
throw new LTXFormatError('unexpected end of input');
|
|
24
|
+
}
|
|
25
|
+
return this.buf[this.pos++];
|
|
26
|
+
}
|
|
27
|
+
/** Reads exactly `n` bytes, advancing the position. Throws on short input. */
|
|
28
|
+
readFull(n) {
|
|
29
|
+
assertFull(this.buf, this.pos, n);
|
|
30
|
+
const out = this.buf.subarray(this.pos, this.pos + n);
|
|
31
|
+
this.pos += n;
|
|
32
|
+
return out;
|
|
33
|
+
}
|
|
34
|
+
/** Returns a view of the bytes in [start, end) without moving the position. */
|
|
35
|
+
slice(start, end) {
|
|
36
|
+
return this.buf.subarray(start, end);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Big-endian byte helpers for LTX marshalling.
|
|
3
|
+
*/
|
|
4
|
+
export declare function writeU8(buf: Uint8Array, off: number, v: number): void;
|
|
5
|
+
export declare function writeU16BE(buf: Uint8Array, off: number, v: number): void;
|
|
6
|
+
export declare function writeU32BE(buf: Uint8Array, off: number, v: number): void;
|
|
7
|
+
export declare function writeU64BE(buf: Uint8Array, off: number, v: bigint): void;
|
|
8
|
+
export declare function readU16BE(buf: Uint8Array, off: number): number;
|
|
9
|
+
export declare function readU32BE(buf: Uint8Array, off: number): number;
|
|
10
|
+
export declare function readU32LE(buf: Uint8Array, off: number): number;
|
|
11
|
+
export declare function readU64BE(buf: Uint8Array, off: number): bigint;
|
|
12
|
+
/** Converts a number to a big-endian 4-byte array. */
|
|
13
|
+
export declare function u32BE(v: number): Uint8Array;
|
|
14
|
+
/** Converts a number to a big-endian 8-byte array. */
|
|
15
|
+
export declare function u64BE(v: bigint): Uint8Array;
|
|
16
|
+
/** Converts a number to a big-endian 2-byte array. */
|
|
17
|
+
export declare function u16BE(v: number): Uint8Array;
|
|
18
|
+
/** Throws unless exactly `n` bytes are available to read. */
|
|
19
|
+
export declare function assertFull(buf: Uint8Array, off: number, n: number): void;
|
|
20
|
+
//# sourceMappingURL=bytes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bytes.d.ts","sourceRoot":"","sources":["../../src/ltx/bytes.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,wBAAgB,OAAO,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAErE;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAGxE;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAKxE;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAMxE;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAO9D;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAO9D;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAM9D;AAED,sDAAsD;AACtD,wBAAgB,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,CAI3C;AAED,sDAAsD;AACtD,wBAAgB,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,CAI3C;AAED,sDAAsD;AACtD,wBAAgB,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,CAI3C;AAED,6DAA6D;AAC7D,wBAAgB,UAAU,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAMxE"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Big-endian byte helpers for LTX marshalling.
|
|
3
|
+
*/
|
|
4
|
+
export function writeU8(buf, off, v) {
|
|
5
|
+
buf[off] = v & 0xff;
|
|
6
|
+
}
|
|
7
|
+
export function writeU16BE(buf, off, v) {
|
|
8
|
+
buf[off] = (v >>> 8) & 0xff;
|
|
9
|
+
buf[off + 1] = v & 0xff;
|
|
10
|
+
}
|
|
11
|
+
export function writeU32BE(buf, off, v) {
|
|
12
|
+
buf[off] = (v >>> 24) & 0xff;
|
|
13
|
+
buf[off + 1] = (v >>> 16) & 0xff;
|
|
14
|
+
buf[off + 2] = (v >>> 8) & 0xff;
|
|
15
|
+
buf[off + 3] = v & 0xff;
|
|
16
|
+
}
|
|
17
|
+
export function writeU64BE(buf, off, v) {
|
|
18
|
+
let n = v;
|
|
19
|
+
for (let i = 0; i < 8; i++) {
|
|
20
|
+
buf[off + (7 - i)] = Number(n & 0xffn);
|
|
21
|
+
n >>= 8n;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export function readU16BE(buf, off) {
|
|
25
|
+
return (buf[off] << 8) | buf[off + 1];
|
|
26
|
+
}
|
|
27
|
+
export function readU32BE(buf, off) {
|
|
28
|
+
return (((buf[off] | 0) << 24) >>> 0 |
|
|
29
|
+
(buf[off + 1] << 16) |
|
|
30
|
+
(buf[off + 2] << 8) |
|
|
31
|
+
buf[off + 3]) >>> 0;
|
|
32
|
+
}
|
|
33
|
+
export function readU32LE(buf, off) {
|
|
34
|
+
return (buf[off] |
|
|
35
|
+
(buf[off + 1] << 8) |
|
|
36
|
+
(buf[off + 2] << 16) |
|
|
37
|
+
((buf[off + 3] | 0) << 24)) >>> 0;
|
|
38
|
+
}
|
|
39
|
+
export function readU64BE(buf, off) {
|
|
40
|
+
let n = 0n;
|
|
41
|
+
for (let i = 0; i < 8; i++) {
|
|
42
|
+
n = (n << 8n) | BigInt(buf[off + i]);
|
|
43
|
+
}
|
|
44
|
+
return n;
|
|
45
|
+
}
|
|
46
|
+
/** Converts a number to a big-endian 4-byte array. */
|
|
47
|
+
export function u32BE(v) {
|
|
48
|
+
const b = new Uint8Array(4);
|
|
49
|
+
writeU32BE(b, 0, v);
|
|
50
|
+
return b;
|
|
51
|
+
}
|
|
52
|
+
/** Converts a number to a big-endian 8-byte array. */
|
|
53
|
+
export function u64BE(v) {
|
|
54
|
+
const b = new Uint8Array(8);
|
|
55
|
+
writeU64BE(b, 0, v);
|
|
56
|
+
return b;
|
|
57
|
+
}
|
|
58
|
+
/** Converts a number to a big-endian 2-byte array. */
|
|
59
|
+
export function u16BE(v) {
|
|
60
|
+
const b = new Uint8Array(2);
|
|
61
|
+
writeU16BE(b, 0, v);
|
|
62
|
+
return b;
|
|
63
|
+
}
|
|
64
|
+
/** Throws unless exactly `n` bytes are available to read. */
|
|
65
|
+
export function assertFull(buf, off, n) {
|
|
66
|
+
if (off + n > buf.length) {
|
|
67
|
+
throw new RangeError(`short buffer: need ${n} bytes at offset ${off}, have ${buf.length - off}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LTX checksum helpers: per-page checksums and the rolling DB checksum.
|
|
3
|
+
*/
|
|
4
|
+
import { Crc64 } from './crc64.js';
|
|
5
|
+
/**
|
|
6
|
+
* ChecksumPage returns a CRC-64 checksum that combines the page number with
|
|
7
|
+
* the page data: `ChecksumFlag | CRC64-ISO(pgno_be4 ++ data)`.
|
|
8
|
+
*/
|
|
9
|
+
export declare function checksumPage(pgno: number, data: Uint8Array): bigint;
|
|
10
|
+
export declare function checksumPageWithHasher(h: Crc64, pgno: number, data: Uint8Array): bigint;
|
|
11
|
+
/**
|
|
12
|
+
* ChecksumReader computes the rolling DB checksum over a byte buffer split
|
|
13
|
+
* into pages of `pageSize`. The "lock page" is skipped entirely (its checksum
|
|
14
|
+
* contributes nothing), matching Go's `ChecksumReader`.
|
|
15
|
+
*
|
|
16
|
+
* For large databases this should later read page-by-page from a file rather
|
|
17
|
+
* than buffering the whole DB; provided as a buffer for Milestone 1.
|
|
18
|
+
*/
|
|
19
|
+
export declare function checksumReader(data: Uint8Array, pageSize: number): bigint;
|
|
20
|
+
//# sourceMappingURL=checksum.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checksum.d.ts","sourceRoot":"","sources":["../../src/ltx/checksum.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGnC;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CAKnE;AAED,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CAKvF;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAWzE"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LTX checksum helpers: per-page checksums and the rolling DB checksum.
|
|
3
|
+
*/
|
|
4
|
+
import { ChecksumFlag, lockPgno } from "./constants.js";
|
|
5
|
+
import { Crc64 } from "./crc64.js";
|
|
6
|
+
import { u32BE } from "./bytes.js";
|
|
7
|
+
/**
|
|
8
|
+
* ChecksumPage returns a CRC-64 checksum that combines the page number with
|
|
9
|
+
* the page data: `ChecksumFlag | CRC64-ISO(pgno_be4 ++ data)`.
|
|
10
|
+
*/
|
|
11
|
+
export function checksumPage(pgno, data) {
|
|
12
|
+
const h = new Crc64();
|
|
13
|
+
h.update(u32BE(pgno));
|
|
14
|
+
h.update(data);
|
|
15
|
+
return ChecksumFlag | h.sum64();
|
|
16
|
+
}
|
|
17
|
+
export function checksumPageWithHasher(h, pgno, data) {
|
|
18
|
+
h.reset();
|
|
19
|
+
h.update(u32BE(pgno));
|
|
20
|
+
h.update(data);
|
|
21
|
+
return ChecksumFlag | h.sum64();
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* ChecksumReader computes the rolling DB checksum over a byte buffer split
|
|
25
|
+
* into pages of `pageSize`. The "lock page" is skipped entirely (its checksum
|
|
26
|
+
* contributes nothing), matching Go's `ChecksumReader`.
|
|
27
|
+
*
|
|
28
|
+
* For large databases this should later read page-by-page from a file rather
|
|
29
|
+
* than buffering the whole DB; provided as a buffer for Milestone 1.
|
|
30
|
+
*/
|
|
31
|
+
export function checksumReader(data, pageSize) {
|
|
32
|
+
const lockPg = lockPgno(pageSize);
|
|
33
|
+
let chksum = 0n;
|
|
34
|
+
let offset = 0;
|
|
35
|
+
for (let pgno = 1; offset < data.length; pgno++, offset += pageSize) {
|
|
36
|
+
const page = data.subarray(offset, offset + pageSize);
|
|
37
|
+
if (pgno !== lockPg) {
|
|
38
|
+
chksum = ChecksumFlag | (chksum ^ checksumPage(pgno, page));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return chksum;
|
|
42
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-level compaction configuration.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors litestream's `compaction_level.go`. Litestream stores raw LTX files
|
|
5
|
+
* at level 0 and progressively merges them into higher levels at increasing
|
|
6
|
+
* time intervals. Each level is compacted on its own wall-clock bucket; a level
|
|
7
|
+
* is compacted at most once per bucket so repeated writes are coalesced.
|
|
8
|
+
*
|
|
9
|
+
* Defaults (matching litestream):
|
|
10
|
+
* - L0: raw LTX (no interval)
|
|
11
|
+
* - L1: every 30s
|
|
12
|
+
* - L2: every 5m
|
|
13
|
+
* - L3: every 1h
|
|
14
|
+
*/
|
|
15
|
+
/** CompactionLevel describes a single compaction tier. */
|
|
16
|
+
export interface CompactionLevel {
|
|
17
|
+
/** The numeric level. Level 0 is raw, never compacted. */
|
|
18
|
+
level: number;
|
|
19
|
+
/** Frequency (ms) that files are compacted from the previous level. 0 for level 0. */
|
|
20
|
+
intervalMs: number;
|
|
21
|
+
}
|
|
22
|
+
/** CompactionLevels is an ordered set of non-snapshot compaction levels. */
|
|
23
|
+
export declare class CompactionLevels {
|
|
24
|
+
private levels;
|
|
25
|
+
constructor(levels: CompactionLevel[]);
|
|
26
|
+
/** Returns the level configuration at `level`. */
|
|
27
|
+
level(level: number): CompactionLevel;
|
|
28
|
+
/** MaxLevel returns the highest non-snapshot compaction level. */
|
|
29
|
+
maxLevel(): number;
|
|
30
|
+
/** SnapshotLevel returns a pseudo level for full snapshots. */
|
|
31
|
+
snapshotLevel(): CompactionLevel;
|
|
32
|
+
/** PrevLevel returns the level that compacts into `level` (-1 if none). */
|
|
33
|
+
prevLevel(level: number): number;
|
|
34
|
+
/** NextLevel returns the level that `level` compacts into (-1 at the top). */
|
|
35
|
+
nextLevel(level: number): number;
|
|
36
|
+
/** Validate checks the levels are ordered, bounded, and have sane intervals. */
|
|
37
|
+
validate(): void;
|
|
38
|
+
/** IsValidLevel returns true if `level` is a valid compaction level. */
|
|
39
|
+
isValidLevel(level: number): boolean;
|
|
40
|
+
/** Returns a copy of the underlying levels. */
|
|
41
|
+
toArray(): CompactionLevel[];
|
|
42
|
+
}
|
|
43
|
+
/** Canonical default compaction configuration (matches litestream). */
|
|
44
|
+
export declare function defaultCompactionLevels(): CompactionLevels;
|
|
45
|
+
/**
|
|
46
|
+
* PrevCompactionAt returns the start of the current compaction bucket for
|
|
47
|
+
* `intervalMs`. Compaction for a level only proceeds once per bucket, so
|
|
48
|
+
* repeated syncs across a window collapse into one compacted file.
|
|
49
|
+
*/
|
|
50
|
+
export declare function prevCompactionAt(now: number, intervalMs: number): number;
|
|
51
|
+
/** NextCompactionAt returns the start of the next compaction bucket. */
|
|
52
|
+
export declare function nextCompactionAt(now: number, intervalMs: number): number;
|
|
53
|
+
/** Interval (ms) constants matching litestream's defaults. */
|
|
54
|
+
export declare const DefaultSnapshotIntervalMs: number;
|
|
55
|
+
export declare const DefaultSnapshotRetentionMs: number;
|
|
56
|
+
export declare const DefaultL0RetentionMs: number;
|
|
57
|
+
export declare const DefaultL0RetentionCheckIntervalMs: number;
|
|
58
|
+
//# sourceMappingURL=compaction-level.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compaction-level.d.ts","sourceRoot":"","sources":["../../src/ltx/compaction-level.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,0DAA0D;AAC1D,MAAM,WAAW,eAAe;IAC9B,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAC;IACd,sFAAsF;IACtF,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,4EAA4E;AAC5E,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAoB;gBAEtB,MAAM,EAAE,eAAe,EAAE;IAKrC,kDAAkD;IAClD,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe;IAUrC,kEAAkE;IAClE,QAAQ,IAAI,MAAM;IAIlB,+DAA+D;IAC/D,aAAa,IAAI,eAAe;IAIhC,2EAA2E;IAC3E,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAKhC,8EAA8E;IAC9E,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAMhC,gFAAgF;IAChF,QAAQ,IAAI,IAAI;IAuBhB,wEAAwE;IACxE,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAKpC,+CAA+C;IAC/C,OAAO,IAAI,eAAe,EAAE;CAG7B;AAED,uEAAuE;AACvE,wBAAgB,uBAAuB,IAAI,gBAAgB,CAO1D;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAGxE;AAED,wEAAwE;AACxE,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAExE;AAED,8DAA8D;AAC9D,eAAO,MAAM,yBAAyB,QAAsB,CAAC;AAC7D,eAAO,MAAM,0BAA0B,QAAsB,CAAC;AAC9D,eAAO,MAAM,oBAAoB,QAAgB,CAAC;AAClD,eAAO,MAAM,iCAAiC,QAAY,CAAC"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-level compaction configuration.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors litestream's `compaction_level.go`. Litestream stores raw LTX files
|
|
5
|
+
* at level 0 and progressively merges them into higher levels at increasing
|
|
6
|
+
* time intervals. Each level is compacted on its own wall-clock bucket; a level
|
|
7
|
+
* is compacted at most once per bucket so repeated writes are coalesced.
|
|
8
|
+
*
|
|
9
|
+
* Defaults (matching litestream):
|
|
10
|
+
* - L0: raw LTX (no interval)
|
|
11
|
+
* - L1: every 30s
|
|
12
|
+
* - L2: every 5m
|
|
13
|
+
* - L3: every 1h
|
|
14
|
+
*/
|
|
15
|
+
import { SnapshotLevel } from "./constants.js";
|
|
16
|
+
import { InvalidArgumentError } from "../errors.js";
|
|
17
|
+
/** CompactionLevels is an ordered set of non-snapshot compaction levels. */
|
|
18
|
+
export class CompactionLevels {
|
|
19
|
+
levels;
|
|
20
|
+
constructor(levels) {
|
|
21
|
+
this.levels = [...levels].sort((a, b) => a.level - b.level);
|
|
22
|
+
this.validate();
|
|
23
|
+
}
|
|
24
|
+
/** Returns the level configuration at `level`. */
|
|
25
|
+
level(level) {
|
|
26
|
+
if (level === SnapshotLevel) {
|
|
27
|
+
throw new InvalidArgumentError('snapshot level has no compaction interval');
|
|
28
|
+
}
|
|
29
|
+
if (level < 0 || level > this.maxLevel()) {
|
|
30
|
+
throw new InvalidArgumentError(`level out of bounds: ${level}`);
|
|
31
|
+
}
|
|
32
|
+
return this.levels[level];
|
|
33
|
+
}
|
|
34
|
+
/** MaxLevel returns the highest non-snapshot compaction level. */
|
|
35
|
+
maxLevel() {
|
|
36
|
+
return this.levels.length - 1;
|
|
37
|
+
}
|
|
38
|
+
/** SnapshotLevel returns a pseudo level for full snapshots. */
|
|
39
|
+
snapshotLevel() {
|
|
40
|
+
return { level: SnapshotLevel, intervalMs: 0 };
|
|
41
|
+
}
|
|
42
|
+
/** PrevLevel returns the level that compacts into `level` (-1 if none). */
|
|
43
|
+
prevLevel(level) {
|
|
44
|
+
if (level === SnapshotLevel)
|
|
45
|
+
return this.maxLevel();
|
|
46
|
+
return level - 1;
|
|
47
|
+
}
|
|
48
|
+
/** NextLevel returns the level that `level` compacts into (-1 at the top). */
|
|
49
|
+
nextLevel(level) {
|
|
50
|
+
if (level === SnapshotLevel)
|
|
51
|
+
return -1;
|
|
52
|
+
if (level === this.maxLevel())
|
|
53
|
+
return SnapshotLevel;
|
|
54
|
+
return level + 1;
|
|
55
|
+
}
|
|
56
|
+
/** Validate checks the levels are ordered, bounded, and have sane intervals. */
|
|
57
|
+
validate() {
|
|
58
|
+
if (this.levels.length === 0) {
|
|
59
|
+
throw new InvalidArgumentError('at least one compaction level is required');
|
|
60
|
+
}
|
|
61
|
+
for (let i = 0; i < this.levels.length; i++) {
|
|
62
|
+
const lvl = this.levels[i];
|
|
63
|
+
if (lvl.level !== i) {
|
|
64
|
+
throw new InvalidArgumentError(`compaction level number out of order: ${lvl.level}, expected ${i}`);
|
|
65
|
+
}
|
|
66
|
+
if (lvl.level > SnapshotLevel - 1) {
|
|
67
|
+
throw new InvalidArgumentError(`compaction level cannot exceed ${SnapshotLevel - 1}`);
|
|
68
|
+
}
|
|
69
|
+
if (lvl.level === 0 && lvl.intervalMs !== 0) {
|
|
70
|
+
throw new InvalidArgumentError('cannot set interval on compaction level zero');
|
|
71
|
+
}
|
|
72
|
+
if (lvl.level !== 0 && lvl.intervalMs <= 0) {
|
|
73
|
+
throw new InvalidArgumentError(`interval required for level ${lvl.level}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/** IsValidLevel returns true if `level` is a valid compaction level. */
|
|
78
|
+
isValidLevel(level) {
|
|
79
|
+
if (level === SnapshotLevel)
|
|
80
|
+
return true;
|
|
81
|
+
return level >= 0 && level < this.levels.length;
|
|
82
|
+
}
|
|
83
|
+
/** Returns a copy of the underlying levels. */
|
|
84
|
+
toArray() {
|
|
85
|
+
return this.levels.map((l) => ({ ...l }));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/** Canonical default compaction configuration (matches litestream). */
|
|
89
|
+
export function defaultCompactionLevels() {
|
|
90
|
+
return new CompactionLevels([
|
|
91
|
+
{ level: 0, intervalMs: 0 },
|
|
92
|
+
{ level: 1, intervalMs: 30_000 },
|
|
93
|
+
{ level: 2, intervalMs: 300_000 },
|
|
94
|
+
{ level: 3, intervalMs: 3_600_000 },
|
|
95
|
+
]);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* PrevCompactionAt returns the start of the current compaction bucket for
|
|
99
|
+
* `intervalMs`. Compaction for a level only proceeds once per bucket, so
|
|
100
|
+
* repeated syncs across a window collapse into one compacted file.
|
|
101
|
+
*/
|
|
102
|
+
export function prevCompactionAt(now, intervalMs) {
|
|
103
|
+
if (intervalMs <= 0)
|
|
104
|
+
return now;
|
|
105
|
+
return Math.floor(now / intervalMs) * intervalMs;
|
|
106
|
+
}
|
|
107
|
+
/** NextCompactionAt returns the start of the next compaction bucket. */
|
|
108
|
+
export function nextCompactionAt(now, intervalMs) {
|
|
109
|
+
return prevCompactionAt(now, intervalMs) + intervalMs;
|
|
110
|
+
}
|
|
111
|
+
/** Interval (ms) constants matching litestream's defaults. */
|
|
112
|
+
export const DefaultSnapshotIntervalMs = 24 * 60 * 60 * 1000; // 24h
|
|
113
|
+
export const DefaultSnapshotRetentionMs = 24 * 60 * 60 * 1000; // 24h
|
|
114
|
+
export const DefaultL0RetentionMs = 5 * 60 * 1000; // 5m
|
|
115
|
+
export const DefaultL0RetentionCheckIntervalMs = 15 * 1000; // 15s
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LTX Compactor merges multiple LTX files (readers) into a single stream,
|
|
3
|
+
* where later files override earlier ones for the same page number.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors Go's `ltx.Compactor`. Used by restore (snapshot + incremental L0
|
|
6
|
+
* files) and by multi-level compaction.
|
|
7
|
+
*/
|
|
8
|
+
import type { Header, Trailer } from './types.js';
|
|
9
|
+
import type { ByteSink } from './sink.js';
|
|
10
|
+
/** Compactor merges LTX readers into a single writer. */
|
|
11
|
+
export declare class Compactor {
|
|
12
|
+
private enc;
|
|
13
|
+
private inputs;
|
|
14
|
+
private _headerFlags;
|
|
15
|
+
private allowNonContiguousTXIDs;
|
|
16
|
+
constructor(sink: ByteSink, readers: Uint8Array[]);
|
|
17
|
+
get headerFlags(): number;
|
|
18
|
+
set headerFlags(flags: number);
|
|
19
|
+
/** AllowNonContiguousTXIDs disables contiguous-TXID validation between inputs. */
|
|
20
|
+
setAllowNonContiguousTXIDs(v: boolean): void;
|
|
21
|
+
/** Header returns the output header (after Compact). */
|
|
22
|
+
Header(): Header;
|
|
23
|
+
/** Trailer returns the output trailer (after Compact). */
|
|
24
|
+
Trailer(): Trailer;
|
|
25
|
+
/** Compact merges all input readers into a single LTX stream. */
|
|
26
|
+
compact(): void;
|
|
27
|
+
private writePageBlock;
|
|
28
|
+
/** Fills input buffers and returns the smallest available page number. */
|
|
29
|
+
private fillPageBuffers;
|
|
30
|
+
/** Writes the buffer with a matching pgno from the latest input. */
|
|
31
|
+
private writePageBuffer;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=compactor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compactor.d.ts","sourceRoot":"","sources":["../../src/ltx/compactor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAc,OAAO,EAAE,MAAM,YAAY,CAAC;AAE9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAW1C,yDAAyD;AACzD,qBAAa,SAAS;IACpB,OAAO,CAAC,GAAG,CAAU;IACrB,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,uBAAuB,CAAS;gBAE5B,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE;IASjD,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,IAAI,WAAW,CAAC,KAAK,EAAE,MAAM,EAE5B;IAED,kFAAkF;IAClF,0BAA0B,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI;IAI5C,wDAAwD;IACxD,MAAM,IAAI,MAAM;IAIhB,0DAA0D;IAC1D,OAAO,IAAI,OAAO;IAIlB,iEAAiE;IACjE,OAAO,IAAI,IAAI;IA2Df,OAAO,CAAC,cAAc;IAYtB,0EAA0E;IAC1E,OAAO,CAAC,eAAe;IAevB,oEAAoE;IACpE,OAAO,CAAC,eAAe;CAiBxB"}
|