@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/src/config.ts CHANGED
@@ -1,5 +1,8 @@
1
1
  import { dsError } from "./util/ds_error.ts";
2
2
  export type Config = {
3
+ autoTuneRequestedMemoryMb: number | null;
4
+ autoTunePresetMb: number | null;
5
+ autoTuneEffectiveMemoryLimitMb: number | null;
3
6
  host: string;
4
7
  rootDir: string;
5
8
  dbPath: string;
@@ -15,9 +18,20 @@ export type Config = {
15
18
  segmentFooterCacheEntries: number;
16
19
  indexRunCacheMaxBytes: number;
17
20
  indexRunMemoryCacheBytes: number;
21
+ lexiconIndexCacheMaxBytes: number;
22
+ lexiconMappedCacheEntries: number;
18
23
  indexL0SpanSegments: number;
19
24
  indexBuildConcurrency: number;
20
25
  indexCheckIntervalMs: number;
26
+ searchCompanionBuildBatchSegments: number;
27
+ searchCompanionYieldBlocks: number;
28
+ searchCompanionFileCacheMaxBytes: number;
29
+ searchCompanionFileCacheMaxAgeMs: number;
30
+ searchCompanionMappedCacheEntries: number;
31
+ searchCompanionTocCacheBytes: number;
32
+ searchCompanionSectionCacheBytes: number;
33
+ searchWalOverlayQuietPeriodMs: number;
34
+ searchWalOverlayMaxBytes: number;
21
35
  indexCompactionFanout: number;
22
36
  indexMaxLevel: number;
23
37
  indexCompactionConcurrency: number;
@@ -31,10 +45,18 @@ export type Config = {
31
45
  ingestMaxBatchBytes: number;
32
46
  ingestMaxQueueRequests: number;
33
47
  ingestMaxQueueBytes: number;
48
+ ingestConcurrency: number;
34
49
  ingestBusyTimeoutMs: number;
35
50
  localBacklogMaxBytes: number;
36
51
  memoryLimitBytes: number;
37
52
  sqliteCacheBytes: number;
53
+ workerSqliteCacheBytes: number;
54
+ readConcurrency: number;
55
+ searchConcurrency: number;
56
+ asyncIndexConcurrency: number;
57
+ heapSnapshotPath: string | null;
58
+ memorySamplerPath: string | null;
59
+ memorySamplerIntervalMs: number;
38
60
  objectStoreTimeoutMs: number;
39
61
  objectStoreRetries: number;
40
62
  objectStoreBaseDelayMs: number;
@@ -42,10 +64,10 @@ export type Config = {
42
64
  expirySweepIntervalMs: number;
43
65
  expirySweepBatchLimit: number;
44
66
  metricsFlushIntervalMs: number;
45
- interpreterWorkers: number;
46
- interpreterCheckIntervalMs: number;
47
- interpreterMaxBatchRows: number;
48
- interpreterMaxBatchBytes: number;
67
+ touchWorkers: number;
68
+ touchCheckIntervalMs: number;
69
+ touchMaxBatchRows: number;
70
+ touchMaxBatchBytes: number;
49
71
  port: number;
50
72
  };
51
73
 
@@ -65,9 +87,20 @@ const KNOWN_DS_ENVS = new Set<string>([
65
87
  "DS_SEGMENT_FOOTER_CACHE_ENTRIES",
66
88
  "DS_INDEX_RUN_CACHE_MAX_BYTES",
67
89
  "DS_INDEX_RUN_MEM_CACHE_BYTES",
90
+ "DS_LEXICON_INDEX_CACHE_MAX_BYTES",
91
+ "DS_LEXICON_MMAP_CACHE_ENTRIES",
68
92
  "DS_INDEX_L0_SPAN",
69
93
  "DS_INDEX_BUILD_CONCURRENCY",
70
94
  "DS_INDEX_CHECK_MS",
95
+ "DS_SEARCH_COMPANION_BATCH_SEGMENTS",
96
+ "DS_SEARCH_COMPANION_YIELD_BLOCKS",
97
+ "DS_SEARCH_COMPANION_FILE_CACHE_MAX_BYTES",
98
+ "DS_SEARCH_COMPANION_FILE_CACHE_MAX_AGE_MS",
99
+ "DS_SEARCH_COMPANION_MMAP_CACHE_ENTRIES",
100
+ "DS_SEARCH_COMPANION_TOC_CACHE_BYTES",
101
+ "DS_SEARCH_COMPANION_SECTION_CACHE_BYTES",
102
+ "DS_SEARCH_WAL_OVERLAY_QUIET_MS",
103
+ "DS_SEARCH_WAL_OVERLAY_MAX_BYTES",
71
104
  "DS_INDEX_COMPACTION_FANOUT",
72
105
  "DS_INDEX_MAX_LEVEL",
73
106
  "DS_INDEX_COMPACT_CONCURRENCY",
@@ -81,12 +114,21 @@ const KNOWN_DS_ENVS = new Set<string>([
81
114
  "DS_INGEST_MAX_BATCH_BYTES",
82
115
  "DS_INGEST_MAX_QUEUE_REQS",
83
116
  "DS_INGEST_MAX_QUEUE_BYTES",
117
+ "DS_INGEST_CONCURRENCY",
84
118
  "DS_INGEST_BUSY_MS",
85
119
  "DS_LOCAL_BACKLOG_MAX_BYTES",
86
120
  "DS_MEMORY_LIMIT_BYTES",
87
121
  "DS_MEMORY_LIMIT_MB",
88
122
  "DS_SQLITE_CACHE_BYTES",
89
123
  "DS_SQLITE_CACHE_MB",
124
+ "DS_WORKER_SQLITE_CACHE_BYTES",
125
+ "DS_WORKER_SQLITE_CACHE_MB",
126
+ "DS_READ_CONCURRENCY",
127
+ "DS_SEARCH_CONCURRENCY",
128
+ "DS_ASYNC_INDEX_CONCURRENCY",
129
+ "DS_HEAP_SNAPSHOT_PATH",
130
+ "DS_MEMORY_SAMPLER_PATH",
131
+ "DS_MEMORY_SAMPLER_INTERVAL_MS",
90
132
  "DS_OBJECTSTORE_TIMEOUT_MS",
91
133
  "DS_OBJECTSTORE_RETRIES",
92
134
  "DS_OBJECTSTORE_RETRY_BASE_MS",
@@ -95,10 +137,13 @@ const KNOWN_DS_ENVS = new Set<string>([
95
137
  "DS_EXPIRY_SWEEP_MS",
96
138
  "DS_EXPIRY_SWEEP_LIMIT",
97
139
  "DS_METRICS_FLUSH_MS",
98
- "DS_INTERPRETER_WORKERS",
99
- "DS_INTERPRETER_CHECK_MS",
100
- "DS_INTERPRETER_MAX_BATCH_ROWS",
101
- "DS_INTERPRETER_MAX_BATCH_BYTES",
140
+ "DS_TOUCH_WORKERS",
141
+ "DS_TOUCH_CHECK_MS",
142
+ "DS_TOUCH_MAX_BATCH_ROWS",
143
+ "DS_TOUCH_MAX_BATCH_BYTES",
144
+ "DS_AUTO_TUNE_REQUESTED_MB",
145
+ "DS_AUTO_TUNE_PRESET_MB",
146
+ "DS_AUTO_TUNE_EFFECTIVE_MEMORY_LIMIT_MB",
102
147
  "DS_STATS_INTERVAL_MS",
103
148
  "DS_BACKPRESSURE_BUDGET_MS",
104
149
  "DS_MOCK_R2_MAX_INMEM_BYTES",
@@ -132,6 +177,14 @@ const KNOWN_DS_ENVS = new Set<string>([
132
177
  "DS_RK_BLOCK_BYTES",
133
178
  "DS_RK_SEED",
134
179
  "DS_RK_R2_GET_DELAY_MS",
180
+ "DS_LARGE_INDEX_FILTER",
181
+ "DS_LARGE_INDEX_FILTER_TOTAL_BYTES",
182
+ "DS_LARGE_INDEX_FILTER_PAYLOAD_BYTES",
183
+ "DS_LARGE_INDEX_FILTER_BATCH_ROWS",
184
+ "DS_LARGE_INDEX_FILTER_SEGMENT_BYTES",
185
+ "DS_LARGE_INDEX_FILTER_INDEX_SPAN",
186
+ "DS_LARGE_INDEX_FILTER_TIMEOUT_MS",
187
+ "DS_LARGE_INDEX_FILTER_R2_MAX_INMEM_BYTES",
135
188
  ]);
136
189
 
137
190
  let warnedUnknownEnv = false;
@@ -178,14 +231,20 @@ export function loadConfig(): Config {
178
231
  warnUnknownEnv();
179
232
  const rootDir = process.env.DS_ROOT ?? "./ds-data";
180
233
  const host = process.env.DS_HOST?.trim() || "127.0.0.1";
234
+ const autoTuneRequestedMemoryMb = envBytes("DS_AUTO_TUNE_REQUESTED_MB");
235
+ const autoTunePresetMb = envBytes("DS_AUTO_TUNE_PRESET_MB");
236
+ const autoTuneEffectiveMemoryLimitMb = envBytes("DS_AUTO_TUNE_EFFECTIVE_MEMORY_LIMIT_MB");
181
237
  const bytesOverride = envBytes("DS_MEMORY_LIMIT_BYTES");
182
238
  const mbOverride = envBytes("DS_MEMORY_LIMIT_MB");
183
239
  const memoryLimitBytes = bytesOverride ?? (mbOverride != null ? mbOverride * 1024 * 1024 : 0);
184
240
  const backlogOverride = envBytes("DS_LOCAL_BACKLOG_MAX_BYTES");
185
241
  const sqliteCacheBytesOverride = envBytes("DS_SQLITE_CACHE_BYTES");
186
242
  const sqliteCacheMbOverride = envBytes("DS_SQLITE_CACHE_MB");
243
+ const workerSqliteCacheBytesOverride = envBytes("DS_WORKER_SQLITE_CACHE_BYTES");
244
+ const workerSqliteCacheMbOverride = envBytes("DS_WORKER_SQLITE_CACHE_MB");
187
245
  const indexMemOverride = envBytes("DS_INDEX_RUN_MEM_CACHE_BYTES");
188
246
  const indexDiskOverride = envBytes("DS_INDEX_RUN_CACHE_MAX_BYTES");
247
+ const lexiconDiskOverride = envBytes("DS_LEXICON_INDEX_CACHE_MAX_BYTES");
189
248
  const localBacklogMaxBytes = backlogOverride ?? 10 * 1024 * 1024 * 1024;
190
249
  const sqliteCacheBytes =
191
250
  sqliteCacheBytesOverride ??
@@ -194,18 +253,38 @@ export function loadConfig(): Config {
194
253
  : memoryLimitBytes > 0
195
254
  ? Math.floor(memoryLimitBytes * 0.25)
196
255
  : 0);
256
+ const workerSqliteCacheBytes =
257
+ workerSqliteCacheBytesOverride ??
258
+ (workerSqliteCacheMbOverride != null
259
+ ? workerSqliteCacheMbOverride * 1024 * 1024
260
+ : sqliteCacheBytes > 0
261
+ ? clampBytes(Math.floor(sqliteCacheBytes / 8), 8 * 1024 * 1024, 32 * 1024 * 1024)
262
+ : 0);
197
263
  const tunedIndexMem =
198
264
  indexMemOverride ??
199
265
  (memoryLimitBytes > 0
200
266
  ? clampBytes(Math.floor(memoryLimitBytes * 0.05), 8 * 1024 * 1024, 128 * 1024 * 1024)
201
267
  : 64 * 1024 * 1024);
268
+ const companionSectionCacheBytes =
269
+ envBytes("DS_SEARCH_COMPANION_SECTION_CACHE_BYTES") ??
270
+ (memoryLimitBytes > 0
271
+ ? clampBytes(Math.floor(memoryLimitBytes * 0.02), 8 * 1024 * 1024, 128 * 1024 * 1024)
272
+ : 32 * 1024 * 1024);
273
+ const companionFileCacheBytes =
274
+ envBytes("DS_SEARCH_COMPANION_FILE_CACHE_MAX_BYTES") ??
275
+ clampBytes(Math.max(512 * 1024 * 1024, Math.floor(localBacklogMaxBytes * 0.1)), 256 * 1024 * 1024, 4 * 1024 * 1024 * 1024);
276
+ const segmentMaxBytes = envNum("DS_SEGMENT_MAX_BYTES", 16 * 1024 * 1024);
277
+ const searchWalOverlayMaxBytes = envBytes("DS_SEARCH_WAL_OVERLAY_MAX_BYTES") ?? segmentMaxBytes;
202
278
  return {
279
+ autoTuneRequestedMemoryMb,
280
+ autoTunePresetMb,
281
+ autoTuneEffectiveMemoryLimitMb,
203
282
  host,
204
283
  rootDir,
205
284
  dbPath: process.env.DS_DB_PATH ?? `${rootDir}/wal.sqlite`,
206
- segmentMaxBytes: envNum("DS_SEGMENT_MAX_BYTES", 16 * 1024 * 1024),
285
+ segmentMaxBytes,
207
286
  blockMaxBytes: envNum("DS_BLOCK_MAX_BYTES", 256 * 1024),
208
- segmentTargetRows: envNum("DS_SEGMENT_TARGET_ROWS", 50_000),
287
+ segmentTargetRows: envNum("DS_SEGMENT_TARGET_ROWS", 100_000),
209
288
  segmentMaxIntervalMs: envNum("DS_SEGMENT_MAX_INTERVAL_MS", 0),
210
289
  segmentCheckIntervalMs: envNum("DS_SEGMENT_CHECK_MS", 250),
211
290
  segmenterWorkers: envNum("DS_SEGMENTER_WORKERS", 0),
@@ -215,9 +294,24 @@ export function loadConfig(): Config {
215
294
  segmentFooterCacheEntries: envNum("DS_SEGMENT_FOOTER_CACHE_ENTRIES", 2048),
216
295
  indexRunCacheMaxBytes: indexDiskOverride ?? 256 * 1024 * 1024,
217
296
  indexRunMemoryCacheBytes: tunedIndexMem,
297
+ lexiconIndexCacheMaxBytes:
298
+ lexiconDiskOverride ??
299
+ (memoryLimitBytes > 0
300
+ ? clampBytes(Math.floor(memoryLimitBytes * 0.03), 8 * 1024 * 1024, 256 * 1024 * 1024)
301
+ : 64 * 1024 * 1024),
302
+ lexiconMappedCacheEntries: envNum("DS_LEXICON_MMAP_CACHE_ENTRIES", 64),
218
303
  indexL0SpanSegments: envNum("DS_INDEX_L0_SPAN", 16),
219
304
  indexBuildConcurrency: envNum("DS_INDEX_BUILD_CONCURRENCY", 4),
220
305
  indexCheckIntervalMs: envNum("DS_INDEX_CHECK_MS", 1000),
306
+ searchCompanionBuildBatchSegments: envNum("DS_SEARCH_COMPANION_BATCH_SEGMENTS", 4),
307
+ searchCompanionYieldBlocks: envNum("DS_SEARCH_COMPANION_YIELD_BLOCKS", 4),
308
+ searchCompanionFileCacheMaxBytes: companionFileCacheBytes,
309
+ searchCompanionFileCacheMaxAgeMs: envNum("DS_SEARCH_COMPANION_FILE_CACHE_MAX_AGE_MS", 24 * 60 * 60 * 1000),
310
+ searchCompanionMappedCacheEntries: envNum("DS_SEARCH_COMPANION_MMAP_CACHE_ENTRIES", 64),
311
+ searchCompanionTocCacheBytes: envNum("DS_SEARCH_COMPANION_TOC_CACHE_BYTES", 1 * 1024 * 1024),
312
+ searchCompanionSectionCacheBytes: companionSectionCacheBytes,
313
+ searchWalOverlayQuietPeriodMs: envNum("DS_SEARCH_WAL_OVERLAY_QUIET_MS", 5_000),
314
+ searchWalOverlayMaxBytes,
221
315
  indexCompactionFanout: envNum("DS_INDEX_COMPACTION_FANOUT", 16),
222
316
  indexMaxLevel: envNum("DS_INDEX_MAX_LEVEL", 4),
223
317
  indexCompactionConcurrency: envNum("DS_INDEX_COMPACT_CONCURRENCY", 4),
@@ -231,10 +325,18 @@ export function loadConfig(): Config {
231
325
  ingestMaxBatchBytes: envNum("DS_INGEST_MAX_BATCH_BYTES", 8 * 1024 * 1024),
232
326
  ingestMaxQueueRequests: envNum("DS_INGEST_MAX_QUEUE_REQS", 50_000),
233
327
  ingestMaxQueueBytes: envNum("DS_INGEST_MAX_QUEUE_BYTES", 64 * 1024 * 1024),
328
+ ingestConcurrency: envNum("DS_INGEST_CONCURRENCY", 2),
234
329
  ingestBusyTimeoutMs: envNum("DS_INGEST_BUSY_MS", 5000),
235
330
  localBacklogMaxBytes,
236
331
  memoryLimitBytes,
237
332
  sqliteCacheBytes,
333
+ workerSqliteCacheBytes,
334
+ readConcurrency: envNum("DS_READ_CONCURRENCY", 4),
335
+ searchConcurrency: envNum("DS_SEARCH_CONCURRENCY", 2),
336
+ asyncIndexConcurrency: envNum("DS_ASYNC_INDEX_CONCURRENCY", 1),
337
+ heapSnapshotPath: process.env.DS_HEAP_SNAPSHOT_PATH?.trim() || null,
338
+ memorySamplerPath: process.env.DS_MEMORY_SAMPLER_PATH?.trim() || null,
339
+ memorySamplerIntervalMs: envNum("DS_MEMORY_SAMPLER_INTERVAL_MS", 1_000),
238
340
  objectStoreTimeoutMs: envNum("DS_OBJECTSTORE_TIMEOUT_MS", 5000),
239
341
  objectStoreRetries: envNum("DS_OBJECTSTORE_RETRIES", 3),
240
342
  objectStoreBaseDelayMs: envNum("DS_OBJECTSTORE_RETRY_BASE_MS", 50),
@@ -242,10 +344,10 @@ export function loadConfig(): Config {
242
344
  expirySweepIntervalMs: envNum("DS_EXPIRY_SWEEP_MS", 60_000),
243
345
  expirySweepBatchLimit: envNum("DS_EXPIRY_SWEEP_LIMIT", 100),
244
346
  metricsFlushIntervalMs: envNum("DS_METRICS_FLUSH_MS", 10_000),
245
- interpreterWorkers: envNum("DS_INTERPRETER_WORKERS", 1),
246
- interpreterCheckIntervalMs: envNum("DS_INTERPRETER_CHECK_MS", 250),
247
- interpreterMaxBatchRows: envNum("DS_INTERPRETER_MAX_BATCH_ROWS", 500),
248
- interpreterMaxBatchBytes: envNum("DS_INTERPRETER_MAX_BATCH_BYTES", 4 * 1024 * 1024),
347
+ touchWorkers: envNum("DS_TOUCH_WORKERS", 1),
348
+ touchCheckIntervalMs: envNum("DS_TOUCH_CHECK_MS", 250),
349
+ touchMaxBatchRows: envNum("DS_TOUCH_MAX_BATCH_ROWS", 500),
350
+ touchMaxBatchBytes: envNum("DS_TOUCH_MAX_BATCH_BYTES", 4 * 1024 * 1024),
249
351
  port: envNum("PORT", 8080),
250
352
  };
251
353
  }