@powersync/service-module-mysql 0.0.0-dev-20250304151813 → 0.0.0-dev-20250307115534
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 +24 -4
- package/dist/module/MySQLModule.d.ts +1 -1
- package/dist/module/MySQLModule.js +2 -3
- package/dist/module/MySQLModule.js.map +1 -1
- package/dist/replication/BinLogReplicationJob.js +1 -0
- package/dist/replication/BinLogReplicationJob.js.map +1 -1
- package/dist/replication/BinLogReplicator.js +1 -0
- package/dist/replication/BinLogReplicator.js.map +1 -1
- package/dist/replication/BinLogStream.d.ts +4 -2
- package/dist/replication/BinLogStream.js +21 -11
- package/dist/replication/BinLogStream.js.map +1 -1
- package/package.json +7 -7
- package/src/module/MySQLModule.ts +2 -3
- package/src/replication/BinLogReplicationJob.ts +1 -0
- package/src/replication/BinLogReplicator.ts +1 -0
- package/src/replication/BinLogStream.ts +38 -21
- package/test/src/BinLogStream.test.ts +25 -18
- package/test/src/BinlogStreamUtils.ts +27 -12
- package/test/src/setup.ts +2 -3
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { putOp, removeOp } from '@powersync/service-core-tests';
|
|
1
|
+
import { storage } from '@powersync/service-core';
|
|
2
|
+
import { METRICS_HELPER, putOp, removeOp } from '@powersync/service-core-tests';
|
|
3
3
|
import { v4 as uuid } from 'uuid';
|
|
4
4
|
import { describe, expect, test } from 'vitest';
|
|
5
5
|
import { BinlogStreamTestContext } from './BinlogStreamUtils.js';
|
|
6
6
|
import { env } from './env.js';
|
|
7
7
|
import { INITIALIZED_MONGO_STORAGE_FACTORY, INITIALIZED_POSTGRES_STORAGE_FACTORY } from './util.js';
|
|
8
|
+
import { ReplicationMetric } from '@powersync/service-types';
|
|
8
9
|
|
|
9
10
|
const BASIC_SYNC_RULES = `
|
|
10
11
|
bucket_definitions:
|
|
@@ -35,9 +36,9 @@ function defineBinlogStreamTests(factory: storage.TestStorageFactory) {
|
|
|
35
36
|
|
|
36
37
|
await context.replicateSnapshot();
|
|
37
38
|
|
|
38
|
-
const startRowCount = (await
|
|
39
|
+
const startRowCount = (await METRICS_HELPER.getMetricValueForTests(ReplicationMetric.ROWS_REPLICATED_TOTAL)) ?? 0;
|
|
39
40
|
const startTxCount =
|
|
40
|
-
(await
|
|
41
|
+
(await METRICS_HELPER.getMetricValueForTests(ReplicationMetric.TRANSACTIONS_REPLICATED_TOTAL)) ?? 0;
|
|
41
42
|
|
|
42
43
|
context.startStreaming();
|
|
43
44
|
const testId = uuid();
|
|
@@ -47,9 +48,9 @@ function defineBinlogStreamTests(factory: storage.TestStorageFactory) {
|
|
|
47
48
|
const data = await context.getBucketData('global[]');
|
|
48
49
|
|
|
49
50
|
expect(data).toMatchObject([putOp('test_data', { id: testId, description: 'test1', num: 1152921504606846976n })]);
|
|
50
|
-
const endRowCount = (await
|
|
51
|
+
const endRowCount = (await METRICS_HELPER.getMetricValueForTests(ReplicationMetric.ROWS_REPLICATED_TOTAL)) ?? 0;
|
|
51
52
|
const endTxCount =
|
|
52
|
-
(await
|
|
53
|
+
(await METRICS_HELPER.getMetricValueForTests(ReplicationMetric.TRANSACTIONS_REPLICATED_TOTAL)) ?? 0;
|
|
53
54
|
expect(endRowCount - startRowCount).toEqual(1);
|
|
54
55
|
expect(endTxCount - startTxCount).toEqual(1);
|
|
55
56
|
});
|
|
@@ -68,9 +69,9 @@ function defineBinlogStreamTests(factory: storage.TestStorageFactory) {
|
|
|
68
69
|
|
|
69
70
|
await context.replicateSnapshot();
|
|
70
71
|
|
|
71
|
-
const startRowCount = (await
|
|
72
|
+
const startRowCount = (await METRICS_HELPER.getMetricValueForTests(ReplicationMetric.ROWS_REPLICATED_TOTAL)) ?? 0;
|
|
72
73
|
const startTxCount =
|
|
73
|
-
(await
|
|
74
|
+
(await METRICS_HELPER.getMetricValueForTests(ReplicationMetric.TRANSACTIONS_REPLICATED_TOTAL)) ?? 0;
|
|
74
75
|
|
|
75
76
|
context.startStreaming();
|
|
76
77
|
|
|
@@ -80,9 +81,9 @@ function defineBinlogStreamTests(factory: storage.TestStorageFactory) {
|
|
|
80
81
|
const data = await context.getBucketData('global[]');
|
|
81
82
|
|
|
82
83
|
expect(data).toMatchObject([putOp('test_DATA', { id: testId, description: 'test1' })]);
|
|
83
|
-
const endRowCount = (await
|
|
84
|
+
const endRowCount = (await METRICS_HELPER.getMetricValueForTests(ReplicationMetric.ROWS_REPLICATED_TOTAL)) ?? 0;
|
|
84
85
|
const endTxCount =
|
|
85
|
-
(await
|
|
86
|
+
(await METRICS_HELPER.getMetricValueForTests(ReplicationMetric.TRANSACTIONS_REPLICATED_TOTAL)) ?? 0;
|
|
86
87
|
expect(endRowCount - startRowCount).toEqual(1);
|
|
87
88
|
expect(endTxCount - startTxCount).toEqual(1);
|
|
88
89
|
});
|
|
@@ -172,10 +173,15 @@ function defineBinlogStreamTests(factory: storage.TestStorageFactory) {
|
|
|
172
173
|
const testId = uuid();
|
|
173
174
|
await connectionManager.query(`INSERT INTO test_data(id, description) VALUES('${testId}','test1')`);
|
|
174
175
|
|
|
176
|
+
const startRowCount = (await METRICS_HELPER.getMetricValueForTests(ReplicationMetric.ROWS_REPLICATED_TOTAL)) ?? 0;
|
|
177
|
+
|
|
175
178
|
await context.replicateSnapshot();
|
|
179
|
+
context.startStreaming();
|
|
176
180
|
|
|
181
|
+
const endRowCount = (await METRICS_HELPER.getMetricValueForTests(ReplicationMetric.ROWS_REPLICATED_TOTAL)) ?? 0;
|
|
177
182
|
const data = await context.getBucketData('global[]');
|
|
178
183
|
expect(data).toMatchObject([putOp('test_data', { id: testId, description: 'test1' })]);
|
|
184
|
+
expect(endRowCount - startRowCount).toEqual(1);
|
|
179
185
|
});
|
|
180
186
|
|
|
181
187
|
test('snapshot with date values', async () => {
|
|
@@ -198,6 +204,7 @@ function defineBinlogStreamTests(factory: storage.TestStorageFactory) {
|
|
|
198
204
|
`);
|
|
199
205
|
|
|
200
206
|
await context.replicateSnapshot();
|
|
207
|
+
context.startStreaming();
|
|
201
208
|
|
|
202
209
|
const data = await context.getBucketData('global[]');
|
|
203
210
|
expect(data).toMatchObject([
|
|
@@ -227,9 +234,9 @@ function defineBinlogStreamTests(factory: storage.TestStorageFactory) {
|
|
|
227
234
|
|
|
228
235
|
await context.replicateSnapshot();
|
|
229
236
|
|
|
230
|
-
const startRowCount = (await
|
|
237
|
+
const startRowCount = (await METRICS_HELPER.getMetricValueForTests(ReplicationMetric.ROWS_REPLICATED_TOTAL)) ?? 0;
|
|
231
238
|
const startTxCount =
|
|
232
|
-
(await
|
|
239
|
+
(await METRICS_HELPER.getMetricValueForTests(ReplicationMetric.TRANSACTIONS_REPLICATED_TOTAL)) ?? 0;
|
|
233
240
|
|
|
234
241
|
context.startStreaming();
|
|
235
242
|
|
|
@@ -256,9 +263,9 @@ function defineBinlogStreamTests(factory: storage.TestStorageFactory) {
|
|
|
256
263
|
timestamp: '2023-03-06T15:47:00.000Z'
|
|
257
264
|
})
|
|
258
265
|
]);
|
|
259
|
-
const endRowCount = (await
|
|
266
|
+
const endRowCount = (await METRICS_HELPER.getMetricValueForTests(ReplicationMetric.ROWS_REPLICATED_TOTAL)) ?? 0;
|
|
260
267
|
const endTxCount =
|
|
261
|
-
(await
|
|
268
|
+
(await METRICS_HELPER.getMetricValueForTests(ReplicationMetric.TRANSACTIONS_REPLICATED_TOTAL)) ?? 0;
|
|
262
269
|
expect(endRowCount - startRowCount).toEqual(2);
|
|
263
270
|
expect(endTxCount - startTxCount).toEqual(2);
|
|
264
271
|
});
|
|
@@ -272,9 +279,9 @@ function defineBinlogStreamTests(factory: storage.TestStorageFactory) {
|
|
|
272
279
|
|
|
273
280
|
await context.replicateSnapshot();
|
|
274
281
|
|
|
275
|
-
const startRowCount = (await
|
|
282
|
+
const startRowCount = (await METRICS_HELPER.getMetricValueForTests(ReplicationMetric.ROWS_REPLICATED_TOTAL)) ?? 0;
|
|
276
283
|
const startTxCount =
|
|
277
|
-
(await
|
|
284
|
+
(await METRICS_HELPER.getMetricValueForTests(ReplicationMetric.TRANSACTIONS_REPLICATED_TOTAL)) ?? 0;
|
|
278
285
|
|
|
279
286
|
context.startStreaming();
|
|
280
287
|
|
|
@@ -282,9 +289,9 @@ function defineBinlogStreamTests(factory: storage.TestStorageFactory) {
|
|
|
282
289
|
const data = await context.getBucketData('global[]');
|
|
283
290
|
|
|
284
291
|
expect(data).toMatchObject([]);
|
|
285
|
-
const endRowCount = (await
|
|
292
|
+
const endRowCount = (await METRICS_HELPER.getMetricValueForTests(ReplicationMetric.ROWS_REPLICATED_TOTAL)) ?? 0;
|
|
286
293
|
const endTxCount =
|
|
287
|
-
(await
|
|
294
|
+
(await METRICS_HELPER.getMetricValueForTests(ReplicationMetric.TRANSACTIONS_REPLICATED_TOTAL)) ?? 0;
|
|
288
295
|
|
|
289
296
|
// There was a transaction, but we should not replicate any actual data
|
|
290
297
|
expect(endRowCount - startRowCount).toEqual(0);
|
|
@@ -4,13 +4,16 @@ import { MySQLConnectionManager } from '@module/replication/MySQLConnectionManag
|
|
|
4
4
|
import { logger } from '@powersync/lib-services-framework';
|
|
5
5
|
import {
|
|
6
6
|
BucketStorageFactory,
|
|
7
|
-
|
|
7
|
+
createCoreReplicationMetrics,
|
|
8
|
+
initializeCoreReplicationMetrics,
|
|
9
|
+
InternalOpId,
|
|
8
10
|
OplogEntry,
|
|
11
|
+
ProtocolOpId,
|
|
9
12
|
ReplicationCheckpoint,
|
|
10
13
|
storage,
|
|
11
14
|
SyncRulesBucketStorage
|
|
12
15
|
} from '@powersync/service-core';
|
|
13
|
-
import { test_utils } from '@powersync/service-core-tests';
|
|
16
|
+
import { METRICS_HELPER, test_utils } from '@powersync/service-core-tests';
|
|
14
17
|
import mysqlPromise from 'mysql2/promise';
|
|
15
18
|
import { clearTestDb, TEST_CONNECTION_OPTIONS } from './util.js';
|
|
16
19
|
|
|
@@ -43,7 +46,10 @@ export class BinlogStreamTestContext {
|
|
|
43
46
|
constructor(
|
|
44
47
|
public factory: BucketStorageFactory,
|
|
45
48
|
public connectionManager: MySQLConnectionManager
|
|
46
|
-
) {
|
|
49
|
+
) {
|
|
50
|
+
createCoreReplicationMetrics(METRICS_HELPER.metricsEngine);
|
|
51
|
+
initializeCoreReplicationMetrics(METRICS_HELPER.metricsEngine);
|
|
52
|
+
}
|
|
47
53
|
|
|
48
54
|
async dispose() {
|
|
49
55
|
this.abortController.abort();
|
|
@@ -96,6 +102,7 @@ export class BinlogStreamTestContext {
|
|
|
96
102
|
}
|
|
97
103
|
const options: BinLogStreamOptions = {
|
|
98
104
|
storage: this.storage,
|
|
105
|
+
metrics: METRICS_HELPER.metricsEngine,
|
|
99
106
|
connections: this.connectionManager,
|
|
100
107
|
abortSignal: this.abortController.signal
|
|
101
108
|
};
|
|
@@ -116,30 +123,38 @@ export class BinlogStreamTestContext {
|
|
|
116
123
|
this.streamPromise = this.binlogStream.streamChanges();
|
|
117
124
|
}
|
|
118
125
|
|
|
119
|
-
async getCheckpoint(options?: { timeout?: number }): Promise<
|
|
126
|
+
async getCheckpoint(options?: { timeout?: number }): Promise<InternalOpId> {
|
|
120
127
|
const connection = await this.connectionManager.getConnection();
|
|
121
128
|
let checkpoint = await Promise.race([
|
|
122
129
|
getClientCheckpoint(connection, this.factory, { timeout: options?.timeout ?? 60_000 }),
|
|
123
130
|
this.streamPromise
|
|
124
131
|
]);
|
|
125
132
|
connection.release();
|
|
126
|
-
if (
|
|
133
|
+
if (checkpoint == null) {
|
|
127
134
|
// This indicates an issue with the test setup - streamingPromise completed instead
|
|
128
135
|
// of getClientCheckpoint()
|
|
129
|
-
throw new Error('Test failure - streamingPromise completed');
|
|
136
|
+
throw new Error('Test failure - streamingPromise completed. Was startStreaming() called?');
|
|
130
137
|
}
|
|
131
|
-
return checkpoint
|
|
138
|
+
return checkpoint;
|
|
132
139
|
}
|
|
133
140
|
|
|
134
|
-
async getBucketsDataBatch(buckets: Record<string,
|
|
141
|
+
async getBucketsDataBatch(buckets: Record<string, InternalOpId>, options?: { timeout?: number }) {
|
|
135
142
|
const checkpoint = await this.getCheckpoint(options);
|
|
136
|
-
const map = new Map<string,
|
|
143
|
+
const map = new Map<string, InternalOpId>(Object.entries(buckets));
|
|
137
144
|
return test_utils.fromAsync(this.storage!.getBucketDataBatch(checkpoint, map));
|
|
138
145
|
}
|
|
139
146
|
|
|
140
|
-
async getBucketData(
|
|
147
|
+
async getBucketData(
|
|
148
|
+
bucket: string,
|
|
149
|
+
start?: ProtocolOpId | InternalOpId | undefined,
|
|
150
|
+
options?: { timeout?: number }
|
|
151
|
+
): Promise<OplogEntry[]> {
|
|
152
|
+
start = start ?? 0n;
|
|
153
|
+
if (typeof start == 'string') {
|
|
154
|
+
start = BigInt(start);
|
|
155
|
+
}
|
|
141
156
|
const checkpoint = await this.getCheckpoint(options);
|
|
142
|
-
const map = new Map<string,
|
|
157
|
+
const map = new Map<string, InternalOpId>([[bucket, start]]);
|
|
143
158
|
const batch = this.storage!.getBucketDataBatch(checkpoint, map);
|
|
144
159
|
const batches = await test_utils.fromAsync(batch);
|
|
145
160
|
return batches[0]?.batch.data ?? [];
|
|
@@ -150,7 +165,7 @@ export async function getClientCheckpoint(
|
|
|
150
165
|
connection: mysqlPromise.Connection,
|
|
151
166
|
storageFactory: BucketStorageFactory,
|
|
152
167
|
options?: { timeout?: number }
|
|
153
|
-
): Promise<
|
|
168
|
+
): Promise<InternalOpId> {
|
|
154
169
|
const start = Date.now();
|
|
155
170
|
const gtid = await readExecutedGtid(connection);
|
|
156
171
|
// This old API needs a persisted checkpoint id.
|
package/test/src/setup.ts
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { container } from '@powersync/lib-services-framework';
|
|
2
|
-
import {
|
|
2
|
+
import { METRICS_HELPER } from '@powersync/service-core-tests';
|
|
3
3
|
import { beforeAll, beforeEach } from 'vitest';
|
|
4
4
|
|
|
5
5
|
beforeAll(async () => {
|
|
6
6
|
// Executes for every test file
|
|
7
7
|
container.registerDefaults();
|
|
8
|
-
await test_utils.initMetrics();
|
|
9
8
|
});
|
|
10
9
|
|
|
11
10
|
beforeEach(async () => {
|
|
12
|
-
|
|
11
|
+
METRICS_HELPER.resetMetrics();
|
|
13
12
|
});
|