@powersync/service-module-postgres-storage 0.16.3 → 0.18.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 +60 -0
- package/dist/migrations/scripts/1782950400000-checkpoint-requested-at.d.ts +3 -0
- package/dist/migrations/scripts/1782950400000-checkpoint-requested-at.js +42 -0
- package/dist/migrations/scripts/1782950400000-checkpoint-requested-at.js.map +1 -0
- package/dist/migrations/scripts/1784900000000-source-metadata.d.ts +3 -0
- package/dist/migrations/scripts/1784900000000-source-metadata.js +22 -0
- package/dist/migrations/scripts/1784900000000-source-metadata.js.map +1 -0
- package/dist/storage/PostgresBucketStorageFactory.js +0 -2
- package/dist/storage/PostgresBucketStorageFactory.js.map +1 -1
- package/dist/storage/PostgresCompactor.d.ts +2 -0
- package/dist/storage/PostgresCompactor.js +20 -0
- package/dist/storage/PostgresCompactor.js.map +1 -1
- package/dist/storage/PostgresSyncRulesStorage.d.ts +16 -1
- package/dist/storage/PostgresSyncRulesStorage.js +200 -131
- package/dist/storage/PostgresSyncRulesStorage.js.map +1 -1
- package/dist/storage/batch/PostgresBucketBatch.d.ts +2 -20
- package/dist/storage/batch/PostgresBucketBatch.js +217 -240
- package/dist/storage/batch/PostgresBucketBatch.js.map +1 -1
- package/dist/storage/checkpoints/PostgresWriteCheckpointAPI.d.ts +1 -1
- package/dist/storage/checkpoints/PostgresWriteCheckpointAPI.js +156 -36
- package/dist/storage/checkpoints/PostgresWriteCheckpointAPI.js.map +1 -1
- package/dist/storage/current-data-store.d.ts +8 -2
- package/dist/storage/current-data-store.js +66 -11
- package/dist/storage/current-data-store.js.map +1 -1
- package/dist/types/models/SourceTable.d.ts +7 -2
- package/dist/types/models/SourceTable.js +6 -2
- package/dist/types/models/SourceTable.js.map +1 -1
- package/dist/types/models/WriteCheckpoint.d.ts +2 -0
- package/dist/types/models/WriteCheckpoint.js +5 -2
- package/dist/types/models/WriteCheckpoint.js.map +1 -1
- package/dist/utils/checkpoints.d.ts +9 -0
- package/dist/utils/checkpoints.js +26 -0
- package/dist/utils/checkpoints.js.map +1 -0
- package/package.json +8 -8
- package/src/migrations/scripts/1782950400000-checkpoint-requested-at.ts +51 -0
- package/src/migrations/scripts/1784900000000-source-metadata.ts +31 -0
- package/src/storage/PostgresBucketStorageFactory.ts +0 -3
- package/src/storage/PostgresCompactor.ts +24 -0
- package/src/storage/PostgresSyncRulesStorage.ts +219 -137
- package/src/storage/batch/PostgresBucketBatch.ts +227 -246
- package/src/storage/checkpoints/PostgresWriteCheckpointAPI.ts +165 -37
- package/src/storage/current-data-store.ts +66 -11
- package/src/types/models/SourceTable.ts +7 -2
- package/src/types/models/WriteCheckpoint.ts +5 -2
- package/src/utils/checkpoints.ts +31 -0
- package/test/src/__snapshots__/storage_sync.test.ts.snap +0 -582
- package/test/src/checkpoint_notifications.test.ts +522 -0
- package/test/src/storage.test.ts +214 -5
- package/test/src/storage_compacting.test.ts +3 -3
- package/test/src/storage_sync.test.ts +48 -4
- package/test/tsconfig.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,13 +1,16 @@
|
|
|
1
|
+
import { framework } from '@powersync/service-core';
|
|
1
2
|
import * as t from 'ts-codec';
|
|
2
3
|
import { bigint, jsonb } from '../codecs.js';
|
|
3
4
|
export const WriteCheckpoint = t.object({
|
|
4
5
|
user_id: t.string,
|
|
5
6
|
lsns: jsonb(t.record(t.string)),
|
|
6
|
-
write_checkpoint: bigint
|
|
7
|
+
write_checkpoint: bigint,
|
|
8
|
+
checkpoint_requested_at: t.Null.or(framework.codecs.date)
|
|
7
9
|
});
|
|
8
10
|
export const CustomWriteCheckpoint = t.object({
|
|
9
11
|
user_id: t.string,
|
|
10
12
|
write_checkpoint: bigint,
|
|
11
|
-
sync_rules_id: bigint
|
|
13
|
+
sync_rules_id: bigint,
|
|
14
|
+
checkpoint_requested_at: t.Null.or(framework.codecs.date)
|
|
12
15
|
});
|
|
13
16
|
//# sourceMappingURL=WriteCheckpoint.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WriteCheckpoint.js","sourceRoot":"","sources":["../../../src/types/models/WriteCheckpoint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,OAAO,EAAE,CAAC,CAAC,MAAM;IACjB,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAC/B,gBAAgB,EAAE,MAAM;
|
|
1
|
+
{"version":3,"file":"WriteCheckpoint.js","sourceRoot":"","sources":["../../../src/types/models/WriteCheckpoint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,OAAO,EAAE,CAAC,CAAC,MAAM;IACjB,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAC/B,gBAAgB,EAAE,MAAM;IACxB,uBAAuB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC;CAC1D,CAAC,CAAC;AAKH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,OAAO,EAAE,CAAC,CAAC,MAAM;IACjB,gBAAgB,EAAE,MAAM;IACxB,aAAa,EAAE,MAAM;IACrB,uBAAuB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC;CAC1D,CAAC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as lib_postgres from '@powersync/lib-service-postgres';
|
|
2
|
+
import { models } from '../types/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Gets the latest active checkpoint document.
|
|
5
|
+
* This is mainly exported for mocking in tests.
|
|
6
|
+
*/
|
|
7
|
+
export declare function getActiveCheckpointDocument({ db }: {
|
|
8
|
+
db: lib_postgres.DatabaseClient;
|
|
9
|
+
}): Promise<models.ActiveCheckpointDecoded | null>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { storage } from '@powersync/service-core';
|
|
2
|
+
import { models } from '../types/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Gets the latest active checkpoint document.
|
|
5
|
+
* This is mainly exported for mocking in tests.
|
|
6
|
+
*/
|
|
7
|
+
export async function getActiveCheckpointDocument({ db }) {
|
|
8
|
+
return db.sql `
|
|
9
|
+
SELECT
|
|
10
|
+
id,
|
|
11
|
+
last_checkpoint,
|
|
12
|
+
last_checkpoint_lsn
|
|
13
|
+
FROM
|
|
14
|
+
sync_rules
|
|
15
|
+
WHERE
|
|
16
|
+
state = ${{ value: storage.SyncRuleState.ACTIVE, type: 'varchar' }}
|
|
17
|
+
OR state = ${{ value: storage.SyncRuleState.ERRORED, type: 'varchar' }}
|
|
18
|
+
ORDER BY
|
|
19
|
+
id DESC
|
|
20
|
+
LIMIT
|
|
21
|
+
1
|
|
22
|
+
`
|
|
23
|
+
.decoded(models.ActiveCheckpoint)
|
|
24
|
+
.first();
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=checkpoints.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkpoints.js","sourceRoot":"","sources":["../../src/utils/checkpoints.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAAC,EAChD,EAAE,EAGH;IACC,OAAO,EAAE,CAAC,GAAG,CAAA;;;;;;;;gBAQC,EAAE,KAAK,EAAE,OAAO,CAAC,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE;mBACrD,EAAE,KAAK,EAAE,OAAO,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE;;;;;GAKzE;SACE,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAAC;SAChC,KAAK,EAAE,CAAC;AACb,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@powersync/service-module-postgres-storage",
|
|
3
3
|
"repository": "https://github.com/powersync-ja/powersync-service",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.18.0",
|
|
5
5
|
"license": "FSL-1.1-ALv2",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"publishConfig": {
|
|
@@ -16,17 +16,17 @@
|
|
|
16
16
|
"lru-cache": "^10.2.2",
|
|
17
17
|
"ts-codec": "^1.3.0",
|
|
18
18
|
"uuid": "^14.0.0",
|
|
19
|
-
"@powersync/lib-service-postgres": "0.5.
|
|
20
|
-
"@powersync/lib-services-framework": "0.
|
|
21
|
-
"@powersync/service-core": "1.
|
|
22
|
-
"@powersync/service-types": "0.
|
|
23
|
-
"@powersync/service-jpgwire": "0.21.
|
|
19
|
+
"@powersync/lib-service-postgres": "0.5.3",
|
|
20
|
+
"@powersync/lib-services-framework": "0.10.0",
|
|
21
|
+
"@powersync/service-core": "1.25.0",
|
|
22
|
+
"@powersync/service-types": "0.17.0",
|
|
23
|
+
"@powersync/service-jpgwire": "0.21.22",
|
|
24
24
|
"@powersync/service-jsonbig": "0.17.13",
|
|
25
|
-
"@powersync/service-sync-rules": "0.
|
|
25
|
+
"@powersync/service-sync-rules": "0.40.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"typescript": "~6.0.3",
|
|
29
|
-
"@powersync/service-core-tests": "0.
|
|
29
|
+
"@powersync/service-core-tests": "0.18.0"
|
|
30
30
|
},
|
|
31
31
|
"scripts": {
|
|
32
32
|
"build": "tsc -b",
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { migrations } from '@powersync/service-core';
|
|
2
|
+
|
|
3
|
+
import { openMigrationDB } from '../migration-utils.js';
|
|
4
|
+
|
|
5
|
+
export const up: migrations.PowerSyncMigrationFunction = async (context) => {
|
|
6
|
+
const {
|
|
7
|
+
service_context: { configuration }
|
|
8
|
+
} = context;
|
|
9
|
+
await using client = openMigrationDB(configuration.storage);
|
|
10
|
+
|
|
11
|
+
await client.transaction(async (db) => {
|
|
12
|
+
await db.sql`
|
|
13
|
+
ALTER TABLE write_checkpoints
|
|
14
|
+
ADD COLUMN checkpoint_requested_at TIMESTAMP WITH TIME ZONE
|
|
15
|
+
`.execute();
|
|
16
|
+
await db.sql`
|
|
17
|
+
ALTER TABLE custom_write_checkpoints
|
|
18
|
+
ADD COLUMN checkpoint_requested_at TIMESTAMP WITH TIME ZONE
|
|
19
|
+
`.execute();
|
|
20
|
+
await db.sql`
|
|
21
|
+
CREATE INDEX write_checkpoints_checkpoint_requested_at ON write_checkpoints (checkpoint_requested_at)
|
|
22
|
+
WHERE
|
|
23
|
+
checkpoint_requested_at IS NOT NULL
|
|
24
|
+
`.execute();
|
|
25
|
+
await db.sql`
|
|
26
|
+
CREATE INDEX custom_write_checkpoints_checkpoint_requested_at ON custom_write_checkpoints (checkpoint_requested_at)
|
|
27
|
+
WHERE
|
|
28
|
+
checkpoint_requested_at IS NOT NULL
|
|
29
|
+
`.execute();
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const down: migrations.PowerSyncMigrationFunction = async (context) => {
|
|
34
|
+
const {
|
|
35
|
+
service_context: { configuration }
|
|
36
|
+
} = context;
|
|
37
|
+
await using client = openMigrationDB(configuration.storage);
|
|
38
|
+
|
|
39
|
+
await client.transaction(async (db) => {
|
|
40
|
+
// Also drops the write_checkpoints_checkpoint_requested_at index.
|
|
41
|
+
await db.sql`
|
|
42
|
+
ALTER TABLE write_checkpoints
|
|
43
|
+
DROP COLUMN checkpoint_requested_at
|
|
44
|
+
`.execute();
|
|
45
|
+
// Also drops the custom_write_checkpoints_checkpoint_requested_at index.
|
|
46
|
+
await db.sql`
|
|
47
|
+
ALTER TABLE custom_write_checkpoints
|
|
48
|
+
DROP COLUMN checkpoint_requested_at
|
|
49
|
+
`.execute();
|
|
50
|
+
});
|
|
51
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { migrations } from '@powersync/service-core';
|
|
2
|
+
|
|
3
|
+
import { openMigrationDB } from '../migration-utils.js';
|
|
4
|
+
|
|
5
|
+
export const up: migrations.PowerSyncMigrationFunction = async (context) => {
|
|
6
|
+
const {
|
|
7
|
+
service_context: { configuration }
|
|
8
|
+
} = context;
|
|
9
|
+
await using client = openMigrationDB(configuration.storage);
|
|
10
|
+
|
|
11
|
+
await client.transaction(async (db) => {
|
|
12
|
+
await db.sql`
|
|
13
|
+
ALTER TABLE source_tables
|
|
14
|
+
ADD COLUMN source_metadata JSONB
|
|
15
|
+
`.execute();
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const down: migrations.PowerSyncMigrationFunction = async (context) => {
|
|
20
|
+
const {
|
|
21
|
+
service_context: { configuration }
|
|
22
|
+
} = context;
|
|
23
|
+
await using client = openMigrationDB(configuration.storage);
|
|
24
|
+
|
|
25
|
+
await client.transaction(async (db) => {
|
|
26
|
+
await db.sql`
|
|
27
|
+
ALTER TABLE source_tables
|
|
28
|
+
DROP COLUMN source_metadata
|
|
29
|
+
`.execute();
|
|
30
|
+
});
|
|
31
|
+
};
|
|
@@ -8,7 +8,6 @@ import { models, NormalizedPostgresStorageConfig } from '../types/types.js';
|
|
|
8
8
|
|
|
9
9
|
import { getStorageApplicationName } from '../utils/application-name.js';
|
|
10
10
|
import { NOTIFICATION_CHANNEL, STORAGE_SCHEMA_NAME } from '../utils/db.js';
|
|
11
|
-
import { notifySyncRulesUpdate } from './batch/PostgresBucketBatch.js';
|
|
12
11
|
import { PostgresSyncRulesStorage } from './PostgresSyncRulesStorage.js';
|
|
13
12
|
import { PostgresPersistedReplicationStream } from './sync-rules/PostgresPersistedSyncConfigContent.js';
|
|
14
13
|
|
|
@@ -220,8 +219,6 @@ export class PostgresBucketStorageFactory extends storage.BucketStorageFactory {
|
|
|
220
219
|
.decoded(models.SyncRules)
|
|
221
220
|
.first();
|
|
222
221
|
|
|
223
|
-
await notifySyncRulesUpdate(this.db, newSyncRulesRow!);
|
|
224
|
-
|
|
225
222
|
return new PostgresPersistedReplicationStream(this.db, newSyncRulesRow!);
|
|
226
223
|
});
|
|
227
224
|
}
|
|
@@ -53,6 +53,7 @@ export class PostgresCompactor {
|
|
|
53
53
|
private clearBatchLimit: number;
|
|
54
54
|
private maxOpId: InternalOpId;
|
|
55
55
|
private buckets: string[] | undefined;
|
|
56
|
+
private deleteCheckpointRequestsBefore: Date | undefined;
|
|
56
57
|
|
|
57
58
|
constructor(
|
|
58
59
|
private db: lib_postgres.DatabaseClient,
|
|
@@ -65,6 +66,7 @@ export class PostgresCompactor {
|
|
|
65
66
|
this.clearBatchLimit = options.clearBatchLimit ?? DEFAULT_CLEAR_BATCH_LIMIT;
|
|
66
67
|
this.maxOpId = options.maxOpId ?? 0n;
|
|
67
68
|
this.buckets = options.compactBuckets;
|
|
69
|
+
this.deleteCheckpointRequestsBefore = options.deleteCheckpointRequestsBefore;
|
|
68
70
|
}
|
|
69
71
|
|
|
70
72
|
/**
|
|
@@ -73,6 +75,8 @@ export class PostgresCompactor {
|
|
|
73
75
|
* See /docs/storage/compacting-operations.md for details.
|
|
74
76
|
*/
|
|
75
77
|
async compact() {
|
|
78
|
+
await this.deleteOldCheckpointRequests();
|
|
79
|
+
|
|
76
80
|
if (this.buckets) {
|
|
77
81
|
for (let bucket of this.buckets) {
|
|
78
82
|
await this.compactSingleBucket(bucket);
|
|
@@ -82,6 +86,26 @@ export class PostgresCompactor {
|
|
|
82
86
|
}
|
|
83
87
|
}
|
|
84
88
|
|
|
89
|
+
private async deleteOldCheckpointRequests() {
|
|
90
|
+
if (this.deleteCheckpointRequestsBefore == null) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
await this.db.sql`
|
|
95
|
+
DELETE FROM write_checkpoints
|
|
96
|
+
WHERE
|
|
97
|
+
checkpoint_requested_at IS NOT NULL
|
|
98
|
+
AND checkpoint_requested_at < ${{ type: 1184, value: this.deleteCheckpointRequestsBefore.toISOString() }}
|
|
99
|
+
`.execute();
|
|
100
|
+
|
|
101
|
+
await this.db.sql`
|
|
102
|
+
DELETE FROM custom_write_checkpoints
|
|
103
|
+
WHERE
|
|
104
|
+
checkpoint_requested_at IS NOT NULL
|
|
105
|
+
AND checkpoint_requested_at < ${{ type: 1184, value: this.deleteCheckpointRequestsBefore.toISOString() }}
|
|
106
|
+
`.execute();
|
|
107
|
+
}
|
|
108
|
+
|
|
85
109
|
private async compactAllBuckets() {
|
|
86
110
|
const DISCOVERY_BATCH_SIZE = 200;
|
|
87
111
|
let lastBucket = '';
|