Skip to content

Antalya 26.6: Hybrid tables - #2144

Open
zvonand wants to merge 11 commits into
antalya-26.6from
feature/antalya-26.6/auto-grp-pr-1694
Open

Antalya 26.6: Hybrid tables#2144
zvonand wants to merge 11 commits into
antalya-26.6from
feature/antalya-26.6/auto-grp-pr-1694

Conversation

@zvonand

@zvonand zvonand commented Aug 3, 2026

Copy link
Copy Markdown
Member

Changelog category (leave one):

  • New Feature

Changelog entry (a user-readable short description of the changes that goes to CHANGELOG.md):

Add support for Hybrid tables, which combine local MergeTree storage with data in object storage behind a configurable watermark. Watermarks can be moved with ALTER TABLE MODIFY SETTING and inspected via the new system.hybrid_watermarks table, and queries now skip segments that cannot match the combination of the WHERE clause and the segment predicate.

DONE
Add support for Hybrid tables, which combine local MergeTree storage with data in object storage behind a configurable watermark. Watermarks can be moved with ALTER TABLE MODIFY SETTING and inspected via the new system.hybrid_watermarks table, and queries now skip segments that cannot match the combination of the WHERE clause and the segment predicate.

DONE (#1694 by @zvonand, #1723 by @mkmkme, #1788 by @mkmkme, #1789 by @mkmkme).

CI/CD Options

Exclude tests:

  • Fast test
  • Integration Tests
  • Stateless tests
  • Stateful tests
  • Performance tests
  • All with ASAN
  • All with TSAN
  • All with MSAN
  • All with UBSAN
  • All with Coverage
  • All with Aarch64
  • All Regression
  • Disable CI Cache

Regression jobs to run:

  • Fast suites (mostly <1h)
  • Aggregate Functions (2h)
  • Alter (1.5h)
  • Benchmark (30m)
  • ClickHouse Keeper (1h)
  • Iceberg (2h)
  • LDAP (1h)
  • Parquet (1.5h)
  • RBAC (1.5h)
  • SSL Server (1h)
  • S3 (2h)
  • S3 Export (2h)
  • Swarms (30m)
  • Tiered Storage (2h)

Combined port of 4 PR(s) (group auto-grp-pr-1694). Cherry-picked from #1694, #1723, #1788, #1789.

zvonand added 6 commits August 3, 2026 10:54
…next commit)

---
Original cherry-pick message follows:

Merge pull request #1694 from Altinity/feature/antalya-26.3/pr-1442

Antalya 26.3 forward-port: Hybrid tables
# Conflicts:
#	src/Core/Settings.cpp
#	src/Interpreters/ClusterProxy/executeQuery.cpp
#	src/Planner/Utils.cpp
#	src/Storages/StorageDistributed.cpp
…move-watermark

Antalya-26.3 Frontport of #1659 - Add ALTER TABLE MODIFY SETTING support for Hybrid watermarks

Source-PR: #1723 (#1723)
…next commit)

---
Original cherry-pick message follows:

Merge pull request #1788 from Altinity/mkmkme/antalya-26.3/hybrid-segment-pruning

Antalya 26.3 Hybrid: added support for segment pruning
# Conflicts:
#	src/Storages/StorageDistributed.cpp
Kept the PR's `StorageDistributed::getStorageSnapshot()` override, which
freezes the Hybrid watermark snapshot in `HybridSnapshotData`.

Adapted: re-added the `getStorageSnapshot()` declaration in
StorageDistributed.h, removed by antalya-26.6 commit 5d159b3
("rewrite getStorageSnapshot to getInMemoryMetadataPtr"), so the
source PR's override body compiles.

Source-PR: #1788 (#1788)
…tem-table

hybrid: added system.hybrid_watermarks to inspect the Hybrid table watermarks
Source-PR: #1789 (#1789)
@zvonand zvonand added releasy Created/managed by RelEasy antalya-26.6 ai-resolved Port conflict auto-resolved by Claude labels Aug 3, 2026
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown

Workflow [PR], commit [bf78917]

@mkmkme
mkmkme self-requested a review August 4, 2026 06:15
@mkmkme mkmkme self-assigned this Aug 4, 2026
@zvonand zvonand added the forwardport This is a frontport of code that existed in previous Antalya versions label Aug 4, 2026
@zvonand

zvonand commented Aug 6, 2026

Copy link
Copy Markdown
Member Author

@blau-ai

@blau-ai

blau-ai commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

CI triage for #2144 (Antalya 26.6: Hybrid tables)

Verdict — the only PR-caused failures are the two new Hybrid stateless tests (03643_hybrid, 03646_hybrid_segment_pruning), and they're a test-stability issue, not a product bug. Everything else is pre-existing / infra / flaky and unrelated to the Hybrid code.

Summary:

Check Class PR-caused?
Stateless 03643_hybrid, 03646_hybrid_segment_pruning (arm_binary + amd_debug) EXPLAIN plan diff under randomized settings yes (test only)
AST fuzzer (amd_debug) LOGICAL_ERROR in FunctionIn::executeImpl ⚠️ likely pre-existing fuzzer flake — needs re-run
Integration test_arrowflight...::test_get_table_types (arm 2/4) Arrow Flight, unrelated ❌ no (flaky)
Stateless s3-storage job (4 FAIL + 3 BROKEN) 595–900 s timeouts on a slow runner ❌ no (infra)
Stateless amd_debug 00071_merge_tree_optimize_aio 900 s timeout ❌ no (infra)
Regression Iceberg 1/2, S3Export part/partition, Swarms (aarch64 + release) object-storage suites, no Hybrid code ❌ no (pre-existing)
Grype Scan reports "0 high/critical vulnerabilities" but marked fail ❌ no (tooling quirk)

1. PR-caused: 03643_hybrid & 03646_hybrid_segment_pruning (stateless)

Both fail on a query-plan diff only — the results are identical, the plan label differs. The EXPLAIN output renders the WHERE step as Filter (…) where the committed reference has Expression (…):

-          Expression ((WHERE + Change column names to column identifiers))
+          Filter ((WHERE + Change column names to column identifiers))
               ReadFromMergeTree (default.local_cold)

(from 03646_hybrid_segment_pruning, amd_debug; 03643_hybrid is the same Expression (WHERE)Filter (WHERE) flip.)

Root cause: clickhouse-test randomizes session settings per run, and one of them controls whether a WHERE clause is rendered as an Expression step or a Filter step. Evidence it's randomization, not a deterministic planner change: 03643_hybrid passed on amd_debug but failed on arm_binary in the same run — a deterministic change would fail identically everywhere. 03646 already pins several settings for exactly this reason (use_query_condition_cache, prefer_localhost_replica, …) but not the one that flips Expression/Filter. These two are the only Hybrid tests that assert EXPLAIN output.

Suggested fix — disable settings randomization for the two EXPLAIN-asserting tests:

--- a/tests/queries/0_stateless/03643_hybrid.sql
+++ b/tests/queries/0_stateless/03643_hybrid.sql
@@ -1,3 +1,4 @@
+-- Tags: no-random-settings
 SELECT 'Hybrid creation requires allow_experimental_hybrid_table';
 SET allow_experimental_hybrid_table = 0;
--- a/tests/queries/0_stateless/03646_hybrid_segment_pruning.sql
+++ b/tests/queries/0_stateless/03646_hybrid_segment_pruning.sql
@@ -1,2 +1,2 @@
--- Tags: no-fasttest
+-- Tags: no-fasttest, no-random-settings
 -- Tag no-fasttest: requires remote() table function

no-random-settings pins the session to defaults, which is what the committed references were generated with (and is why 03643 passed on the job that happened to draw default-equivalent settings). Alternative if you'd rather keep randomization: add an explicit SET query_plan_merge_filters = <value matching the reference>; next to the other pinned settings in 03646 and at the top of 03643. Either way the fix is test-only — the Hybrid pruning logic is producing correct rows. I can't run clickhouse-test in this container, so a follow-up CI run is the confirmation.

2. AST fuzzer (amd_debug) — likely pre-existing, please re-run

The server aborted on a LOGICAL_ERROR (code 49, which aborts in debug builds). The crash site is generic IN-operator execution, with no Hybrid frames in the stack:

