@syncular/server 0.0.6-185 → 0.0.6-201
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/dist/blobs/adapters/database.d.ts.map +1 -1
- package/dist/blobs/adapters/database.js +3 -2
- package/dist/blobs/adapters/database.js.map +1 -1
- package/dist/blobs/manager.d.ts.map +1 -1
- package/dist/blobs/manager.js +12 -7
- package/dist/blobs/manager.js.map +1 -1
- package/dist/handlers/create-handler.d.ts +6 -0
- package/dist/handlers/create-handler.d.ts.map +1 -1
- package/dist/handlers/create-handler.js +7 -2
- package/dist/handlers/create-handler.js.map +1 -1
- package/dist/handlers/types.d.ts +10 -0
- package/dist/handlers/types.d.ts.map +1 -1
- package/dist/notify.d.ts +30 -0
- package/dist/notify.d.ts.map +1 -1
- package/dist/notify.js +100 -0
- package/dist/notify.js.map +1 -1
- package/dist/pull.d.ts +11 -0
- package/dist/pull.d.ts.map +1 -1
- package/dist/pull.js +123 -25
- package/dist/pull.js.map +1 -1
- package/dist/push.d.ts +10 -0
- package/dist/push.d.ts.map +1 -1
- package/dist/push.js +529 -443
- package/dist/push.js.map +1 -1
- package/package.json +2 -2
- package/src/blobs/adapters/database.ts +6 -4
- package/src/blobs/manager.ts +17 -11
- package/src/handlers/create-handler.ts +15 -1
- package/src/handlers/types.ts +12 -0
- package/src/notify.test.ts +125 -1
- package/src/notify.ts +155 -1
- package/src/pull.ts +200 -34
- package/src/push.ts +743 -572
package/src/pull.ts
CHANGED
|
@@ -41,7 +41,37 @@ import {
|
|
|
41
41
|
import { resolveEffectiveScopesForSubscriptions } from './subscriptions/resolve';
|
|
42
42
|
|
|
43
43
|
const defaultScopeCache = createMemoryScopeCache();
|
|
44
|
-
const
|
|
44
|
+
const DEFAULT_MAX_SNAPSHOT_BUNDLE_ROW_FRAME_BYTES = 512 * 1024;
|
|
45
|
+
const MAX_ADAPTIVE_SNAPSHOT_BUNDLE_ROW_FRAME_BYTES = 4 * 1024 * 1024;
|
|
46
|
+
const DEFAULT_INLINE_SNAPSHOT_ROW_FRAME_BYTES = 256 * 1024;
|
|
47
|
+
const EMPTY_SNAPSHOT_ROW_FRAMES = encodeSnapshotRows([]);
|
|
48
|
+
|
|
49
|
+
interface PullBootstrapTimings {
|
|
50
|
+
snapshotQueryMs: number;
|
|
51
|
+
rowFrameEncodeMs: number;
|
|
52
|
+
chunkCacheLookupMs: number;
|
|
53
|
+
chunkGzipMs: number;
|
|
54
|
+
chunkHashMs: number;
|
|
55
|
+
chunkPersistMs: number;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
interface SnapshotChunkEncodeResult {
|
|
59
|
+
body: Uint8Array;
|
|
60
|
+
sha256: string;
|
|
61
|
+
gzipMs: number;
|
|
62
|
+
hashMs: number;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function createPullBootstrapTimings(): PullBootstrapTimings {
|
|
66
|
+
return {
|
|
67
|
+
snapshotQueryMs: 0,
|
|
68
|
+
rowFrameEncodeMs: 0,
|
|
69
|
+
chunkCacheLookupMs: 0,
|
|
70
|
+
chunkGzipMs: 0,
|
|
71
|
+
chunkHashMs: 0,
|
|
72
|
+
chunkPersistMs: 0,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
45
75
|
|
|
46
76
|
function concatByteChunks(chunks: readonly Uint8Array[]): Uint8Array {
|
|
47
77
|
if (chunks.length === 1) {
|
|
@@ -186,28 +216,73 @@ async function gzipByteChunks(
|
|
|
186
216
|
return gzipBytes(concatByteChunks(chunks));
|
|
187
217
|
}
|
|
188
218
|
|
|
189
|
-
async function
|
|
219
|
+
async function encodeCompressedSnapshotChunk(
|
|
220
|
+
chunks: readonly Uint8Array[]
|
|
221
|
+
): Promise<SnapshotChunkEncodeResult> {
|
|
222
|
+
const gzipStartedAt = Date.now();
|
|
223
|
+
const gzipPromise = gzipByteChunks(chunks).then((body) => ({
|
|
224
|
+
body,
|
|
225
|
+
gzipMs: Math.max(0, Date.now() - gzipStartedAt),
|
|
226
|
+
}));
|
|
227
|
+
const hashStartedAt = Date.now();
|
|
228
|
+
const hashPromise = sha256HexFromByteChunks(chunks).then((sha256) => ({
|
|
229
|
+
sha256,
|
|
230
|
+
hashMs: Math.max(0, Date.now() - hashStartedAt),
|
|
231
|
+
}));
|
|
232
|
+
const [{ body, gzipMs }, { sha256, hashMs }] = await Promise.all([
|
|
233
|
+
gzipPromise,
|
|
234
|
+
hashPromise,
|
|
235
|
+
]);
|
|
236
|
+
return { body, sha256, gzipMs, hashMs };
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
async function encodeCompressedSnapshotChunkToStream(
|
|
240
|
+
chunks: readonly Uint8Array[]
|
|
241
|
+
): Promise<{
|
|
190
242
|
stream: ReadableStream<Uint8Array>;
|
|
191
|
-
byteLength
|
|
243
|
+
byteLength: number;
|
|
244
|
+
sha256: string;
|
|
245
|
+
gzipMs: number;
|
|
246
|
+
hashMs: number;
|
|
192
247
|
}> {
|
|
193
|
-
|
|
194
|
-
const source = byteChunksToStream(chunks).pipeThrough(
|
|
195
|
-
new CompressionStream('gzip')
|
|
196
|
-
);
|
|
197
|
-
return {
|
|
198
|
-
stream: bufferSourceStreamToUint8ArrayStream(source),
|
|
199
|
-
};
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
const compressed = await gzipBytes(concatByteChunks(chunks));
|
|
248
|
+
const encoded = await encodeCompressedSnapshotChunk(chunks);
|
|
203
249
|
return {
|
|
204
250
|
stream: bufferSourceStreamToUint8ArrayStream(
|
|
205
|
-
byteChunksToStream([
|
|
251
|
+
byteChunksToStream([encoded.body])
|
|
206
252
|
),
|
|
207
|
-
byteLength:
|
|
253
|
+
byteLength: encoded.body.length,
|
|
254
|
+
sha256: encoded.sha256,
|
|
255
|
+
gzipMs: encoded.gzipMs,
|
|
256
|
+
hashMs: encoded.hashMs,
|
|
208
257
|
};
|
|
209
258
|
}
|
|
210
259
|
|
|
260
|
+
function resolveSnapshotBundleMaxBytes(args: {
|
|
261
|
+
configuredMaxBytes?: number;
|
|
262
|
+
pageRowCount: number;
|
|
263
|
+
pageRowFrameBytes: number;
|
|
264
|
+
}): number {
|
|
265
|
+
if (
|
|
266
|
+
typeof args.configuredMaxBytes === 'number' &&
|
|
267
|
+
Number.isFinite(args.configuredMaxBytes) &&
|
|
268
|
+
args.configuredMaxBytes > 0
|
|
269
|
+
) {
|
|
270
|
+
return Math.max(1, args.configuredMaxBytes);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (args.pageRowCount <= 0 || args.pageRowFrameBytes <= 0) {
|
|
274
|
+
return DEFAULT_MAX_SNAPSHOT_BUNDLE_ROW_FRAME_BYTES;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return Math.max(
|
|
278
|
+
DEFAULT_MAX_SNAPSHOT_BUNDLE_ROW_FRAME_BYTES,
|
|
279
|
+
Math.min(
|
|
280
|
+
MAX_ADAPTIVE_SNAPSHOT_BUNDLE_ROW_FRAME_BYTES,
|
|
281
|
+
args.pageRowFrameBytes
|
|
282
|
+
)
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
|
|
211
286
|
export interface PullResult {
|
|
212
287
|
response: SyncPullResponse;
|
|
213
288
|
/**
|
|
@@ -217,6 +292,8 @@ export interface PullResult {
|
|
|
217
292
|
effectiveScopes: ScopeValues;
|
|
218
293
|
/** Minimum nextCursor across active subscriptions (for pruning cursor tracking). */
|
|
219
294
|
clientCursor: number;
|
|
295
|
+
/** Internal bootstrap timing breakdown used for benchmark-gated diagnostics. */
|
|
296
|
+
bootstrapTimings?: PullBootstrapTimings;
|
|
220
297
|
}
|
|
221
298
|
|
|
222
299
|
interface PendingExternalChunkWrite {
|
|
@@ -419,6 +496,7 @@ async function readLatestExternalCommitByTable<DB extends SyncCoreDb>(
|
|
|
419
496
|
.select((eb) => eb.fn.max('tc.commit_seq').as('latest_commit_seq'))
|
|
420
497
|
.where('tc.partition_id', '=', args.partitionId)
|
|
421
498
|
.where('cm.client_id', '=', EXTERNAL_CLIENT_ID)
|
|
499
|
+
.where('cm.change_count', '=', 0)
|
|
422
500
|
.where('tc.commit_seq', '>', args.afterCursor)
|
|
423
501
|
.where('tc.table', 'in', tableNames)
|
|
424
502
|
.groupBy('tc.table')
|
|
@@ -480,7 +558,7 @@ export async function pull<
|
|
|
480
558
|
request.limitSnapshotRows,
|
|
481
559
|
1000,
|
|
482
560
|
1,
|
|
483
|
-
|
|
561
|
+
20000
|
|
484
562
|
);
|
|
485
563
|
const maxSnapshotPages = sanitizeLimit(
|
|
486
564
|
request.maxSnapshotPages,
|
|
@@ -490,6 +568,7 @@ export async function pull<
|
|
|
490
568
|
);
|
|
491
569
|
const dedupeRows = request.dedupeRows === true;
|
|
492
570
|
const pendingExternalChunkWrites: PendingExternalChunkWrite[] = [];
|
|
571
|
+
const bootstrapTimings = createPullBootstrapTimings();
|
|
493
572
|
|
|
494
573
|
// Resolve effective scopes for each subscription
|
|
495
574
|
const resolved = await resolveEffectiveScopesForSubscriptions({
|
|
@@ -581,6 +660,11 @@ export async function pull<
|
|
|
581
660
|
args.handlers,
|
|
582
661
|
sub.table
|
|
583
662
|
).map((handler) => handler.table);
|
|
663
|
+
const preferInlineBootstrapSnapshot =
|
|
664
|
+
cursor >= 0 ||
|
|
665
|
+
sub.bootstrapState != null ||
|
|
666
|
+
(latestExternalCommitForTable !== undefined &&
|
|
667
|
+
latestExternalCommitForTable > cursor);
|
|
584
668
|
|
|
585
669
|
const initState: SyncBootstrapState = {
|
|
586
670
|
asOfCommitSeq: maxCommitSeq,
|
|
@@ -636,17 +720,29 @@ export async function pull<
|
|
|
636
720
|
ttlMs: number;
|
|
637
721
|
rowFrameByteLength: number;
|
|
638
722
|
rowFrameParts: Uint8Array[];
|
|
723
|
+
inlineRows: unknown[] | null;
|
|
639
724
|
}
|
|
640
725
|
|
|
641
726
|
const flushSnapshotBundle = async (
|
|
642
727
|
bundle: SnapshotBundle
|
|
643
728
|
): Promise<void> => {
|
|
729
|
+
if (bundle.inlineRows) {
|
|
730
|
+
snapshots.push({
|
|
731
|
+
table: bundle.table,
|
|
732
|
+
rows: bundle.inlineRows,
|
|
733
|
+
isFirstPage: bundle.isFirstPage,
|
|
734
|
+
isLastPage: bundle.isLastPage,
|
|
735
|
+
});
|
|
736
|
+
return;
|
|
737
|
+
}
|
|
738
|
+
|
|
644
739
|
const nowIso = new Date().toISOString();
|
|
645
740
|
const bundleRowLimit = Math.max(
|
|
646
741
|
1,
|
|
647
742
|
limitSnapshotRows * bundle.pageCount
|
|
648
743
|
);
|
|
649
744
|
|
|
745
|
+
const cacheLookupStartedAt = Date.now();
|
|
650
746
|
const cached = await readSnapshotChunkRefByPageKey(trx, {
|
|
651
747
|
partitionId,
|
|
652
748
|
scopeKey: cacheKey,
|
|
@@ -658,6 +754,10 @@ export async function pull<
|
|
|
658
754
|
compression: SYNC_SNAPSHOT_CHUNK_COMPRESSION,
|
|
659
755
|
nowIso,
|
|
660
756
|
});
|
|
757
|
+
bootstrapTimings.chunkCacheLookupMs += Math.max(
|
|
758
|
+
0,
|
|
759
|
+
Date.now() - cacheLookupStartedAt
|
|
760
|
+
);
|
|
661
761
|
|
|
662
762
|
let chunkRef = cached;
|
|
663
763
|
if (!chunkRef) {
|
|
@@ -689,13 +789,13 @@ export async function pull<
|
|
|
689
789
|
});
|
|
690
790
|
return;
|
|
691
791
|
}
|
|
692
|
-
const
|
|
693
|
-
bundle.rowFrameParts
|
|
694
|
-
);
|
|
695
|
-
const compressedBody = await gzipByteChunks(
|
|
792
|
+
const encodedChunk = await encodeCompressedSnapshotChunk(
|
|
696
793
|
bundle.rowFrameParts
|
|
697
794
|
);
|
|
795
|
+
bootstrapTimings.chunkGzipMs += encodedChunk.gzipMs;
|
|
796
|
+
bootstrapTimings.chunkHashMs += encodedChunk.hashMs;
|
|
698
797
|
const chunkId = randomId();
|
|
798
|
+
const chunkPersistStartedAt = Date.now();
|
|
699
799
|
chunkRef = await insertSnapshotChunk(trx, {
|
|
700
800
|
chunkId,
|
|
701
801
|
partitionId,
|
|
@@ -706,10 +806,14 @@ export async function pull<
|
|
|
706
806
|
rowLimit: bundleRowLimit,
|
|
707
807
|
encoding: SYNC_SNAPSHOT_CHUNK_ENCODING,
|
|
708
808
|
compression: SYNC_SNAPSHOT_CHUNK_COMPRESSION,
|
|
709
|
-
sha256,
|
|
710
|
-
body:
|
|
809
|
+
sha256: encodedChunk.sha256,
|
|
810
|
+
body: encodedChunk.body,
|
|
711
811
|
expiresAt,
|
|
712
812
|
});
|
|
813
|
+
bootstrapTimings.chunkPersistMs += Math.max(
|
|
814
|
+
0,
|
|
815
|
+
Date.now() - chunkPersistStartedAt
|
|
816
|
+
);
|
|
713
817
|
}
|
|
714
818
|
|
|
715
819
|
snapshots.push({
|
|
@@ -750,7 +854,7 @@ export async function pull<
|
|
|
750
854
|
if (activeBundle) {
|
|
751
855
|
await flushSnapshotBundle(activeBundle);
|
|
752
856
|
}
|
|
753
|
-
const bundleHeader =
|
|
857
|
+
const bundleHeader = EMPTY_SNAPSHOT_ROW_FRAMES;
|
|
754
858
|
activeBundle = {
|
|
755
859
|
table: nextTableName,
|
|
756
860
|
startCursor: nextState.rowCursor,
|
|
@@ -761,9 +865,11 @@ export async function pull<
|
|
|
761
865
|
tableHandler.snapshotChunkTtlMs ?? 24 * 60 * 60 * 1000,
|
|
762
866
|
rowFrameByteLength: bundleHeader.length,
|
|
763
867
|
rowFrameParts: [bundleHeader],
|
|
868
|
+
inlineRows: null,
|
|
764
869
|
};
|
|
765
870
|
}
|
|
766
871
|
|
|
872
|
+
const snapshotQueryStartedAt = Date.now();
|
|
767
873
|
const page: { rows: unknown[]; nextCursor: string | null } =
|
|
768
874
|
await tableHandler.snapshot(
|
|
769
875
|
{
|
|
@@ -776,15 +882,29 @@ export async function pull<
|
|
|
776
882
|
},
|
|
777
883
|
sub.params
|
|
778
884
|
);
|
|
885
|
+
bootstrapTimings.snapshotQueryMs += Math.max(
|
|
886
|
+
0,
|
|
887
|
+
Date.now() - snapshotQueryStartedAt
|
|
888
|
+
);
|
|
779
889
|
|
|
890
|
+
const rowFrameEncodeStartedAt = Date.now();
|
|
780
891
|
const rowFrames = encodeSnapshotRowFrames(page.rows ?? []);
|
|
892
|
+
bootstrapTimings.rowFrameEncodeMs += Math.max(
|
|
893
|
+
0,
|
|
894
|
+
Date.now() - rowFrameEncodeStartedAt
|
|
895
|
+
);
|
|
896
|
+
const bundleMaxBytes = resolveSnapshotBundleMaxBytes({
|
|
897
|
+
configuredMaxBytes: tableHandler.snapshotBundleMaxBytes,
|
|
898
|
+
pageRowCount: page.rows?.length ?? 0,
|
|
899
|
+
pageRowFrameBytes: rowFrames.length,
|
|
900
|
+
});
|
|
781
901
|
if (
|
|
782
902
|
activeBundle.pageCount > 0 &&
|
|
783
903
|
activeBundle.rowFrameByteLength + rowFrames.length >
|
|
784
|
-
|
|
904
|
+
bundleMaxBytes
|
|
785
905
|
) {
|
|
786
906
|
await flushSnapshotBundle(activeBundle);
|
|
787
|
-
const bundleHeader =
|
|
907
|
+
const bundleHeader = EMPTY_SNAPSHOT_ROW_FRAMES;
|
|
788
908
|
activeBundle = {
|
|
789
909
|
table: nextTableName,
|
|
790
910
|
startCursor: nextState.rowCursor,
|
|
@@ -795,8 +915,20 @@ export async function pull<
|
|
|
795
915
|
tableHandler.snapshotChunkTtlMs ?? 24 * 60 * 60 * 1000,
|
|
796
916
|
rowFrameByteLength: bundleHeader.length,
|
|
797
917
|
rowFrameParts: [bundleHeader],
|
|
918
|
+
inlineRows: null,
|
|
798
919
|
};
|
|
799
920
|
}
|
|
921
|
+
|
|
922
|
+
if (
|
|
923
|
+
preferInlineBootstrapSnapshot &&
|
|
924
|
+
activeBundle.pageCount === 0 &&
|
|
925
|
+
page.nextCursor == null &&
|
|
926
|
+
rowFrames.length <= DEFAULT_INLINE_SNAPSHOT_ROW_FRAME_BYTES
|
|
927
|
+
) {
|
|
928
|
+
activeBundle.inlineRows = page.rows ?? [];
|
|
929
|
+
} else {
|
|
930
|
+
activeBundle.inlineRows = null;
|
|
931
|
+
}
|
|
800
932
|
activeBundle.rowFrameParts.push(rowFrames);
|
|
801
933
|
activeBundle.rowFrameByteLength += rowFrames.length;
|
|
802
934
|
activeBundle.pageCount += 1;
|
|
@@ -1040,6 +1172,7 @@ export async function pull<
|
|
|
1040
1172
|
pendingExternalChunkWrites,
|
|
1041
1173
|
4,
|
|
1042
1174
|
async (pending) => {
|
|
1175
|
+
const cacheLookupStartedAt = Date.now();
|
|
1043
1176
|
let chunkRef = await readSnapshotChunkRefByPageKey(db, {
|
|
1044
1177
|
partitionId: pending.cacheLookup.partitionId,
|
|
1045
1178
|
scopeKey: pending.cacheLookup.scopeKey,
|
|
@@ -1050,14 +1183,25 @@ export async function pull<
|
|
|
1050
1183
|
encoding: SYNC_SNAPSHOT_CHUNK_ENCODING,
|
|
1051
1184
|
compression: SYNC_SNAPSHOT_CHUNK_COMPRESSION,
|
|
1052
1185
|
});
|
|
1186
|
+
bootstrapTimings.chunkCacheLookupMs += Math.max(
|
|
1187
|
+
0,
|
|
1188
|
+
Date.now() - cacheLookupStartedAt
|
|
1189
|
+
);
|
|
1053
1190
|
|
|
1054
1191
|
if (!chunkRef) {
|
|
1055
|
-
const sha256 = await sha256HexFromByteChunks(
|
|
1056
|
-
pending.rowFrameParts
|
|
1057
|
-
);
|
|
1058
1192
|
if (chunkStorage.storeChunkStream) {
|
|
1059
|
-
const {
|
|
1060
|
-
|
|
1193
|
+
const {
|
|
1194
|
+
stream: bodyStream,
|
|
1195
|
+
byteLength,
|
|
1196
|
+
sha256,
|
|
1197
|
+
gzipMs,
|
|
1198
|
+
hashMs,
|
|
1199
|
+
} = await encodeCompressedSnapshotChunkToStream(
|
|
1200
|
+
pending.rowFrameParts
|
|
1201
|
+
);
|
|
1202
|
+
bootstrapTimings.chunkGzipMs += gzipMs;
|
|
1203
|
+
bootstrapTimings.chunkHashMs += hashMs;
|
|
1204
|
+
const chunkPersistStartedAt = Date.now();
|
|
1061
1205
|
chunkRef = await chunkStorage.storeChunkStream({
|
|
1062
1206
|
partitionId: pending.cacheLookup.partitionId,
|
|
1063
1207
|
scopeKey: pending.cacheLookup.scopeKey,
|
|
@@ -1072,10 +1216,17 @@ export async function pull<
|
|
|
1072
1216
|
bodyStream,
|
|
1073
1217
|
expiresAt: pending.expiresAt,
|
|
1074
1218
|
});
|
|
1219
|
+
bootstrapTimings.chunkPersistMs += Math.max(
|
|
1220
|
+
0,
|
|
1221
|
+
Date.now() - chunkPersistStartedAt
|
|
1222
|
+
);
|
|
1075
1223
|
} else {
|
|
1076
|
-
const
|
|
1224
|
+
const encodedChunk = await encodeCompressedSnapshotChunk(
|
|
1077
1225
|
pending.rowFrameParts
|
|
1078
1226
|
);
|
|
1227
|
+
bootstrapTimings.chunkGzipMs += encodedChunk.gzipMs;
|
|
1228
|
+
bootstrapTimings.chunkHashMs += encodedChunk.hashMs;
|
|
1229
|
+
const chunkPersistStartedAt = Date.now();
|
|
1079
1230
|
chunkRef = await chunkStorage.storeChunk({
|
|
1080
1231
|
partitionId: pending.cacheLookup.partitionId,
|
|
1081
1232
|
scopeKey: pending.cacheLookup.scopeKey,
|
|
@@ -1085,10 +1236,14 @@ export async function pull<
|
|
|
1085
1236
|
rowLimit: pending.cacheLookup.rowLimit,
|
|
1086
1237
|
encoding: SYNC_SNAPSHOT_CHUNK_ENCODING,
|
|
1087
1238
|
compression: SYNC_SNAPSHOT_CHUNK_COMPRESSION,
|
|
1088
|
-
sha256,
|
|
1089
|
-
body:
|
|
1239
|
+
sha256: encodedChunk.sha256,
|
|
1240
|
+
body: encodedChunk.body,
|
|
1090
1241
|
expiresAt: pending.expiresAt,
|
|
1091
1242
|
});
|
|
1243
|
+
bootstrapTimings.chunkPersistMs += Math.max(
|
|
1244
|
+
0,
|
|
1245
|
+
Date.now() - chunkPersistStartedAt
|
|
1246
|
+
);
|
|
1092
1247
|
}
|
|
1093
1248
|
}
|
|
1094
1249
|
|
|
@@ -1106,6 +1261,14 @@ export async function pull<
|
|
|
1106
1261
|
span.setAttribute('commit_count', stats.commitCount);
|
|
1107
1262
|
span.setAttribute('change_count', stats.changeCount);
|
|
1108
1263
|
span.setAttribute('snapshot_page_count', stats.snapshotPageCount);
|
|
1264
|
+
span.setAttributes({
|
|
1265
|
+
bootstrap_snapshot_query_ms: bootstrapTimings.snapshotQueryMs,
|
|
1266
|
+
bootstrap_row_frame_encode_ms: bootstrapTimings.rowFrameEncodeMs,
|
|
1267
|
+
bootstrap_chunk_cache_lookup_ms: bootstrapTimings.chunkCacheLookupMs,
|
|
1268
|
+
bootstrap_chunk_gzip_ms: bootstrapTimings.chunkGzipMs,
|
|
1269
|
+
bootstrap_chunk_hash_ms: bootstrapTimings.chunkHashMs,
|
|
1270
|
+
bootstrap_chunk_persist_ms: bootstrapTimings.chunkPersistMs,
|
|
1271
|
+
});
|
|
1109
1272
|
span.setStatus('ok');
|
|
1110
1273
|
|
|
1111
1274
|
recordPullMetrics({
|
|
@@ -1115,7 +1278,10 @@ export async function pull<
|
|
|
1115
1278
|
stats,
|
|
1116
1279
|
});
|
|
1117
1280
|
|
|
1118
|
-
return
|
|
1281
|
+
return {
|
|
1282
|
+
...result,
|
|
1283
|
+
bootstrapTimings,
|
|
1284
|
+
};
|
|
1119
1285
|
} catch (error) {
|
|
1120
1286
|
const durationMs = Math.max(0, Date.now() - startedAtMs);
|
|
1121
1287
|
|