@gscdump/engine 0.33.3 → 0.33.4
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/rollups.d.mts +19 -8
- package/dist/rollups.mjs +39 -21
- package/package.json +3 -3
package/dist/rollups.d.mts
CHANGED
|
@@ -377,14 +377,22 @@ declare const queryCanonicalDailyRollup: RollupDef;
|
|
|
377
377
|
* Resumable, cross-invocation build of `query_canonical_daily` for a high-
|
|
378
378
|
* cardinality site whose full windowed build exceeds one job reservation (300s).
|
|
379
379
|
*
|
|
380
|
-
* Each call builds
|
|
381
|
-
*
|
|
382
|
-
*
|
|
383
|
-
*
|
|
384
|
-
*
|
|
385
|
-
* (the read path is unchanged — still one rollup file) and deletes the staging,
|
|
380
|
+
* Each call builds from `(windowOffset, pageOffset)` until `deadlineMs`, writes
|
|
381
|
+
* that batch's rows to a PART parquet, and returns `{ done:false, nextWindowOffset,
|
|
382
|
+
* nextPageOffset }` for the caller to re-enqueue. When the last window is fully
|
|
383
|
+
* paged it publishes a multi-file envelope listing every part (parts are disjoint
|
|
384
|
+
* by `(query_canonical, date)`, so the read path just unions them — no merge),
|
|
386
385
|
* returning `{ done:true }`. `builtAt` MUST be stable across the continuation chain
|
|
387
|
-
* (it versions both the
|
|
386
|
+
* (it versions both the part keys and the final rollup key).
|
|
387
|
+
*
|
|
388
|
+
* INTRA-WINDOW resumability: the deadline is checked between OUTPUT PAGES, not just
|
|
389
|
+
* between windows. A single high-cardinality window's paged aggregation can exceed
|
|
390
|
+
* one 300s reservation on its own; checking only between windows let that window
|
|
391
|
+
* run unbounded and stale-reservation-loop forever (huuto.net/comparaja.pt never
|
|
392
|
+
* completed window 0). `pageOffset` lets a continuation resume the SAME window at
|
|
393
|
+
* the next page, so no single invocation runs past the deadline by more than one
|
|
394
|
+
* page. Parts are keyed by `(windowOffset, pageOffset)` so a mid-window pause and
|
|
395
|
+
* its continuation write disjoint, non-colliding files.
|
|
388
396
|
*/
|
|
389
397
|
declare function rebuildCanonicalDailyResumable(opts: {
|
|
390
398
|
engine: RollupEngine;
|
|
@@ -392,11 +400,14 @@ declare function rebuildCanonicalDailyResumable(opts: {
|
|
|
392
400
|
dataSource: DataSource;
|
|
393
401
|
searchType?: SearchType;
|
|
394
402
|
builtAt: number;
|
|
395
|
-
windowOffset: number;
|
|
403
|
+
windowOffset: number; /** Resume the `windowOffset` window at this output-page offset (0 = window start). */
|
|
404
|
+
pageOffset?: number; /** Output rows per page (default `ROLLUP_PAGE_ROWS_DAILY`). Injectable for tests. */
|
|
405
|
+
pageRows?: number;
|
|
396
406
|
deadlineMs: number;
|
|
397
407
|
}): Promise<{
|
|
398
408
|
done: boolean;
|
|
399
409
|
nextWindowOffset: number;
|
|
410
|
+
nextPageOffset: number;
|
|
400
411
|
windowsTotal: number;
|
|
401
412
|
windowsBuilt: number;
|
|
402
413
|
rowsWritten: number;
|
package/dist/rollups.mjs
CHANGED
|
@@ -764,6 +764,8 @@ function mapDailyRow(r) {
|
|
|
764
764
|
async function rebuildCanonicalDailyResumable(opts) {
|
|
765
765
|
const { engine, ctx, dataSource, searchType, builtAt, windowOffset, deadlineMs } = opts;
|
|
766
766
|
const sType = searchType !== void 0 ? { searchType } : {};
|
|
767
|
+
const startPageOffset = opts.pageOffset ?? 0;
|
|
768
|
+
const pageRows = opts.pageRows ?? 7e4;
|
|
767
769
|
const windows = planRollupWindows((await engine.listPartitions({
|
|
768
770
|
ctx,
|
|
769
771
|
table: "queries",
|
|
@@ -785,39 +787,54 @@ async function rebuildCanonicalDailyResumable(opts) {
|
|
|
785
787
|
const sortKey = queryCanonicalDailyRollup.parquetSortKey;
|
|
786
788
|
const batchRows = [];
|
|
787
789
|
let i = windowOffset;
|
|
788
|
-
|
|
790
|
+
let page = startPageOffset;
|
|
791
|
+
let nextWindowOffset = windowsTotal;
|
|
792
|
+
let nextPageOffset = 0;
|
|
793
|
+
windowLoop: for (; i < windowsTotal; i++) {
|
|
789
794
|
const w = windows[i];
|
|
790
|
-
const
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
795
|
+
const coreSql = sqlFor(w);
|
|
796
|
+
for (;;) {
|
|
797
|
+
const result = await engine.runSQL({
|
|
798
|
+
ctx,
|
|
799
|
+
table: "queries",
|
|
800
|
+
...sType,
|
|
801
|
+
fileSets: {
|
|
802
|
+
FILES: {
|
|
803
|
+
table: "queries",
|
|
804
|
+
partitions: w.partitions
|
|
805
|
+
},
|
|
806
|
+
...extraFileSets
|
|
799
807
|
},
|
|
800
|
-
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
pageRows
|
|
805
|
-
|
|
806
|
-
|
|
808
|
+
sql: `${coreSql}\nORDER BY date, query_canonical\nLIMIT ${pageRows} OFFSET ${page}`
|
|
809
|
+
});
|
|
810
|
+
for (const r of result.rows) batchRows.push(mapDailyRow(r));
|
|
811
|
+
const windowDone = result.rows.length < pageRows;
|
|
812
|
+
page += pageRows;
|
|
813
|
+
if (windowDone) {
|
|
814
|
+
page = 0;
|
|
815
|
+
break;
|
|
816
|
+
}
|
|
817
|
+
if (Date.now() > deadlineMs) {
|
|
818
|
+
nextWindowOffset = i;
|
|
819
|
+
nextPageOffset = page;
|
|
820
|
+
break windowLoop;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
807
823
|
if (Date.now() > deadlineMs) {
|
|
808
|
-
i
|
|
824
|
+
nextWindowOffset = i + 1;
|
|
825
|
+
nextPageOffset = 0;
|
|
809
826
|
break;
|
|
810
827
|
}
|
|
811
828
|
}
|
|
812
|
-
const
|
|
813
|
-
const partKey = rollupParquetKey(ctx, `${CANONICAL_DAILY_PART_STEM}__w${windowOffset}`, builtAt, searchType);
|
|
829
|
+
const partKey = rollupParquetKey(ctx, `${CANONICAL_DAILY_PART_STEM}__w${windowOffset}_p${startPageOffset}`, builtAt, searchType);
|
|
814
830
|
await dataSource.write(partKey, encodeRowsToParquetFlex(batchRows, {
|
|
815
831
|
columns: cols,
|
|
816
832
|
sortKey
|
|
817
833
|
}));
|
|
818
|
-
if (nextWindowOffset < windowsTotal) return {
|
|
834
|
+
if (nextWindowOffset < windowsTotal || nextPageOffset > 0) return {
|
|
819
835
|
done: false,
|
|
820
836
|
nextWindowOffset,
|
|
837
|
+
nextPageOffset,
|
|
821
838
|
windowsTotal,
|
|
822
839
|
windowsBuilt: nextWindowOffset - windowOffset,
|
|
823
840
|
rowsWritten: batchRows.length
|
|
@@ -839,6 +856,7 @@ async function rebuildCanonicalDailyResumable(opts) {
|
|
|
839
856
|
return {
|
|
840
857
|
done: true,
|
|
841
858
|
nextWindowOffset,
|
|
859
|
+
nextPageOffset,
|
|
842
860
|
windowsTotal,
|
|
843
861
|
windowsBuilt: nextWindowOffset - windowOffset,
|
|
844
862
|
rowsWritten: batchRows.length
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gscdump/engine",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.33.
|
|
4
|
+
"version": "0.33.4",
|
|
5
5
|
"description": "Append-only Parquet/DuckDB storage engine + planner + adapters for the gscdump pipeline. Node + edge runtimes; opt-in heavy peers.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Harlan Wilton",
|
|
@@ -181,8 +181,8 @@
|
|
|
181
181
|
"dependencies": {
|
|
182
182
|
"drizzle-orm": "1.0.0-rc.3",
|
|
183
183
|
"proper-lockfile": "^4.1.2",
|
|
184
|
-
"@gscdump/contracts": "0.33.
|
|
185
|
-
"gscdump": "0.33.
|
|
184
|
+
"@gscdump/contracts": "0.33.4",
|
|
185
|
+
"gscdump": "0.33.4"
|
|
186
186
|
},
|
|
187
187
|
"devDependencies": {
|
|
188
188
|
"@duckdb/duckdb-wasm": "^1.32.0",
|