@prisma/streams-server 0.1.1 → 0.1.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.
Files changed (91) hide show
  1. package/CONTRIBUTING.md +8 -0
  2. package/package.json +2 -1
  3. package/src/app.ts +290 -17
  4. package/src/app_core.ts +1833 -698
  5. package/src/app_local.ts +144 -4
  6. package/src/auto_tune.ts +62 -0
  7. package/src/bootstrap.ts +159 -1
  8. package/src/concurrency_gate.ts +108 -0
  9. package/src/config.ts +116 -14
  10. package/src/db/db.ts +1201 -131
  11. package/src/db/schema.ts +308 -8
  12. package/src/foreground_activity.ts +55 -0
  13. package/src/index/indexer.ts +254 -124
  14. package/src/index/lexicon_file_cache.ts +261 -0
  15. package/src/index/lexicon_format.ts +93 -0
  16. package/src/index/lexicon_indexer.ts +789 -0
  17. package/src/index/secondary_indexer.ts +824 -0
  18. package/src/index/secondary_schema.ts +105 -0
  19. package/src/ingest.ts +10 -12
  20. package/src/manifest.ts +143 -8
  21. package/src/memory.ts +183 -8
  22. package/src/metrics.ts +15 -29
  23. package/src/metrics_emitter.ts +26 -3
  24. package/src/notifier.ts +121 -5
  25. package/src/objectstore/accounting.ts +92 -0
  26. package/src/objectstore/mock_r2.ts +1 -1
  27. package/src/objectstore/r2.ts +17 -1
  28. package/src/profiles/evlog/schema.ts +234 -0
  29. package/src/profiles/evlog.ts +299 -0
  30. package/src/profiles/generic.ts +47 -0
  31. package/src/profiles/index.ts +205 -0
  32. package/src/profiles/metrics/block_format.ts +109 -0
  33. package/src/profiles/metrics/normalize.ts +366 -0
  34. package/src/profiles/metrics/schema.ts +319 -0
  35. package/src/profiles/metrics.ts +85 -0
  36. package/src/profiles/profile.ts +225 -0
  37. package/src/{touch/engine.ts → profiles/stateProtocol/changes.ts} +3 -20
  38. package/src/profiles/stateProtocol/routes.ts +389 -0
  39. package/src/profiles/stateProtocol/types.ts +6 -0
  40. package/src/profiles/stateProtocol/validation.ts +51 -0
  41. package/src/profiles/stateProtocol.ts +100 -0
  42. package/src/read_filter.ts +468 -0
  43. package/src/reader.ts +2151 -164
  44. package/src/runtime/host_runtime.ts +5 -0
  45. package/src/runtime_memory.ts +200 -0
  46. package/src/runtime_memory_sampler.ts +235 -0
  47. package/src/schema/read_json.ts +43 -0
  48. package/src/schema/registry.ts +563 -59
  49. package/src/search/agg_format.ts +638 -0
  50. package/src/search/aggregate.ts +389 -0
  51. package/src/search/binary/codec.ts +162 -0
  52. package/src/search/binary/docset.ts +67 -0
  53. package/src/search/binary/restart_strings.ts +181 -0
  54. package/src/search/binary/varint.ts +34 -0
  55. package/src/search/bitset.ts +19 -0
  56. package/src/search/col_format.ts +382 -0
  57. package/src/search/col_runtime.ts +59 -0
  58. package/src/search/column_encoding.ts +43 -0
  59. package/src/search/companion_file_cache.ts +319 -0
  60. package/src/search/companion_format.ts +313 -0
  61. package/src/search/companion_manager.ts +1086 -0
  62. package/src/search/companion_plan.ts +218 -0
  63. package/src/search/fts_format.ts +423 -0
  64. package/src/search/fts_runtime.ts +333 -0
  65. package/src/search/query.ts +875 -0
  66. package/src/search/schema.ts +245 -0
  67. package/src/segment/cache.ts +93 -2
  68. package/src/segment/cached_segment.ts +89 -0
  69. package/src/segment/format.ts +108 -36
  70. package/src/segment/segmenter.ts +79 -5
  71. package/src/segment/segmenter_worker.ts +35 -6
  72. package/src/segment/segmenter_workers.ts +42 -12
  73. package/src/server.ts +150 -36
  74. package/src/sqlite/adapter.ts +185 -14
  75. package/src/sqlite/runtime_stats.ts +163 -0
  76. package/src/stats.ts +3 -3
  77. package/src/stream_size_reconciler.ts +100 -0
  78. package/src/touch/canonical_change.ts +7 -0
  79. package/src/touch/live_metrics.ts +94 -64
  80. package/src/touch/live_templates.ts +15 -1
  81. package/src/touch/manager.ts +166 -88
  82. package/src/touch/{interpreter_worker.ts → processor_worker.ts} +19 -14
  83. package/src/touch/spec.ts +95 -92
  84. package/src/touch/touch_journal.ts +4 -0
  85. package/src/touch/worker_pool.ts +8 -14
  86. package/src/touch/worker_protocol.ts +3 -3
  87. package/src/uploader.ts +77 -6
  88. package/src/util/bloom256.ts +2 -2
  89. package/src/util/byte_lru.ts +73 -0
  90. package/src/util/lru.ts +8 -0
  91. package/src/util/stream_paths.ts +19 -0
