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.
@@ -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":"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"}
1
+ {"version":3,"file":"pg-proxy-do-backend.d.ts","sourceRoot":"","sources":["../src/pg-proxy-do-backend.ts"],"names":[],"mappings":"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"}
@@ -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
- const MAX_REWRITE_CACHE_ENTRIES = 2048;
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
- if (this.inTransaction) {
4922
- try {
4923
- await this.rollbackTransaction();
4924
- }
4925
- catch {
4926
- this.clearTransactionState();
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
- this.closed = true;
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 && this.txID ? { transactionID: this.txID } : null),
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
- transactionSnapshotName(table) {
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_${this.txID}_${this.txSnapshotCounter++}_${safeTable}`;
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: [this.txID, this.txOwner, table, snapshot],
5896
+ params: [txID, this.txOwner, table, snapshot],
5864
5897
  });
5865
5898
  await this.doRawBatch(statements);
5866
5899
  this.txDataSnapshots.set(table, snapshot);