#5  DB::abortOnFailedAssertion
#11 DB::(anonymous namespace)::FunctionIn::executeImpl
#13 DB::FunctionToExecutableFunctionAdaptor::executeImpl
#20 DB::FilterTransform::doTransform

The fuzzer was mutating the new Hybrid .sql files, but the failure is in core FunctionIn execution — characteristic of a pre-existing fuzzer find rediscovered via random mutation. I can't fully exclude the PR because it does touch IN-set construction (src/Interpreters/ActionsVisitor.cpp), and I couldn't pull the exact fuzzed query (it lives in the fuzzer artifact, not the job log). Next step: re-run the AST fuzzer. If it reproduces, grab the failing query from the fuzzer report and I'll dig in.

3–7. Not PR-related

  • Integration (arm_binary, distributed plan, 2/4): single failure test_arrowflight_interface/test_sql_server.py::test_get_table_types — Arrow Flight interface, nothing to do with Hybrid. Flaky/pre-existing → safe to re-run.
  • Stateless (amd_debug, distributed plan, s3 storage): 04033_tpc_ds_q14, 04092_text_index_like_large_postings, 00160_merge_and_index_in_in, 00804_test_alter_compression_codecs all failed at 595–900 s, plus 3 BROKEN (deltalake, 04070_url_base_setting) — a cluster of timeouts in one wall-clock window = overloaded/slow runner. None are Hybrid tests. Infra → re-run.
  • Stateless (amd_debug, parallel): the second failure 00071_merge_tree_optimize_aio hit the 900 s timeout — infra, unrelated.
  • Regression Iceberg (1/2), S3Export (part/partition), Swarms (both aarch64 and release): these exercise Iceberg / S3-export / swarm features; the PR diff touches none of that code, and the antalya-26.6 base workflow is also red on these. Pre-existing.
  • Grype Scan: the check text says "Completed with 0 high/critical vulnerabilities" yet is marked fail — a scanner/gating quirk, not this PR.

What I recommend

  1. Apply the test-tag fix in §1 (the real, actionable item).
  2. Re-run AST fuzzer + the flaky Integration / infra-timeout jobs.

