Skip to content

CAS after #2647: relink capability, Packed index, test gate, oracles - #2704

Open
filimonov wants to merge 9 commits into
antalya-26.8from
feature/antalya-26.8/cas-disk-transactions-followups
Open

filimonov wants to merge 9 commits into
antalya-26.8from
feature/antalya-26.8/cas-disk-transactions-followups

Conversation

@filimonov

Copy link
Copy Markdown
Member

Seven commits on top of #2647: the fetch-by-relink promise moves from replication protocol version 11 to a request capability, Packed part loads read the archive index with a small buffer, and the CAS stateless lane stops passing silently without its fixture. The branch carries the commits of #2647 (and of #2579 under it) until they merge; the series is the 7 commits starting at "CAS: gate fetch-by-relink on a capability, not on replication protocol version 11".

Changes

  • Fetch-by-relink: the receiver sends cas_capabilities=relink_confirm; the sender offers a relink only to a receiver that sends it and answers server_protocol_version with upstream's ceiling (10). client_protocol_version 11 no longer selects anything, so a mixed cluster with an upstream build cannot pair the number with the relink stream shape.
  • DataPartStorageOnDiskPacked::resetReader reads the archive index with a 4 KiB buffer instead of the caller's full-size, possibly prefetching one.
  • checkpointTransaction has one body in DataPartStorageOnDiskBase (no-op on a content-addressed disk) instead of two identical overrides.
  • allowsPackedParts is forwarded by MetadataStorageFromCacheObjectStorage and MetadataStorageWithPathWrapper like the other capability flags.
  • Tests: clickhouse-test gains the positive cas-storage tag (skipped unless --cas-storage); 05217 and 05385 fail loudly without the CAS fixture instead of printing the expected output; 05220 removed (it asserted nothing after 476ea80; 05301 covers a Full source staying Full). New oracles: 05394 (one manifest_put per mutation with projections), 05395 (a deduplicated INSERT leaves no committed tmp_* ref), 05396 (three root-object PUTs per INSERT); gtest AuditSinkFailureDoesNotFailTheDurableMoveOrDrop; test_relink_is_selected_by_the_capability_not_the_version.
  • Docs: replication between 26.6.x and 26.8 servers during an upgrade (both speak protocol version 10 with different meanings).

Risks / notes

  • The relink cookie changes the fetch request between 26.8 builds: a receiver built before this PR (version 11, no cookie) gets the part bytes instead of a relink until both sides are upgraded. Correct, slower.
  • 05217 and 05385 need --cas-storage and the CAS fixture of the stateless job; without the flag they are skipped, with the flag and no fixture they fail.

Testing

  • Release build of the branch head: gtest CAS* 2703/2703; stateless 20/20 (05000, 05004, 05054, 05218, 05219, 05301, 05386–05392, 05394–05396, 04284, 04285, 04292, 04299); integration test_cas_replicated_relink 19/19, test_cas_ref_move_compat, test_cas_s3/test.py::test_cas_s3_packed_parts.

Related: #2647 (base: ref-log owner Move)
Related: #2579 (packed parts)
Related: #2540

Changelog category (leave one):

  • Improvement

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

Replica fetch-by-relink on content-addressed disks is negotiated by a request capability instead of replication protocol version 11, so mixed clusters with upstream builds never misread the number. Loading a Packed part reads the archive index with a small buffer.

Documentation entry for user-facing changes

  • Documentation is written: docs/en/antalya/cas/architecture/replication.md (26.6.x and 26.8 servers during an upgrade), docs/en/antalya/cas/configuration.md.

CI/CD Options

Exclude tests:

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

Regression jobs to run:

  • Fast suites (mostly <1h)
  • Aggregate Functions (2h)
  • Alter (1.5h)
  • Benchmark (30m)
  • CAS (content-addressed storage; Antalya only)
  • ClickHouse Keeper (1h)
  • Iceberg (2h)
  • LDAP (1h)
  • OAuth (5m)
  • Parquet (1.5h)
  • RBAC (1.5h)
  • SSL Server (1h)
  • S3 (2h)
  • S3 Export (2h)
  • Swarms (30m)
  • Tiered Storage (2h)

🤖 Generated with Claude Code

filimonov and others added 8 commits October 24, 2026 11:58
…l version 11