package/CONTRIBUTING.md CHANGED
@@ -38,12 +38,20 @@ bun run check:result-policy
38
38
  bun test
39
39
  bun run test:conformance:local
40
40
  bun run test:conformance
41
+ bun run test:large-index-filter
41
42
  ```
42
43
 
43
44
  Notes:
44
45
 
45
46
  - `bun test` is the current fast repository baseline.
46
47
  - `test:conformance:local` and `test:conformance` run the upstream black-box suite against local and full server modes.
48
+ - `test:large-index-filter` is an opt-in full-mode integration/performance test
49
+ that writes 1 GiB of indexed JSON data into a MockR2-backed stream and
50
+ measures filtered read time. The packaged script pins `16 MiB` segments to
51
+ match the production default. Use `DS_LARGE_INDEX_FILTER=1 bun test
52
+ test/large_index_filter.test.ts` directly only when you intentionally want to
53
+ override the segment size or other large-test settings. It is intentionally
54
+ excluded from the fast baseline.
47
55
  - The current upstream conformance status is tracked in [conformance.md](./conformance.md).
48
56
 
49
57
  ## Development Expectations
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prisma/streams-server",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Bun-only self-hosted Prisma Streams server.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -35,6 +35,7 @@
35
35
  "./package.json": "./package.json"
36
36
  },
37
37
  "dependencies": {
38
+ "@durable-streams/client": "^0.2.1",
38
39
  "ajv": "^8.12.0",
39
40
  "better-result": "^2.7.0",
40
41
  "env-paths": "^3.0.0",
package/src/app.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type { Config } from "./config";
2
2
  import { createAppCore, type App } from "./app_core";
3
3
  import type { ObjectStore } from "./objectstore/interface";
4
+ import { AccountingObjectStore } from "./objectstore/accounting";
4
5
  import { MockR2Store } from "./objectstore/mock_r2";
5
6
  import { StreamReader } from "./reader";
6
7
  import { SegmentDiskCache } from "./segment/cache";
@@ -10,8 +11,13 @@ import { Uploader } from "./uploader";
10
11
  import { retry } from "./util/retry";
11
12
  import { schemaObjectKey, streamHash16Hex } from "./util/stream_paths";
12
13
  import type { StatsCollector } from "./stats";
13
- import { IndexManager } from "./index/indexer";
14
+ import { IndexManager, type StreamIndexLookup } from "./index/indexer";
15
+ import { SecondaryIndexManager } from "./index/secondary_indexer";
14
16
  import type { SchemaRegistry } from "./schema/registry";
17
+ import { SearchCompanionManager } from "./search/companion_manager";
18
+ import { LexiconIndexManager } from "./index/lexicon_indexer";
19
+ import { readSqliteRuntimeMemoryStats } from "./sqlite/runtime_stats";
20
+ import { sumRuntimeMemoryValues } from "./runtime_memory";
15
21
 
16
22
  export type { App } from "./app_core";
17
23
 
@@ -19,29 +25,157 @@ export type CreateAppOptions = {
19
25
  stats?: StatsCollector;
20
26
  };
21
27
 
28
+ class CombinedIndexController implements StreamIndexLookup {
29
+ constructor(
30
+ private readonly routingIndex: IndexManager,
31
+ private readonly secondaryIndex: SecondaryIndexManager,
32
+ private readonly companionIndex: SearchCompanionManager,
33
+ private readonly lexiconIndex: LexiconIndexManager
34
+ ) {}
35
+
36
+ start(): void {
37
+ this.routingIndex.start();
38
+ this.secondaryIndex.start();
39
+ this.companionIndex.start();
40
+ this.lexiconIndex.start();
41
+ }
42
+
43
+ stop(): void {
44
+ this.routingIndex.stop();
45
+ this.secondaryIndex.stop();
46
+ this.companionIndex.stop();
47
+ this.lexiconIndex.stop();
48
+ }
49
+
50
+ enqueue(stream: string): void {
51
+ this.routingIndex.enqueue(stream);
52
+ this.secondaryIndex.enqueue(stream);
53
+ this.companionIndex.enqueue(stream);
54
+ this.lexiconIndex.enqueue(stream);
55
+ }
56
+
57
+ candidateSegmentsForRoutingKey(stream: string, keyBytes: Uint8Array) {
58
+ return this.routingIndex.candidateSegmentsForRoutingKey(stream, keyBytes);
59
+ }
60
+
61
+ candidateSegmentsForSecondaryIndex(stream: string, indexName: string, keyBytes: Uint8Array) {
62
+ return this.secondaryIndex.candidateSegmentsForSecondaryIndex(stream, indexName, keyBytes);
63
+ }
64
+
65
+ getAggSegmentCompanion(stream: string, segmentIndex: number) {
66
+ return this.companionIndex.getAggSegmentCompanion(stream, segmentIndex);
67
+ }
68
+
69
+ getColSegmentCompanion(stream: string, segmentIndex: number) {
70
+ return this.companionIndex.getColSegmentCompanion(stream, segmentIndex);
71
+ }
72
+
73
+ getFtsSegmentCompanion(stream: string, segmentIndex: number) {
74
+ return this.companionIndex.getFtsSegmentCompanion(stream, segmentIndex);
75
+ }
76
+
77
+ getFtsSegmentCompanionWithStats(stream: string, segmentIndex: number) {
78
+ return this.companionIndex.getFtsSegmentCompanionWithStats(stream, segmentIndex);
79
+ }
80
+
81
+ getMetricsBlockSegmentCompanion(stream: string, segmentIndex: number) {
82
+ return this.companionIndex.getMetricsBlockSegmentCompanion(stream, segmentIndex);
83
+ }
84
+
85
+ listRoutingKeysResult(stream: string, after: string | null, limit: number) {
86
+ return this.lexiconIndex.listRoutingKeysResult(stream, after, limit);
87
+ }
88
+
89
+ getLocalStorageUsage(stream: string) {
90
+ return {
91
+ routing_index_cache_bytes: this.routingIndex.getLocalCacheBytes(stream),
92
+ exact_index_cache_bytes: this.secondaryIndex.getLocalCacheBytes(stream),
93
+ companion_cache_bytes: this.companionIndex.getLocalCacheBytes(stream),
94
+ lexicon_index_cache_bytes: this.lexiconIndex.getLocalCacheBytes(stream),
95
+ };
96
+ }
97
+ }
98
+
22
99
  export function createApp(cfg: Config, os?: ObjectStore, opts: CreateAppOptions = {}): App {
23
100
  return createAppCore(cfg, {
24
101
  stats: opts.stats,
25
- createRuntime: ({ config, db, stats, backpressure, metrics }) => {
26
- const store = os ?? new MockR2Store();
27
- const segmenterHooks: SegmenterHooks | undefined =
28
- stats || backpressure
29
- ? {
30
- onSegmentSealed: (payloadBytes, segmentBytes) => {
31
- if (stats) stats.recordSegmentSealed(payloadBytes, segmentBytes);
32
- if (backpressure) backpressure.adjustOnSeal(payloadBytes, segmentBytes);
33
- },
34
- }
35
- : undefined;
102
+ createRuntime: ({ config, db, ingest, registry, notifier, stats, backpressure, metrics, memorySampler, memory, asyncIndexGate, foregroundActivity }) => {
103
+ const rawStore = os ?? new MockR2Store();
104
+ const store = new AccountingObjectStore(rawStore, db);
105
+ const segmenterHooks: SegmenterHooks = {
106
+ onSegmentSealed: (stream, payloadBytes, segmentBytes) => {
107
+ if (stats) stats.recordSegmentSealed(payloadBytes, segmentBytes);
108
+ if (backpressure) backpressure.adjustOnSeal(payloadBytes, segmentBytes);
109
+ notifier.notifyDetailsChanged(stream);
110
+ },
111
+ };
36
112
  const diskCache = new SegmentDiskCache(`${config.rootDir}/cache`, config.segmentCacheMaxBytes);
37
- const uploader = new Uploader(config, db, store, diskCache, stats, backpressure);
38
- const indexer = new IndexManager(config, db, store, diskCache, (stream) => uploader.publishManifest(stream), metrics);
39
- uploader.setHooks({ onSegmentsUploaded: (stream) => indexer.enqueue(stream) });
40
- const reader = new StreamReader(config, db, store, diskCache, indexer);
113
+ const uploader = new Uploader(config, db, store, diskCache, stats, backpressure, undefined, memorySampler);
114
+ const routingIndexer = new IndexManager(
115
+ config,
116
+ db,
117
+ store,
118
+ diskCache,
119
+ (stream) => uploader.publishManifest(stream),
120
+ metrics,
121
+ (stream) => notifier.notifyDetailsChanged(stream),
122
+ memorySampler,
123
+ registry,
124
+ asyncIndexGate,
125
+ foregroundActivity
126
+ );
127
+ const secondaryIndexer = new SecondaryIndexManager(
128
+ config,
129
+ db,
130
+ store,
131
+ registry,
132
+ diskCache,
133
+ (stream) => uploader.publishManifest(stream),
134
+ (stream) => notifier.notifyDetailsChanged(stream),
135
+ memorySampler,
136
+ asyncIndexGate,
137
+ foregroundActivity
138
+ );
139
+ const companionIndexer = new SearchCompanionManager(
140
+ config,
141
+ db,
142
+ store,
143
+ registry,
144
+ diskCache,
145
+ (stream) => uploader.publishManifest(stream),
146
+ (stream) => notifier.notifyDetailsChanged(stream),
147
+ metrics,
148
+ memorySampler,
149
+ asyncIndexGate,
150
+ foregroundActivity
151
+ );
152
+ const lexiconIndexer = new LexiconIndexManager(
153
+ config,
154
+ db,
155
+ store,
156
+ diskCache,
157
+ (stream) => uploader.publishManifest(stream),
158
+ (stream) => notifier.notifyDetailsChanged(stream),
159
+ metrics,
160
+ registry,
161
+ asyncIndexGate,
162
+ foregroundActivity
163
+ );
164
+ const indexer = new CombinedIndexController(
165
+ routingIndexer,
166
+ secondaryIndexer,
167
+ companionIndexer,
168
+ lexiconIndexer
169
+ );
170
+ uploader.setHooks({
171
+ onSegmentsUploaded: (stream) => indexer.enqueue(stream),
172
+ onMetadataChanged: (stream) => notifier.notifyDetailsChanged(stream),
173
+ });
174
+ const reader = new StreamReader(config, db, store, registry, diskCache, indexer, memorySampler, memory);
41
175
  const segmenter =
42
176
  config.segmenterWorkers > 0
43
177
  ? new SegmenterWorkerPool(config, config.segmenterWorkers, {}, segmenterHooks)
44
- : new Segmenter(config, db, {}, segmenterHooks);
178
+ : new Segmenter(config, db, {}, segmenterHooks, memorySampler);
45
179
 
46
180
  return {
47
181
  store,
@@ -49,6 +183,7 @@ export function createApp(cfg: Config, os?: ObjectStore, opts: CreateAppOptions
49
183
  segmenter,
50
184
  uploader,
51
185
  indexer,
186
+ segmentDiskCache: diskCache,
52
187
  uploadSchemaRegistry: async (stream: string, reg: SchemaRegistry): Promise<void> => {
53
188
  const shash = streamHash16Hex(stream);
54
189
  const key = schemaObjectKey(shash);
@@ -62,11 +197,149 @@ export function createApp(cfg: Config, os?: ObjectStore, opts: CreateAppOptions
62
197
  timeoutMs: config.objectStoreTimeoutMs,
63
198
  }
64
199
  );
200
+ db.setSchemaUploadedSizeBytes(stream, body.byteLength);
201
+ },
202
+ getLocalStorageUsage: (stream: string) => ({
203
+ segment_cache_bytes: diskCache.bytesForObjectKeyPrefix(`streams/${streamHash16Hex(stream)}/segments/`),
204
+ ...indexer.getLocalStorageUsage?.(stream),
205
+ }),
206
+ getRuntimeMemorySnapshot: () => {
207
+ const ingestMemory = ingest.getMemoryStats();
208
+ const segmenterMemory = segmenter.getMemoryStats?.() ?? {
209
+ active_builds: 0,
210
+ active_streams: 0,
211
+ active_payload_bytes: 0,
212
+ active_segment_bytes_estimate: 0,
213
+ active_rows: 0,
214
+ };
215
+ const uploaderMemory = uploader.getMemoryStats?.() ?? {
216
+ inflight_segments: 0,
217
+ inflight_segment_bytes: 0,
218
+ manifest_inflight_streams: 0,
219
+ };
220
+ const routingIndexMemory = routingIndexer.getMemoryStats();
221
+ const secondaryIndexMemory = secondaryIndexer.getMemoryStats();
222
+ const companionMemory = companionIndexer.getMemoryStats();
223
+ const lexiconMemory = lexiconIndexer.getMemoryStats();
224
+ const segmentDiskStats = diskCache.stats();
225
+ const mockR2InMemoryBytes = rawStore instanceof MockR2Store ? rawStore.memoryBytes() : 0;
226
+ const mockR2ObjectCount = rawStore instanceof MockR2Store ? rawStore.size() : 0;
227
+ const sqliteRuntime = readSqliteRuntimeMemoryStats();
228
+ const heapEstimates = {
229
+ ingest_queue_payload_bytes: ingestMemory.queuedPayloadBytes,
230
+ routing_run_cache_bytes: routingIndexMemory.runCacheBytes,
231
+ exact_run_cache_bytes: secondaryIndexMemory.runCacheBytes,
232
+ mock_r2_in_memory_bytes: mockR2InMemoryBytes,
233
+ };
234
+ const mappedFiles = {
235
+ segment_cache_mapped_bytes: segmentDiskStats.mappedBytes,
236
+ routing_run_disk_cache_mapped_bytes: routingIndexMemory.runDiskMappedBytes,
237
+ exact_run_disk_cache_mapped_bytes: secondaryIndexMemory.runDiskMappedBytes,
238
+ lexicon_index_mapped_bytes: lexiconMemory.mappedFileBytes,
239
+ companion_bundle_mapped_bytes: companionMemory.mappedFileBytes,
240
+ };
241
+ const diskCaches = {
242
+ segment_disk_cache_bytes: segmentDiskStats.usedBytes,
243
+ routing_run_disk_cache_bytes: routingIndexMemory.runDiskCacheBytes,
244
+ exact_run_disk_cache_bytes: secondaryIndexMemory.runDiskCacheBytes,
245
+ lexicon_disk_cache_bytes: lexiconMemory.fileCacheBytes,
246
+ companion_disk_cache_bytes: companionMemory.fileCacheBytes,
247
+ };
248
+ const pipelineBuffers = {
249
+ segmenter_active_payload_bytes: segmenterMemory.active_payload_bytes,
250
+ segmenter_active_segment_bytes_estimate: segmenterMemory.active_segment_bytes_estimate,
251
+ uploader_inflight_segment_bytes: uploaderMemory.inflight_segment_bytes,
252
+ };
253
+ const sqliteRuntimeBytes = {
254
+ sqlite_memory_used_bytes: sqliteRuntime.memory_used_bytes,
255
+ sqlite_memory_highwater_bytes: sqliteRuntime.memory_highwater_bytes,
256
+ sqlite_pagecache_overflow_bytes: sqliteRuntime.pagecache_overflow_bytes,
257
+ sqlite_pagecache_overflow_highwater_bytes: sqliteRuntime.pagecache_overflow_highwater_bytes,
258
+ };
259
+ const configuredBudgets = {
260
+ sqlite_cache_budget_bytes: config.sqliteCacheBytes,
261
+ worker_sqlite_cache_budget_bytes: config.workerSqliteCacheBytes,
262
+ segment_cache_budget_bytes: config.segmentCacheMaxBytes,
263
+ routing_run_cache_budget_bytes: config.indexRunMemoryCacheBytes,
264
+ routing_run_disk_cache_budget_bytes: config.indexRunCacheMaxBytes,
265
+ exact_run_cache_budget_bytes: config.indexRunMemoryCacheBytes,
266
+ exact_run_disk_cache_budget_bytes: config.indexRunCacheMaxBytes,
267
+ lexicon_disk_cache_budget_bytes: config.lexiconIndexCacheMaxBytes,
268
+ companion_disk_cache_budget_bytes: config.searchCompanionFileCacheMaxBytes,
269
+ };
270
+ const counts = {
271
+ ingest_queue_requests: ingestMemory.queuedRequests,
272
+ segment_disk_cache_entries: segmentDiskStats.entryCount,
273
+ segment_mapped_files: segmentDiskStats.mappedEntryCount,
274
+ segment_pinned_files: segmentDiskStats.pinnedEntryCount,
275
+ routing_run_cache_entries: routingIndexMemory.runCacheEntries,
276
+ routing_run_disk_cache_entries: routingIndexMemory.runDiskCacheEntries,
277
+ routing_run_disk_cache_mapped_entries: routingIndexMemory.runDiskMappedEntries,
278
+ routing_run_disk_cache_pinned_entries: routingIndexMemory.runDiskPinnedEntries,
279
+ exact_run_cache_entries: secondaryIndexMemory.runCacheEntries,
280
+ exact_run_disk_cache_entries: secondaryIndexMemory.runDiskCacheEntries,
281
+ exact_run_disk_cache_mapped_entries: secondaryIndexMemory.runDiskMappedEntries,
282
+ exact_run_disk_cache_pinned_entries: secondaryIndexMemory.runDiskPinnedEntries,
283
+ secondary_index_stream_idle_ticks: secondaryIndexMemory.streamIdleTickEntries,
284
+ lexicon_cached_files: lexiconMemory.fileCacheEntries,
285
+ lexicon_mapped_files: lexiconMemory.mappedFileEntries,
286
+ lexicon_pinned_files: lexiconMemory.pinnedFileEntries,
287
+ companion_cached_files: companionMemory.fileCacheEntries,
288
+ companion_mapped_files: companionMemory.mappedFileEntries,
289
+ companion_pinned_files: companionMemory.pinnedFileEntries,
290
+ mock_r2_object_count: mockR2ObjectCount,
291
+ mock_r2_in_memory_bytes: mockR2InMemoryBytes,
292
+ pending_upload_segments: uploader.countSegmentsWaiting(),
293
+ uploader_inflight_segments: uploaderMemory.inflight_segments,
294
+ uploader_manifest_inflight_streams: uploaderMemory.manifest_inflight_streams,
295
+ segmenter_active_builds: segmenterMemory.active_builds,
296
+ segmenter_active_streams: segmenterMemory.active_streams,
297
+ segmenter_active_rows: segmenterMemory.active_rows,
298
+ sqlite_pagecache_used_slots: sqliteRuntime.pagecache_used_slots,
299
+ sqlite_pagecache_used_slots_highwater: sqliteRuntime.pagecache_used_slots_highwater,
300
+ sqlite_malloc_count: sqliteRuntime.malloc_count,
301
+ sqlite_malloc_count_highwater: sqliteRuntime.malloc_count_highwater,
302
+ sqlite_open_connections: sqliteRuntime.open_connections,
303
+ sqlite_prepared_statements: sqliteRuntime.prepared_statements,
304
+ };
305
+ return {
306
+ subsystems: {
307
+ heap_estimates: heapEstimates,
308
+ mapped_files: mappedFiles,
309
+ disk_caches: diskCaches,
310
+ configured_budgets: configuredBudgets,
311
+ pipeline_buffers: pipelineBuffers,
312
+ sqlite_runtime: sqliteRuntimeBytes,
313
+ counts,
314
+ },
315
+ totals: {
316
+ heap_estimate_bytes: sumRuntimeMemoryValues(heapEstimates),
317
+ mapped_file_bytes: sumRuntimeMemoryValues(mappedFiles),
318
+ disk_cache_bytes: sumRuntimeMemoryValues(diskCaches),
319
+ configured_budget_bytes: sumRuntimeMemoryValues(configuredBudgets),
320
+ pipeline_buffer_bytes: sumRuntimeMemoryValues(pipelineBuffers),
321
+ sqlite_runtime_bytes: sumRuntimeMemoryValues(sqliteRuntimeBytes),
322
+ },
323
+ };
65
324
  },
66
325
  start: () => {
67
326
  segmenter.start();
68
327
  uploader.start();
69
328
  indexer.start();
329
+ setTimeout(() => {
330
+ try {
331
+ let offset = 0;
332
+ const pageSize = 1000;
333
+ for (;;) {
334
+ const streams = db.listStreams(pageSize, offset);
335
+ for (const row of streams) indexer.enqueue(row.stream);
336
+ if (streams.length < pageSize) break;
337
+ offset += streams.length;
338
+ }
339
+ } catch {
340
+ // App may have been closed before the startup catch-up kickoff ran.
341
+ }
342
+ }, 0);
70
343
  },
71
344
  };
72
345
  },