Skip to content

Commit 1e260f8

Browse files
rustyconoverclaude
andcommitted
feat(cache): result-cache worker support + example fixtures
Port the upstream table-function result cache (vgi 02a52ad, vgi-python 33740fe) plus two smaller syncs. Full launcher suite: 237 pass / 23 skip / 0 fail (was 194 / 28 / 38), verified inline and under VGI_RPC_SHM_SIZE_BYTES. The C++ extension caches a complete cacheable scan and replays it, gated on a worker advertising vgi.cache.* on its FIRST emitted batch. - vgi/cache/CacheControl (new package): the vgi.cache.* vocabulary (ttl/expires/ scope/no_store/etag/last_modified/revalidatable/stale_*/not_modified) plus the request-side IF_NONE_MATCH_KEY / IF_MODIFIED_SINCE_KEY. Builder -> toMetadata(). No OutputCollector change was needed: emit(root, customMetadata) already existed, so CacheControl is purely a metadata renderer, and conditional revalidation reads the validator off the tick's AnnotatedBatch.customMetadata(). - 19 fixtures: CacheFunctions (13 simple), CacheParallelFunctions (cache_parallel/ cache_ordered/cache_interleaved, per-execution queue fan-out), CacheTypesFunction (STRUCT/LIST/DECIMAL/TIMESTAMP + NULLs through the spill blob), CacheFilteredFunction, CachePartitionedFunction. 14 cache data tables, plus cache_versioned (columns-based AT -> cache_versioned_scan(version) in both catalog_table_scan_function_get and _scan_branches_get). - Worker.registerUnlistedTable(fn): cache_multicol backs a data table but is NOT a callable table function. vgi-python's Table(function=F) does not imply F is in the catalog's functions list, but registerTables both dispatches and advertises. Without this the table-fn count is 122, not the asserted 121. table/positional_args.test needed no framework fix — CatalogTable already threads scanFunctionPositional into the scan RPC, so the vgi-python bug 43974b5 fixes never existed here. The failure was a fixture mismatch: example.data.large_sequence passed sequence(1_000_001); upstream pins 1,000,000 rows / max 999,999. VGI_TEST_BRANCH_DIR (vgi-python 395b71d): the native-branch and rff_* fixtures hardcoded /tmp/..., but upstream now gates those 6 tests behind require-env VGI_TEST_BRANCH_DIR and has the worker read the same env — so they were silently SKIPPING. Main.BRANCH_DIR reads it (default java.io.tmpdir) and ci/run-integration.sh exports it. Worker and test must name the same directory; the paths are compared byte-for-byte. Five of the six now run; multi_branch_iceberg still needs VGI_TEST_ICEBERG. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent ac74d0e commit 1e260f8

13 files changed

Lines changed: 1997 additions & 12 deletions

File tree

CLAUDE.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,85 @@ older interfaces** (`TableFunction`, `TableInOutFunction`, etc.) — the
287287
`ScalarFn` style hasn't been extended to those because their richer
288288
lifecycle methods + per-execution state don't translate one-for-one.
289289

