@powersync/service-core 1.23.1 → 1.23.3
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 +27 -0
- package/dist/api/RouteAPI.d.ts +25 -11
- package/dist/replication/AbstractReplicator.d.ts +8 -0
- package/dist/replication/AbstractReplicator.js.map +1 -1
- package/dist/routes/RouterEngine.d.ts +1 -0
- package/dist/routes/RouterEngine.js +6 -1
- package/dist/routes/RouterEngine.js.map +1 -1
- package/dist/routes/configure-fastify.d.ts +52 -44
- package/dist/routes/configure-fastify.js +15 -2
- package/dist/routes/configure-fastify.js.map +1 -1
- package/dist/routes/endpoints/checkpointing.js +1 -3
- package/dist/routes/endpoints/checkpointing.js.map +1 -1
- package/dist/routes/endpoints/socket-route.js +2 -1
- package/dist/routes/endpoints/socket-route.js.map +1 -1
- package/dist/storage/BucketStorageBatch.d.ts +60 -11
- package/dist/storage/BucketStorageBatch.js.map +1 -1
- package/dist/storage/ChecksumCache.d.ts +11 -6
- package/dist/storage/ChecksumCache.js +5 -4
- package/dist/storage/ChecksumCache.js.map +1 -1
- package/dist/storage/SyncRulesBucketStorage.d.ts +35 -5
- package/dist/storage/SyncRulesBucketStorage.js.map +1 -1
- package/dist/storage/WriteCheckpointAPI.d.ts +1 -1
- package/dist/sync/BucketChecksumState.d.ts +5 -2
- package/dist/sync/BucketChecksumState.js +36 -8
- package/dist/sync/BucketChecksumState.js.map +1 -1
- package/dist/sync/RequestTracker.d.ts +7 -0
- package/dist/sync/RequestTracker.js +12 -0
- package/dist/sync/RequestTracker.js.map +1 -1
- package/dist/sync/sync.js +118 -38
- package/dist/sync/sync.js.map +1 -1
- package/dist/system/ServiceContext.d.ts +2 -0
- package/dist/system/ServiceContext.js +2 -0
- package/dist/system/ServiceContext.js.map +1 -1
- package/dist/tracing/PerformanceTracer.d.ts +7 -1
- package/dist/tracing/PerformanceTracer.js +8 -0
- package/dist/tracing/PerformanceTracer.js.map +1 -1
- package/dist/util/checkpointing.d.ts +3 -8
- package/dist/util/checkpointing.js +1 -16
- package/dist/util/checkpointing.js.map +1 -1
- package/dist/util/config/compound-config-collector.js +10 -2
- package/dist/util/config/compound-config-collector.js.map +1 -1
- package/dist/util/config/defaults.d.ts +1 -0
- package/dist/util/config/defaults.js +1 -0
- package/dist/util/config/defaults.js.map +1 -1
- package/dist/util/config/types.d.ts +1 -0
- package/dist/util/util-index.d.ts +1 -0
- package/dist/util/util-index.js +1 -0
- package/dist/util/util-index.js.map +1 -1
- package/dist/util/utils.d.ts +1 -1
- package/dist/util/utils.js +1 -1
- package/dist/util/write-checkpoint-batcher.d.ts +19 -0
- package/dist/util/write-checkpoint-batcher.js +90 -0
- package/dist/util/write-checkpoint-batcher.js.map +1 -0
- package/package.json +5 -5
- package/src/api/RouteAPI.ts +25 -11
- package/src/replication/AbstractReplicator.ts +8 -0
- package/src/routes/RouterEngine.ts +7 -1
- package/src/routes/configure-fastify.ts +25 -2
- package/src/routes/endpoints/checkpointing.ts +1 -4
- package/src/routes/endpoints/socket-route.ts +2 -1
- package/src/storage/BucketStorageBatch.ts +61 -11
- package/src/storage/ChecksumCache.ts +27 -14
- package/src/storage/SyncRulesBucketStorage.ts +42 -5
- package/src/storage/WriteCheckpointAPI.ts +1 -1
- package/src/sync/BucketChecksumState.ts +65 -8
- package/src/sync/RequestTracker.ts +20 -0
- package/src/sync/sync.ts +148 -44
- package/src/system/ServiceContext.ts +7 -0
- package/src/tracing/PerformanceTracer.ts +18 -1
- package/src/util/checkpointing.ts +3 -22
- package/src/util/config/compound-config-collector.ts +13 -1
- package/src/util/config/defaults.ts +1 -0
- package/src/util/config/types.ts +1 -0
- package/src/util/util-index.ts +1 -0
- package/src/util/utils.ts +1 -1
- package/src/util/write-checkpoint-batcher.ts +122 -0
- package/test/src/checksum_cache.test.ts +22 -0
- package/test/src/config.test.ts +42 -0
- package/test/src/sync/BucketChecksumState.test.ts +41 -1
- package/test/src/util/checkpointing.test.ts +170 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -19,6 +19,11 @@ import { SyncStorageWriteCheckpointAPI } from './WriteCheckpointAPI.js';
|
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Storage for a specific replication stream.
|
|
22
|
+
*
|
|
23
|
+
* Replication writes source changes, source table metadata, snapshot progress,
|
|
24
|
+
* resume positions, and checkpoint boundaries through this interface. The sync
|
|
25
|
+
* API reads the same stream state as checkpoints, checksums, bucket data,
|
|
26
|
+
* parameter lookup rows, and write-checkpoint acknowledgements.
|
|
22
27
|
*/
|
|
23
28
|
export interface SyncRulesBucketStorage
|
|
24
29
|
extends ObserverClient<SyncRulesBucketStorageListener>,
|
|
@@ -31,13 +36,18 @@ export interface SyncRulesBucketStorage
|
|
|
31
36
|
readonly logger: Logger;
|
|
32
37
|
|
|
33
38
|
/**
|
|
34
|
-
* Create a
|
|
39
|
+
* Create a writer for a source-specific unit of replication work.
|
|
35
40
|
*
|
|
36
|
-
* The writer
|
|
41
|
+
* The writer may be used for a long-running streaming attempt, a table
|
|
42
|
+
* snapshot, a page of snapshot work, or a short setup step. Pending work
|
|
43
|
+
* that should be persisted must be flushed, committed, or kept alive at the
|
|
44
|
+
* appropriate source boundary before the writer is disposed.
|
|
37
45
|
*/
|
|
38
46
|
createWriter(options: CreateWriterOptions): Promise<BucketStorageBatch>;
|
|
39
47
|
|
|
40
48
|
/**
|
|
49
|
+
* Callback wrapper around `createWriter()`.
|
|
50
|
+
*
|
|
41
51
|
* @deprecated Use `createWriter()` with `await using` instead.
|
|
42
52
|
*/
|
|
43
53
|
startBatch(
|
|
@@ -103,7 +113,7 @@ export interface SyncRulesBucketStorage
|
|
|
103
113
|
*
|
|
104
114
|
* This is a best-effort optimization:
|
|
105
115
|
* 1. This may include more changes than what actually occurred.
|
|
106
|
-
* 2. This may return invalidateDataBuckets or invalidateParameterBuckets instead of
|
|
116
|
+
* 2. This may return invalidateDataBuckets or invalidateParameterBuckets instead of returning
|
|
107
117
|
* specific changes.
|
|
108
118
|
* @param options
|
|
109
119
|
*/
|
|
@@ -128,7 +138,7 @@ export interface SyncRulesBucketStorage
|
|
|
128
138
|
* @param options batch size options
|
|
129
139
|
*/
|
|
130
140
|
getBucketDataBatch(
|
|
131
|
-
checkpoint:
|
|
141
|
+
checkpoint: ReplicationCheckpoint,
|
|
132
142
|
dataBuckets: BucketDataRequest[],
|
|
133
143
|
options?: BucketDataBatchOptions
|
|
134
144
|
): AsyncIterable<SyncBucketDataChunk>;
|
|
@@ -141,7 +151,11 @@ export interface SyncRulesBucketStorage
|
|
|
141
151
|
* This may be slow, depending on the size of the buckets.
|
|
142
152
|
* The checksums are cached internally to compensate for this, but does not cover all cases.
|
|
143
153
|
*/
|
|
144
|
-
getChecksums(
|
|
154
|
+
getChecksums(
|
|
155
|
+
checkpoint: ReplicationCheckpoint,
|
|
156
|
+
buckets: BucketChecksumRequest[],
|
|
157
|
+
options?: BucketChecksumOptions
|
|
158
|
+
): Promise<util.ChecksumMap>;
|
|
145
159
|
|
|
146
160
|
/**
|
|
147
161
|
* Clear checksum cache. Primarily intended for tests.
|
|
@@ -169,6 +183,12 @@ export interface BucketChecksumRequest {
|
|
|
169
183
|
source: BucketDataSource;
|
|
170
184
|
}
|
|
171
185
|
|
|
186
|
+
export interface BucketChecksumOptions {
|
|
187
|
+
requestHint?: BucketRequestHint;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export type BucketRequestHint = 'bulk' | 'incremental';
|
|
191
|
+
|
|
172
192
|
export interface ReplicationStreamStatus {
|
|
173
193
|
/**
|
|
174
194
|
* Source position to resume replication from.
|
|
@@ -181,6 +201,9 @@ export interface ReplicationStreamStatus {
|
|
|
181
201
|
}
|
|
182
202
|
export interface ResolveTablesOptions {
|
|
183
203
|
connection_id: number;
|
|
204
|
+
/**
|
|
205
|
+
* Source table or collection metadata discovered during snapshot or streaming.
|
|
206
|
+
*/
|
|
184
207
|
source: SourceEntityDescriptor;
|
|
185
208
|
/**
|
|
186
209
|
* For tests only - custom id generator for stable ids.
|
|
@@ -193,11 +216,23 @@ export interface ResolveTablesOptions {
|
|
|
193
216
|
}
|
|
194
217
|
|
|
195
218
|
export interface ResolveTablesResult {
|
|
219
|
+
/**
|
|
220
|
+
* Current source table mappings that should receive replicated data.
|
|
221
|
+
*/
|
|
196
222
|
tables: SourceTable[];
|
|
223
|
+
/**
|
|
224
|
+
* Outdated source table mappings that should be removed by the connector.
|
|
225
|
+
*/
|
|
197
226
|
dropTables: SourceTable[];
|
|
198
227
|
}
|
|
199
228
|
|
|
229
|
+
/**
|
|
230
|
+
* Options for creating a storage writer.
|
|
231
|
+
*/
|
|
200
232
|
export interface CreateWriterOptions extends ParseSyncConfigOptions {
|
|
233
|
+
/**
|
|
234
|
+
* Source-specific zero or empty replication position.
|
|
235
|
+
*/
|
|
201
236
|
zeroLSN: string;
|
|
202
237
|
/**
|
|
203
238
|
* Whether or not to store a copy of the current data.
|
|
@@ -359,6 +394,8 @@ export interface TerminateOptions extends ClearStorageOptions {
|
|
|
359
394
|
}
|
|
360
395
|
|
|
361
396
|
export interface BucketDataBatchOptions {
|
|
397
|
+
requestHint?: BucketRequestHint;
|
|
398
|
+
|
|
362
399
|
/** Limit number of documents returned. Defaults to 1000. */
|
|
363
400
|
limit?: number;
|
|
364
401
|
|
|
@@ -58,7 +58,7 @@ export type LastWriteCheckpointFilters = CustomWriteCheckpointFilters | ManagedW
|
|
|
58
58
|
export interface BaseWriteCheckpointAPI {
|
|
59
59
|
readonly writeCheckpointMode: WriteCheckpointMode;
|
|
60
60
|
setWriteCheckpointMode(mode: WriteCheckpointMode): void;
|
|
61
|
-
|
|
61
|
+
createManagedWriteCheckpoints(checkpoints: ManagedWriteCheckpointOptions[]): Promise<Map<string, bigint>>;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
/**
|
|
@@ -22,9 +22,24 @@ import {
|
|
|
22
22
|
} from '@powersync/lib-services-framework';
|
|
23
23
|
import { JwtPayload } from '../auth/JwtPayload.js';
|
|
24
24
|
import { ParameterSetLimitExceededError } from '../storage/storage-index.js';
|
|
25
|
+
import { PerformanceTracer } from '../tracing/PerformanceTracer.js';
|
|
25
26
|
import { SyncContext } from './SyncContext.js';
|
|
26
27
|
import { getIntersection, hasIntersection } from './util.js';
|
|
27
28
|
|
|
29
|
+
export type SyncCheckpointTraceCategory =
|
|
30
|
+
// buildNextCheckpointLine, excluding parameter computation and checksum lookups
|
|
31
|
+
| 'checkpoint'
|
|
32
|
+
// Parameter lookups
|
|
33
|
+
| 'parameters'
|
|
34
|
+
// Checksum calculations
|
|
35
|
+
| 'checksum'
|
|
36
|
+
// Waiting for a data lock to become available
|
|
37
|
+
| 'acquiring_lock'
|
|
38
|
+
// Data fetches. Holds one data lock for this period.
|
|
39
|
+
| 'bucket_data'
|
|
40
|
+
// Sending data to client, may include serialization overhead. Holds one data lock for this period in most cases.
|
|
41
|
+
| 'sending';
|
|
42
|
+
|
|
28
43
|
export interface BucketChecksumStateOptions {
|
|
29
44
|
syncContext: SyncContext;
|
|
30
45
|
bucketStorage: BucketChecksumStateStorage;
|
|
@@ -112,13 +127,18 @@ export class BucketChecksumState {
|
|
|
112
127
|
* @param next The updated checkpoint
|
|
113
128
|
* @returns A {@link CheckpointLine} if any of the buckets watched by this connected was updated, or otherwise `null`.
|
|
114
129
|
*/
|
|
115
|
-
async buildNextCheckpointLine(
|
|
130
|
+
async buildNextCheckpointLine(
|
|
131
|
+
next: storage.StorageCheckpointUpdate,
|
|
132
|
+
tracer?: PerformanceTracer<SyncCheckpointTraceCategory>
|
|
133
|
+
): Promise<CheckpointLine | null> {
|
|
134
|
+
tracer ??= new PerformanceTracer<SyncCheckpointTraceCategory>(`sync checkpoint ${next.base.checkpoint}`);
|
|
135
|
+
|
|
116
136
|
const { writeCheckpoint, base } = next;
|
|
117
137
|
const userIdForLogs = this.parameterState.syncParams.userId;
|
|
118
138
|
|
|
119
139
|
const storage = this.bucketStorage;
|
|
120
140
|
|
|
121
|
-
const update = await this.parameterState.getCheckpointUpdate(next);
|
|
141
|
+
const update = await this.parameterState.getCheckpointUpdate(next, tracer);
|
|
122
142
|
const { buckets: allBuckets, updatedBuckets, usedParameterResults } = update;
|
|
123
143
|
|
|
124
144
|
/** Set of all buckets in this checkpoint. */
|
|
@@ -161,6 +181,7 @@ export class BucketChecksumState {
|
|
|
161
181
|
|
|
162
182
|
// Re-check updated buckets only
|
|
163
183
|
let checksumLookups: storage.BucketChecksumRequest[] = [];
|
|
184
|
+
let hasNewBucket = false;
|
|
164
185
|
|
|
165
186
|
let newChecksums = new Map<string, util.BucketChecksum>();
|
|
166
187
|
for (let desc of bucketDescriptionMap.values()) {
|
|
@@ -174,11 +195,17 @@ export class BucketChecksumState {
|
|
|
174
195
|
newChecksums.set(desc.bucket, existing);
|
|
175
196
|
} else {
|
|
176
197
|
checksumLookups.push({ bucket: desc.bucket, source: desc.source });
|
|
198
|
+
hasNewBucket ||= !this.lastChecksums.has(desc.bucket);
|
|
177
199
|
}
|
|
178
200
|
}
|
|
179
201
|
|
|
180
202
|
if (checksumLookups.length > 0) {
|
|
181
|
-
|
|
203
|
+
const requestHint: storage.BucketRequestHint = hasNewBucket ? 'bulk' : 'incremental';
|
|
204
|
+
let updatedChecksums: util.ChecksumMap;
|
|
205
|
+
|
|
206
|
+
using _ = tracer.span('checksum');
|
|
207
|
+
updatedChecksums = await storage.getChecksums(base, checksumLookups, { requestHint });
|
|
208
|
+
|
|
182
209
|
for (let [bucket, value] of updatedChecksums.entries()) {
|
|
183
210
|
newChecksums.set(bucket, value);
|
|
184
211
|
}
|
|
@@ -186,12 +213,23 @@ export class BucketChecksumState {
|
|
|
186
213
|
checksumMap = newChecksums;
|
|
187
214
|
} else {
|
|
188
215
|
// Re-check all buckets
|
|
189
|
-
const
|
|
190
|
-
|
|
216
|
+
const hasNewBucket =
|
|
217
|
+
this.lastChecksums == null ||
|
|
218
|
+
[...bucketDescriptionMap.values()].some((b) => !this.lastChecksums!.has(b.bucket));
|
|
219
|
+
const requestHint: storage.BucketRequestHint = hasNewBucket ? 'bulk' : 'incremental';
|
|
220
|
+
const bucketList = [...bucketDescriptionMap.values()].map((b) => ({
|
|
221
|
+
bucket: b.bucket,
|
|
222
|
+
source: b.source
|
|
223
|
+
}));
|
|
224
|
+
|
|
225
|
+
using _ = tracer.span('checksum');
|
|
226
|
+
checksumMap = await storage.getChecksums(base, bucketList, { requestHint });
|
|
191
227
|
}
|
|
192
228
|
|
|
193
229
|
// Subset of buckets for which there may be new data in this batch.
|
|
194
230
|
let bucketsToFetch: ResolvedBucket[];
|
|
231
|
+
let bucketDataRequestHint: storage.BucketRequestHint;
|
|
232
|
+
const newBucketDownloads = new Set<string>();
|
|
195
233
|
|
|
196
234
|
let checkpointLine: util.StreamingSyncCheckpointDiff | util.StreamingSyncCheckpoint;
|
|
197
235
|
|
|
@@ -232,6 +270,12 @@ export class BucketChecksumState {
|
|
|
232
270
|
bucketsToFetch = [...generateBucketsToFetch].map((b) => {
|
|
233
271
|
return bucketDescriptionMap.get(b)!;
|
|
234
272
|
});
|
|
273
|
+
for (const bucket of diff.updatedBuckets) {
|
|
274
|
+
if (!this.lastChecksums!.has(bucket.bucket)) {
|
|
275
|
+
newBucketDownloads.add(bucket.bucket);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
bucketDataRequestHint = newBucketDownloads.size > 0 ? 'bulk' : 'incremental';
|
|
235
279
|
|
|
236
280
|
deferredLog = () => {
|
|
237
281
|
let message = `Updated checkpoint: ${base.checkpoint} | `;
|
|
@@ -280,6 +324,10 @@ export class BucketChecksumState {
|
|
|
280
324
|
);
|
|
281
325
|
};
|
|
282
326
|
bucketsToFetch = allBuckets;
|
|
327
|
+
for (const bucket of bucketsToFetch) {
|
|
328
|
+
newBucketDownloads.add(bucket.bucket);
|
|
329
|
+
}
|
|
330
|
+
bucketDataRequestHint = 'bulk';
|
|
283
331
|
|
|
284
332
|
const subscriptions: util.StreamDescription[] = [];
|
|
285
333
|
const streamNameToIndex = new Map<string, number>();
|
|
@@ -321,6 +369,7 @@ export class BucketChecksumState {
|
|
|
321
369
|
return {
|
|
322
370
|
checkpointLine,
|
|
323
371
|
bucketsToFetch,
|
|
372
|
+
bucketDataRequestHint,
|
|
324
373
|
advance: () => {
|
|
325
374
|
hasAdvanced = true;
|
|
326
375
|
// bucketDataPositions must be updated in-place - it represents the current state of
|
|
@@ -512,12 +561,15 @@ export class BucketParameterState {
|
|
|
512
561
|
return (desc.subscribedToByDefault && this.includeDefaultStreams) || this.subscribedStreamNames.has(desc.name);
|
|
513
562
|
}
|
|
514
563
|
|
|
515
|
-
async getCheckpointUpdate(
|
|
564
|
+
async getCheckpointUpdate(
|
|
565
|
+
checkpoint: storage.StorageCheckpointUpdate,
|
|
566
|
+
tracer: PerformanceTracer<SyncCheckpointTraceCategory>
|
|
567
|
+
): Promise<CheckpointUpdate> {
|
|
516
568
|
const querier = this.querier;
|
|
517
569
|
let update: CheckpointUpdate;
|
|
518
570
|
if (querier.hasDynamicBuckets) {
|
|
519
571
|
try {
|
|
520
|
-
update = await this.getCheckpointUpdateDynamic(checkpoint);
|
|
572
|
+
update = await this.getCheckpointUpdateDynamic(checkpoint, tracer);
|
|
521
573
|
} catch (e: unknown) {
|
|
522
574
|
if (e instanceof ParameterSetLimitExceededError) {
|
|
523
575
|
// Too many parameter results, create a breakdown of which streams are responsible for the most queries and
|
|
@@ -580,7 +632,10 @@ export class BucketParameterState {
|
|
|
580
632
|
/**
|
|
581
633
|
* For dynamic buckets, we need to re-query the list of buckets every time.
|
|
582
634
|
*/
|
|
583
|
-
private async getCheckpointUpdateDynamic(
|
|
635
|
+
private async getCheckpointUpdateDynamic(
|
|
636
|
+
checkpoint: storage.StorageCheckpointUpdate,
|
|
637
|
+
tracer: PerformanceTracer<SyncCheckpointTraceCategory>
|
|
638
|
+
): Promise<CheckpointUpdate> {
|
|
584
639
|
const querier = this.querier;
|
|
585
640
|
const staticBuckets = this.staticBuckets.values();
|
|
586
641
|
const update = checkpoint.update;
|
|
@@ -636,6 +691,7 @@ export class BucketParameterState {
|
|
|
636
691
|
}
|
|
637
692
|
|
|
638
693
|
try {
|
|
694
|
+
using _ = tracer.span('parameters', definition);
|
|
639
695
|
const results = await checkpoint.base.getParameterSets(lookups, remainingBudget);
|
|
640
696
|
const numRows = results.reduce((a, b) => a + b.rows.length, 0);
|
|
641
697
|
|
|
@@ -692,6 +748,7 @@ export class BucketParameterState {
|
|
|
692
748
|
export interface CheckpointLine {
|
|
693
749
|
checkpointLine: util.StreamingSyncCheckpointDiff | util.StreamingSyncCheckpoint;
|
|
694
750
|
bucketsToFetch: ResolvedBucket[];
|
|
751
|
+
bucketDataRequestHint: storage.BucketRequestHint;
|
|
695
752
|
|
|
696
753
|
/**
|
|
697
754
|
* Call when a checkpoint line is being sent to a client, to update the internal state.
|
|
@@ -15,6 +15,8 @@ export class RequestTracker {
|
|
|
15
15
|
largeBuckets: Record<string, number> = {};
|
|
16
16
|
|
|
17
17
|
private encoding: string | undefined = undefined;
|
|
18
|
+
private lastCheckpointLogOperationsSynced = 0;
|
|
19
|
+
private lastCheckpointLogDataSyncedBytes = 0;
|
|
18
20
|
|
|
19
21
|
constructor(private metrics: MetricsEngine) {
|
|
20
22
|
this.metrics = metrics;
|
|
@@ -68,6 +70,19 @@ export class RequestTracker {
|
|
|
68
70
|
encoding: this.encoding
|
|
69
71
|
};
|
|
70
72
|
}
|
|
73
|
+
|
|
74
|
+
getIncrementalCheckpointStats(): CheckpointLogStats {
|
|
75
|
+
const operationsSynced = this.operationsSynced - this.lastCheckpointLogOperationsSynced;
|
|
76
|
+
const dataSyncedBytes = this.dataSyncedBytes - this.lastCheckpointLogDataSyncedBytes;
|
|
77
|
+
|
|
78
|
+
this.lastCheckpointLogOperationsSynced = this.operationsSynced;
|
|
79
|
+
this.lastCheckpointLogDataSyncedBytes = this.dataSyncedBytes;
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
operations_synced: operationsSynced,
|
|
83
|
+
data_synced_bytes: dataSyncedBytes
|
|
84
|
+
};
|
|
85
|
+
}
|
|
71
86
|
}
|
|
72
87
|
|
|
73
88
|
export interface OperationCounts {
|
|
@@ -83,6 +98,11 @@ export interface OperationsSentStats {
|
|
|
83
98
|
total: number;
|
|
84
99
|
}
|
|
85
100
|
|
|
101
|
+
export interface CheckpointLogStats {
|
|
102
|
+
operations_synced: number;
|
|
103
|
+
data_synced_bytes: number;
|
|
104
|
+
}
|
|
105
|
+
|
|
86
106
|
export function statsForBatch(batch: SyncBucketData): OperationsSentStats {
|
|
87
107
|
let put = 0;
|
|
88
108
|
let remove = 0;
|