The receiver advertised `client_protocol_version=11` to mean "I confirm a relink offer before I promote". Upstream owns that number space (its ceiling is 10) and may assign 11 another wire meaning, so a mixed cluster could pair an upstream receiver's 11 with this build's relink offer, or this build's 11 with an upstream sender's stream shape.

The promise now travels as its own request parameter, `cas_capabilities=relink_confirm`: the sender offers a relink only to a receiver that sends it, and answers `server_protocol_version` with upstream's ceiling. The protocol version never selects a relink.

Test: test_relink_is_selected_by_the_capability_not_the_version (version 10 with the capability gets the offer; 11 without it gets the bytes and `server_protocol_version=10`; 10 without it gets the bytes).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Mikhail Filimonov <mfilimonov@altinity.com>
(cherry picked from commit 45a60a3f796a9708a41d439d256f58d15bb2de6f)
…need the CAS lane say so

`DataPartStorageOnDiskPacked::resetReader` read the archive index through `readArchive` with the caller's read settings, so every Packed part load opened a full-size, possibly prefetching buffer (the previous reader constructor used `adjustBufferSize(4096)`). The index read gets the small buffer back.

05217 and 05385 printed their expected output when the default disk was not content-addressed or the `cas_packed_mixed` policy was missing, so a lane with a broken fixture passed with no coverage; 05385 and 05301 also lacked `no-fasttest`. `clickhouse-test` gains a positive `cas-storage` tag (skipped unless `--cas-storage`); both tests carry it and fail loudly when the fixture is missing. 05220 asserted nothing: it was written for `choosePartFormatForMutation`, which 476ea80 removed, and 05301 covers a Full source staying Full.

`allowsPackedParts` gets a doc comment on `IDisk` and `IMetadataStorage`, and `MetadataStorageFromCacheObjectStorage` and `MetadataStorageWithPathWrapper` forward it like the other capability flags (`wrapWithCache` reuses the CAS storage today, so the default `true` was latent).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Mikhail Filimonov <mfilimonov@altinity.com>
(cherry picked from commit 294786b1443696dc6a2286a9c33369ef25af4141)
… say where the conflict counter counts

`AuditSinkFailureDoesNotFailTheDurableMoveOrDrop`: with an event sink that throws, `moveRefExact` and `dropRefExact` still land and report success, and both audit events reach the sink.

Comments: the two-rows-one-manifest branch of `moveRefExact` stays `CORRUPTED_DATA` (the ledger is replayed from the ref log, so only a damaged log gets there; no MergeTree caller keys a rename on the code). `throwCasOwnershipConflict` counts on the throwing thread, which inside an `appendRefOps` builder is the append leader, so per-query attribution is best-effort while the global counter is exact.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Mikhail Filimonov <mfilimonov@altinity.com>
(cherry picked from commit 50e95e658b95cc88a5730191c3e38586d7be29d7)
… deduplicated INSERT

05394: a mutation of a Full part with five projections costs one `manifest_put`, no `ref_repoint`, no `build_abort`, on both mutation branches (a column no projection uses is updated; an unused column is dropped) — `checkpointTransaction` is a no-op on a content-addressed disk.

05395: a deduplicated `INSERT` (same `insert_deduplication_token` twice) commits its part under `tmp_*` before the parts lock like every other insert; the rejected part's ref is dropped again, so every committed `tmp_*` ref is moved or dropped and none stays.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Mikhail Filimonov <mfilimonov@altinity.com>
Three: the manifest, the ref-log append that publishes the part under its temporary name, and the ref-log append that moves it to its final name. A protocol change (one append per part, CAS-347) shows up here as a number.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Mikhail Filimonov <mfilimonov@altinity.com>
The Full and Packed storages carried the same body (no-op on a content-addressed disk, upstream commit+begin otherwise); it lives in `DataPartStorageOnDiskBase` now. Pinned by 05394 (one manifest per mutation with projections) and 05000.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Mikhail Filimonov <mfilimonov@altinity.com>
…rade

Both builds speak replication protocol version 10 with different meanings, so a 26.6.x replica fetching from a 26.8 server can fail until the upgrade completes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Mikhail Filimonov <mfilimonov@altinity.com>
 merge

Signed-off-by: Mikhail Filimonov <mfilimonov@altinity.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Workflow [PR], commit [40898f9]

@k-morozov
k-morozov self-requested a review October 27, 2026 07:36

This branch has not been deployed

No deployments
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.

2 participants