290+
## State of play (as of 2026-07-10)
291+
292+
**2026-07-10 — ported the upstream result-cache feature (vgi `02a52ad`, vgi-python
293+
`33740fe`) plus two smaller syncs; full launcher suite green (237 pass / 23 skip /
294+
0 fail, was 194/28/38).** The dominant piece is the **table-function result cache**:
295+
the C++ extension now caches a complete cacheable scan and replays it, gated on a
296+
worker advertising `vgi.cache.*` on its **first emitted batch**. 35 new
297+
`cache/*.test` files drove the port.
298+
299+
- **`vgi/cache/CacheControl`** (new package) — the `vgi.cache.*` vocabulary
300+
(`ttl`/`expires`/`scope`/`no_store`/`etag`/`last_modified`/`revalidatable`/
301+
`stale_*`/`not_modified`) + the request-side `IF_NONE_MATCH_KEY` /
302+
`IF_MODIFIED_SINCE_KEY`. Builder → `toMetadata()``Map<String,String>`.
303+
**No OutputCollector change was needed**`emit(root, customMetadata)` already
304+
existed, so `CacheControl` is purely a metadata renderer, and conditional
305+
revalidation reads the validator straight off the tick's `AnnotatedBatch
306+
.customMetadata()` (override `produceTick(AnnotatedBatch, …)`). That is the whole
307+
framework delta; contrast vgi-python, which had to thread `cache_control=` through
308+
three collector classes and `_merge_cache_control`.
309+
- **19 fixtures** in `example/table/`: `CacheFunctions` (13 simple),
310+
`CacheParallelFunctions` (`cache_parallel`/`cache_ordered`/`cache_interleaved`
311+
per-execution `ConcurrentLinkedQueue` fan-out, the `PartitionedSequenceFunction`
312+
pattern, not `BoundStorage.queuePush`), `CacheTypesFunction` (STRUCT/LIST/
313+
DECIMAL/TIMESTAMP + NULLs through the spill blob), `CacheFilteredFunction`,
314+
`CachePartitionedFunction`.
315+
- **`cache_multicol` is a table but NOT a table function.** vgi-python's
316+
`Table(function=F)` doesn't imply `F` is in the catalog's `functions` list, but
317+
Java's `registerTables` both dispatches *and* lists. New
318+
**`Worker.registerUnlistedTable(fn)`** + `unlistedTables()` (skipped in
319+
`catalog_schema_contents_functions`) closes the gap — without it the table-fn
320+
count is 122, not the asserted **121**. (Upstream's inventory comment reads
321+
103 → 121, i.e. +18 functions for 19 fixtures; that one is the difference.)
322+
- **14 cache data tables** in `Main.registerCatalogTable`, plus `cache_versioned`
323+
(columns-based, AT → `cache_versioned_scan(version)` via a `resolveCacheVersion`
324+
special-case in **both** `catalog_table_scan_function_get` and
325+
`_scan_branches_get`, and a pass-through in `CatalogRegistry.resolveVersion`) —
326+
the `tt_pushdown_cols` precedent exactly.
327+
- **`table/positional_args.test` (new) needed no framework fix.** Java's
328+
`CatalogTable` already threads `scanFunctionPositional` into the scan RPC, so the
329+
vgi-python bug `43974b5` fixes never existed here. The failure was a fixture
330+
mismatch: `example.data.large_sequence` passed `sequence(1_000_001)`; upstream
331+
pins 1,000,000 rows / max 999,999. Fixed the arg + cardinality.
332+
- **`VGI_TEST_BRANCH_DIR`** (vgi-python `395b71d`) — the native-branch + `rff_*`
333+
fixtures hardcoded `/tmp/...`; upstream now gates those **6** tests behind
334+
`require-env VGI_TEST_BRANCH_DIR` and has the worker read the same env, so they
335+
were silently *skipping*. `Main.BRANCH_DIR` reads it (default `java.io.tmpdir`),
336+
and both `ci/run-integration.sh` and `/tmp/run_test.sh` export it. Worker and
337+
test must name the **same** directory — the paths are compared byte-for-byte.
338+
This turned 5 of those 6 into passes; `multi_branch_iceberg` still needs
339+
`VGI_TEST_ICEBERG`.
340+
341+
Verified inline **and** under shm (`VGI_RPC_SHM_SIZE_BYTES=67108864`), both
342+
identical. `cache/identity_isolation.test` + `cache/http_symmetry.test` skip on the
343+
launch lane (`require-env VGI_HTTP_TRANSPORT`); `cache/parallel_2gb.test_slow` isn't
344+
a `.test`. No CI changes beyond the branch dir.
345+
346+
**vgi-rpc-java: ported the intermediary/wire surface (vgi-rpc `1a96b88`, `9434c7d`,
347+
`59952c3`, `13d9dc9`).** These are additive public API, not needed by any
348+
integration test:
349+
- `wire/Wire` gained `readRequest`/`writeRequest` (+ `Request` record),
350+
`buildErrorStream`, `findStateToken` (walks *concatenated* IPC streams — a
351+
producer init response is a header stream followed by the data stream),
352+
`findProtocolVersion`, `readUnaryResult`/`writeUnaryResult` (+ `UnaryResult`).
353+
Covered by `WireIntermediaryTest`.
354+
- `http/ContentCodec.decode(data, contentEncoding, maxOutputSize)` — zstd/gzip,
355+
comma-list decoded in reverse; `HttpServer.UPLOAD_URL_{METHOD,PARAMS_SCHEMA,
356+
RESPONSE_SCHEMA}` + `MAX_UPLOAD_URL_COUNT` made public.
357+
- **Not ported, deliberately:** vgi-rpc `2858d29` (HEAD `/health` → 405) is a
358+
Falcon-specific bug. Jetty's `HttpServlet.doHead` synthesizes HEAD from `doGet`;
359+
verified `HEAD /health` already returns 200 with the same capability headers.
360+
vgi-rpc `8ea49aa` (raw-TCP transport) and `42701df` (shm request-batch
361+
resolution + per-connection segment cache) were already in Java (`36aae83`,
362+
`ShmSession`/`d95a67b`).
363+
364+
> **Harness note:** `/tmp/run_test.sh` was wiped again and is reconstructed to use
365+
> the repo's committed `ci/wrappers/` (not the old `/tmp/vgi-worker-*`) against
366+
> `~/Development/vgi/build/release/test/unittest`. It also exports
367+
> `VGI_TEST_BRANCH_DIR`.
368+
290369
## State of play (as of 2026-06-19)
291370

292371
**2026-06-19 — synced the upstream enum-validation + narrow-bind batch (vgi

ci/run-integration.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,12 @@ mkdir -p "$STAGE/test/sql/integration"
7171
# http — boot the worker as an HTTP server and attach over http:// (mirrors
7272
# vgi's `make test_http`).
7373
export VGI_WORKER_BIN
74+
# Scratch dir for the native-branch / required-field-filter fixtures. The tests
75+
# COPY their parquet/csv here and the worker's scan branches read the same path
76+
# back, so both sides must name the SAME directory (upstream gates those 6 tests
77+
# behind `require-env VGI_TEST_BRANCH_DIR`; unset, they silently skip).
78+
export VGI_TEST_BRANCH_DIR="${VGI_TEST_BRANCH_DIR:-$(mktemp -d)}"
79+
echo "branch scratch dir: $VGI_TEST_BRANCH_DIR"
7480
# An empty VGI_RPC_SHM_SIZE_BYTES must not reach the C++ client (it would try to
7581
# attach a zero-size segment); only a real value enables the shm side channel.
7682
[ -n "${VGI_RPC_SHM_SIZE_BYTES:-}" ] || unset VGI_RPC_SHM_SIZE_BYTES

0 commit comments

Comments
 (0)