orez 0.4.19 → 0.4.21
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/pg-proxy-do-backend.d.ts +6 -0
- package/dist/pg-proxy-do-backend.d.ts.map +1 -1
- package/dist/pg-proxy-do-backend.js +47 -14
- package/dist/pg-proxy-do-backend.js.map +1 -1
- package/dist/recovery.d.ts.map +1 -1
- package/dist/recovery.js +14 -0
- package/dist/recovery.js.map +1 -1
- package/dist/worker/shims/node-stub.d.ts +16 -0
- package/dist/worker/shims/node-stub.d.ts.map +1 -1
- package/dist/worker/shims/node-stub.js +59 -1
- package/dist/worker/shims/node-stub.js.map +1 -1
- package/dist/worker/zero-cache-embed-cf.d.ts.map +1 -1
- package/dist/worker/zero-cache-embed-cf.js +15 -1
- package/dist/worker/zero-cache-embed-cf.js.map +1 -1
- package/dist/zero-http/transport.d.ts.map +1 -1
- package/dist/zero-http/transport.js +20 -3
- package/dist/zero-http/transport.js.map +1 -1
- package/package.json +3 -3
|
@@ -27,6 +27,7 @@ export declare class DoBackend {
|
|
|
27
27
|
private portals;
|
|
28
28
|
private publicationTableInfoCache;
|
|
29
29
|
private readyPromise;
|
|
30
|
+
private operationMutex;
|
|
30
31
|
private inTransaction;
|
|
31
32
|
private txID;
|
|
32
33
|
private txSnapshot;
|
|
@@ -51,6 +52,7 @@ export declare class DoBackend {
|
|
|
51
52
|
private reloadPublicationsIfEmpty;
|
|
52
53
|
private repairShardMetadataPublications;
|
|
53
54
|
private persistDurableMetadata;
|
|
55
|
+
private runExclusive;
|
|
54
56
|
close(): Promise<void>;
|
|
55
57
|
private readyForQuery;
|
|
56
58
|
private cloneSchemaMetadata;
|
|
@@ -68,6 +70,7 @@ export declare class DoBackend {
|
|
|
68
70
|
syncToFs?: boolean;
|
|
69
71
|
throwOnError?: boolean;
|
|
70
72
|
}): Promise<Uint8Array>;
|
|
73
|
+
private execProtocolRawLocked;
|
|
71
74
|
private protocolMessageLength;
|
|
72
75
|
private hasMultipleProtocolMessages;
|
|
73
76
|
private execProtocolMessage;
|
|
@@ -88,10 +91,12 @@ export declare class DoBackend {
|
|
|
88
91
|
private handleDescribe;
|
|
89
92
|
private handleClose;
|
|
90
93
|
exec(sql: string): Promise<any[]>;
|
|
94
|
+
private execLocked;
|
|
91
95
|
private handleTransactionControl;
|
|
92
96
|
query<T = Record<string, unknown>>(sql: string, params?: any[]): Promise<{
|
|
93
97
|
rows: T[];
|
|
94
98
|
}>;
|
|
99
|
+
private queryLocked;
|
|
95
100
|
private url;
|
|
96
101
|
private rewriteSQLStatements;
|
|
97
102
|
private canCacheRewrite;
|
|
@@ -101,6 +106,7 @@ export declare class DoBackend {
|
|
|
101
106
|
private inlineStatementParams;
|
|
102
107
|
private doExec;
|
|
103
108
|
private doExecResult;
|
|
109
|
+
private currentTransactionID;
|
|
104
110
|
private transactionSnapshotName;
|
|
105
111
|
private tableExistsInDo;
|
|
106
112
|
private snapshotTransactionTable;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pg-proxy-do-backend.d.ts","sourceRoot":"","sources":["../src/pg-proxy-do-backend.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pg-proxy-do-backend.d.ts","sourceRoot":"","sources":["../src/pg-proxy-do-backend.ts"],"names":[],"mappings":"AA06HA,wBAAsB,+BAA+B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CACzE,KAAK,CAAC;IACJ,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IACjB,kBAAkB,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IACtD,mBAAmB,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CACxD,CAAC,CACH,CAkDA;AAwkCD,qBAAa,SAAS;IACpB,KAAK,UAAQ;IACb,MAAM,UAAQ;IACd,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,UAAU,CAAY;IAC9B,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,oBAAoB,CAAa;IACzC,OAAO,CAAC,gBAAgB,CAAwC;IAChE,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,YAAY,CAAoC;IAGxD,OAAO,CAAC,4BAA4B,CAAoB;IACxD,OAAO,CAAC,YAAY,CAAmC;IACvD,OAAO,CAAC,kBAAkB,CAAuC;IACjE,OAAO,CAAC,OAAO,CAAiC;IAOhD,OAAO,CAAC,yBAAyB,CAAsC;IACvE,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,cAAc,CAAc;IAQpC,OAAO,CAAC,aAAa,CAAQ;IAC7B,OAAO,CAAC,IAAI,CAAsB;IAClC,OAAO,CAAC,UAAU,CAA2C;IAC7D,OAAO,CAAC,eAAe,CAAmC;IAC1D,OAAO,CAAC,iBAAiB,CAAI;IAM7B,OAAO,CAAC,yBAAyB,CAAQ;IAGzC,OAAO,CAAC,eAAe,CAAQ;IAC/B,OAAO,CAAC,iBAAiB,CAAQ;IAOjC,OAAO,CAAC,OAAO,CAAQ;gBAGrB,KAAK,EAAE,MAAM,EACb,MAAM,GAAE,MAAmB,EAC3B,SAAS,SAAY,EACrB,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE;IAcnD,IAAI,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAE7B;IAED,OAAO,CAAC,WAAW;YAWL,IAAI;YAUJ,0BAA0B;YAwB1B,mBAAmB;IAIjC,OAAO,CAAC,iBAAiB;IASzB,OAAO,CAAC,mBAAmB;YAyBb,mBAAmB;YA2CnB,yBAAyB;YAsBzB,+BAA+B;YA8B/B,sBAAsB;YAgCtB,YAAY;IASpB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAa5B,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,iBAAiB;IAmBzB,OAAO,CAAC,qBAAqB;IAQ7B,OAAO,CAAC,kCAAkC;IAS1C,OAAO,CAAC,kCAAkC;IAsB1C,OAAO,CAAC,qBAAqB;IAW7B,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,gBAAgB;YAMV,gBAAgB;YAOhB,iBAAiB;YAuBjB,mBAAmB;IAwB3B,eAAe,CACnB,OAAO,EAAE,UAAU,EACnB,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,YAAY,CAAC,EAAE,OAAO,CAAA;KAAE,GACvD,OAAO,CAAC,UAAU,CAAC;YAIR,qBAAqB;IAwBnC,OAAO,CAAC,qBAAqB;IAY7B,OAAO,CAAC,2BAA2B;YAKrB,mBAAmB;YAoCnB,iBAAiB;YAgGjB,sBAAsB;IA+BpC,OAAO,CAAC,yBAAyB;IAgCjC,OAAO,CAAC,sBAAsB;IAkC9B,gBAAgB,IAAI,MAAM,EAAE;IAI5B,OAAO,CAAC,oBAAoB;IAyB5B,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,wBAAwB;YAYlB,sBAAsB;YAQtB,mCAAmC;IAkBjD,OAAO,CAAC,WAAW;IAuFnB,OAAO,CAAC,UAAU;YAWJ,aAAa;IA8H3B,OAAO,CAAC,UAAU;YAIJ,cAAc;IAuB5B,OAAO,CAAC,WAAW;IAgBb,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;YAIzB,UAAU;YAmCV,wBAAwB;IAqBhC,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrC,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,GAAG,EAAE,GACb,OAAO,CAAC;QAAE,IAAI,EAAE,CAAC,EAAE,CAAA;KAAE,CAAC;YAIX,WAAW;IA0GzB,OAAO,CAAC,GAAG;IAQX,OAAO,CAAC,oBAAoB;IAuB5B,OAAO,CAAC,eAAe;IAevB,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,UAAU;IAalB,OAAO,CAAC,yBAAyB;IAkBjC,OAAO,CAAC,qBAAqB;YAkCf,MAAM;YAIN,YAAY;IA6C1B,OAAO,CAAC,oBAAoB;IAO5B,OAAO,CAAC,uBAAuB;YAKjB,eAAe;YAQf,wBAAwB;YA2BxB,+BAA+B;YAc/B,wBAAwB;YAOxB,UAAU;IAYxB,qFAAqF;YACvE,cAAc;YAsBd,mBAAmB;YA4BnB,yBAAyB;YAmBzB,0BAA0B;YAU1B,WAAW;YA2EX,YAAY;YAKZ,YAAY;YAOZ,gBAAgB;IAY9B,OAAO,CAAC,sBAAsB;IAyB9B,OAAO,CAAC,kCAAkC;IA0B1C,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,eAAe;IAYvB,OAAO,CAAC,0BAA0B;IAmBlC,OAAO,CAAC,eAAe;IAsFvB,OAAO,CAAC,wBAAwB;IAYhC,OAAO,CAAC,oBAAoB;YAUd,qBAAqB;YAiBrB,yBAAyB;IA8EvC,OAAO,CAAC,iBAAiB;YAcX,cAAc;YAiBd,8BAA8B;YAmD9B,iCAAiC;YAwEjC,yBAAyB;IA0DvC,OAAO,CAAC,oBAAoB;YAyCd,qBAAqB;YAiBrB,sBAAsB;YAatB,qBAAqB;IAoBnC,OAAO,CAAC,iBAAiB;IAezB,OAAO,CAAC,UAAU;IA+ClB,OAAO,CAAC,YAAY;IAqGpB,OAAO,CAAC,gBAAgB;IA8BxB,OAAO,CAAC,cAAc;IA2GtB,OAAO,CAAC,gBAAgB;IA0CxB,OAAO,CAAC,aAAa;IAqCrB,OAAO,CAAC,eAAe;IA6DvB,OAAO,CAAC,4BAA4B,CAAoB;IAExD,OAAO,CAAC,aAAa;IAiBrB,OAAO,CAAC,uBAAuB;IAuB/B,OAAO,CAAC,iBAAiB;IAyBzB,OAAO,CAAC,4BAA4B;IAoDpC,OAAO,CAAC,eAAe;IAiBvB,OAAO,CAAC,oBAAoB;YA0Bd,cAAc;IAoB5B,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,mBAAmB;YAOb,oBAAoB;YAgBpB,kBAAkB;YAIlB,mBAAmB;CAkClC"}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { deparseSync, loadModule, parseSync } from 'pgsql-parser';
|
|
3
3
|
import { TX_MANIFEST_DDL, TX_MANIFEST_TABLE } from './cf-do/tx-journal.js';
|
|
4
4
|
import { RETURNING_INTERNAL_PREFIX } from './do-sql-tracking.js';
|
|
5
|
+
import { Mutex } from './mutex.js';
|
|
5
6
|
import { signalReplicationChange } from './replication/handler.js';
|
|
6
7
|
import { markSQLiteKeywordIdentifiers, restoreSQLiteKeywordIdentifierMarkers, } from './sqlite-keyword-identifiers.js';
|
|
7
8
|
/**
|
|
@@ -39,7 +40,11 @@ const PG_TYPE_TIMESTAMP = 1114;
|
|
|
39
40
|
const PG_TYPE_TIMESTAMPTZ = 1184;
|
|
40
41
|
const PG_TYPE_BYTEA = 17;
|
|
41
42
|
const PG_TYPE_INT2 = 21;
|
|
42
|
-
|
|
43
|
+
// per-DoBackend cache. with ~20 concurrent DoBackend sessions sharing one 128MB
|
|
44
|
+
// DO isolate, 2048 entries each (each holding rewritten SQL + schema metadata)
|
|
45
|
+
// is needless heap — the distinct-statement working set per session during sync
|
|
46
|
+
// is small. 256 keeps the hot path cached while bounding aggregate footprint.
|
|
47
|
+
const MAX_REWRITE_CACHE_ENTRIES = 256;
|
|
43
48
|
const METADATA_TABLE = '_orez_pg_metadata';
|
|
44
49
|
// how long reloadPublicationsIfEmpty waits between re-reads while publications
|
|
45
50
|
// stay empty — short enough that the first write after a concurrently-created
|
|
@@ -4691,6 +4696,7 @@ export class DoBackend {
|
|
|
4691
4696
|
// on DDL / metadata / publication changes and on rollback.
|
|
4692
4697
|
publicationTableInfoCache = null;
|
|
4693
4698
|
readyPromise = null;
|
|
4699
|
+
operationMutex = new Mutex();
|
|
4694
4700
|
// Transaction state. The Durable Object refuses raw SQL BEGIN/COMMIT/SAVEPOINT
|
|
4695
4701
|
// (Cloudflare requires ctx.storage.transaction()), so PG-style multi-call
|
|
4696
4702
|
// transactions can't ride on SQLite's own transaction machinery. Instead we
|
|
@@ -4917,16 +4923,27 @@ export class DoBackend {
|
|
|
4917
4923
|
}
|
|
4918
4924
|
catch { }
|
|
4919
4925
|
}
|
|
4926
|
+
async runExclusive(fn) {
|
|
4927
|
+
await this.operationMutex.acquire();
|
|
4928
|
+
try {
|
|
4929
|
+
return await fn();
|
|
4930
|
+
}
|
|
4931
|
+
finally {
|
|
4932
|
+
this.operationMutex.release();
|
|
4933
|
+
}
|
|
4934
|
+
}
|
|
4920
4935
|
async close() {
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
4936
|
+
return this.runExclusive(async () => {
|
|
4937
|
+
if (this.inTransaction) {
|
|
4938
|
+
try {
|
|
4939
|
+
await this.rollbackTransaction();
|
|
4940
|
+
}
|
|
4941
|
+
catch {
|
|
4942
|
+
this.clearTransactionState();
|
|
4943
|
+
}
|
|
4927
4944
|
}
|
|
4928
|
-
|
|
4929
|
-
|
|
4945
|
+
this.closed = true;
|
|
4946
|
+
});
|
|
4930
4947
|
}
|
|
4931
4948
|
readyForQuery() {
|
|
4932
4949
|
return buildReadyForQuery(this.inTransaction ? STATUS_TRANSACTION : STATUS_IDLE);
|
|
@@ -5064,6 +5081,9 @@ export class DoBackend {
|
|
|
5064
5081
|
}
|
|
5065
5082
|
}
|
|
5066
5083
|
async execProtocolRaw(message, options) {
|
|
5084
|
+
return this.runExclusive(() => this.execProtocolRawLocked(message, options));
|
|
5085
|
+
}
|
|
5086
|
+
async execProtocolRawLocked(message, options) {
|
|
5067
5087
|
if (!this.ready)
|
|
5068
5088
|
await this.waitReady;
|
|
5069
5089
|
if (this.hasMultipleProtocolMessages(message)) {
|
|
@@ -5342,7 +5362,7 @@ export class DoBackend {
|
|
|
5342
5362
|
operation: tracking.operation,
|
|
5343
5363
|
returnRows: tracking.returnRows,
|
|
5344
5364
|
...(rowColumns ? { rowColumns: [...rowColumns.keys()] } : null),
|
|
5345
|
-
...(this.inTransaction
|
|
5365
|
+
...(this.inTransaction ? { transactionID: this.currentTransactionID() } : null),
|
|
5346
5366
|
};
|
|
5347
5367
|
}
|
|
5348
5368
|
visibleResultForTracking(result, tracking) {
|
|
@@ -5583,6 +5603,9 @@ export class DoBackend {
|
|
|
5583
5603
|
}
|
|
5584
5604
|
// ── High-level API ──────────────────────────────────────────────────────
|
|
5585
5605
|
async exec(sql) {
|
|
5606
|
+
return this.runExclusive(() => this.execLocked(sql));
|
|
5607
|
+
}
|
|
5608
|
+
async execLocked(sql) {
|
|
5586
5609
|
if (!this.ready)
|
|
5587
5610
|
await this.waitReady;
|
|
5588
5611
|
if (await this.handleTransactionControl(sql))
|
|
@@ -5632,6 +5655,9 @@ export class DoBackend {
|
|
|
5632
5655
|
return true;
|
|
5633
5656
|
}
|
|
5634
5657
|
async query(sql, params) {
|
|
5658
|
+
return this.runExclusive(() => this.queryLocked(sql, params));
|
|
5659
|
+
}
|
|
5660
|
+
async queryLocked(sql, params) {
|
|
5635
5661
|
if (!this.ready)
|
|
5636
5662
|
await this.waitReady;
|
|
5637
5663
|
if (await this.handleTransactionControl(sql))
|
|
@@ -5830,9 +5856,15 @@ export class DoBackend {
|
|
|
5830
5856
|
}
|
|
5831
5857
|
throw lastErr instanceof Error ? lastErr : new Error(String(lastErr));
|
|
5832
5858
|
}
|
|
5833
|
-
|
|
5859
|
+
currentTransactionID() {
|
|
5860
|
+
if (!this.inTransaction || !this.txID) {
|
|
5861
|
+
throw new Error('internal transaction state is missing a transaction id');
|
|
5862
|
+
}
|
|
5863
|
+
return this.txID;
|
|
5864
|
+
}
|
|
5865
|
+
transactionSnapshotName(txID, table) {
|
|
5834
5866
|
const safeTable = table.replace(/[^A-Za-z0-9_]/g, '_');
|
|
5835
|
-
return `_orez_tx_${
|
|
5867
|
+
return `_orez_tx_${txID}_${this.txSnapshotCounter++}_${safeTable}`;
|
|
5836
5868
|
}
|
|
5837
5869
|
async tableExistsInDo(table) {
|
|
5838
5870
|
const result = await this.doExecResult("SELECT 1 AS ok FROM sqlite_master WHERE type = 'table' AND name = ? LIMIT 1", [table]);
|
|
@@ -5843,6 +5875,7 @@ export class DoBackend {
|
|
|
5843
5875
|
return;
|
|
5844
5876
|
if (table.startsWith('_orez_tx_'))
|
|
5845
5877
|
return;
|
|
5878
|
+
const txID = this.currentTransactionID();
|
|
5846
5879
|
// skip the sqlite_master probe when we already have schema metadata for
|
|
5847
5880
|
// the table — registration only happens after a successful CREATE, so its
|
|
5848
5881
|
// presence is proof the table exists. saves one /exec on the first write
|
|
@@ -5851,7 +5884,7 @@ export class DoBackend {
|
|
|
5851
5884
|
// snapshot + manifest row land in one atomic /batch, so a DO kill at any
|
|
5852
5885
|
// point leaves either no trace or a journal entry recovery can roll back.
|
|
5853
5886
|
// the DDL is idempotent and rides the same batch (no extra round-trip).
|
|
5854
|
-
const snapshot = exists ? this.transactionSnapshotName(table) : null;
|
|
5887
|
+
const snapshot = exists ? this.transactionSnapshotName(txID, table) : null;
|
|
5855
5888
|
const statements = [{ sql: TX_MANIFEST_DDL }];
|
|
5856
5889
|
if (snapshot) {
|
|
5857
5890
|
statements.push({
|
|
@@ -5860,7 +5893,7 @@ export class DoBackend {
|
|
|
5860
5893
|
}
|
|
5861
5894
|
statements.push({
|
|
5862
5895
|
sql: `INSERT INTO "${TX_MANIFEST_TABLE}" (tx_id, owner, original, snapshot) VALUES (?, ?, ?, ?)`,
|
|
5863
|
-
params: [
|
|
5896
|
+
params: [txID, this.txOwner, table, snapshot],
|
|
5864
5897
|
});
|
|
5865
5898
|
await this.doRawBatch(statements);
|
|
5866
5899
|
this.txDataSnapshots.set(table, snapshot);
|