You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
On a content-addressed (CAS) disk, a recoverable CAS write refusal (Code 210NETWORK_ERROR, “retrying later”) thrown from PartWriteTxn::abandon during ContentAddressedTransaction::publishStaging can escape into MergeTreeTransaction::afterCommit / TransactionLog::finalizeCommittedTransaction, both marked noexcept. That calls std::terminate, aborts the server with SIGABRT (6), and the CI job reports Server died with a mass cascade of later test failures.
Discovered on PR #2300 ASan CAS S3 stateless CI. This is not ASAN MemoryTracker / RSS accounting noise: the Fatal window has no memory-limit / OOM / AddressSanitizer report; afterCommit even installs LockMemoryExceptionInThread (blocks tracker faults).
This issue:
Causes process abort (std::terminate → SIGABRT) on sanitizer CAS S3 lanes under load
Turns a retryable CAS condition into an unrecoverable server death
Inflates CI with hundreds of cascade FAILs after the abort
Is a CAS product bug (deterministic once Code 210 hits this path); ASan load makes the trigger more likely but is not the root cause
How to reproduce the behavior
Environment
Version:26.6.4.20001.altinityantalya (PR CAS improvements #2300 head f377ba3a499beacf5d032f3d34a69185765b8699, merge d898800…)
Build type:amd_asan_ubsan, default MergeTree policy = CAS S3
Run stateless tests with CAS S3 as the default MergeTree storage policy under ASan (as in CI job below), including 01169_old_alter_partition_isolation_stress.
Under concurrent CAS load on the same table namespace, a COMMIT that persists txn_version.txt (CSN metadata) hits a CAS pre-attempt refuse on the scratch-build abandon() after repoint.
Observe Fatal: Terminate called for uncaught exception with Code 210, then Received signal Aborted (6) on query COMMIT;.
Minimal local repro of the contract bug (once Code 210 is injected on abandon during publishStaging while inside MergeTree COMMIT finalize) should not require the full stress test; the CI path is:
COMMIT
→ TransactionLog::finalizeCommittedTransaction (noexcept)
→ MergeTreeTransaction::afterCommit (noexcept)
→ setAndStoreCreationCSN → write txn_version.txt on CAS part
→ ContentAddressedTransaction::publishStaging (repoint path)
→ PartWriteTxn::abandon() // precommit-removal append
→ CasRefLedger append refused BEFORE any request (NoAttemptSent)
→ throw NETWORK_ERROR "retrying later"
→ std::terminate
Expected behavior
A recoverable CAS Code 210 during scratch-build abandon() / metadata publish should either:
be caught and logged (as ~ContentAddressedTransaction already does for destructor abandon), and/or
surface as a normal failed COMMIT / retryable client error before the noexcept barrier,
and must not abort the server.
Actual behavior
On sanitizer CAS S3 builds
Server aborts:
Terminate called for uncaught exception:
Code: 210. DB::Exception: CAS write could not be committed
(CAS ref-log append for namespace '…@cas@' txn … was refused BEFORE any request was sent …);
retrying later. (NETWORK_ERROR)
(query: COMMIT;) Received signal Aborted (6)
Related log line (destructor path — correctly caught)
Same Code 210 during unwind is logged and swallowed:
ContentAddressedTransaction: abandoning a build during transaction destruction
(a live precommit binding may persist until remount): Code: 210. …
So the destructor already treats abandon failure as non-fatal; publishStaging does not.
Root cause analysis
afterCommit is noexcept and writes per-part version metadata to disk (VersionMetadataOnDisk::storeInfoToDataPartStorage → txn_version.txt).
On CAS, a standalone write on an already-committed part uses the repoint path in ContentAddressedTransaction::publishStaging: scratch precommitAdd → repointRef → abandon() of the scratch build.
Source comment at ContentAddressedTransaction.cpp (~376–379) already states that scratch abandon()can itself throw; the code only protects the CommitOutcome slot, not the process.
PartWriteTxn::abandon performs a correctness-bearing precommit-removal via appendRefOps. A pre-attempt gate refuse (CasUnresolvedReason::NoAttemptSent — mount fence or operation deadline before the first putIfAbsent) becomes makeCasWriteRetryLaterExceptionPtr (Code 210).
That exception leaves publishStaging and hits the noexcept MergeTree txn finalize → std::terminate.
Not MemoryTracker going negative / snapping to RSS under ASAN: no tracker/OOM evidence in the Fatal window; afterCommit blocks memory exceptions via LockMemoryExceptionInThread.
Suggested fix direction
Catch / absorb retry-later around abandon() in publishStaging (mirror ~ContentAddressedTransaction), and/or
Ensure MergeTree afterCommit disk writes cannot throw into noexcept (fail the commit earlier, or make the CAS metadata write path noexcept-safe).
Additional context
CI failure
Job: Stateless tests (amd_asan_ubsan, cas s3 storage, parallel, 2/2)
✅ I checked the Altinity Stable Builds lifecycle table, and the Altinity Stable Build version I'm using is still supported.
Type of problem
Bug report - something's broken
Describe the situation
On a content-addressed (CAS) disk, a recoverable CAS write refusal (Code 210
NETWORK_ERROR, “retrying later”) thrown fromPartWriteTxn::abandonduringContentAddressedTransaction::publishStagingcan escape intoMergeTreeTransaction::afterCommit/TransactionLog::finalizeCommittedTransaction, both markednoexcept. That callsstd::terminate, aborts the server with SIGABRT (6), and the CI job reportsServer diedwith a mass cascade of later test failures.Discovered on PR #2300 ASan CAS S3 stateless CI. This is not ASAN MemoryTracker / RSS accounting noise: the Fatal window has no memory-limit / OOM / AddressSanitizer report;
afterCommiteven installsLockMemoryExceptionInThread(blocks tracker faults).This issue:
std::terminate→ SIGABRT) on sanitizer CAS S3 lanes under loadHow to reproduce the behavior
Environment
26.6.4.20001.altinityantalya(PR CAS improvements #2300 headf377ba3a499beacf5d032f3d34a69185765b8699, merged898800…)amd_asan_ubsan, default MergeTree policy = CAS S301169_old_alter_partition_isolation_stress(transactional partition stress; concurrent INSERTs / ALTER PARTITION /COMMIT)Steps
01169_old_alter_partition_isolation_stress.COMMITthat persiststxn_version.txt(CSN metadata) hits a CAS pre-attempt refuse on the scratch-buildabandon()after repoint.Terminate called for uncaught exceptionwith Code 210, thenReceived signal Aborted (6)on queryCOMMIT;.Minimal local repro of the contract bug (once Code 210 is injected on abandon during publishStaging while inside MergeTree
COMMITfinalize) should not require the full stress test; the CI path is:Expected behavior
A recoverable CAS Code 210 during scratch-build
abandon()/ metadata publish should either:~ContentAddressedTransactionalready does for destructor abandon), and/orCOMMIT/ retryable client error before thenoexceptbarrier,and must not abort the server.
Actual behavior
On sanitizer CAS S3 builds
Server aborts:
Relevant stack (trimmed):
Related log line (destructor path — correctly caught)
Same Code 210 during unwind is logged and swallowed:
So the destructor already treats abandon failure as non-fatal;
publishStagingdoes not.Root cause analysis
afterCommitisnoexceptand writes per-part version metadata to disk (VersionMetadataOnDisk::storeInfoToDataPartStorage→txn_version.txt).ContentAddressedTransaction::publishStaging: scratchprecommitAdd→repointRef→abandon()of the scratch build.ContentAddressedTransaction.cpp(~376–379) already states that scratchabandon()can itself throw; the code only protects theCommitOutcomeslot, not the process.PartWriteTxn::abandonperforms a correctness-bearing precommit-removal viaappendRefOps. A pre-attempt gate refuse (CasUnresolvedReason::NoAttemptSent— mount fence or operation deadline before the firstputIfAbsent) becomesmakeCasWriteRetryLaterExceptionPtr(Code 210).publishStagingand hits thenoexceptMergeTree txn finalize →std::terminate.Not MemoryTracker going negative / snapping to RSS under ASAN: no tracker/OOM evidence in the Fatal window;
afterCommitblocks memory exceptions viaLockMemoryExceptionInThread.Suggested fix direction
abandon()inpublishStaging(mirror~ContentAddressedTransaction), and/orafterCommitdisk writes cannot throw intonoexcept(fail the commit earlier, or make the CAS metadata write path noexcept-safe).Additional context
CI failure
feature/antalya-26.6/CAS-improvementsf377ba3a499beacf5d032f3d34a69185765b8699Binary CAS S3 lanes on the same SHA were green; ASan
1/2was green — load/timing sensitive trigger, hard abort once hit.Related
cas/docs/PR-2300-CI-VERIFICATION.mdin clickhouse-regression_ckptCode 210 under ATTACH), #2332 (mount lease under concurrent FINAL)