@powersync/service-module-postgres-storage 0.16.3 → 0.17.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 +33 -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/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 +162 -151
- 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/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/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 +169 -154
- package/src/storage/checkpoints/PostgresWriteCheckpointAPI.ts +165 -37
- package/src/storage/current-data-store.ts +66 -11
- 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 +4 -4
- package/test/tsconfig.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -21,42 +21,152 @@ export class PostgresWriteCheckpointAPI {
|
|
|
21
21
|
if (this.writeCheckpointMode !== storage.WriteCheckpointMode.MANAGED) {
|
|
22
22
|
throw new framework.errors.ValidationError(`Attempting to create a managed Write Checkpoint when the current Write Checkpoint mode is set to "${this.writeCheckpointMode}"`);
|
|
23
23
|
}
|
|
24
|
-
const uniqueCheckpoints =
|
|
24
|
+
const uniqueCheckpoints = storage.uniqueManagedWriteCheckpoints(checkpoints);
|
|
25
25
|
if (uniqueCheckpoints.length == 0) {
|
|
26
|
-
return new Map();
|
|
26
|
+
return { writeCheckpoints: new Map(), shouldAdvance: false };
|
|
27
27
|
}
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
28
|
+
const writeCheckpoints = new Map();
|
|
29
|
+
const generatedCheckpoints = uniqueCheckpoints.filter((checkpoint) => checkpoint.checkpoint_request_id == null);
|
|
30
|
+
const suppliedCheckpoints = uniqueCheckpoints.filter((checkpoint) => checkpoint.checkpoint_request_id != null);
|
|
31
|
+
if (generatedCheckpoints.length > 0) {
|
|
32
|
+
const mappedCheckpoints = generatedCheckpoints.map((checkpoint) => ({
|
|
33
|
+
user_id: checkpoint.user_id,
|
|
34
|
+
lsns: checkpoint.heads
|
|
35
|
+
}));
|
|
36
|
+
const generatedRows = await this.db.sql `
|
|
37
|
+
WITH
|
|
38
|
+
json_data AS (
|
|
39
|
+
SELECT
|
|
40
|
+
CHECKPOINT ->> 'user_id' AS user_id,
|
|
41
|
+
CHECKPOINT -> 'lsns' AS lsns
|
|
42
|
+
FROM
|
|
43
|
+
jsonb_array_elements(${{ type: 'jsonb', value: mappedCheckpoints }}) AS
|
|
44
|
+
CHECKPOINT
|
|
45
|
+
)
|
|
46
|
+
INSERT INTO
|
|
47
|
+
write_checkpoints (
|
|
48
|
+
user_id,
|
|
49
|
+
lsns,
|
|
50
|
+
write_checkpoint,
|
|
51
|
+
checkpoint_requested_at
|
|
52
|
+
)
|
|
53
|
+
SELECT
|
|
54
|
+
user_id,
|
|
55
|
+
lsns,
|
|
56
|
+
1,
|
|
57
|
+
NULL
|
|
58
|
+
FROM
|
|
59
|
+
json_data
|
|
60
|
+
ON CONFLICT (user_id) DO UPDATE
|
|
61
|
+
SET
|
|
62
|
+
write_checkpoint = write_checkpoints.write_checkpoint + 1,
|
|
63
|
+
lsns = EXCLUDED.lsns,
|
|
64
|
+
checkpoint_requested_at = NULL
|
|
65
|
+
RETURNING
|
|
66
|
+
*;
|
|
67
|
+
`
|
|
68
|
+
.decoded(models.WriteCheckpoint)
|
|
69
|
+
.rows();
|
|
70
|
+
for (const row of generatedRows) {
|
|
71
|
+
writeCheckpoints.set(row.user_id, row.write_checkpoint);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (suppliedCheckpoints.length > 0) {
|
|
75
|
+
// Supplied request ids are monotonic. Greater values update the checkpoint
|
|
76
|
+
// id and heads, while equal retries only refresh the retention timestamp.
|
|
77
|
+
// Stale requests return the stored id without changing the row.
|
|
78
|
+
const mappedCheckpoints = suppliedCheckpoints.map((checkpoint) => ({
|
|
79
|
+
user_id: checkpoint.user_id,
|
|
80
|
+
lsns: checkpoint.heads,
|
|
81
|
+
checkpoint_request_id: String(checkpoint.checkpoint_request_id)
|
|
82
|
+
}));
|
|
83
|
+
const suppliedRows = await this.db.sql `
|
|
84
|
+
WITH
|
|
85
|
+
json_data AS (
|
|
86
|
+
SELECT
|
|
87
|
+
CHECKPOINT ->> 'user_id' AS user_id,
|
|
88
|
+
CHECKPOINT -> 'lsns' AS lsns,
|
|
89
|
+
(
|
|
90
|
+
CHECKPOINT ->> 'checkpoint_request_id'
|
|
91
|
+
)::int8 AS checkpoint_request_id
|
|
92
|
+
FROM
|
|
93
|
+
jsonb_array_elements(${{ type: 'jsonb', value: mappedCheckpoints }}) AS
|
|
94
|
+
CHECKPOINT
|
|
95
|
+
)
|
|
96
|
+
INSERT INTO
|
|
97
|
+
write_checkpoints (
|
|
98
|
+
user_id,
|
|
99
|
+
lsns,
|
|
100
|
+
write_checkpoint,
|
|
101
|
+
checkpoint_requested_at
|
|
102
|
+
)
|
|
103
|
+
SELECT
|
|
104
|
+
user_id,
|
|
105
|
+
lsns,
|
|
106
|
+
checkpoint_request_id,
|
|
107
|
+
NOW()
|
|
108
|
+
FROM
|
|
109
|
+
json_data
|
|
110
|
+
ON CONFLICT (user_id) DO UPDATE
|
|
111
|
+
SET
|
|
112
|
+
write_checkpoint = CASE
|
|
113
|
+
WHEN EXCLUDED.write_checkpoint > write_checkpoints.write_checkpoint THEN EXCLUDED.write_checkpoint
|
|
114
|
+
ELSE write_checkpoints.write_checkpoint
|
|
115
|
+
END,
|
|
116
|
+
lsns = CASE
|
|
117
|
+
WHEN EXCLUDED.write_checkpoint > write_checkpoints.write_checkpoint THEN EXCLUDED.lsns
|
|
118
|
+
ELSE write_checkpoints.lsns
|
|
119
|
+
END,
|
|
120
|
+
checkpoint_requested_at = NOW()
|
|
121
|
+
WHERE
|
|
122
|
+
EXCLUDED.write_checkpoint >= write_checkpoints.write_checkpoint
|
|
123
|
+
RETURNING
|
|
124
|
+
*;
|
|
125
|
+
`
|
|
126
|
+
.decoded(models.WriteCheckpoint)
|
|
127
|
+
.rows();
|
|
128
|
+
for (const row of suppliedRows) {
|
|
129
|
+
writeCheckpoints.set(row.user_id, row.write_checkpoint);
|
|
130
|
+
}
|
|
131
|
+
// RETURNING only excludes stale requests rejected by the monotonic
|
|
132
|
+
// conflict condition. Those requests still need the stored id.
|
|
133
|
+
const returnedSuppliedUserIds = new Set(suppliedRows.map((row) => row.user_id));
|
|
134
|
+
const unchangedUserIds = suppliedCheckpoints
|
|
135
|
+
.map((checkpoint) => checkpoint.user_id)
|
|
136
|
+
.filter((userId) => !returnedSuppliedUserIds.has(userId));
|
|
137
|
+
if (unchangedUserIds.length > 0) {
|
|
138
|
+
const mappedUserIds = unchangedUserIds.map((user_id) => ({ user_id }));
|
|
139
|
+
const unchangedRows = await this.db.sql `
|
|
140
|
+
WITH
|
|
141
|
+
json_data AS (
|
|
142
|
+
SELECT
|
|
143
|
+
CHECKPOINT ->> 'user_id' AS user_id
|
|
144
|
+
FROM
|
|
145
|
+
jsonb_array_elements(${{ type: 'jsonb', value: mappedUserIds }}) AS
|
|
146
|
+
CHECKPOINT
|
|
147
|
+
)
|
|
35
148
|
SELECT
|
|
36
|
-
|
|
37
|
-
CHECKPOINT -> 'lsns' AS lsns
|
|
149
|
+
write_checkpoints.*
|
|
38
150
|
FROM
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
.rows();
|
|
59
|
-
return new Map(rows.map((row) => [row.user_id, row.write_checkpoint]));
|
|
151
|
+
write_checkpoints
|
|
152
|
+
JOIN json_data ON write_checkpoints.user_id = json_data.user_id;
|
|
153
|
+
`
|
|
154
|
+
.decoded(models.WriteCheckpoint)
|
|
155
|
+
.rows();
|
|
156
|
+
for (const row of unchangedRows) {
|
|
157
|
+
writeCheckpoints.set(row.user_id, row.write_checkpoint);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
// Postgres storage does not track a per-row processed indicator: a write
|
|
162
|
+
// checkpoint is considered processed at read time by comparing its lsns
|
|
163
|
+
// against the replicated head (see lastManagedWriteCheckpoint). We therefore
|
|
164
|
+
// force the source marker whenever any checkpoint was matched, which also
|
|
165
|
+
// covers stale or duplicate requests whose stored checkpoint may still be
|
|
166
|
+
// pending. Forcing a marker for an already-processed checkpoint is wasteful
|
|
167
|
+
// but harmless.
|
|
168
|
+
const shouldAdvance = generatedCheckpoints.length > 0 || suppliedCheckpoints.length > 0;
|
|
169
|
+
return { writeCheckpoints, shouldAdvance };
|
|
60
170
|
}
|
|
61
171
|
async lastWriteCheckpoint(filters) {
|
|
62
172
|
switch (this.writeCheckpointMode) {
|
|
@@ -120,7 +230,8 @@ export async function batchCreateCustomWriteCheckpoints(db, checkpoints) {
|
|
|
120
230
|
// Cannot encode bigint directly using JSON.stringify.
|
|
121
231
|
// The ::int8 in the query below will take care of casting back to a number
|
|
122
232
|
checkpoint: String(cp.checkpoint),
|
|
123
|
-
sync_rules_id: cp.sync_rules_id
|
|
233
|
+
sync_rules_id: cp.sync_rules_id,
|
|
234
|
+
checkpoint_requested_at: cp.checkpoint_requested_at?.toISOString() ?? null
|
|
124
235
|
};
|
|
125
236
|
});
|
|
126
237
|
await db.sql `
|
|
@@ -131,7 +242,12 @@ export async function batchCreateCustomWriteCheckpoints(db, checkpoints) {
|
|
|
131
242
|
CHECKPOINT
|
|
132
243
|
)
|
|
133
244
|
INSERT INTO
|
|
134
|
-
custom_write_checkpoints (
|
|
245
|
+
custom_write_checkpoints (
|
|
246
|
+
user_id,
|
|
247
|
+
write_checkpoint,
|
|
248
|
+
sync_rules_id,
|
|
249
|
+
checkpoint_requested_at
|
|
250
|
+
)
|
|
135
251
|
SELECT
|
|
136
252
|
CHECKPOINT ->> 'user_id'::varchar,
|
|
137
253
|
(
|
|
@@ -139,12 +255,16 @@ export async function batchCreateCustomWriteCheckpoints(db, checkpoints) {
|
|
|
139
255
|
)::int8,
|
|
140
256
|
(
|
|
141
257
|
CHECKPOINT ->> 'sync_rules_id'
|
|
142
|
-
)::int4
|
|
258
|
+
)::int4,
|
|
259
|
+
(
|
|
260
|
+
CHECKPOINT ->> 'checkpoint_requested_at'
|
|
261
|
+
)::timestamptz
|
|
143
262
|
FROM
|
|
144
263
|
json_data
|
|
145
264
|
ON CONFLICT (user_id, sync_rules_id) DO UPDATE
|
|
146
265
|
SET
|
|
147
|
-
write_checkpoint = EXCLUDED.write_checkpoint
|
|
266
|
+
write_checkpoint = EXCLUDED.write_checkpoint,
|
|
267
|
+
checkpoint_requested_at = EXCLUDED.checkpoint_requested_at;
|
|
148
268
|
`.execute();
|
|
149
269
|
}
|
|
150
270
|
//# sourceMappingURL=PostgresWriteCheckpointAPI.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PostgresWriteCheckpointAPI.js","sourceRoot":"","sources":["../../../src/storage/checkpoints/PostgresWriteCheckpointAPI.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,SAAS,MAAM,mCAAmC,CAAC;AAC/D,OAAO,EAAgB,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAO9C,MAAM,OAAO,0BAA0B;IAC5B,EAAE,CAA8B;IACjC,KAAK,CAA8B;IAE3C,YAAY,OAAqC;QAC/C,IAAI,CAAC,EAAE,GAAG,OAAO,CAAC,EAAE,CAAC;QACrB,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;IAC5B,CAAC;IAED,IAAI,mBAAmB;QACrB,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,sBAAsB,CAAC,IAAiC;QACtD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACpB,CAAC;IAED,KAAK,CAAC,iCAAiC,CACrC,WAAmD,EACnD,KAAmB;QAEnB,OAAO,iCAAiC,CAAC,IAAI,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC;IACjE,CAAC;IAED,KAAK,CAAC,6BAA6B,CACjC,WAAoD;QAEpD,IAAI,IAAI,CAAC,mBAAmB,KAAK,OAAO,CAAC,mBAAmB,CAAC,OAAO,EAAE,CAAC;YACrE,MAAM,IAAI,SAAS,CAAC,MAAM,CAAC,eAAe,CACxC,qGAAqG,IAAI,CAAC,mBAAmB,GAAG,CACjI,CAAC;QACJ,CAAC;QAED,MAAM,iBAAiB,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"PostgresWriteCheckpointAPI.js","sourceRoot":"","sources":["../../../src/storage/checkpoints/PostgresWriteCheckpointAPI.ts"],"names":[],"mappings":"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"}
|
|
@@ -77,9 +77,15 @@ export declare class PostgresCurrentDataStore {
|
|
|
77
77
|
groupId: number;
|
|
78
78
|
lastCheckpoint: bigint;
|
|
79
79
|
}): Promise<void>;
|
|
80
|
-
|
|
80
|
+
/**
|
|
81
|
+
* Delete up to `limit` rows for the group, returning the number of candidate
|
|
82
|
+
* rows found by the scan (see PostgresSyncRulesStorage#deleteGroupBatch for
|
|
83
|
+
* why the scan is counted rather than the delete).
|
|
84
|
+
*/
|
|
85
|
+
deleteGroupRowsBatch(db: Queryable, options: {
|
|
81
86
|
groupId: number;
|
|
82
|
-
|
|
87
|
+
limit: number;
|
|
88
|
+
}): Promise<bigint>;
|
|
83
89
|
private wherePendingDelete;
|
|
84
90
|
}
|
|
85
91
|
export {};
|
|
@@ -244,20 +244,75 @@ export class PostgresCurrentDataStore {
|
|
|
244
244
|
AND pending_delete <= ${{ type: 'int8', value: options.lastCheckpoint }}
|
|
245
245
|
`.execute();
|
|
246
246
|
}
|
|
247
|
-
|
|
247
|
+
/**
|
|
248
|
+
* Delete up to `limit` rows for the group, returning the number of candidate
|
|
249
|
+
* rows found by the scan (see PostgresSyncRulesStorage#deleteGroupBatch for
|
|
250
|
+
* why the scan is counted rather than the delete).
|
|
251
|
+
*/
|
|
252
|
+
async deleteGroupRowsBatch(db, options) {
|
|
248
253
|
if (this.softDeleteEnabled) {
|
|
249
|
-
await db.sql `
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
+
const result = await db.sql `
|
|
255
|
+
WITH
|
|
256
|
+
batch AS (
|
|
257
|
+
SELECT
|
|
258
|
+
ctid
|
|
259
|
+
FROM
|
|
260
|
+
v3_current_data
|
|
261
|
+
WHERE
|
|
262
|
+
group_id = ${{ type: 'int4', value: options.groupId }}
|
|
263
|
+
LIMIT
|
|
264
|
+
${{ type: 'int4', value: options.limit }}
|
|
265
|
+
),
|
|
266
|
+
deleted AS (
|
|
267
|
+
DELETE FROM v3_current_data
|
|
268
|
+
WHERE
|
|
269
|
+
ctid IN (
|
|
270
|
+
SELECT
|
|
271
|
+
ctid
|
|
272
|
+
FROM
|
|
273
|
+
batch
|
|
274
|
+
)
|
|
275
|
+
RETURNING
|
|
276
|
+
1
|
|
277
|
+
)
|
|
278
|
+
SELECT
|
|
279
|
+
COUNT(*) AS count
|
|
280
|
+
FROM
|
|
281
|
+
batch
|
|
282
|
+
`.first();
|
|
283
|
+
return result?.count ?? 0n;
|
|
254
284
|
}
|
|
255
285
|
else {
|
|
256
|
-
await db.sql `
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
286
|
+
const result = await db.sql `
|
|
287
|
+
WITH
|
|
288
|
+
batch AS (
|
|
289
|
+
SELECT
|
|
290
|
+
ctid
|
|
291
|
+
FROM
|
|
292
|
+
current_data
|
|
293
|
+
WHERE
|
|
294
|
+
group_id = ${{ type: 'int4', value: options.groupId }}
|
|
295
|
+
LIMIT
|
|
296
|
+
${{ type: 'int4', value: options.limit }}
|
|
297
|
+
),
|
|
298
|
+
deleted AS (
|
|
299
|
+
DELETE FROM current_data
|
|
300
|
+
WHERE
|
|
301
|
+
ctid IN (
|
|
302
|
+
SELECT
|
|
303
|
+
ctid
|
|
304
|
+
FROM
|
|
305
|
+
batch
|
|
306
|
+
)
|
|
307
|
+
RETURNING
|
|
308
|
+
1
|
|
309
|
+
)
|
|
310
|
+
SELECT
|
|
311
|
+
COUNT(*) AS count
|
|
312
|
+
FROM
|
|
313
|
+
batch
|
|
314
|
+
`.first();
|
|
315
|
+
return result?.count ?? 0n;
|
|
261
316
|
}
|
|
262
317
|
}
|
|
263
318
|
wherePendingDelete(options) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"current-data-store.js","sourceRoot":"","sources":["../../src/storage/current-data-store.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"current-data-store.js","sourceRoot":"","sources":["../../src/storage/current-data-store.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,MAAM,gCAAgC,CAAC;AACzD,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAI5C,MAAM,wBAAwB,GAAG,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC;AAClG,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC,CAAC;AAQlF,MAAM,CAAC,MAAM,qBAAqB,GAAG,cAAc,CAAC;AACpD,MAAM,CAAC,MAAM,qBAAqB,GAAG,iBAAiB,CAAC;AAEvD,MAAM,OAAO,wBAAwB;IAC1B,KAAK,CAAS;IACd,iBAAiB,CAAU;IAEpC,YAAY,aAA2C;QACrD,IAAI,CAAC,iBAAiB,GAAG,aAAa,CAAC,qBAAqB,CAAC;QAC7D,IAAI,CAAC,KAAK,GAAG,aAAa,CAAC,qBAAqB,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,qBAAqB,CAAC;IACnG,CAAC;IAED,kBAAkB,CAChB,EAAa,EACb,OAIC;QAED,OAAO,EAAE,CAAC,UAAU,CAA6C;YAC/D,SAAS,EAAE;;;;;;YAML,IAAI,CAAC,KAAK;;;;YAIV,IAAI,CAAC,kBAAkB,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;;;;OAIpD;YACD,MAAM,EAAE;gBACN,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE;gBACxC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,aAAa,EAAE;gBACjD,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE;aACvC;SACF,CAAC,CAAC;IACL,CAAC;IAED,iBAAiB,CAAC,GAA+C;QAC/D,OAAO,wBAAwB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC9C,CAAC;IAED,cAAc,CACZ,EAAa,EACb,OAGC;QAED,OAAO,EAAE,CAAC,UAAU,CAIjB;YACD,SAAS,EAAE;;;;;;;;;;;;;;YAcL,IAAI,CAAC,KAAK;;;;;;OAMf;YACD,MAAM,EAAE;gBACN,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE;gBACzC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE;aACzC;SACF,CAAC,CAAC;IACL,CAAC;IAED,gBAAgB,CACd,EAAa,EACb,OAIC;QAED,MAAM,aAAa,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,8BAA8B,CAAC,CAAC,CAAC,KAAK,CAAC;QACxF,OAAO,EAAE,CAAC,UAAU,CAAM;YACxB,SAAS,EAAE;;YAEL,aAAa;;YAEb,IAAI,CAAC,KAAK;;;;;;;;;;;;OAYf;YACD,MAAM,EAAE;gBACN,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE;gBACzC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE;aACzC;SACF,CAAC,CAAC;IACL,CAAC;IAED,eAAe,CAAC,GAAQ,EAAE,gBAAyB;QACjD,IAAI,gBAAgB,EAAE,CAAC;YACrB,OAAO,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACpC,CAAC;QACD,OAAO,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACtG,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,EAAa,EAAE,OAA+B;QAC/D,IAAI,OAAO,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YACxB,OAAO;QACT,CAAC;QAED,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC3B,MAAM,EAAE,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;8BA4BY,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE;;;;;;;;;;;;;;;OAevD,CAAC,OAAO,EAAE,CAAC;YACZ,OAAO;QACT,CAAC;QAED,MAAM,EAAE,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;4BAuBY,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE;;;;;;;;;;;;;KAavD,CAAC,OAAO,EAAE,CAAC;IACd,CAAC;IAED,KAAK,CAAC,YAAY,CAChB,EAAa,EACb,OAGC;QAED,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YAChC,OAAO;QACT,CAAC;QACD,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC3B,MAAM,EAAE,CAAC,GAAG,CAAA;;;;;;;mCAOiB;gBACzB,IAAI,EAAE,OAAO;gBACb,KAAK,EAAE,OAAO,CAAC,OAAO;aACvB;;;;uCAI8B,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE;;;OAGxE,CAAC,OAAO,EAAE,CAAC;YACZ,OAAO;QACT,CAAC;QAED,MAAM,EAAE,CAAC,GAAG,CAAA;;;;;;;iCAOiB;YACzB,IAAI,EAAE,OAAO;YACb,KAAK,EAAE,OAAO,CAAC,OAAO;SACvB;;;;kCAI2B,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE;;;KAGrE,CAAC,OAAO,EAAE,CAAC;IACd,CAAC;IAED,KAAK,CAAC,qBAAqB,CAAC,EAAa,EAAE,OAAoD;QAC7F,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC5B,OAAO;QACT,CAAC;QACD,MAAM,EAAE,CAAC,GAAG,CAAA;;;qBAGK,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE;;gCAE7B,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,cAAc,EAAE;KAC1E,CAAC,OAAO,EAAE,CAAC;IACd,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,oBAAoB,CAAC,EAAa,EAAE,OAA2C;QACnF,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC3B,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,GAAG,CAAA;;;;;;;;2BAQN,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE;;gBAEnD,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE;;;;;;;;;;;;;;;;;;OAkB/C,CAAC,KAAK,EAAqB,CAAC;YAC7B,OAAO,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC;QAC7B,CAAC;aAAM,CAAC;YACN,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,GAAG,CAAA;;;;;;;;2BAQN,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE;;gBAEnD,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE;;;;;;;;;;;;;;;;;;OAkB/C,CAAC,KAAK,EAAqB,CAAC;YAC7B,OAAO,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC;QAC7B,CAAC;IACH,CAAC;IAEO,kBAAkB,CAAC,OAAkC;QAC3D,IAAI,IAAI,CAAC,iBAAiB,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;YACnD,OAAO,4BAA4B,CAAC;QACtC,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;CACF"}
|
|
@@ -3,6 +3,7 @@ export declare const WriteCheckpoint: t.ObjectCodec<{
|
|
|
3
3
|
user_id: t.IdentityCodec<t.CodecType.String>;
|
|
4
4
|
lsns: t.Codec<Record<string, string>, string, string, t.CodecProps>;
|
|
5
5
|
write_checkpoint: t.Codec<bigint, string | number, string, t.CodecProps>;
|
|
6
|
+
checkpoint_requested_at: t.Union<t.Codec<null, null, string, t.CodecProps>, t.Codec<Date, string | import("@powersync/service-sync-rules").DateTimeValue, string, t.CodecProps>>;
|
|
6
7
|
}>;
|
|
7
8
|
export type WriteCheckpoint = t.Encoded<typeof WriteCheckpoint>;
|
|
8
9
|
export type WriteCheckpointDecoded = t.Decoded<typeof WriteCheckpoint>;
|
|
@@ -10,6 +11,7 @@ export declare const CustomWriteCheckpoint: t.ObjectCodec<{
|
|
|
10
11
|
user_id: t.IdentityCodec<t.CodecType.String>;
|
|
11
12
|
write_checkpoint: t.Codec<bigint, string | number, string, t.CodecProps>;
|
|
12
13
|
sync_rules_id: t.Codec<bigint, string | number, string, t.CodecProps>;
|
|
14
|
+
checkpoint_requested_at: t.Union<t.Codec<null, null, string, t.CodecProps>, t.Codec<Date, string | import("@powersync/service-sync-rules").DateTimeValue, string, t.CodecProps>>;
|
|
13
15
|
}>;
|
|
14
16
|
export type CustomWriteCheckpoint = t.Encoded<typeof CustomWriteCheckpoint>;
|
|
15
17
|
export type CustomWriteCheckpointDecoded = t.Decoded<typeof CustomWriteCheckpoint>;
|
|
@@ -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.17.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.21",
|
|
19
|
+
"@powersync/lib-service-postgres": "0.5.3",
|
|
20
|
+
"@powersync/lib-services-framework": "0.10.0",
|
|
21
|
+
"@powersync/service-core": "1.24.0",
|
|
22
|
+
"@powersync/service-types": "0.17.0",
|
|
24
23
|
"@powersync/service-jsonbig": "0.17.13",
|
|
25
|
-
"@powersync/service-
|
|
24
|
+
"@powersync/service-jpgwire": "0.21.22",
|
|
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
|
+
};
|
|
@@ -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 = '';
|