Skip to content

Commit d750756

Browse files
committed
specs/avail-pyramid-v2: §7 rebuild for read-side pruning + §6 update
§7 (new): EC2 follow-up rebuild for `avail-v2/<tier>/` parquets. Current shards are `num_row_groups=1` + `(cell, dt)`-sorted → defeats hyparquet RG pruning → CFW OOMs on sub-day v2 queries. Fix: `(dt, cell)` sort + `row_group_size=8192` in `avail_v2.py`, then rebuild all (tier × period) pairs. Read-side patches (`7ddb7104` + `c466d71d`) already wired; they're no-ops until rebuild. §6: cross out "Don't push to h:main" — pyrmts now publishes a `dist` branch on GitHub, `gbfs/api/` switched to `pds gh` refs, and CI on h:main is green again. Also notes the upstream pyrmts ask: SPEC.md §321/§323 already list "Row-group sizing" + "Sort order" as Open questions; ctbk now has a concrete layout pin worth proposing a writer helper around.
1 parent c466d71 commit d750756

1 file changed

Lines changed: 97 additions & 2 deletions

File tree

specs/avail-pyramid-v2.md

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,13 +289,108 @@ After EC2 has written shards to R2:
289289
290290
## 6. Things NOT to do on EC2
291291

292-
- Don't push to `h:main` (Github). Push to `e:` (EC2-mediator remote)
293-
only. CI deploy on `h` would break due to `workspace:*` pyrmts deps.
292+
- ~~Don't push to `h:main` (Github). Push to `e:` (EC2-mediator remote)
293+
only. CI deploy on `h` would break due to `workspace:*` pyrmts deps.~~
294+
No longer applies (2026-05-25): pyrmts has a `dist` branch on GitHub
295+
and `gbfs/api/` is on `pds gh` refs, so `git push h main` triggers a
296+
clean CI deploy. Push to `h:` freely.
294297
- Don't run the live CFW workers from EC2. Keep `wrangler deploy` on
295298
the laptop (or skip it entirely until the build is verified).
296299
- Don't delete any of the legacy/cascade/PoC data on R2 — keep through
297300
the validation period.
298301

302+
## 7. Rebuild: parquet layout for read-side pruning (EC2, follow-up)
303+
304+
> Added 2026-05-25, after CFW OOMs surfaced on `/api/avail-v2[/cells]`
305+
> sub-day queries.
306+
307+
### Diagnosis
308+
309+
`ctbk avail-v2-build` wrote shards with pyarrow defaults:
310+
- `num_row_groups = 1` per shard (default `row_group_size=1M`; v2 1h
311+
shards have ~956K rows, so they fit in a single RG).
312+
- Rows sorted `(cell, dt_sec)` (see `avail_v2.py:272`).
313+
314+
Together this defeats hyparquet's row-group `dt`-stats pruning:
315+
even when the CFW reader passes `binCol='dt' + range=…` (now wired in
316+
`avail_geo.ts` + `avail_pyrmts.ts`), there's only one RG, and its
317+
`dt`-stats span the entire shard period. So every query loads the
318+
whole decompressed shard (~130 MB for v2 1h) → blows the 128 MB CFW
319+
free-tier memory limit on any sub-day query.
320+
321+
This is the unaddressed half of pyrmts SPEC.md "Open questions" §
322+
("Row-group sizing" + "Sort order"). The reader has the pruning
323+
primitive; the writer doesn't yet have a convention or helper.
324+
325+
### Changes
326+
327+
In `ctbk/avail_v2.py`:
328+
329+
1. **Resort rows by `(dt, cell)`** instead of `(cell, dt)`. h3's
330+
resolution-in-high-bits property is nice-to-have for resolution
331+
pruning but pyrmts doesn't currently do that pruning, so dt-first
332+
is the right primary key for now. (Lines 272 + 457; both shard
333+
writers.)
334+
2. **Set `row_group_size`** in the `pq.write_table(...)` call (line
335+
296). Start with `8192`; tune if needed. Goal: each RG covers a
336+
narrow `dt` window so stats prune effectively.
337+
3. (Optional, defer if it's not necessary for the OOM fix) **Sort
338+
monoid output similarly** in the cascade step — if cascaded tiers
339+
inherit the input shape this happens for free, otherwise mirror
340+
the change.
341+
342+
### Rebuild driver
343+
344+
All built (tier × period) pairs need re-write. From EC2:
345+
346+
```bash
347+
# Idempotent re-runs are fine — they overwrite. Order doesn't matter
348+
# semantically but build finest tiers first so cascade has its inputs.
349+
ctbk avail-v2-build --tier 1m --force # ~521 shards across 49 dates
350+
# Then cascade up
351+
ctbk avail-v2-build --tier 2m --derive-from 1m --force
352+
# … continue through the ladder up to 1y
353+
```
354+
355+
(If `--force` doesn't exist yet on `avail-v2-build`, add it — flag to
356+
overwrite existing R2 objects rather than skip-if-exists.)
357+
358+
Total rebuild scope: 18 tiers × shards-per-tier. Embarrassingly
359+
parallel per (tier, period); current 1m build took ~hours on EC2,
360+
expect similar.
361+
362+
### Validation
363+
364+
After rebuild, the OOM-reproducer should now succeed:
365+
366+
```bash
367+
curl -A 'ctbk-probe' \
368+
"https://ctbk-gbfs-api.ryan-0dc.workers.dev/api/avail-v2?from=2026-05-22T00:00:00Z&to=2026-05-23T00:00:00Z&bbox=40.74,-74.00,40.78,-73.96&bin_budget=24&cell_budget=200"
369+
```
370+
371+
Expect 200 + small JSON body (~few KB). If still OOMs: inspect the
372+
shard's `pqm` output — `num_row_groups` should be hundreds, each
373+
row group's `dt` stats should span minutes-to-low-hours, not the
374+
full shard period.
375+
376+
### Note: read-side patches already landed
377+
378+
- `gbfs/api/src/avail_geo.ts` threads `{ binCol, range }` to
379+
`fetchSegmentRows` (commit `7ddb7104`).
380+
- `gbfs/api/src/avail_pyrmts.ts` (shadow mode) threads the same opts
381+
to `fetchShardData` (next commit).
382+
383+
Both are no-ops until this rebuild lands; once it does, they take
384+
effect without further CFW changes.
385+
386+
### Upstream pyrmts follow-up
387+
388+
Open SPEC.md questions §321/§323 ("Row-group sizing", "Sort order")
389+
become tractable now that ctbk has a real layout pin. Worth proposing
390+
a `pyrmts.write_tier_parquet(rows, pyramid, …)` helper that handles
391+
RG sizing + binCol-first sort by default, so future consumers don't
392+
hit this trap.
393+
299394
## Open
300395

301396
- Histogram column format: `pa.json_extension_type()` (pyarrow ≥18)

0 commit comments

Comments
 (0)