@platformatic/sqlite-js-stream-s3 0.2.1 → 0.3.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/index.d.ts CHANGED
@@ -5,6 +5,6 @@
5
5
  * factory, so `newReplicaClientFromURL('s3://bucket/prefix')` resolves after
6
6
  * this addon is loaded.
7
7
  */
8
- export { S3ReplicaClient, newReplicaClientFromURL, ReplicaClientType, type S3ClientLike, type S3ReplicaClientOptions, } from './replica-client.ts';
8
+ export { S3ReplicaClient, newReplicaClientFromURL, isFenced, GenerationMetadataKey, GenerationObjectName, ReplicaClientType, type GenerationFence, type GenerationState, type S3ClientLike, type S3ReplicaClientOptions, } from './replica-client.ts';
9
9
  export { S3Leaser } from './leaser.ts';
10
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,iBAAiB,EACjB,KAAK,YAAY,EACjB,KAAK,sBAAsB,GAC5B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,QAAQ,EACR,qBAAqB,EACrB,oBAAoB,EACpB,iBAAiB,EACjB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,sBAAsB,GAC5B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@
5
5
  * factory, so `newReplicaClientFromURL('s3://bucket/prefix')` resolves after
6
6
  * this addon is loaded.
7
7
  */
8
- export { S3ReplicaClient, newReplicaClientFromURL, ReplicaClientType, } from "./replica-client.js";
8
+ export { S3ReplicaClient, newReplicaClientFromURL, isFenced, GenerationMetadataKey, GenerationObjectName, ReplicaClientType, } from "./replica-client.js";
9
9
  export { S3Leaser } from "./leaser.js";
10
10
  import { registerReplicaClientFactory } from '@platformatic/sqlite-js-stream';
11
11
  import { newReplicaClientFromURL } from "./replica-client.js";
