Skip to content

docs: sync results-cache invalidation, Arrow on_conflict, SQLite null keys, query nesting limit, and v2.4 per-dataset cdc_prefetch_buffer - #2454

Merged
lukekim merged 2 commits into
trunkfrom
docs-sync/2026-10-28-forward-data
Oct 28, 2026
Merged

lukekim merged 2 commits into
trunkfrom
docs-sync/2026-10-28-forward-data

Conversation

@spiceemma

Copy link
Copy Markdown
Contributor

Summary

Results cache: view, catalog, and function changes clear cached results; xxh32 keys use XXH64 (spiceai/spiceai#15698, vNext). The caching page said SQL results are invalidated "only by client writes, dataset reload, and dataset unload", which is no longer true on trunk. A new "Cached Results and Definition Changes" section lists the changes that now clear every cached SQL result with the plan cache (view update or removal, catalog replacement on hot reload, function set change), states that a query started before the clear does not store its result, and notes the v2.4.x behavior. The xxh32 bullet, marked deprecated by a22646a, now also says xxh32 builds keys with XXH64. reference/spicepod/runtime.md carries the same bullet but is left alone because open PR #2450 edits that file.
The v2.4.x note ends with the stale-while-revalidate bound: a stale result stays servable until item_ttl + stale_while_revalidate_ttl when SWR is set, per v2.4.0 crates/cache/src/lib.rs:865 let max_servable_age = ttl.saturating_add(stale_while_revalidate_ttl.unwrap_or_default());.

Arrow acceleration on_conflict, primary_key, and indexes (spiceai/spiceai#15623, vNext + 2.4.x). datasets.md and views.md said on_conflict, primary_key, and indexes are "Not supported for in-memory Arrow acceleration engine". Arrow builds a primary key and indexes as a hash index (v2.4.0 and trunk), so the primary_key and indexes sentences now say that and link the Hash Index page. The on_conflict sentence is per version. vNext: the target must be the primary key, every strategy works, and the upsert_dedup options refuse a table with a __row_num or __max_row_num column. 2.4.x: only upsert takes effect, drop is ignored with a warning, and the two dedup strategies act as plain upsert, so a write that repeats a key fails with Primary key values must be unique.

SQLite and DuckDB reject null primary keys (spiceai/spiceai#15494, vNext). The "Primary key columns must be non-null" section described only Cayenne. It now says DuckDB and SQLite reject a write with a null in a primary key column before it reaches the engine, that SQLite treats a NaN key as null, and that SQLite stored null-key rows in v2.4.x.

Query nesting depth limit (spiceai/spiceai#15722, vNext). Extends #2441, which documented the 512-level expression limit. A new "Nesting depth limit" section on the Subqueries page documents the fixed 64-level query nesting limit (subqueries, derived tables, and CTEs that read one another), the 63/64 CTE-chain boundary, EXPLAIN coverage, the HTTP 400 / InvalidArgument result, and the exact error text. The WITH clause on the SELECT page and the expression-limit paragraph in operators.md link to it.

Per-dataset cdc_prefetch_buffer has no effect in v2.4.0 (spiceai/spiceai#15439, 2.4.x only). The 2.4.x CDC page offered cdc_prefetch_buffer as a per-dataset override, with an example comment "buffers more aggressively". In v2.4.0 both change-queue constructions read the process-wide value, so the per-dataset value does nothing. The 2.4.x example drops that line, and a note gives the effective source of the value, the gauge that reports it, and the workaround. vNext already describes the fixed behavior and is unchanged.

Source PRs

Propagation was checked with gh api repos/spiceai/spiceai/compare/v2.4.0...<merge-sha> --jq .status. Each returned diverged, so none of the merge commits is in v2.4.0 (released 2026-10-27).

Items

Reproduction

1. Results cache invalidation (#15698), Unverified, code inspection only

Doc said (vNext features/caching/index.md): "SQL results are invalidated only by client writes, dataset reload, and dataset unload; an accelerated refresh leaves them to expire by age."

Code says (spiceai trunk eb5d4cb8):

  • crates/runtime/src/init/view.rs:916 remove_view calls self.df.clear_cached_plans_and_results().await;. update_view (:921) and replace_view (:768) both call remove_view.
  • crates/runtime/src/init/catalog.rs:282: if replaced_a_catalog { self.df.clear_cached_plans_and_results().await; }
  • crates/runtime/src/datafusion/udf.rs:450: runtime.df.clear_cached_plans_and_results().await;
  • crates/cache/src/lib.rs:1143 invalidate_all calls self.table_changes.record_change_everywhere(...) before self.cache.invalidate_all().
  • crates/cache/src/lib.rs:442: HashingAlgorithm::XXH32 | HashingAlgorithm::XXH64 => Ok(HashBuilder::XxHash64(...))
  • At v2.4.0, view.rs:798 and catalog.rs:282 call only clear_cached_plans().

Behavior claim: after a view is updated, a repeated query returns the new definition's result, and after the view is removed the query fails. This comes from the PR's integration test results_cache_follows_a_redefined_or_removed_view and its spiced run. I did not run either.

2. Arrow on_conflict / primary_key / indexes (#15623), Unverified, code inspection only

Doc said (vNext and 2.4.x reference/spicepod/datasets.md, views.md): "Not supported for in-memory Arrow acceleration engine." This appeared under indexes, primary_key, and on_conflict.

Code says:

  • trunk crates/data_components/src/arrow/write.rs:161-170: with_on_conflict accepts OnConflict::Upsert(_) | OnConflict::DoNothing(_). :182 adds with_upsert_options. :251-269: verify_on_conflict_matches_primary_key returns "Primary key columns must match the on_conflict definition". :740-750 returns DataFusionError::Plan("on_conflict upsert options cannot be used on a table with a column named ...") for DEDUP_WORKING_COLUMNS = ["__row_num", "__max_row_num"], and that check runs only after duplicates are found.
  • trunk crates/data_components/src/arrow.rs:233,269: .with_upsert_options(upsert_options_from(&cmd.options)?).
  • v2.4.0 arrow/write.rs:153-160: if !matches!(on_conflict, OnConflict::Upsert(_)) { warn!("In-memory tables only support Upsert on_conflict ... Setting will be ignored.") }. v2.4.0 arrow.rs never reads upsert_remove_duplicates / upsert_last_write_wins. write.rs:715-755 returns "Primary key values must be unique".
  • v2.4.0 arrow.rs:147-207: the primary key and indexes build an IndexedMemTable (hash index) when the runtime sets hash_index, which it does "when a primary_key or secondary indexes are specified".

Behavior claim: the PR's before/after spiced runs show Arrow matching DuckDB on all six cases after the fix. I did not run them.

3. SQLite/DuckDB null primary keys (#15494), Unverified, code inspection only

Doc said (vNext features/data-acceleration/constraints.md): only Cayenne was described as rejecting null primary keys.

Code says (trunk):

  • crates/data-accelerator-api/src/pk_write_guard.rs: the module doc says it "Rejects a NULL primary key, and a key a single batch repeats, before the write reaches DuckDB or SQLite", and "SQLite stores a bound NaN as NULL, so under NanKey::Null a NaN key is refused the same way." null_primary_key_message (:186) produces Primary key column '<c>' has null values. ....
  • crates/accelerators/accelerator-sqlite/src/lib.rs:647-652 wraps the writer with keep_first::NanKey::Null. accelerator-duckdb/src/lib.rs:1743-1748 wraps it with NanKey::Value.
  • v2.4.0 accelerator-sqlite/src/lib.rs has 0 occurrences of pk_write_guard.

Behavior claim: SQLite rejects a null key. The PR's live script shows [{"count":1}] on trunk before the fix and rejection after. I did not run it.

4. Query nesting depth limit (#15722), Unverified, code inspection only

This is an addition. No existing sentence covered it.

Code says (trunk crates/runtime-query-engine/src/sql_depth_guard.rs):

  • :103 pub const MAX_QUERY_NESTING_DEPTH: usize = 64;
  • :236 if depth > MAX_QUERY_NESTING_DEPTH { return self.reject(too_deep_query_error()); }
  • :375-380 gives the message text quoted on the page.
  • Test cte_chain_is_bounded_at_the_query_cap: cte_chain(63) passes and cte_chain(64) is rejected, including under EXPLAIN.

The HTTP 400 / InvalidArgument mapping is the same DataFusionError::Plan path as the 512-level expression limit that #2441 documented. The PR's spiced run reports HTTP 400 for a 64-step chain. I did not run it.

5. v2.4.0 per-dataset cdc_prefetch_buffer (#15439), Unverified, code inspection only

Doc said (2.4.x features/cdc/index.md): cdc_prefetch_buffer can be overridden per dataset, with the example cdc_prefetch_buffer: 1024 # ...and buffers more aggressively.

Code says (v2.4.0):

  • crates/runtime-table/src/accelerated/mod.rs:1121: let capacity = refresh_task::changes::cdc_config().prefetch_buffer;
  • refresh_task.rs:739: changes::cdc_config().prefetch_buffer,. Both are process-wide.
  • No other runtime reader of .prefetch_buffer exists in changes.rs, apart from the overlay and tests.
  • crates/runtime-metrics/src/acceleration.rs:406: gauge dataset_acceleration_cdc_prefetch_buffer_capacity.
  • Trunk replaces both reads with dataset_cdc_config(self.cdc_param_overrides.as_deref()).

Behavior claim: in v2.4.0 the per-dataset value does not change the queue capacity. The PR's tests on its parent commit fail with left: Some(128.0), right: Some(1024.0). I did not run them on v2.4.0.

Verification

$ grep -rln "Not supported for in-memory Arrow" website/docs website/versioned_docs/version-2.4.x
(no output)
$ grep -rl "Not supported for in-memory Arrow" website/versioned_docs | wc -l
22   # 2.3.x and older snapshots; not changed here, see follow-ups
$ grep -rn "cached-results-and-definition-changes\|nesting-depth-limit" website/docs | wc -l
3
$ grep -rn "xxh32" website/docs | grep -v features/caching
website/docs/reference/spicepod/runtime.md:80, :155   # left for open spiceai/docs#2450

Style grep on added lines (the brief's pattern): no matches (exit 1).

Code refs: spiceai trunk eb5d4cb8fbd19b7e665b64e326031f8d536de5ed and tag v2.4.0, read with gh api repos/spiceai/spiceai/contents/<path>?ref=<ref>.

Checks:

  • cd website && npm run build at 8f735a15: [SUCCESS] Generated static files in "build"., exit 0, no broken links or anchors
  • Live spiced reproduction: not run. Every item is labeled Unverified, code inspection only.

Review gate

  • Adversarial review: codex — job review-mvsnwhmw-5nv05h — verdict approve, no findings on 8f735a15. The first pass (job review-mvsnnstc-4v57k3, on ec47f6f4) raised 1 medium finding, that the v2.4.x note bounded stale results by item_ttl alone; fixed in 8f735a15 with the stale_while_revalidate_ttl bound.
  • /security-review: skipped — the skill was not invoked for this content-only diff; a manual scan of the added lines for credentials, tokens, internal hosts, private repository references, and local paths found none.
  • /simplify: not run — documentation-only diff, no code.

Follow-ups (not in this PR)

  • website/docs/reference/spicepod/runtime.md has the same xxh32 bullet. Add the XXH64 sentence after docs(sql): define datasets and catalogs with SQL DDL #2450 merges.
  • The Not supported for in-memory Arrow sentences for primary_key and indexes remain in version-2.3.x through version-1.5.x (22 files). Arrow has supported both since the v1.11 hash index. Each snapshot needs per-version verification before it is corrected.

Emma Spice added 2 commits October 28, 2026 14:53
… keys, query nesting limit, and v2.4 per-dataset cdc_prefetch_buffer

Documents spiceai/spiceai#15698, #15623, #15494, #15722, and #15439.
Copilot AI balanced review requested due to automatic review settings October 28, 2026 22:12
@spiceemma
spiceemma requested a review from a team as a code owner October 28, 2026 22:12
@spiceemma spiceemma self-assigned this Oct 28, 2026
@github-actions

github-actions Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

✅ Pull with Spice Passed

Passing checks:

  • ✅ Title meets minimum length requirement (10 characters)
  • ✅ Has at least one of the required labels: area/blog, area/docs, area/cookbook, dependencies
  • ✅ No banned labels detected
  • ✅ Has at least one assignee: spiceemma

@github-actions

Copy link
Copy Markdown
Contributor

🔍 Pull with Spice Failed

Passing checks:

  • ✅ Title meets minimum length requirement (10 characters)
  • ✅ Has at least one of the required labels: area/blog, area/docs, area/cookbook, dependencies
  • ✅ No banned labels detected

Failed checks:

  • ❌ At least one assignee is required for this pull request.

Please address these issues and update your pull request.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approved

No active review issues are reported for this documentation-only update.

No open issues 🎉

What changed in this PR

This documentation-only PR aligns the Spice reference pages with vNext runtime behavior and clarifies differences in v2.4.x.

Changes:

  • Documents results-cache invalidation after definition changes and the deprecated xxh32 setting’s use of XXH64.
  • Corrects Arrow index and conflict-resolution support, documents null primary-key rejection, and clarifies the v2.4.0 CDC buffer limitation.
  • Adds the 64-level query nesting limit and links it from related SQL reference pages.
File Description
website/​versioned_docs/​version-2.4.x/​reference/​spicepod/​views.md Corrects Arrow index, primary-key, and conflict-resolution support for views.
website/​versioned_docs/​version-2.4.x/​reference/​spicepod/​datasets.md Corrects Arrow index, primary-key, and conflict-resolution support for datasets.
website/​versioned_docs/​version-2.4.x/​features/​cdc/​index.md Documents the ineffective per-dataset buffer setting and instance-wide workaround.
website/​docs/​reference/​sql/​subqueries.md Documents query nesting limits, boundaries, and errors.
website/​docs/​reference/​sql/​select.md Links CTE nesting behavior to the query depth limit.
website/​docs/​reference/​sql/​operators.md Distinguishes query nesting limits from expression depth limits.
website/​docs/​reference/​spicepod/​views.md Documents vNext Arrow indexing and conflict-resolution constraints for views.
website/​docs/​reference/​spicepod/​datasets.md Documents vNext Arrow indexing and conflict-resolution constraints for datasets.
website/​docs/​features/​data-acceleration/​constraints.md Explains DuckDB and SQLite null primary-key rejection and SQLite NaN handling.
website/​docs/​features/​caching/​index.md Explains definition-change invalidation, earlier-version behavior, and XXH64 key hashing.

Review effort: Balanced

@github-actions

Copy link
Copy Markdown
Contributor

🚀 deployed to https://f96b3a25.spiceai-org-website.pages.dev

@lukekim
lukekim merged commit 2d6647c into trunk Oct 28, 2026
8 of 13 checks passed
@lukekim
lukekim deleted the docs-sync/2026-10-28-forward-data branch October 28, 2026 22:44

This branch was successfully deployed

1 active deployment
preview — 8f735a15 Deployed Oct 28, 2026 by github-actions[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants