@platformatic/sqlite-js-stream-s3 0.2.1 → 0.4.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 S3DeletePrefixOptions, 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,qBAAqB,EAC1B,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,76 @@ 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;
40
67
  }
68
+ /** Configuration for {@link S3ReplicaClient.deletePrefix}. */
69
+ export interface S3DeletePrefixOptions {
70
+ /** S3 bucket name. Required. */
71
+ bucket: string;
72
+ /**
73
+ * Prefix to delete: the replica at this prefix and every replica under
74
+ * `prefix/` (`a` covers `a` and `a/b`, not `ab`). Leading/trailing slashes
75
+ * are normalized away. Must not be empty.
76
+ */
77
+ prefix: string;
78
+ /** AWS region. Defaults to the AWS SDK region resolution chain. */
79
+ region?: string;
80
+ /** Custom endpoint URL (e.g. for MinIO / LocalStack). */
81
+ endpoint?: string;
82
+ accessKeyId?: string;
83
+ secretAccessKey?: string;
84
+ sessionToken?: string;
85
+ /** Inject a preconfigured client. */
86
+ client?: S3ClientLike;
87
+ /**
88
+ * Fences the deletion: it fails with {@link ErrGenerationSuperseded} if a
89
+ * replica under the prefix has a higher generation, checked before deleting
90
+ * any of its objects (best effort, see {@link S3ReplicaClient.deletePrefix}).
91
+ * `null` (the default) deletes unconditionally.
92
+ */
93
+ generation?: bigint | null;
94
+ }
95
+ /** Name of the generation object, relative to the replica prefix. */
96
+ export declare const GenerationObjectName = "generation.json";
97
+ /** Object metadata key carrying the generation of a fenced LTX upload. */
98
+ export declare const GenerationMetadataKey = "ltx-generation";
99
+ /**
100
+ * A fence: `generation` was registered when the latest TXID of the replica was
101
+ * `txid`. Files of lower generations with a `maxTXID` above `txid` are ignored.
102
+ */
103
+ export interface GenerationFence {
104
+ generation: bigint;
105
+ txid: bigint;
106
+ }
107
+ /** Contents of the generation object. */
108
+ export interface GenerationState {
109
+ /** The highest registered generation. */
110
+ generation: bigint;
111
+ /** Fences, in registration order (one per generation that completed registration). */
112
+ fences: GenerationFence[];
113
+ }
114
+ /**
115
+ * Returns true if a file of `generation` ending at `maxTXID` is part of the
116
+ * replica: no fence of a higher generation was recorded below `maxTXID`.
117
+ */
118
+ export declare function isFenced(fences: readonly GenerationFence[], generation: bigint, maxTXID: bigint): boolean;
41
119
  /** S3ReplicaClient writes LTX files to an Amazon S3 bucket. */
42
120
  export declare class S3ReplicaClient implements ReplicaClient {
43
121
  readonly bucket: string;
44
122
  readonly prefix: string;
45
123
  private client;
46
124
  private logger;
125
+ private generation;
126
+ /** The higher generation that superseded this client, once observed. */
127
+ private supersededBy;
128
+ /** Generation of listed objects, keyed by `key` + ETag (objects are immutable). */
129
+ private readonly objectGenerations;
47
130
  constructor(opts: S3ReplicaClientOptions);
48
131
  type(): string;
49
132
  /** Best-effort connectivity check; real I/O errors surface on first use. */
@@ -55,10 +138,95 @@ export declare class S3ReplicaClient implements ReplicaClient {
55
138
  private levelPrefix;
56
139
  /** Returns the object key for a level and TXID range. */
57
140
  private fileKey;
141
+ /** Returns the key of the generation object. */
142
+ private generationKey;
143
+ /** Current fenced-write generation, or `null` when fencing is disabled. */
144
+ getGeneration(): bigint | null;
145
+ /** Reads the generation object, or returns `null` if fencing was never used. */
146
+ getGenerationState(): Promise<GenerationState | null>;
147
+ private readGenerationObject;
148
+ /**
149
+ * Writes the generation object if it was not changed since it was read with
150
+ * `etag` (`null`: if it does not exist). Returns false on a lost race.
151
+ */
152
+ private writeGenerationObject;
153
+ /** Records that this client was superseded by `generation` and returns the error. */
154
+ private superseded;
155
+ /**
156
+ * Fails with {@link ErrGenerationSuperseded} if a generation higher than this
157
+ * client's is registered. A no-op when fencing is disabled.
158
+ */
159
+ private assertGeneration;
160
+ /**
161
+ * Raises the replica's generation to `generation`, failing with
162
+ * {@link ErrGenerationSuperseded} if a higher one is already registered, and
163
+ * records a fence at the replica's latest TXID as read after the
164
+ * registration. From then on, files of lower generations above that TXID
165
+ * are ignored by every listing, and uploads and deletions of lower
166
+ * generations fail once they observe the new generation.
167
+ *
168
+ * Call it before restoring: the restore then sees every file that a former
169
+ * writer can still make part of the replica. Registering the current
170
+ * generation again is a no-op that keeps its fence.
171
+ */
172
+ registerGeneration(generation: bigint): Promise<void>;
173
+ /** Returns the generation of an object (from `ltx-generation`), or null if it is gone. */
174
+ private objectGeneration;
175
+ private rememberGeneration;
176
+ /**
177
+ * Lists the LTX files of a level. When the replica has fences, files ending
178
+ * above the lowest fence need their generation (a HeadObject request, cached
179
+ * per key and ETag), and those written by a superseded writer are skipped.
180
+ */
58
181
  ltxFiles(opts: LTXFilesOptions): AsyncIterable<FileInfo>;
59
182
  openLtxFile(opts: OpenLTXFileOptions): Promise<Readable>;
60
183
  writeLtxFile(opts: WriteLTXFileOptions, body: AsyncIterable<Uint8Array | string>): Promise<FileInfo>;
184
+ /**
185
+ * Creates a fenced LTX object with `If-None-Match: *`. If the key already
186
+ * exists:
187
+ * - written by a higher generation: this client is superseded;
188
+ * - written by this generation (a retried upload), or by a lower one but
189
+ * still part of the replica: it holds the same transactions, so it is
190
+ * kept and its metadata returned;
191
+ * - otherwise it is a superseded writer's file, replaced with `If-Match`.
192
+ * With `probe`, the key is checked with HeadObject before the first write.
193
+ * Returns null when this call created the object.
194
+ */
195
+ private commitFenced;
196
+ /**
197
+ * Deletes LTX files. A fenced client first checks that its generation is
198
+ * still the latest and fails with {@link ErrGenerationSuperseded} otherwise
199
+ * (a deletion sent just before a new generation registers still applies).
200
+ */
61
201
  deleteLtxFiles(infos: FileInfo[]): Promise<void>;
202
+ /**
203
+ * Deletes every replica under a prefix: every object whose key starts with
204
+ * `prefix/`, which covers the replica at `prefix` and every replica under
205
+ * it, generation objects (`generation.json`) and lease objects included
206
+ * (unlike {@link deleteAll}, which keeps the generation). Resolves with the
207
+ * sorted prefixes of the deleted replicas: those with an LTX file, a
208
+ * generation object or a lease object.
209
+ *
210
+ * The generation objects are deleted last, so former writers stay fenced
211
+ * while the files are deleted. Once they are gone, nothing fences those
212
+ * writers anymore: a writer that is still running can upload again and
213
+ * create the replica anew. Stop the writers first.
214
+ *
215
+ * With {@link S3DeletePrefixOptions.generation}, the deletion is fenced as
216
+ * the deletions of a fenced client are, on a best-effort basis: the
217
+ * generation object of each replica is read before deleting its first
218
+ * object, and again before deleting the generation objects, and the
219
+ * deletion fails with {@link ErrGenerationSuperseded} if it holds a higher
220
+ * generation. S3 cannot check one object and delete another atomically, so
221
+ * a generation registered between a check and a `DeleteObjects` request
222
+ * does not stop it, and the replicas already processed stay deleted.
223
+ */
224
+ static deletePrefix(opts: S3DeletePrefixOptions): Promise<string[]>;
225
+ /**
226
+ * Deletes every object under the prefix except the generation object, so a
227
+ * superseded writer stays fenced. A fenced client checks its generation
228
+ * first, as {@link deleteLtxFiles} does.
229
+ */
62
230
  deleteAll(): Promise<void>;
63
231
  }
64
232
  /**
@@ -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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"}