@powersync/service-module-postgres 0.7.0 → 0.8.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/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # @powersync/service-module-postgres
2
2
 
3
+ ## 0.8.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 436eee6: Minor optimizations to new checkpoint calulations.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [436eee6]
12
+ - Updated dependencies [15283d4]
13
+ - Updated dependencies [88d4cb3]
14
+ - Updated dependencies [f55e36a]
15
+ - @powersync/service-core@1.7.0
16
+ - @powersync/service-sync-rules@0.24.0
17
+ - @powersync/lib-services-framework@0.5.2
18
+ - @powersync/lib-service-postgres@0.3.2
19
+
20
+ ## 0.7.1
21
+
22
+ ### Patch Changes
23
+
24
+ - ffc8d98: Fix write checkpoint race condition
25
+ - Updated dependencies [ffc8d98]
26
+ - @powersync/service-core@0.18.1
27
+
3
28
  ## 0.7.0
4
29
 
5
30
  ### Minor Changes
@@ -1,4 +1,4 @@
1
- import { api, ParseSyncRulesOptions } from '@powersync/service-core';
1
+ import { api, ParseSyncRulesOptions, ReplicationHeadCallback } from '@powersync/service-core';
2
2
  import * as pgwire from '@powersync/service-jpgwire';
3
3
  import * as sync_rules from '@powersync/service-sync-rules';
4
4
  import * as service_types from '@powersync/service-types';
@@ -22,5 +22,6 @@ export declare class PostgresRouteAPIAdapter implements api.RouteAPI {
22
22
  protected getDebugTableInfo(tablePattern: sync_rules.TablePattern, name: string, relationId: number | null, syncRules: sync_rules.SqlSyncRules): Promise<service_types.TableInfo>;
23
23
  getReplicationLag(options: api.ReplicationLagOptions): Promise<number | undefined>;
24
24
  getReplicationHead(): Promise<string>;
25
+ createReplicationHead<T>(callback: ReplicationHeadCallback<T>): Promise<T>;
25
26
  getConnectionSchema(): Promise<service_types.DatabaseSchema[]>;
26
27
  }
@@ -217,11 +217,16 @@ FROM pg_replication_slots WHERE slot_name = $1 LIMIT 1;`,
217
217
  // However, on Aurora (Postgres compatible), it can return an entirely different LSN,
218
218
  // causing the write checkpoints to never be replicated back to the client.
219
219
  // For those, we need to use pg_current_wal_lsn() instead.
220
- const { results } = await lib_postgres.retriedQuery(this.pool, { statement: `SELECT pg_current_wal_lsn() as lsn` }, KEEPALIVE_STATEMENT);
221
- // Specifically use the lsn from the first statement, not the second one.
220
+ const { results } = await lib_postgres.retriedQuery(this.pool, `SELECT pg_current_wal_lsn() as lsn`);
222
221
  const lsn = results[0].rows[0][0];
223
222
  return String(lsn);
224
223
  }
224
+ async createReplicationHead(callback) {
225
+ const currentLsn = await this.getReplicationHead();
226
+ const r = await callback(currentLsn);
227
+ await lib_postgres.retriedQuery(this.pool, KEEPALIVE_STATEMENT);
228
+ return r;
229
+ }
225
230
  async getConnectionSchema() {
226
231
  // https://github.com/Borvik/vscode-postgres/blob/88ec5ed061a0c9bced6c5d4ec122d0759c3f3247/src/language/server.ts
227
232
  const results = await lib_postgres.retriedQuery(this.pool, `SELECT
