@tungthedev/streams-server 0.2.0
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/CODE_OF_CONDUCT.md +45 -0
- package/CONTRIBUTING.md +76 -0
- package/LICENSE +201 -0
- package/README.md +58 -0
- package/SECURITY.md +42 -0
- package/bin/prisma-streams-server +2 -0
- package/package.json +46 -0
- package/src/app.ts +583 -0
- package/src/app_core.ts +3144 -0
- package/src/app_local.ts +206 -0
- package/src/auth.ts +124 -0
- package/src/auto_tune.ts +69 -0
- package/src/backpressure.ts +66 -0
- package/src/bootstrap.ts +613 -0
- package/src/compute/demo_entry.ts +415 -0
- package/src/compute/demo_site.ts +1242 -0
- package/src/compute/entry.ts +19 -0
- package/src/compute/package_entry.ts +4 -0
- package/src/compute/virtual-modules.d.ts +15 -0
- package/src/compute/worker_module_url.ts +9 -0
- package/src/concurrency_gate.ts +108 -0
- package/src/config.ts +402 -0
- package/src/db/bootstrap_store.ts +9 -0
- package/src/db/db.ts +2424 -0
- package/src/db/schema.ts +925 -0
- package/src/db/sqlite_manifest_snapshot.ts +81 -0
- package/src/db/sqlite_touch_store.ts +491 -0
- package/src/db/sqlite_wal_store.ts +472 -0
- package/src/details/full_mode_details.ts +568 -0
- package/src/expiry_sweeper.ts +47 -0
- package/src/foreground_activity.ts +55 -0
- package/src/hist.ts +169 -0
- package/src/index/binary_fuse.ts +379 -0
- package/src/index/indexer.ts +947 -0
- package/src/index/lexicon_file_cache.ts +261 -0
- package/src/index/lexicon_format.ts +93 -0
- package/src/index/lexicon_indexer.ts +863 -0
- package/src/index/run_cache.ts +84 -0
- package/src/index/run_format.ts +213 -0
- package/src/index/schedule.ts +28 -0
- package/src/index/secondary_indexer.ts +901 -0
- package/src/index/secondary_schema.ts +105 -0
- package/src/ingest.ts +309 -0
- package/src/lens/lens.ts +501 -0
- package/src/manifest.ts +249 -0
- package/src/memory.ts +334 -0
- package/src/metrics.ts +147 -0
- package/src/metrics_emitter.ts +83 -0
- package/src/notifier.ts +180 -0
- package/src/objectstore/accounting.ts +151 -0
- package/src/objectstore/interface.ts +13 -0
- package/src/objectstore/mock_r2.ts +269 -0
- package/src/objectstore/null.ts +32 -0
- package/src/objectstore/r2.ts +318 -0
- package/src/observe/pairing.ts +61 -0
- package/src/observe/request.ts +772 -0
- package/src/offset.ts +70 -0
- package/src/postgres/bootstrap.ts +269 -0
- package/src/postgres/companions.ts +197 -0
- package/src/postgres/control_restore.ts +109 -0
- package/src/postgres/details.ts +189 -0
- package/src/postgres/lexicon_index.ts +260 -0
- package/src/postgres/routing_index.ts +189 -0
- package/src/postgres/rows.ts +132 -0
- package/src/postgres/schema.ts +355 -0
- package/src/postgres/secondary_index.ts +238 -0
- package/src/postgres/segments.ts +900 -0
- package/src/postgres/stats.ts +103 -0
- package/src/postgres/store.ts +947 -0
- package/src/postgres/touch.ts +591 -0
- package/src/postgres/types.ts +32 -0
- package/src/profiles/evlog/schema.ts +234 -0
- package/src/profiles/evlog.ts +473 -0
- package/src/profiles/generic.ts +51 -0
- package/src/profiles/index.ts +237 -0
- package/src/profiles/metrics/block_format.ts +109 -0
- package/src/profiles/metrics/normalize.ts +366 -0
- package/src/profiles/metrics/schema.ts +319 -0
- package/src/profiles/metrics.ts +83 -0
- package/src/profiles/otelTraces/normalize.ts +955 -0
- package/src/profiles/otelTraces/otlp.ts +1002 -0
- package/src/profiles/otelTraces/schema.ts +408 -0
- package/src/profiles/otelTraces.ts +390 -0
- package/src/profiles/profile.ts +284 -0
- package/src/profiles/stateProtocol/change_event_conformance.typecheck.ts +35 -0
- package/src/profiles/stateProtocol/changes.ts +24 -0
- package/src/profiles/stateProtocol/ingest.ts +115 -0
- package/src/profiles/stateProtocol/routes.ts +511 -0
- package/src/profiles/stateProtocol/types.ts +6 -0
- package/src/profiles/stateProtocol/validation.ts +51 -0
- package/src/profiles/stateProtocol.ts +107 -0
- package/src/read_filter.ts +468 -0
- package/src/reader.ts +2986 -0
- package/src/runtime/hash.ts +156 -0
- package/src/runtime/hash_vendor/LICENSE.hash-wasm +38 -0
- package/src/runtime/hash_vendor/NOTICE.md +8 -0
- package/src/runtime/hash_vendor/xxhash3.umd.min.cjs +7 -0
- package/src/runtime/hash_vendor/xxhash32.umd.min.cjs +7 -0
- package/src/runtime/hash_vendor/xxhash64.umd.min.cjs +7 -0
- package/src/runtime/host_runtime.ts +5 -0
- package/src/runtime_memory.ts +200 -0
- package/src/runtime_memory_sampler.ts +237 -0
- package/src/schema/lens_schema.ts +290 -0
- package/src/schema/proof.ts +547 -0
- package/src/schema/read_json.ts +51 -0
- package/src/schema/registry.ts +966 -0
- package/src/search/agg_format.ts +638 -0
- package/src/search/aggregate.ts +409 -0
- package/src/search/binary/codec.ts +162 -0
- package/src/search/binary/docset.ts +67 -0
- package/src/search/binary/restart_strings.ts +181 -0
- package/src/search/binary/varint.ts +34 -0
- package/src/search/bitset.ts +19 -0
- package/src/search/col_format.ts +382 -0
- package/src/search/col_runtime.ts +59 -0
- package/src/search/column_encoding.ts +43 -0
- package/src/search/companion_file_cache.ts +319 -0
- package/src/search/companion_format.ts +327 -0
- package/src/search/companion_manager.ts +1305 -0
- package/src/search/companion_plan.ts +229 -0
- package/src/search/exact_format.ts +281 -0
- package/src/search/exact_runtime.ts +55 -0
- package/src/search/fts_format.ts +423 -0
- package/src/search/fts_runtime.ts +333 -0
- package/src/search/query.ts +875 -0
- package/src/search/schema.ts +245 -0
- package/src/segment/cache.ts +270 -0
- package/src/segment/cached_segment.ts +89 -0
- package/src/segment/format.ts +403 -0
- package/src/segment/segmenter.ts +412 -0
- package/src/segment/segmenter_worker.ts +72 -0
- package/src/segment/segmenter_workers.ts +130 -0
- package/src/server.ts +264 -0
- package/src/server_auto_tune.ts +158 -0
- package/src/sqlite/adapter.ts +335 -0
- package/src/sqlite/runtime_stats.ts +163 -0
- package/src/stats.ts +205 -0
- package/src/store/append.ts +50 -0
- package/src/store/bootstrap_restore_store.ts +71 -0
- package/src/store/capabilities.ts +86 -0
- package/src/store/full_mode_details_store.ts +71 -0
- package/src/store/index_store.ts +104 -0
- package/src/store/profile_touch_store.ts +1 -0
- package/src/store/rows.ts +144 -0
- package/src/store/schema_profile_store.ts +73 -0
- package/src/store/schema_publication.ts +6 -0
- package/src/store/segment_manifest_store.ts +129 -0
- package/src/store/segment_read_store.ts +22 -0
- package/src/store/stats_accounting_store.ts +83 -0
- package/src/store/touch_store.ts +98 -0
- package/src/store/wal_store.ts +21 -0
- package/src/stream_size_reconciler.ts +100 -0
- package/src/touch/canonical_change.ts +7 -0
- package/src/touch/live_keys.ts +158 -0
- package/src/touch/live_metrics.ts +841 -0
- package/src/touch/live_templates.ts +449 -0
- package/src/touch/manager.ts +1292 -0
- package/src/touch/process_batch.ts +576 -0
- package/src/touch/processor_worker.ts +85 -0
- package/src/touch/spec.ts +459 -0
- package/src/touch/touch_journal.ts +771 -0
- package/src/touch/touch_key_id.ts +20 -0
- package/src/touch/worker_pool.ts +191 -0
- package/src/touch/worker_protocol.ts +57 -0
- package/src/types/proper-lockfile.d.ts +1 -0
- package/src/uploader.ts +358 -0
- package/src/util/base32_crockford.ts +81 -0
- package/src/util/bloom256.ts +67 -0
- package/src/util/byte_lru.ts +73 -0
- package/src/util/cleanup.ts +22 -0
- package/src/util/crc32c.ts +29 -0
- package/src/util/ds_error.ts +15 -0
- package/src/util/duration.ts +17 -0
- package/src/util/endian.ts +53 -0
- package/src/util/json_pointer.ts +148 -0
- package/src/util/log.ts +25 -0
- package/src/util/lru.ts +53 -0
- package/src/util/retry.ts +35 -0
- package/src/util/siphash.ts +71 -0
- package/src/util/stream_paths.ts +50 -0
- package/src/util/time.ts +14 -0
- package/src/util/yield.ts +3 -0
- package/src/util/zstd.ts +24 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import type { Pool } from "pg";
|
|
2
|
+
import type { SecondaryIndexStore } from "../store/index_store";
|
|
3
|
+
import type { SecondaryIndexRunRow, SecondaryIndexStateRow } from "../store/rows";
|
|
4
|
+
import type { PgExecutor } from "./types";
|
|
5
|
+
import { pgInt, toBigInt, toBytes, PostgresIndexSharedStore } from "./rows";
|
|
6
|
+
|
|
7
|
+
export class PostgresSecondaryIndexStore extends PostgresIndexSharedStore implements SecondaryIndexStore {
|
|
8
|
+
async getSecondaryIndexState(stream: string, indexName: string): Promise<SecondaryIndexStateRow | null> {
|
|
9
|
+
return getPostgresSecondaryIndexState(this.pool, stream, indexName);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async listSecondaryIndexStates(stream: string): Promise<SecondaryIndexStateRow[]> {
|
|
13
|
+
return listPostgresSecondaryIndexStates(this.pool, stream);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async upsertSecondaryIndexState(
|
|
17
|
+
stream: string,
|
|
18
|
+
indexName: string,
|
|
19
|
+
indexSecret: Uint8Array,
|
|
20
|
+
configHash: string,
|
|
21
|
+
indexedThrough: number
|
|
22
|
+
): Promise<void> {
|
|
23
|
+
await upsertPostgresSecondaryIndexState(this.pool, this.nowMs(), stream, indexName, indexSecret, configHash, indexedThrough);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async updateSecondaryIndexedThrough(stream: string, indexName: string, indexedThrough: number): Promise<void> {
|
|
27
|
+
await this.pool.query(
|
|
28
|
+
`UPDATE secondary_index_state
|
|
29
|
+
SET indexed_through = $1, updated_at_ms = $2
|
|
30
|
+
WHERE stream = $3 AND index_name = $4;`,
|
|
31
|
+
[indexedThrough, pgInt(this.nowMs()), stream, indexName]
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async listSecondaryIndexRuns(stream: string, indexName: string): Promise<SecondaryIndexRunRow[]> {
|
|
36
|
+
return listPostgresSecondaryIndexRuns(this.pool, stream, indexName, false);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async listRetiredSecondaryIndexRuns(stream: string, indexName: string): Promise<SecondaryIndexRunRow[]> {
|
|
40
|
+
return listPostgresRetiredSecondaryIndexRuns(this.pool, stream, indexName);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async insertSecondaryIndexRun(row: Omit<SecondaryIndexRunRow, "retired_gen" | "retired_at_ms">): Promise<void> {
|
|
44
|
+
await insertPostgresSecondaryIndexRun(this.pool, row);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async retireSecondaryIndexRuns(runIds: string[], retiredGen: number, retiredAtMs: bigint): Promise<void> {
|
|
48
|
+
await retirePostgresSecondaryIndexRuns(this.pool, runIds, retiredGen, retiredAtMs);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async deleteSecondaryIndexRuns(runIds: string[]): Promise<void> {
|
|
52
|
+
if (runIds.length === 0) return;
|
|
53
|
+
await this.pool.query(`DELETE FROM secondary_index_runs WHERE run_id = ANY($1::text[]);`, [runIds]);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async deleteSecondaryIndex(stream: string, indexName: string): Promise<void> {
|
|
57
|
+
const client = await this.pool.connect();
|
|
58
|
+
try {
|
|
59
|
+
await client.query("BEGIN");
|
|
60
|
+
await client.query(`DELETE FROM secondary_index_runs WHERE stream = $1 AND index_name = $2;`, [stream, indexName]);
|
|
61
|
+
await client.query(`DELETE FROM secondary_index_state WHERE stream = $1 AND index_name = $2;`, [stream, indexName]);
|
|
62
|
+
await client.query("COMMIT");
|
|
63
|
+
} catch (error) {
|
|
64
|
+
await client.query("ROLLBACK").catch(() => {});
|
|
65
|
+
throw error;
|
|
66
|
+
} finally {
|
|
67
|
+
client.release();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export async function insertPostgresSecondaryIndexRun(
|
|
73
|
+
executor: PgExecutor,
|
|
74
|
+
row: Omit<SecondaryIndexRunRow, "retired_gen" | "retired_at_ms">,
|
|
75
|
+
opts: { idempotent?: boolean } = {}
|
|
76
|
+
): Promise<void> {
|
|
77
|
+
const conflictSql = opts.idempotent
|
|
78
|
+
? `ON CONFLICT(run_id) DO UPDATE SET
|
|
79
|
+
stream = excluded.stream,
|
|
80
|
+
index_name = excluded.index_name,
|
|
81
|
+
level = excluded.level,
|
|
82
|
+
start_segment = excluded.start_segment,
|
|
83
|
+
end_segment = excluded.end_segment,
|
|
84
|
+
object_key = excluded.object_key,
|
|
85
|
+
size_bytes = excluded.size_bytes,
|
|
86
|
+
filter_len = excluded.filter_len,
|
|
87
|
+
record_count = excluded.record_count,
|
|
88
|
+
retired_gen = NULL,
|
|
89
|
+
retired_at_ms = NULL`
|
|
90
|
+
: "";
|
|
91
|
+
await executor.query(
|
|
92
|
+
`INSERT INTO secondary_index_runs(
|
|
93
|
+
run_id, stream, index_name, level, start_segment, end_segment, object_key, size_bytes, filter_len, record_count
|
|
94
|
+
)
|
|
95
|
+
VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
|
|
96
|
+
${conflictSql};`,
|
|
97
|
+
[
|
|
98
|
+
row.run_id,
|
|
99
|
+
row.stream,
|
|
100
|
+
row.index_name,
|
|
101
|
+
row.level,
|
|
102
|
+
row.start_segment,
|
|
103
|
+
row.end_segment,
|
|
104
|
+
row.object_key,
|
|
105
|
+
row.size_bytes,
|
|
106
|
+
row.filter_len,
|
|
107
|
+
row.record_count,
|
|
108
|
+
]
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export async function upsertPostgresSecondaryIndexState(
|
|
113
|
+
executor: PgExecutor,
|
|
114
|
+
nowMs: bigint,
|
|
115
|
+
stream: string,
|
|
116
|
+
indexName: string,
|
|
117
|
+
indexSecret: Uint8Array,
|
|
118
|
+
configHash: string,
|
|
119
|
+
indexedThrough: number
|
|
120
|
+
): Promise<void> {
|
|
121
|
+
await executor.query(
|
|
122
|
+
`INSERT INTO secondary_index_state(stream, index_name, index_secret, config_hash, indexed_through, updated_at_ms)
|
|
123
|
+
VALUES($1, $2, $3, $4, $5, $6)
|
|
124
|
+
ON CONFLICT(stream, index_name) DO UPDATE SET
|
|
125
|
+
index_secret = excluded.index_secret,
|
|
126
|
+
config_hash = excluded.config_hash,
|
|
127
|
+
indexed_through = excluded.indexed_through,
|
|
128
|
+
updated_at_ms = excluded.updated_at_ms;`,
|
|
129
|
+
[stream, indexName, Buffer.from(indexSecret), configHash, indexedThrough, pgInt(nowMs)]
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export async function retirePostgresSecondaryIndexRuns(
|
|
134
|
+
executor: PgExecutor,
|
|
135
|
+
runIds: string[],
|
|
136
|
+
retiredGen: number,
|
|
137
|
+
retiredAtMs: bigint
|
|
138
|
+
): Promise<void> {
|
|
139
|
+
if (runIds.length === 0) return;
|
|
140
|
+
await executor.query(`UPDATE secondary_index_runs SET retired_gen = $1, retired_at_ms = $2 WHERE run_id = ANY($3::text[]);`, [
|
|
141
|
+
retiredGen,
|
|
142
|
+
pgInt(retiredAtMs),
|
|
143
|
+
runIds,
|
|
144
|
+
]);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export async function loadPostgresSecondaryIndexManifest(
|
|
148
|
+
executor: PgExecutor,
|
|
149
|
+
stream: string
|
|
150
|
+
): Promise<{
|
|
151
|
+
secondaryIndexStates: SecondaryIndexStateRow[];
|
|
152
|
+
secondaryIndexRuns: SecondaryIndexRunRow[];
|
|
153
|
+
retiredSecondaryIndexRuns: SecondaryIndexRunRow[];
|
|
154
|
+
}> {
|
|
155
|
+
const secondaryIndexStates = await listPostgresSecondaryIndexStates(executor, stream);
|
|
156
|
+
const secondaryIndexRuns = (
|
|
157
|
+
await Promise.all(secondaryIndexStates.map((state) => listPostgresSecondaryIndexRuns(executor, stream, state.index_name, false)))
|
|
158
|
+
).flat();
|
|
159
|
+
const retiredSecondaryIndexRuns = (
|
|
160
|
+
await Promise.all(secondaryIndexStates.map((state) => listPostgresRetiredSecondaryIndexRuns(executor, stream, state.index_name)))
|
|
161
|
+
).flat();
|
|
162
|
+
return { secondaryIndexStates, secondaryIndexRuns, retiredSecondaryIndexRuns };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async function getPostgresSecondaryIndexState(
|
|
166
|
+
executor: PgExecutor,
|
|
167
|
+
stream: string,
|
|
168
|
+
indexName: string
|
|
169
|
+
): Promise<SecondaryIndexStateRow | null> {
|
|
170
|
+
const res = await executor.query(`SELECT * FROM secondary_index_state WHERE stream = $1 AND index_name = $2 LIMIT 1;`, [
|
|
171
|
+
stream,
|
|
172
|
+
indexName,
|
|
173
|
+
]);
|
|
174
|
+
return res.rows[0] ? coerceSecondaryIndexStateRow(res.rows[0]) : null;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async function listPostgresSecondaryIndexStates(executor: PgExecutor, stream: string): Promise<SecondaryIndexStateRow[]> {
|
|
178
|
+
const res = await executor.query(`SELECT * FROM secondary_index_state WHERE stream = $1 ORDER BY index_name ASC;`, [stream]);
|
|
179
|
+
return res.rows.map(coerceSecondaryIndexStateRow);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async function listPostgresSecondaryIndexRuns(
|
|
183
|
+
executor: PgExecutor,
|
|
184
|
+
stream: string,
|
|
185
|
+
indexName: string,
|
|
186
|
+
includeRetired: boolean
|
|
187
|
+
): Promise<SecondaryIndexRunRow[]> {
|
|
188
|
+
const retiredClause = includeRetired ? "" : " AND retired_gen IS NULL";
|
|
189
|
+
const res = await executor.query(
|
|
190
|
+
`SELECT * FROM secondary_index_runs
|
|
191
|
+
WHERE stream = $1 AND index_name = $2${retiredClause}
|
|
192
|
+
ORDER BY level ASC, start_segment ASC, end_segment ASC;`,
|
|
193
|
+
[stream, indexName]
|
|
194
|
+
);
|
|
195
|
+
return res.rows.map(coerceSecondaryIndexRunRow);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async function listPostgresRetiredSecondaryIndexRuns(
|
|
199
|
+
executor: PgExecutor,
|
|
200
|
+
stream: string,
|
|
201
|
+
indexName: string
|
|
202
|
+
): Promise<SecondaryIndexRunRow[]> {
|
|
203
|
+
const res = await executor.query(
|
|
204
|
+
`SELECT * FROM secondary_index_runs
|
|
205
|
+
WHERE stream = $1 AND index_name = $2 AND retired_gen IS NOT NULL
|
|
206
|
+
ORDER BY retired_gen ASC, retired_at_ms ASC, level ASC, start_segment ASC;`,
|
|
207
|
+
[stream, indexName]
|
|
208
|
+
);
|
|
209
|
+
return res.rows.map(coerceSecondaryIndexRunRow);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function coerceSecondaryIndexStateRow(row: any): SecondaryIndexStateRow {
|
|
213
|
+
return {
|
|
214
|
+
stream: String(row.stream),
|
|
215
|
+
index_name: String(row.index_name),
|
|
216
|
+
index_secret: toBytes(row.index_secret),
|
|
217
|
+
config_hash: String(row.config_hash),
|
|
218
|
+
indexed_through: Number(row.indexed_through),
|
|
219
|
+
updated_at_ms: toBigInt(row.updated_at_ms),
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function coerceSecondaryIndexRunRow(row: any): SecondaryIndexRunRow {
|
|
224
|
+
return {
|
|
225
|
+
run_id: String(row.run_id),
|
|
226
|
+
stream: String(row.stream),
|
|
227
|
+
index_name: String(row.index_name),
|
|
228
|
+
level: Number(row.level),
|
|
229
|
+
start_segment: Number(row.start_segment),
|
|
230
|
+
end_segment: Number(row.end_segment),
|
|
231
|
+
object_key: String(row.object_key),
|
|
232
|
+
size_bytes: Number(row.size_bytes),
|
|
233
|
+
filter_len: Number(row.filter_len),
|
|
234
|
+
record_count: Number(row.record_count),
|
|
235
|
+
retired_gen: row.retired_gen == null ? null : Number(row.retired_gen),
|
|
236
|
+
retired_at_ms: row.retired_at_ms == null ? null : toBigInt(row.retired_at_ms),
|
|
237
|
+
};
|
|
238
|
+
}
|