@gscdump/engine 0.33.8 → 0.33.10
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 +13 -13
- package/dist/rollups.mjs +23 -19
- package/package.json +3 -3
package/dist/rollups.d.mts
CHANGED
|
@@ -15,7 +15,7 @@ interface RollupEngine {
|
|
|
15
15
|
runSQL: (opts: {
|
|
16
16
|
ctx: TenantCtx;
|
|
17
17
|
fileSets: Record<string, FileSetRef>;
|
|
18
|
-
table?:
|
|
18
|
+
table?: TableName$1;
|
|
19
19
|
sql: string;
|
|
20
20
|
params?: unknown[];
|
|
21
21
|
/**
|
|
@@ -26,7 +26,7 @@ interface RollupEngine {
|
|
|
26
26
|
*/
|
|
27
27
|
searchType?: SearchType;
|
|
28
28
|
}) => Promise<{
|
|
29
|
-
rows:
|
|
29
|
+
rows: Row$1[];
|
|
30
30
|
}>;
|
|
31
31
|
/**
|
|
32
32
|
* Read the live manifest for a (tenant, table[, searchType]) cohort —
|
|
@@ -37,7 +37,7 @@ interface RollupEngine {
|
|
|
37
37
|
*/
|
|
38
38
|
listPartitions: (opts: {
|
|
39
39
|
ctx: TenantCtx;
|
|
40
|
-
table:
|
|
40
|
+
table: TableName$1;
|
|
41
41
|
searchType?: SearchType;
|
|
42
42
|
}) => Promise<Array<{
|
|
43
43
|
partition: string;
|
|
@@ -385,14 +385,13 @@ declare const queryCanonicalDailyRollup: RollupDef;
|
|
|
385
385
|
* returning `{ done:true }`. `builtAt` MUST be stable across the continuation chain
|
|
386
386
|
* (it versions both the part keys and the final rollup key).
|
|
387
387
|
*
|
|
388
|
-
* INTRA-WINDOW resumability: the deadline is checked between
|
|
389
|
-
* between windows. A single high-cardinality
|
|
390
|
-
*
|
|
391
|
-
*
|
|
392
|
-
*
|
|
393
|
-
*
|
|
394
|
-
*
|
|
395
|
-
* its continuation write disjoint, non-colliding files.
|
|
388
|
+
* INTRA-WINDOW resumability: the deadline is checked between raw-query hash shards,
|
|
389
|
+
* not just between date windows. A single high-cardinality day can spend a full
|
|
390
|
+
* reservation inside one grouped/sorted aggregate before the deadline check gets
|
|
391
|
+
* control back. `pageOffset` is the next shard index for the current window, so a
|
|
392
|
+
* continuation resumes the SAME day at the next shard. Parts are keyed by
|
|
393
|
+
* `(windowOffset, pageOffset)`; multiple parts may contain the same canonical/date
|
|
394
|
+
* from different raw-query shards, and rollup reads sum over the union.
|
|
396
395
|
*/
|
|
397
396
|
declare function rebuildCanonicalDailyResumable(opts: {
|
|
398
397
|
engine: RollupEngine;
|
|
@@ -400,10 +399,11 @@ declare function rebuildCanonicalDailyResumable(opts: {
|
|
|
400
399
|
dataSource: DataSource;
|
|
401
400
|
searchType?: SearchType;
|
|
402
401
|
builtAt: number;
|
|
403
|
-
windowOffset: number; /** Resume the `windowOffset` window at this
|
|
402
|
+
windowOffset: number; /** Resume the `windowOffset` window at this shard offset (0 = window start). */
|
|
404
403
|
pageOffset?: number; /** Output rows per page (default `ROLLUP_PAGE_ROWS_DAILY`). Injectable for tests. */
|
|
405
404
|
pageRows?: number; /** Cap each input window's day span (default `DAILY_MAX_WINDOW_DAYS`). */
|
|
406
|
-
maxWindowDays?: number;
|
|
405
|
+
maxWindowDays?: number; /** Split each date window by raw-query hash before grouping (1 = no sharding). */
|
|
406
|
+
shardCount?: number;
|
|
407
407
|
deadlineMs: number;
|
|
408
408
|
}): Promise<{
|
|
409
409
|
done: boolean;
|
package/dist/rollups.mjs
CHANGED
|
@@ -728,8 +728,11 @@ const queryCanonicalDailyRollup = {
|
|
|
728
728
|
})).map(mapDailyRow);
|
|
729
729
|
}
|
|
730
730
|
};
|
|
731
|
+
function canonicalDailyShardPredicate(queryExpr, shardIndex, shardCount) {
|
|
732
|
+
return shardCount <= 1 ? "" : ` AND (hash(${queryExpr}) % ${shardCount}) = ${shardIndex}`;
|
|
733
|
+
}
|
|
731
734
|
function dailyWindowSqlFor(useDim, canonExpr) {
|
|
732
|
-
return useDim ? (w) => `
|
|
735
|
+
return useDim ? (w, shard) => `
|
|
733
736
|
SELECT
|
|
734
737
|
${canonExpr} AS query_canonical,
|
|
735
738
|
CAST(q.date AS VARCHAR) AS date,
|
|
@@ -738,18 +741,18 @@ function dailyWindowSqlFor(useDim, canonExpr) {
|
|
|
738
741
|
SUM(q.sum_position)::DOUBLE AS sum_position
|
|
739
742
|
FROM read_parquet({{FILES}}, union_by_name = true) q
|
|
740
743
|
LEFT JOIN read_parquet({{QUERY_DIM}}, union_by_name = true) qd ON q.query = qd.query
|
|
741
|
-
WHERE q.date >= '${w.start}' AND q.date <= '${w.end}'
|
|
744
|
+
WHERE q.date >= '${w.start}' AND q.date <= '${w.end}'${canonicalDailyShardPredicate("q.query", shard?.index ?? 0, shard?.count ?? 1)}
|
|
742
745
|
GROUP BY ${canonExpr}, q.date
|
|
743
|
-
` : (w) => `
|
|
746
|
+
` : (w, shard) => `
|
|
744
747
|
SELECT
|
|
745
748
|
${canonExpr} AS query_canonical,
|
|
746
|
-
CAST(date AS VARCHAR) AS date,
|
|
747
|
-
SUM(clicks)::BIGINT AS clicks,
|
|
748
|
-
SUM(impressions)::BIGINT AS impressions,
|
|
749
|
-
SUM(sum_position)::DOUBLE AS sum_position
|
|
750
|
-
FROM read_parquet({{FILES}}, union_by_name = true)
|
|
751
|
-
WHERE date >= '${w.start}' AND date <= '${w.end}'
|
|
752
|
-
GROUP BY ${canonExpr}, date
|
|
749
|
+
CAST(q.date AS VARCHAR) AS date,
|
|
750
|
+
SUM(q.clicks)::BIGINT AS clicks,
|
|
751
|
+
SUM(q.impressions)::BIGINT AS impressions,
|
|
752
|
+
SUM(q.sum_position)::DOUBLE AS sum_position
|
|
753
|
+
FROM read_parquet({{FILES}}, union_by_name = true) q
|
|
754
|
+
WHERE q.date >= '${w.start}' AND q.date <= '${w.end}'${canonicalDailyShardPredicate("q.query", shard?.index ?? 0, shard?.count ?? 1)}
|
|
755
|
+
GROUP BY ${canonExpr}, q.date
|
|
753
756
|
`;
|
|
754
757
|
}
|
|
755
758
|
function mapDailyRow(r) {
|
|
@@ -767,6 +770,7 @@ async function rebuildCanonicalDailyResumable(opts) {
|
|
|
767
770
|
const startPageOffset = opts.pageOffset ?? 0;
|
|
768
771
|
const pageRows = opts.pageRows ?? 7e4;
|
|
769
772
|
const maxWindowDays = opts.maxWindowDays ?? 7;
|
|
773
|
+
const shardCount = Math.max(1, Math.floor(opts.shardCount ?? 1));
|
|
770
774
|
const windows = planRollupWindows((await engine.listPartitions({
|
|
771
775
|
ctx,
|
|
772
776
|
table: "queries",
|
|
@@ -803,8 +807,11 @@ async function rebuildCanonicalDailyResumable(opts) {
|
|
|
803
807
|
};
|
|
804
808
|
for (; i < windowsTotal; i++) {
|
|
805
809
|
const w = windows[i];
|
|
806
|
-
|
|
807
|
-
|
|
810
|
+
for (; page < shardCount;) {
|
|
811
|
+
const coreSql = sqlFor(w, {
|
|
812
|
+
index: page,
|
|
813
|
+
count: shardCount
|
|
814
|
+
});
|
|
808
815
|
const result = await engine.runSQL({
|
|
809
816
|
ctx,
|
|
810
817
|
table: "queries",
|
|
@@ -816,15 +823,11 @@ async function rebuildCanonicalDailyResumable(opts) {
|
|
|
816
823
|
},
|
|
817
824
|
...extraFileSets
|
|
818
825
|
},
|
|
819
|
-
sql: `${coreSql}\nORDER BY date, query_canonical\nLIMIT ${pageRows}
|
|
826
|
+
sql: `${coreSql}\nORDER BY date, query_canonical\nLIMIT ${pageRows}`
|
|
820
827
|
});
|
|
828
|
+
if (result.rows.length >= pageRows) throw new Error(`query_canonical_daily shard overflow: window=${i} shard=${page}/${shardCount} returned >= ${pageRows} rows; increase shardCount or pageRows`);
|
|
821
829
|
await flushPage(i, page, result.rows.map(mapDailyRow));
|
|
822
|
-
|
|
823
|
-
page += pageRows;
|
|
824
|
-
if (windowDone) {
|
|
825
|
-
page = 0;
|
|
826
|
-
break;
|
|
827
|
-
}
|
|
830
|
+
page += 1;
|
|
828
831
|
if (Date.now() > deadlineMs) {
|
|
829
832
|
nextWindowOffset = i;
|
|
830
833
|
nextPageOffset = page;
|
|
@@ -833,6 +836,7 @@ async function rebuildCanonicalDailyResumable(opts) {
|
|
|
833
836
|
}
|
|
834
837
|
}
|
|
835
838
|
if (pausedMidWindow) break;
|
|
839
|
+
page = 0;
|
|
836
840
|
if (Date.now() > deadlineMs) {
|
|
837
841
|
nextWindowOffset = i + 1;
|
|
838
842
|
nextPageOffset = 0;
|
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.10",
|
|
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": "0.33.
|
|
185
|
-
"
|
|
184
|
+
"@gscdump/contracts": "0.33.10",
|
|
185
|
+
"gscdump": "0.33.10"
|
|
186
186
|
},
|
|
187
187
|
"devDependencies": {
|
|
188
188
|
"@duckdb/duckdb-wasm": "^1.32.0",
|