@@ -1 +1 @@
1
- {"version":3,"file":"PostgresRouteAPIAdapter.js","sourceRoot":"","sources":["../../src/api/PostgresRouteAPIAdapter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PostgresRouteAPIAdapter.js","sourceRoot":"","sources":["../../src/api/PostgresRouteAPIAdapter.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
8
- "version": "0.7.0",
8
+ "version": "0.8.0",
9
9
  "main": "dist/index.js",
10
10
  "license": "FSL-1.1-Apache-2.0",
11
11
  "type": "module",
@@ -28,20 +28,20 @@
28
28
  "ts-codec": "^1.3.0",
29
29
  "uri-js": "^4.4.1",
30
30
  "uuid": "^9.0.1",
31
- "@powersync/lib-service-postgres": "0.3.1",
32
- "@powersync/lib-services-framework": "0.5.1",
33
- "@powersync/service-core": "0.18.0",
31
+ "@powersync/lib-service-postgres": "0.3.2",
32
+ "@powersync/lib-services-framework": "0.5.2",
33
+ "@powersync/service-core": "1.7.0",
34
34
  "@powersync/service-jpgwire": "0.19.0",
35
35
  "@powersync/service-jsonbig": "0.17.10",
36
- "@powersync/service-sync-rules": "0.23.4",
36
+ "@powersync/service-sync-rules": "0.24.0",
37
37
  "@powersync/service-types": "0.8.0"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@types/semver": "^7.5.4",
41
41
  "@types/uuid": "^9.0.4",
42
- "@powersync/service-core-tests": "0.4.0",
43
- "@powersync/service-module-mongodb-storage": "0.5.0",
44
- "@powersync/service-module-postgres-storage": "0.3.0"
42
+ "@powersync/service-core-tests": "0.5.0",
43
+ "@powersync/service-module-mongodb-storage": "0.6.0",
44
+ "@powersync/service-module-postgres-storage": "0.4.0"
45
45
  },
46
46
  "scripts": {
47
47
  "build": "tsc -b",
@@ -1,6 +1,6 @@
1
1
  import * as lib_postgres from '@powersync/lib-service-postgres';
2
2
  import { ErrorCode, ServiceError } from '@powersync/lib-services-framework';
3
- import { api, ParseSyncRulesOptions } from '@powersync/service-core';
3
+ import { api, ParseSyncRulesOptions, ReplicationHeadCallback } from '@powersync/service-core';
4
4
  import * as pgwire from '@powersync/service-jpgwire';
5
5
  import * as sync_rules from '@powersync/service-sync-rules';
6
6
  import * as service_types from '@powersync/service-types';
@@ -241,17 +241,22 @@ FROM pg_replication_slots WHERE slot_name = $1 LIMIT 1;`,
241
241
  // However, on Aurora (Postgres compatible), it can return an entirely different LSN,
242
242
  // causing the write checkpoints to never be replicated back to the client.
243
243
  // For those, we need to use pg_current_wal_lsn() instead.
244
- const { results } = await lib_postgres.retriedQuery(
245
- this.pool,
246
- { statement: `SELECT pg_current_wal_lsn() as lsn` },
247
- KEEPALIVE_STATEMENT
248
- );
244
+ const { results } = await lib_postgres.retriedQuery(this.pool, `SELECT pg_current_wal_lsn() as lsn`);
249
245
 
250
- // Specifically use the lsn from the first statement, not the second one.
251
246
  const lsn = results[0].rows[0][0];
252
247
  return String(lsn);
253
248
  }
254
249
 
250
+ async createReplicationHead<T>(callback: ReplicationHeadCallback<T>): Promise<T> {
251
+ const currentLsn = await this.getReplicationHead();
252
+
253
+ const r = await callback(currentLsn);
254
+
255
+ await lib_postgres.retriedQuery(this.pool, KEEPALIVE_STATEMENT);
256
+
257
+ return r;
258
+ }
259
+
255
260
  async getConnectionSchema(): Promise<service_types.DatabaseSchema[]> {
256
261
  // https://github.com/Borvik/vscode-postgres/blob/88ec5ed061a0c9bced6c5d4ec122d0759c3f3247/src/language/server.ts
257
262
  const results = await lib_postgres.retriedQuery(
@@ -0,0 +1,74 @@
1
+ import { PostgresRouteAPIAdapter } from '@module/api/PostgresRouteAPIAdapter.js';
2
+ import { checkpointUserId, createWriteCheckpoint } from '@powersync/service-core';
3
+ import { describe, test } from 'vitest';
4
+ import { INITIALIZED_MONGO_STORAGE_FACTORY } from './util.js';
5
+ import { WalStreamTestContext } from './wal_stream_utils.js';
6
+ import { env } from './env.js';
7
+
8
+ import timers from 'node:timers/promises';
9
+
10
+ const BASIC_SYNC_RULES = `bucket_definitions:
11
+ global:
12
+ data:
13
+ - SELECT id, description, other FROM "test_data"`;
14
+
15
+ describe.skipIf(!(env.CI || env.SLOW_TESTS))('checkpoint tests', () => {
16
+ test('write checkpoints', { timeout: 50_000 }, async () => {
17
+ const factory = INITIALIZED_MONGO_STORAGE_FACTORY;
18
+ await using context = await WalStreamTestContext.open(factory);
19
+
20
+ await context.updateSyncRules(BASIC_SYNC_RULES);
21
+ const { pool } = context;
22
+ const api = new PostgresRouteAPIAdapter(pool);
23
+
24
+ await pool.query(`CREATE TABLE test_data(id text primary key, description text, other text)`);
25
+
26
+ await context.replicateSnapshot();
27
+
28
+ context.startStreaming();
29
+ const storage = context.storage!;
30
+
31
+ const controller = new AbortController();
32
+ try {
33
+ const stream = storage.watchWriteCheckpoint({
34
+ user_id: checkpointUserId('test_user', 'test_client'),
35
+ signal: controller.signal
36
+ });
37
+
38
+ let lastWriteCheckpoint: bigint | null = null;
39
+
40
+ (async () => {
41
+ try {
42
+ for await (const cp of stream) {
43
+ lastWriteCheckpoint = cp.writeCheckpoint;
44
+ }
45
+ } catch (e) {
46
+ if (e.name != 'AbortError') {
47
+ throw e;
48
+ }
49
+ }
50
+ })();
51
+
52
+ for (let i = 0; i < 10; i++) {
53
+ const cp = await createWriteCheckpoint({
54
+ userId: 'test_user',
55
+ clientId: 'test_client',
56
+ api,
57
+ storage: context.factory
58
+ });
59
+
60
+ const start = Date.now();
61
+ while (lastWriteCheckpoint == null || lastWriteCheckpoint < BigInt(cp.writeCheckpoint)) {
62
+ if (Date.now() - start > 5_000) {
63
+ throw new Error(
64
+ `Timeout while waiting for checkpoint. last: ${lastWriteCheckpoint}, waiting for: ${cp.writeCheckpoint}`
65
+ );
66
+ }
67
+ await timers.setTimeout(5, undefined, { signal: controller.signal });
68
+ }
69
+ }
70
+ } finally {
71
+ controller.abort();
72
+ }
73
+ });
74
+ });
@@ -71,21 +71,13 @@ function defineSlowTests(factory: storage.TestStorageFactory) {
71
71
  // Past issues that this could reproduce intermittently:
72
72
  // * Skipping LSNs after a keepalive message
73
73
  // * Skipping LSNs when source transactions overlap
74
- test(
75
- 'repeated replication - basic',
76
- async () => {
77
- await testRepeatedReplication({ compact: false, maxBatchSize: 50, numBatches: 5 });
78
- },
79
- { timeout: TEST_DURATION_MS + TIMEOUT_MARGIN_MS }
80
- );
81
-
82
- test(
83
- 'repeated replication - compacted',
84
- async () => {
85
- await testRepeatedReplication({ compact: true, maxBatchSize: 100, numBatches: 2 });
86
- },
87
- { timeout: TEST_DURATION_MS + TIMEOUT_MARGIN_MS }
88
- );
74
+ test('repeated replication - basic', { timeout: TEST_DURATION_MS + TIMEOUT_MARGIN_MS }, async () => {
75
+ await testRepeatedReplication({ compact: false, maxBatchSize: 50, numBatches: 5 });
76
+ });
77
+
78
+ test('repeated replication - compacted', { timeout: TEST_DURATION_MS + TIMEOUT_MARGIN_MS }, async () => {
79
+ await testRepeatedReplication({ compact: true, maxBatchSize: 100, numBatches: 2 });
80
+ });
89
81
 
90
82
  async function testRepeatedReplication(testOptions: { compact: boolean; maxBatchSize: number; numBatches: number }) {
91
83
  const connections = new PgManager(TEST_CONNECTION_OPTIONS, {});
@@ -101,7 +93,7 @@ bucket_definitions:
101
93
  - SELECT * FROM "test_data"
102
94
  `;
103
95
  const syncRules = await f.updateSyncRules({ content: syncRuleContent });
104
- using storage = f.getInstance(syncRules);
96
+ const storage = f.getInstance(syncRules);
105
97
  abortController = new AbortController();
106
98
  const options: WalStreamOptions = {
107
99
  abort_signal: abortController.signal,
@@ -314,116 +306,112 @@ bucket_definitions:
314
306
  //
315
307
  // If the first LSN does not correctly match with the first replication transaction,
316
308
  // we may miss some updates.
317
- test(
318
- 'repeated initial replication',
319
- async () => {
320
- const pool = await connectPgPool();
321
- await clearTestDb(pool);
322
- await using f = await factory();
323
-
324
- const syncRuleContent = `
309
+ test('repeated initial replication', { timeout: TEST_DURATION_MS + TIMEOUT_MARGIN_MS }, async () => {
310
+ const pool = await connectPgPool();
311
+ await clearTestDb(pool);
312
+ await using f = await factory();
313
+
314
+ const syncRuleContent = `
325
315
  bucket_definitions:
326
316
  global:
327
317
  data:
328
318
  - SELECT id, description FROM "test_data"
329
319
  `;
330
- const syncRules = await f.updateSyncRules({ content: syncRuleContent });
331
- using storage = f.getInstance(syncRules);
320
+ const syncRules = await f.updateSyncRules({ content: syncRuleContent });
321
+ const storage = f.getInstance(syncRules);
332
322
 
333
- // 1. Setup some base data that will be replicated in initial replication
334
- await pool.query(`CREATE TABLE test_data(id uuid primary key default uuid_generate_v4(), description text)`);
323
+ // 1. Setup some base data that will be replicated in initial replication
324
+ await pool.query(`CREATE TABLE test_data(id uuid primary key default uuid_generate_v4(), description text)`);
335
325
 
336
- let statements: pgwire.Statement[] = [];
326
+ let statements: pgwire.Statement[] = [];
337
327
 
338
- const n = Math.floor(Math.random() * 200);
339
- for (let i = 0; i < n; i++) {
340
- statements.push({
341
- statement: `INSERT INTO test_data(description) VALUES('test_init')`
342
- });
343
- }
344
- await pool.query(...statements);
345
-
346
- const start = Date.now();
347
- let i = 0;
348
-
349
- while (Date.now() - start < TEST_DURATION_MS) {
350
- // 2. Each iteration starts with a clean slate
351
- await pool.query(`SELECT pg_drop_replication_slot(slot_name) FROM pg_replication_slots WHERE active = FALSE`);
352
- i += 1;
353
-
354
- const connections = new PgManager(TEST_CONNECTION_OPTIONS, {});
355
- const replicationConnection = await connections.replicationConnection();
356
-
357
- abortController = new AbortController();
358
- const options: WalStreamOptions = {
359
- abort_signal: abortController.signal,
360
- connections,
361
- storage: storage
362
- };
363
- walStream = new WalStream(options);
364
-
365
- await storage.clear();
366
-
367
- // 3. Start initial replication, then streaming, but don't wait for any of this
368
- let initialReplicationDone = false;
369
- streamPromise = (async () => {
370
- await walStream.initReplication(replicationConnection);
371
- await storage.autoActivate();
328
+ const n = Math.floor(Math.random() * 200);
329
+ for (let i = 0; i < n; i++) {
330
+ statements.push({
331
+ statement: `INSERT INTO test_data(description) VALUES('test_init')`
332
+ });
333
+ }
334
+ await pool.query(...statements);
335
+
336
+ const start = Date.now();
337
+ let i = 0;
338
+
339
+ while (Date.now() - start < TEST_DURATION_MS) {
340
+ // 2. Each iteration starts with a clean slate
341
+ await pool.query(`SELECT pg_drop_replication_slot(slot_name) FROM pg_replication_slots WHERE active = FALSE`);
342
+ i += 1;
343
+
344
+ const connections = new PgManager(TEST_CONNECTION_OPTIONS, {});
345
+ const replicationConnection = await connections.replicationConnection();
346
+
347
+ abortController = new AbortController();
348
+ const options: WalStreamOptions = {
349
+ abort_signal: abortController.signal,
350
+ connections,
351
+ storage: storage
352
+ };
353
+ walStream = new WalStream(options);
354
+
355
+ await storage.clear();
356
+
357
+ // 3. Start initial replication, then streaming, but don't wait for any of this
358
+ let initialReplicationDone = false;
359
+ streamPromise = (async () => {
360
+ await walStream.initReplication(replicationConnection);
361
+ await storage.autoActivate();
362
+ initialReplicationDone = true;
363
+ await walStream.streamChanges(replicationConnection);
364
+ })()
365
+ .catch((e) => {
372
366
  initialReplicationDone = true;
373
- await walStream.streamChanges(replicationConnection);
374
- })()
375
- .catch((e) => {
376
- initialReplicationDone = true;
377
- throw e;
378
- })
379
- .then((v) => {
380
- return v;
381
- });
367
+ throw e;
368
+ })
369
+ .then((v) => {
370
+ return v;
371
+ });
382
372
 
383
- // 4. While initial replication is still running, write more changes
384
- while (!initialReplicationDone) {
385
- let statements: pgwire.Statement[] = [];
386
- const n = Math.floor(Math.random() * 10) + 1;
387
- for (let i = 0; i < n; i++) {
388
- const description = `test${i}`;
389
- statements.push({
390
- statement: `INSERT INTO test_data(description) VALUES('test1') returning id as test_id`,
391
- params: [{ type: 'varchar', value: description }]
392
- });
393
- }
394
- const results = await pool.query(...statements);
395
- const ids = results.results.map((sub) => {
396
- return sub.rows[0][0] as string;
397
- });
398
- await new Promise((resolve) => setTimeout(resolve, Math.random() * 30));
399
- const deleteStatements: pgwire.Statement[] = ids.map((id) => {
400
- return {
401
- statement: `DELETE FROM test_data WHERE id = $1`,
402
- params: [{ type: 'uuid', value: id }]
403
- };
373
+ // 4. While initial replication is still running, write more changes
374
+ while (!initialReplicationDone) {
375
+ let statements: pgwire.Statement[] = [];
376
+ const n = Math.floor(Math.random() * 10) + 1;
377
+ for (let i = 0; i < n; i++) {
378
+ const description = `test${i}`;
379
+ statements.push({
380
+ statement: `INSERT INTO test_data(description) VALUES('test1') returning id as test_id`,
381
+ params: [{ type: 'varchar', value: description }]
404
382
  });
405
- await pool.query(...deleteStatements);
406
- await new Promise((resolve) => setTimeout(resolve, Math.random() * 10));
407
- }
408
-
409
- // 5. Once initial replication is done, wait for the streaming changes to complete syncing.
410
- // getClientCheckpoint() effectively waits for the above replication to complete
411
- // Race with streamingPromise to catch replication errors here.
412
- let checkpoint = await Promise.race([
413
- getClientCheckpoint(pool, storage.factory, { timeout: TIMEOUT_MARGIN_MS }),
414
- streamPromise
415
- ]);
416
- if (typeof checkpoint == undefined) {
417
- // This indicates an issue with the test setup - streamingPromise completed instead
418
- // of getClientCheckpoint()
419
- throw new Error('Test failure - streamingPromise completed');
420
383
  }
384
+ const results = await pool.query(...statements);
385
+ const ids = results.results.map((sub) => {
386
+ return sub.rows[0][0] as string;
387
+ });
388
+ await new Promise((resolve) => setTimeout(resolve, Math.random() * 30));
389
+ const deleteStatements: pgwire.Statement[] = ids.map((id) => {
390
+ return {
391
+ statement: `DELETE FROM test_data WHERE id = $1`,
392
+ params: [{ type: 'uuid', value: id }]
393
+ };
394
+ });
395
+ await pool.query(...deleteStatements);
396
+ await new Promise((resolve) => setTimeout(resolve, Math.random() * 10));
397
+ }
421
398
 
422
- abortController.abort();
423
- await streamPromise;
424
- await connections.end();
399
+ // 5. Once initial replication is done, wait for the streaming changes to complete syncing.
400
+ // getClientCheckpoint() effectively waits for the above replication to complete
401
+ // Race with streamingPromise to catch replication errors here.
402
+ let checkpoint = await Promise.race([
403
+ getClientCheckpoint(pool, storage.factory, { timeout: TIMEOUT_MARGIN_MS }),
404
+ streamPromise
405
+ ]);
406
+ if (typeof checkpoint == undefined) {
407
+ // This indicates an issue with the test setup - streamingPromise completed instead
408
+ // of getClientCheckpoint()
409
+ throw new Error('Test failure - streamingPromise completed');
425
410
  }
426
- },
427
- { timeout: TEST_DURATION_MS + TIMEOUT_MARGIN_MS }
428
- );
411
+
412
+ abortController.abort();
413
+ await streamPromise;
414
+ await connections.end();
415
+ }
416
+ });
429
417
  }
package/test/src/util.ts CHANGED
@@ -62,13 +62,13 @@ export function connectPgPool() {
62
62
 
63
63
  export async function getClientCheckpoint(
64
64
  db: pgwire.PgClient,
65
- bucketStorage: BucketStorageFactory,
65
+ storageFactory: BucketStorageFactory,
66
66
  options?: { timeout?: number }
67
67
  ): Promise<OpId> {
68
68
  const start = Date.now();
69
69
 
70
70
  const api = new PostgresRouteAPIAdapter(db);
71
- const lsn = await api.getReplicationHead();
71
+ const lsn = await api.createReplicationHead(async (lsn) => lsn);
72
72
 
73
73
  // This old API needs a persisted checkpoint id.
74
74
  // Since we don't use LSNs anymore, the only way to get that is to wait.
@@ -77,8 +77,9 @@ export async function getClientCheckpoint(
77
77
 
78
78
  logger.info(`Waiting for LSN checkpoint: ${lsn}`);
79
79
  while (Date.now() - start < timeout) {
80
- const cp = await bucketStorage.getActiveCheckpoint();
81
- if (!cp.hasSyncRules()) {
80
+ const storage = await storageFactory.getActiveStorage();
81
+ const cp = await storage?.getCheckpoint();
82
+ if (cp == null) {
82
83
  throw new Error('No sync rules available');
83
84
  }
84
85
  if (cp.lsn && cp.lsn >= lsn) {
@@ -45,7 +45,6 @@ export class WalStreamTestContext implements AsyncDisposable {
45
45
  this.abortController.abort();
46
46
  await this.streamPromise;
47
47
  await this.connectionManager.destroy();
48
- this.storage?.[Symbol.dispose]();
49
48
  await this.factory?.[Symbol.asyncDispose]();
50
49
  }
51
50