@@ -1 +1 @@
1
- {"version":3,"file":"leaser.d.ts","sourceRoot":"","sources":["../src/leaser.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAQH,OAAO,EAIL,KAAK,EAEL,KAAK,MAAM,EACZ,MAAM,gCAAgC,CAAC;AAExC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAwDxD,wEAAwE;AACxE,qBAAa,QAAS,YAAW,MAAM;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,KAAK,CAAS;gBAEV,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,YAAY,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAUrG,YAAY,IAAI,OAAO,CAAC,KAAK,CAAC;IAuC9B,UAAU,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IA2BxC,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;YAiBjC,SAAS;CAoBxB"}
1
+ {"version":3,"file":"leaser.d.ts","sourceRoot":"","sources":["../src/leaser.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAQH,OAAO,EAIL,KAAK,EAEL,KAAK,MAAM,EACZ,MAAM,gCAAgC,CAAC;AAExC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGxD,wEAAwE;AACxE,qBAAa,QAAS,YAAW,MAAM;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,KAAK,CAAS;gBAEV,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,YAAY,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAUrG,YAAY,IAAI,OAAO,CAAC,KAAK,CAAC;IAuC9B,UAAU,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IA2BxC,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;YAiBjC,SAAS;CAoBxB"}
package/dist/leaser.js CHANGED
@@ -7,61 +7,7 @@
7
7
  */
8
8
  import { DeleteObjectCommand, GetObjectCommand, PutObjectCommand, } from '@aws-sdk/client-s3';
9
9
  import { DefaultLeasePath, DefaultLeaseTTL, ErrLeaseNotHeld, Lease, LeaseExistsError, } from '@platformatic/sqlite-js-stream';
10
- /** Reads all bytes from an S3 body (stream or Buffer). */
11
- async function readBody(body) {
12
- // AWS SDK v3 returns a mix; normalize to a Uint8Array.
13
- if (body instanceof Uint8Array)
14
- return body;
15
- if (typeof body?.on === 'function') {
16
- // Node stream.
17
- const chunks = [];
18
- for await (const chunk of body) {
19
- chunks.push(typeof chunk === 'string' ? new TextEncoder().encode(chunk) : chunk);
20
- }
21
- let total = 0;
22
- for (const c of chunks)
23
- total += c.length;
24
- const out = new Uint8Array(total);
25
- let o = 0;
26
- for (const c of chunks) {
27
- out.set(c, o);
28
- o += c.length;
29
- }
30
- return out;
31
- }
32
- // Web ReadableStream or Buffer.
33
- if (typeof body?.getReader === 'function') {
34
- const reader = body.getReader();
35
- const chunks = [];
36
- for (;;) {
37
- const { done, value } = await reader.read();
38
- if (done)
39
- break;
40
- chunks.push(value);
41
- }
42
- let total = 0;
43
- for (const c of chunks)
44
- total += c.length;
45
- const out = new Uint8Array(total);
46
- let o = 0;
47
- for (const c of chunks) {
48
- out.set(c, o);
49
- o += c.length;
50
- }
51
- return out;
52
- }
53
- return new Uint8Array(body);
54
- }
55
- function isPreconditionFailed(err) {
56
- const code = err?.$metadata?.httpStatusCode;
57
- const name = err?.name ?? '';
58
- return code === 412 || name === 'PreconditionFailed';
59
- }
60
- function isNotFound(err) {
61
- const code = err?.$metadata?.httpStatusCode;
62
- const name = err?.name ?? '';
63
- return code === 404 || name === 'NoSuchKey' || name === 'NotFound';
64
- }
10
+ import { isNotFound, isPreconditionFailed, readBody } from "./util.js";
65
11
  /** S3Leaser acquires/renews/releases a lease object in an S3 bucket. */
66
12
  export class S3Leaser {
67
13
  bucket;
@@ -10,6 +10,26 @@
10
10
  *
11
11
  * Creation timestamps are preserved on upload as the `ltx-timestamp` object
12
12
  * metadata; listing falls back to the object's `LastModified`.
13
+ *
14
+ * The client also supports *fenced writes* (see {@link S3ReplicaClient.registerGeneration}).
15
+ * S3 cannot check one object and write another in a single request, so fencing
16
+ * is a protocol built from conditional writes:
17
+ *
18
+ * - `{prefix}/generation.json` holds the current generation and a list of
19
+ * *fences*. A fence `(generation, txid)` records the latest TXID of the
20
+ * replica right after `generation` was registered. Registering is a
21
+ * conditional write (`If-Match` / `If-None-Match: *`) that only raises the
22
+ * generation; the fence is then added with another conditional write.
23
+ * - LTX files of a fenced client are written with `If-None-Match: *`, so a TXID
24
+ * range is written once per level, and carry their generation in the
25
+ * `ltx-generation` metadata. A file with no `ltx-generation` is generation 0.
26
+ * - Listings ignore a file whose generation is lower than a fence's generation
27
+ * and whose `maxTXID` is above that fence's TXID: it was written by a
28
+ * superseded writer after the new one read the replica.
29
+ * - After each upload, a fenced client re-reads the generation object and fails
30
+ * with {@link ErrGenerationSuperseded} if a higher generation is registered.
31
+ * An upload that resolves was therefore written while its generation was the
32
+ * latest, and every later generation sees it.
13
33
  */
14
34
  import { Readable } from 'node:stream';
15
35
  import { type FileInfo, type Logger, type LTXFilesOptions, type OpenLTXFileOptions, type ReplicaClient, type WriteLTXFileOptions } from '@platformatic/sqlite-js-stream';
@@ -37,13 +57,49 @@ export interface S3ReplicaClientOptions {
37
57
  sessionToken?: string;
38
58
  /** Inject a preconfigured client. Mostly for tests. */
39
59
  client?: S3ClientLike;
60
+ /**
61
+ * Fenced-write generation, or `null` (the default) to disable fencing. Set
62
+ * by {@link S3ReplicaClient.registerGeneration}; when set, uploads and
63
+ * deletions fail with {@link ErrGenerationSuperseded} once a higher
64
+ * generation is registered.
65
+ */
66
+ generation?: bigint | null;
67
+ }
68
+ /** Name of the generation object, relative to the replica prefix. */
69
+ export declare const GenerationObjectName = "generation.json";
70
+ /** Object metadata key carrying the generation of a fenced LTX upload. */
71
+ export declare const GenerationMetadataKey = "ltx-generation";
72
+ /**
73
+ * A fence: `generation` was registered when the latest TXID of the replica was
74
+ * `txid`. Files of lower generations with a `maxTXID` above `txid` are ignored.
75
+ */
76
+ export interface GenerationFence {
77
+ generation: bigint;
78
+ txid: bigint;
79
+ }
80
+ /** Contents of the generation object. */
81
+ export interface GenerationState {
82
+ /** The highest registered generation. */
83
+ generation: bigint;
84
+ /** Fences, in registration order (one per generation that completed registration). */
85
+ fences: GenerationFence[];
40
86
  }
87
+ /**
88
+ * Returns true if a file of `generation` ending at `maxTXID` is part of the
89
+ * replica: no fence of a higher generation was recorded below `maxTXID`.
90
+ */
91
+ export declare function isFenced(fences: readonly GenerationFence[], generation: bigint, maxTXID: bigint): boolean;
41
92
  /** S3ReplicaClient writes LTX files to an Amazon S3 bucket. */
42
93
  export declare class S3ReplicaClient implements ReplicaClient {
43
94
  readonly bucket: string;
44
95
  readonly prefix: string;
45
96
  private client;
46
97
  private logger;
98
+ private generation;
99
+ /** The higher generation that superseded this client, once observed. */
100
+ private supersededBy;
101
+ /** Generation of listed objects, keyed by `key` + ETag (objects are immutable). */
102
+ private readonly objectGenerations;
47
103
  constructor(opts: S3ReplicaClientOptions);
48
104
  type(): string;
49
105
  /** Best-effort connectivity check; real I/O errors surface on first use. */
@@ -55,10 +111,72 @@ export declare class S3ReplicaClient implements ReplicaClient {
55
111
  private levelPrefix;
56
112
  /** Returns the object key for a level and TXID range. */
57
113
  private fileKey;
114
+ /** Returns the key of the generation object. */
115
+ private generationKey;
116
+ /** Current fenced-write generation, or `null` when fencing is disabled. */
117
+ getGeneration(): bigint | null;
118
+ /** Reads the generation object, or returns `null` if fencing was never used. */
119
+ getGenerationState(): Promise<GenerationState | null>;
120
+ private readGenerationObject;
121
+ /**
122
+ * Writes the generation object if it was not changed since it was read with
123
+ * `etag` (`null`: if it does not exist). Returns false on a lost race.
124
+ */
125
+ private writeGenerationObject;
126
+ /** Records that this client was superseded by `generation` and returns the error. */
127
+ private superseded;
128
+ /**
129
+ * Fails with {@link ErrGenerationSuperseded} if a generation higher than this
130
+ * client's is registered. A no-op when fencing is disabled.
131
+ */
132
+ private assertGeneration;
133
+ /**
134
+ * Raises the replica's generation to `generation`, failing with
135
+ * {@link ErrGenerationSuperseded} if a higher one is already registered, and
136
+ * records a fence at the replica's latest TXID as read after the
137
+ * registration. From then on, files of lower generations above that TXID
138
+ * are ignored by every listing, and uploads and deletions of lower
139
+ * generations fail once they observe the new generation.
140
+ *
141
+ * Call it before restoring: the restore then sees every file that a former
142
+ * writer can still make part of the replica. Registering the current
143
+ * generation again is a no-op that keeps its fence.
144
+ */
145
+ registerGeneration(generation: bigint): Promise<void>;
146
+ /** Returns the generation of an object (from `ltx-generation`), or null if it is gone. */
147
+ private objectGeneration;
148
+ private rememberGeneration;
149
+ /**
150
+ * Lists the LTX files of a level. When the replica has fences, files ending
151
+ * above the lowest fence need their generation (a HeadObject request, cached
152
+ * per key and ETag), and those written by a superseded writer are skipped.
153
+ */
58
154
  ltxFiles(opts: LTXFilesOptions): AsyncIterable<FileInfo>;
59
155
  openLtxFile(opts: OpenLTXFileOptions): Promise<Readable>;
60
156
  writeLtxFile(opts: WriteLTXFileOptions, body: AsyncIterable<Uint8Array | string>): Promise<FileInfo>;
157
+ /**
158
+ * Creates a fenced LTX object with `If-None-Match: *`. If the key already
159
+ * exists:
160
+ * - written by a higher generation: this client is superseded;
161
+ * - written by this generation (a retried upload), or by a lower one but
162
+ * still part of the replica: it holds the same transactions, so it is
163
+ * kept and its metadata returned;
164
+ * - otherwise it is a superseded writer's file, replaced with `If-Match`.
165
+ * With `probe`, the key is checked with HeadObject before the first write.
166
+ * Returns null when this call created the object.
167
+ */
168
+ private commitFenced;
169
+ /**
170
+ * Deletes LTX files. A fenced client first checks that its generation is
171
+ * still the latest and fails with {@link ErrGenerationSuperseded} otherwise
172
+ * (a deletion sent just before a new generation registers still applies).
173
+ */
61
174
  deleteLtxFiles(infos: FileInfo[]): Promise<void>;
175
+ /**
176
+ * Deletes every object under the prefix except the generation object, so a
177
+ * superseded writer stays fenced. A fenced client checks its generation
178
+ * first, as {@link deleteLtxFiles} does.
179
+ */
62
180
  deleteAll(): Promise<void>;
63
181
  }
64
182
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"replica-client.d.ts","sourceRoot":"","sources":["../src/replica-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAgBvC,OAAO,EAOL,KAAK,QAAQ,EACb,KAAK,MAAM,EACX,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACzB,MAAM,gCAAgC,CAAC;AAExC,wEAAwE;AACxE,eAAO,MAAM,iBAAiB,OAAO,CAAC;AAEtC;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;CAClC;AAED,iDAAiD;AACjD,MAAM,WAAW,sBAAsB;IACrC,gCAAgC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yDAAyD;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uDAAuD;IACvD,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAuBD,+DAA+D;AAC/D,qBAAa,eAAgB,YAAW,aAAa;IACnD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,MAAM,CAAsB;gBAExB,IAAI,EAAE,sBAAsB;IAqBxC,IAAI,IAAI,MAAM;IAId,4EAA4E;IACtE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ3B,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI/B,4DAA4D;IAC5D,SAAS,IAAI,MAAM;IAInB,sCAAsC;IACtC,OAAO,CAAC,WAAW;IAInB,yDAAyD;IACzD,OAAO,CAAC,OAAO;IAIR,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,aAAa,CAAC,QAAQ,CAAC;IAkCzD,WAAW,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,QAAQ,CAAC;IAwCxD,YAAY,CAAC,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,aAAa,CAAC,UAAU,GAAG,MAAM,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC;IA6HpG,cAAc,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAchD,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;CAoBjC;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,eAAe,GAAG,IAAI,EAC7B,QAAQ,EAAE,MAAM,GAAG,IAAI,GACtB,aAAa,CAaf"}
1
+ {"version":3,"file":"replica-client.d.ts","sourceRoot":"","sources":["../src/replica-client.ts"],"names":[],"mappings":"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"}