I have the §1 diff ready. How would you like it delivered — a direct commit to feature/antalya-26.6/auto-grp-pr-1694, or a separate blau/* PR? I won't push until you say which.

Evidence from run 30806815194. I can't build/run ClickHouse in this container, so classifications are from CI logs + static reading; the §1 fix is validated by a re-run.

@zvonand

zvonand commented Aug 7, 2026

Copy link
Copy Markdown
Member Author

@mkmkme could you pls take a look at the fails? ^^

@mkmkme

mkmkme commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

@mkmkme could you pls take a look at the fails? ^^

Yup, will do

mkmkme and others added 3 commits August 7, 2026 13:17
The `Hybrid` table engine forward-ported here registers unconditionally in
`registerStorages`, so it appears in `system.table_engines` regardless of
`allow_experimental_hybrid_table`. It was not present in the `engine_to_type`
map in `commandSelector.cpp`, so `commandGetTableTypes` and `commandGetTables`
translated it through the `'UNKNOWN TABLE TYPE'` fallback of `transform`. That
made `test_arrowflight_interface/test_sql_server.py::test_get_table_types` fail
with `'UNKNOWN TABLE TYPE' in types`, and it would also report Hybrid tables as
`UNKNOWN TABLE TYPE` to Flight SQL and ADBC clients doing table discovery.

`Hybrid` is registered from `StorageDistributed.cpp` and is a member of the
`Distributed` family, so it is mapped to `REMOTE TABLE` like `Distributed`.

This did not show up before the forward port because the two halves lived on
different branches: `antalya-26.3` has the `Hybrid` engine but no ArrowFlight
server, while `antalya-26.6` has the ArrowFlight server but no `Hybrid` engine.

Follows the same fix as b3a647c, which added
`Filesystem` to the same map for the same test failure.

CI report: https://altinity-build-artifacts.s3.amazonaws.com/json.html?PR=2144&sha=78baf9814831565b534e6a0338c83e500ca12aff&name_0=PR
Related: #2144

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`03643_hybrid` and `03646_hybrid_segment_pruning` are the only Hybrid tests that
assert `EXPLAIN` output, and both fail intermittently because `clickhouse-test`
randomizes session settings that change the rendered plan. Three separate
culprits were confirmed from the CI artifacts, each randomized to a non-default
value with probability 0.05:

* `query_plan_optimize_prewhere = 0` — `03646` on amd_debug. With the prewhere
  optimization disabled the WHERE step stays a `FilterStep` instead of being
  replaced by an `ExpressionStep`, so the plan renders
  `Filter ((WHERE + Change column names to column identifiers))` where the
  reference has `Expression (...)`. See `optimizePrewhere`, which only
  substitutes `ExpressionStep` when the filter is fully moved to `PREWHERE`.
* `optimize_move_to_prewhere = 0` — `03643` on arm_binary. Same rendering flip,
  gated earlier in the same function.
* `optimize_use_projections = 0` — `03646` on arm_binary. Test 6 then reads
  `ReadFromMergeTree` instead of `ReadFromPreparedSource (_exact_count_projection)`,
  which is a different failure mode from the two above.

Chasing individual settings does not converge: these tests assert whole plan
shapes, so any current or future randomized plan setting reopens the same
failure. `no-random-settings` pins the session to the defaults the references
were generated with and closes the whole class.

The existing `SET` statements in `03646` are kept. The tag is not a superset of
them: the `ParallelReplicas` job variants enable parallel replicas through the
server config (`--parallel-rep` installs `users.d/enable_parallel_replicas.xml`,
which puts `enable_parallel_replicas = 1` in the default profile) rather than
through settings randomization, and that file does not set
`parallel_replicas_local_plan`, so it stays at its default there and still has
to be pinned by the test.

CI report: https://altinity-build-artifacts.s3.amazonaws.com/json.html?PR=2144&sha=78baf9814831565b534e6a0338c83e500ca12aff&name_0=PR
Related: #2144

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`03645_hybrid_watermarks`, `03646_hybrid_segment_pruning` and
`03682_system_hybrid_watermarks` all carried `no-fasttest` with the reason
`requires remote() table function`. That reason does not hold: 366 stateless
tests call `remote` or `remoteSecure`, carry no `no-fasttest` tag, and pass the
Fast test job, some with dozens of calls.

The strongest evidence is in this same group of tests. `03643_hybrid` is
untagged, passes Fast test, and exercises a strictly larger set of remote
infrastructure than any of the three: `cluster('test_shard_localhost')` plus
`remote` to `127.0.0.1:9000`, `127.0.0.2:9000` and `localhost:9000`. The three
tagged tests only use `remote('localhost:9000')` or `remote('127.0.0.1:9000')`.

Failpoints are not a reason either, which is the only other feature that
distinguishes `03682` from the untagged Hybrid tests: 61 stateless tests use
`SYSTEM ENABLE FAILPOINT` and run to completion in the Fast test job.

The `no-parallel` tag on `03682` is kept, since a process-wide failpoint really
does conflict with parallel execution.

Fast test is the earliest signal in the pipeline, so skipping three of the seven
Hybrid tests there — including the segment pruning test, which is the one that
has actually been failing — costs real coverage for no reason.

Related: #2144

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@mkmkme

mkmkme commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

Pushed three commits:

  1. Actually fix the arrowflight test. Blau marked it as flaky, but in fact it was caused by this PR. Arrowflight was added after 26.3, and it lists all the tables. Hybrid needs to be added to this list, so I added it
  2. Added no-random-settings as suggested by blau. Thanks
  3. Removed no-fasttest from hybrid stateless tests. The original justification that they use remote() and therefore can't run in fast test was wrong. There's plenty of fast tests using remote() so there's no good justification to exclude the hybrid ones

@zvonand zvonand mentioned this pull request Aug 7, 2026
60 tasks
@mkmkme

mkmkme commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator

@blau-ai

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-resolved Port conflict auto-resolved by Claude antalya-26.6 forwardport This is a frontport of code that existed in previous Antalya versions releasy Created/managed by RelEasy

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants