Skip to content

store writer txn instead of write_req when write_req is processed#192

Merged
MrGuin merged 6 commits into
mainfrom
fix_reader_writer_cntl
Nov 7, 2025
Merged

store writer txn instead of write_req when write_req is processed#192
MrGuin merged 6 commits into
mainfrom
fix_reader_writer_cntl

Conversation

@MrGuin

@MrGuin MrGuin commented Nov 6, 2025

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • Refactor
    • Optimized internal writer state handling in the concurrency control layer for improved memory efficiency and transaction tracking; no public API changes.
  • Bug Fixes
    • Made catalog commit handling more robust by explicitly cleaning updated entries and updating schema state during truncation.
    • Replaced an assertion with a logged warning and graceful READ_CATALOG_CONFLICT return when schema write-lock assumptions are not met.

@coderabbitai

coderabbitai Bot commented Nov 6, 2025

Copy link
Copy Markdown

Walkthrough

Refactor: the writer state in ReaderWriterCntl was changed from an atomic pointer to a tagged 64-bit atomic that can encode either a CcRequestBase* or a transaction id. Related encode/decode helpers and all internal uses were updated; catalog CCM handling for TruncateTable and InitCcm read-lock behavior was also adjusted.

Changes

Cohort / File(s) Summary
ReaderWriter header
include/cc/reader_writer_cntl.h
Added #include "cc_req_base.h". Replaced std::atomic<CcRequestBase*> write_req_{nullptr} with std::atomic<uint64_t> writer_{0} and added comment describing tagged 64-bit slot (bit0 indicates pointer vs txn id).
ReaderWriter implementation
src/cc/reader_writer_cntl.cpp
Implemented tagged-writer encoding/decoding helpers (IsWriterPtr, EncodeWriterPtr, EncodeWriterTxn, DecodeWriterPtr, DecodeWriterTxn) and replaced all uses of write_req_ with the new writer_ encoding: updated AddReader, FinishReader, AddWriter, FinishWriter logic for reading/writing/clearing the tagged writer state and txn handling.
Catalog CCM handling
include/cc/catalog_cc_map.h
In PostCommit TruncateTable path: explicitly clean CCM entry for the table on the affected node group and update CCM schema with new dirty schema/version before standby sync. In GetTableSchema InitCcm path: removed assertion about dirty schema when a write lock exists; now logs a warning and returns READ_CATALOG_CONFLICT.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Client
  participant ReaderWriterCntl
  participant Queue

  Client->>ReaderWriterCntl: AddWriter(write_req)
  alt store pointer
    ReaderWriterCntl->>ReaderWriterCntl: writer_ = EncodeWriterPtr(write_req)
  else store txn-after-processing
    ReaderWriterCntl->>ReaderWriterCntl: writer_ = EncodeWriterTxn(txn_id)
  end
  ReaderWriterCntl->>Queue: enqueue if needed

  Client->>ReaderWriterCntl: FinishReader(reader_req)
  ReaderWriterCntl->>ReaderWriterCntl: load writer_ (IsWriterPtr / Decode)
  alt writer is ptr
    ReaderWriterCntl->>ReaderWriterCntl: transition writer -> ProcessedWriter, store txn encoding
    ReaderWriterCntl->>Queue: enqueue writer
  else writer is txn
    ReaderWriterCntl->>ReaderWriterCntl: validate txn id
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Attention points:
    • Correctness of bit tagging, alignment, and pointer vs txn discrimination.
    • Atomic operations and memory ordering semantics when swapping pointer/txn encodings.
    • All code paths updating/clearing writer_ (AddWriter, FinishWriter, FinishReader).
    • Catalog CCM changes around TruncateTable PostCommit and GetTableSchema InitCcm read-lock behavior.

Suggested reviewers

  • liunyl

Poem

🐰
In a slot of sixty-four, I tuck a tiny clue,
Pointer or transaction — either will do.
Bits hop and whisper, swapping names on cue,
Queues wake and dance, then onward they flew. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The pull request description is missing entirely. No content addressing the template requirements (tests, documentation, issue references, RFC links, or test results) was provided. Add a comprehensive description including rationale, test coverage verification, documentation status, and reference the related issue using 'fixes' keyword if applicable.
Docstring Coverage ⚠️ Warning Docstring coverage is 7.14% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: refactoring to store writer transaction IDs instead of write request pointers when processed.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix_reader_writer_cntl

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between da0a984 and ec8fd7c.

📒 Files selected for processing (1)
  • include/cc/catalog_cc_map.h (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: thweetkomputer
Repo: eloqdata/tx_service PR: 150
File: include/cc/local_cc_shards.h:626-631
Timestamp: 2025-10-09T03:56:58.811Z
Learning: For the LocalCcShards class in include/cc/local_cc_shards.h: Writer locks (unique_lock) should continue using the original meta_data_mux_ (std::shared_mutex) rather than fast_meta_data_mux_ (FastMetaDataMutex) at this stage. Only reader locks may use the FastMetaDataMutex wrapper.
🔇 Additional comments (2)
include/cc/catalog_cc_map.h (2)

793-798: Truncate CCM cleanup aligns with schema reset.

Cleaning the CCM before pushing the new schema/version pair keeps truncated tables from serving stale rows, and the explicit UpdateCcmSchema call makes the fresh metadata visible immediately. Nicely tightened.


2378-2383: Graceful conflict handling for InitCcm.

Downgrading the old assert to a logged READ_CATALOG_CONFLICT lets callers retry cleanly while still surfacing the lock holder context. Much better ergonomics.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 421a933 and 9a009fd.

📒 Files selected for processing (2)
  • include/cc/reader_writer_cntl.h (2 hunks)
  • src/cc/reader_writer_cntl.cpp (6 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: thweetkomputer
Repo: eloqdata/tx_service PR: 150
File: include/cc/local_cc_shards.h:626-631
Timestamp: 2025-10-09T03:56:58.811Z
Learning: For the LocalCcShards class in include/cc/local_cc_shards.h: Writer locks (unique_lock) should continue using the original meta_data_mux_ (std::shared_mutex) rather than fast_meta_data_mux_ (FastMetaDataMutex) at this stage. Only reader locks may use the FastMetaDataMutex wrapper.
📚 Learning: 2025-10-09T03:56:58.811Z
Learnt from: thweetkomputer
Repo: eloqdata/tx_service PR: 150
File: include/cc/local_cc_shards.h:626-631
Timestamp: 2025-10-09T03:56:58.811Z
Learning: For the LocalCcShards class in include/cc/local_cc_shards.h: Writer locks (unique_lock) should continue using the original meta_data_mux_ (std::shared_mutex) rather than fast_meta_data_mux_ (FastMetaDataMutex) at this stage. Only reader locks may use the FastMetaDataMutex wrapper.

Applied to files:

  • src/cc/reader_writer_cntl.cpp
  • include/cc/reader_writer_cntl.h
📚 Learning: 2025-09-25T06:15:41.186Z
Learnt from: liunyl
Repo: eloqdata/tx_service PR: 142
File: include/tx_req_result.h:140-159
Timestamp: 2025-09-25T06:15:41.186Z
Learning: When cc_notify_ is true in TxResult, both Finish() and Wait() are guaranteed to be called on the same thread, eliminating concurrency concerns and making relaxed memory ordering sufficient for status_combo_ updates.

Applied to files:

  • src/cc/reader_writer_cntl.cpp
  • include/cc/reader_writer_cntl.h

Comment thread src/cc/reader_writer_cntl.cpp Outdated
@githubzilla githubzilla force-pushed the fix_reader_writer_cntl branch from 9a009fd to ae0b73f Compare November 7, 2025 04:39

@githubzilla githubzilla left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

+1

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/cc/reader_writer_cntl.cpp (1)

89-110: Critical: Guard against nullptr before dereferencing (similar issue at lines 114-128).

The assertion on lines 93-95 validates writer existence in debug builds, but there's a race condition that can lead to undefined behavior in release builds:

  1. Thread A calls FinishWriter, stores nullptr to writer_ (line 198)
  2. Before Thread A sets status to Invalid (line 199), Thread B calls AddWriter
  3. Thread B observes stale PendingWriter status and loads nullptr from writer_ (line 89)
  4. In release builds, lines 97-100 dereference nullptr without protection

Apply this defensive fix for both the PendingWriter case (lines 97-100) and the ProcessedWriter case (lines 122-125):

-            uint64_t writer_txn =
-                std::holds_alternative<CcRequestBase *>(writer)
-                    ? std::get<CcRequestBase *>(writer)->Txn()
-                    : std::get<uint64_t>(writer);
+            uint64_t writer_txn;
+            if (std::holds_alternative<CcRequestBase *>(writer))
+            {
+                CcRequestBase *write_req_ptr = std::get<CcRequestBase *>(writer);
+                if (write_req_ptr == nullptr)
+                {
+                    return AddWriterResult::Invalid;
+                }
+                writer_txn = write_req_ptr->Txn();
+            }
+            else
+            {
+                writer_txn = std::get<uint64_t>(writer);
+            }
🧹 Nitpick comments (1)
src/cc/reader_writer_cntl.cpp (1)

198-199: Consider strengthening memory ordering for the final state transition.

The two relaxed stores create a window where other threads might observe writer_ == nullptr before seeing WriteStatus::Invalid. While the critical nullptr dereference issue is addressed in AddWriter, using memory_order_release here would provide clearer happens-before semantics for the state transition.

-    writer_.store(nullptr, std::memory_order_relaxed);
-    cntl_block_.store({0, WriteStatus::Invalid}, std::memory_order_relaxed);
+    writer_.store(nullptr, std::memory_order_release);
+    cntl_block_.store({0, WriteStatus::Invalid}, std::memory_order_release);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9a009fd and ae0b73f.

📒 Files selected for processing (3)
  • CMakeLists.txt (2 hunks)
  • include/cc/reader_writer_cntl.h (2 hunks)
  • src/cc/reader_writer_cntl.cpp (6 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: thweetkomputer
Repo: eloqdata/tx_service PR: 150
File: include/cc/local_cc_shards.h:626-631
Timestamp: 2025-10-09T03:56:58.811Z
Learning: For the LocalCcShards class in include/cc/local_cc_shards.h: Writer locks (unique_lock) should continue using the original meta_data_mux_ (std::shared_mutex) rather than fast_meta_data_mux_ (FastMetaDataMutex) at this stage. Only reader locks may use the FastMetaDataMutex wrapper.
📚 Learning: 2025-10-09T03:56:58.811Z
Learnt from: thweetkomputer
Repo: eloqdata/tx_service PR: 150
File: include/cc/local_cc_shards.h:626-631
Timestamp: 2025-10-09T03:56:58.811Z
Learning: For the LocalCcShards class in include/cc/local_cc_shards.h: Writer locks (unique_lock) should continue using the original meta_data_mux_ (std::shared_mutex) rather than fast_meta_data_mux_ (FastMetaDataMutex) at this stage. Only reader locks may use the FastMetaDataMutex wrapper.

Applied to files:

  • src/cc/reader_writer_cntl.cpp
  • include/cc/reader_writer_cntl.h
📚 Learning: 2025-09-25T06:15:41.186Z
Learnt from: liunyl
Repo: eloqdata/tx_service PR: 142
File: include/tx_req_result.h:140-159
Timestamp: 2025-09-25T06:15:41.186Z
Learning: When cc_notify_ is true in TxResult, both Finish() and Wait() are guaranteed to be called on the same thread, eliminating concurrency concerns and making relaxed memory ordering sufficient for status_combo_ updates.

Applied to files:

  • src/cc/reader_writer_cntl.cpp
  • include/cc/reader_writer_cntl.h
🧬 Code graph analysis (1)
src/cc/reader_writer_cntl.cpp (1)
include/cc/reader_writer_cntl.h (1)
  • ccs_ (68-93)
🔇 Additional comments (6)
CMakeLists.txt (1)

227-227: LGTM!

Adding the atomic library is necessary to support std::atomic<std::variant<CcRequestBase *, uint64_t>> on platforms where atomic operations on types larger than the native word size require runtime support from libatomic.

include/cc/reader_writer_cntl.h (2)

6-8: LGTM!

The new includes are necessary for the variant-based writer state representation. The <variant> header provides the std::variant type, and "cc_req_base.h" provides the full definition of CcRequestBase needed for the variant.


69-69: LGTM!

The transition from std::atomic<CcRequestBase *> to std::atomic<std::variant<CcRequestBase *, uint64_t>> enables storing either a request pointer or a transaction identifier, supporting more flexible writer state management. Initializing with nullptr correctly constructs the CcRequestBase* alternative.

src/cc/reader_writer_cntl.cpp (3)

51-76: LGTM!

The logic correctly handles the variant: it checks for the CcRequestBase* alternative, validates the pointer is non-null before dereferencing, and stores the transaction number after successfully transitioning to ProcessedWriter status.


150-166: LGTM!

The two-phase update pattern is correct: store the request pointer first (line 150) for potential use by FinishReader, then replace it with the transaction number (line 164) after successfully transitioning to ProcessedWriter status. This ensures both code paths (caller processing or last-reader processing) have the necessary information.


172-187: LGTM!

The validation logic correctly handles both variant alternatives: checking the pointer and its transaction number for the CcRequestBase* case, or directly comparing the transaction number for the uint64_t case. Early returns prevent incorrect cleanup of mismatched transactions.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
include/cc/reader_writer_cntl.h (1)

8-8: Consider removing this include to reduce compilation dependencies.

Since the writer_ variant only stores a CcRequestBase* (pointer), the forward declaration at line 13 should be sufficient. Including the full header increases compilation dependencies unnecessarily unless the implementation requires the complete type definition for operations beyond pointer storage.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ae0b73f and 0288109.

📒 Files selected for processing (1)
  • include/cc/reader_writer_cntl.h (2 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: thweetkomputer
Repo: eloqdata/tx_service PR: 150
File: include/cc/local_cc_shards.h:626-631
Timestamp: 2025-10-09T03:56:58.811Z
Learning: For the LocalCcShards class in include/cc/local_cc_shards.h: Writer locks (unique_lock) should continue using the original meta_data_mux_ (std::shared_mutex) rather than fast_meta_data_mux_ (FastMetaDataMutex) at this stage. Only reader locks may use the FastMetaDataMutex wrapper.
📚 Learning: 2025-10-09T03:56:58.811Z
Learnt from: thweetkomputer
Repo: eloqdata/tx_service PR: 150
File: include/cc/local_cc_shards.h:626-631
Timestamp: 2025-10-09T03:56:58.811Z
Learning: For the LocalCcShards class in include/cc/local_cc_shards.h: Writer locks (unique_lock) should continue using the original meta_data_mux_ (std::shared_mutex) rather than fast_meta_data_mux_ (FastMetaDataMutex) at this stage. Only reader locks may use the FastMetaDataMutex wrapper.

Applied to files:

  • include/cc/reader_writer_cntl.h
📚 Learning: 2025-09-25T06:15:41.186Z
Learnt from: liunyl
Repo: eloqdata/tx_service PR: 142
File: include/tx_req_result.h:140-159
Timestamp: 2025-09-25T06:15:41.186Z
Learning: When cc_notify_ is true in TxResult, both Finish() and Wait() are guaranteed to be called on the same thread, eliminating concurrency concerns and making relaxed memory ordering sufficient for status_combo_ updates.

Applied to files:

  • include/cc/reader_writer_cntl.h

Comment thread include/cc/reader_writer_cntl.h Outdated
@MrGuin MrGuin force-pushed the fix_reader_writer_cntl branch from 0288109 to da0a984 Compare November 7, 2025 05:53

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0288109 and da0a984.

📒 Files selected for processing (2)
  • include/cc/reader_writer_cntl.h (3 hunks)
  • src/cc/reader_writer_cntl.cpp (7 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: thweetkomputer
Repo: eloqdata/tx_service PR: 150
File: include/cc/local_cc_shards.h:626-631
Timestamp: 2025-10-09T03:56:58.811Z
Learning: For the LocalCcShards class in include/cc/local_cc_shards.h: Writer locks (unique_lock) should continue using the original meta_data_mux_ (std::shared_mutex) rather than fast_meta_data_mux_ (FastMetaDataMutex) at this stage. Only reader locks may use the FastMetaDataMutex wrapper.
📚 Learning: 2025-10-09T03:56:58.811Z
Learnt from: thweetkomputer
Repo: eloqdata/tx_service PR: 150
File: include/cc/local_cc_shards.h:626-631
Timestamp: 2025-10-09T03:56:58.811Z
Learning: For the LocalCcShards class in include/cc/local_cc_shards.h: Writer locks (unique_lock) should continue using the original meta_data_mux_ (std::shared_mutex) rather than fast_meta_data_mux_ (FastMetaDataMutex) at this stage. Only reader locks may use the FastMetaDataMutex wrapper.

Applied to files:

  • src/cc/reader_writer_cntl.cpp
  • include/cc/reader_writer_cntl.h
📚 Learning: 2025-09-25T06:15:41.186Z
Learnt from: liunyl
Repo: eloqdata/tx_service PR: 142
File: include/tx_req_result.h:140-159
Timestamp: 2025-09-25T06:15:41.186Z
Learning: When cc_notify_ is true in TxResult, both Finish() and Wait() are guaranteed to be called on the same thread, eliminating concurrency concerns and making relaxed memory ordering sufficient for status_combo_ updates.

Applied to files:

  • src/cc/reader_writer_cntl.cpp
📚 Learning: 2025-10-20T04:30:07.884Z
Learnt from: liunyl
Repo: eloqdata/tx_service PR: 149
File: include/cc/cc_request.h:1876-1927
Timestamp: 2025-10-20T04:30:07.884Z
Learning: ScanNextBatchCc in include/cc/cc_request.h is used only for hash-partition scans; range-partition scans are handled by ScanSliceCc.

Applied to files:

  • include/cc/reader_writer_cntl.h
🧬 Code graph analysis (1)
src/cc/reader_writer_cntl.cpp (1)
include/cc/reader_writer_cntl.h (1)
  • ccs_ (67-70)

Comment on lines +90 to 115
// If the load precedes the store of writer in AddWriter(), the
// loaded write request is nullptr. By the time AddWriter() finishes
// store, the read ref count must be 0 and AddWriter() will return
// successful. If the load succeeds the store, the last reader and the
// writer will race to set the write status to ProcessedWriter. Whoever
// wins will process the write request.
CcRequestBase *write_req = write_req_.load(std::memory_order_relaxed);
if (write_req != nullptr)
uint64_t writer = writer_.load(std::memory_order_relaxed);
if (IsWriterPtr(writer))
{
cntl = {0, WriteStatus::PendingWriter};
if (cntl_block_.compare_exchange_strong(
cntl,
{0, WriteStatus::ProcessedWriter},
std::memory_order_acq_rel))
CcRequestBase *write_req = DecodeWriterPtr(writer);
if (write_req != nullptr)
{
ccs_->Enqueue(write_req);
cntl = {0, WriteStatus::PendingWriter};
if (cntl_block_.compare_exchange_strong(
cntl,
{0, WriteStatus::ProcessedWriter},
std::memory_order_acq_rel))
{
// Store the writer txn after setting the write status to
// ProcessedWriter.
writer_.store(EncodeWriterTxn(write_req->Txn()),
std::memory_order_relaxed);
ccs_->Enqueue(write_req);
}
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Use acquire/release on writer_ to prevent stuck writers.

Every load/store of writer_ is memory_order_relaxed. If the final reader races with the AddWriter() store, it can legally see the old 0 value, skip the enqueue path, and return while the control block stays {0, PendingWriter}. Because AddWriter() has already returned WritePending, nothing will promote the request, so the writer remains blocked indefinitely. The C++ memory model explicitly allows this outcome without a happens-before edge between the relaxed operations.

Please promote the hand-off to use release stores and matching acquire loads (FinishReader, both AddWriter branches, FinishWriter, and the txn stores) so the pointer/txn value is visible before the state machine acts on it.

-        uint64_t writer = writer_.load(std::memory_order_relaxed);
+        uint64_t writer = writer_.load(std::memory_order_acquire);
...
-    writer_.store(EncodeWriterPtr(write_req), std::memory_order_relaxed);
+    writer_.store(EncodeWriterPtr(write_req), std::memory_order_release);
...
-        writer_.store(EncodeWriterTxn(write_req->Txn()),
-                      std::memory_order_relaxed);
+        writer_.store(EncodeWriterTxn(write_req->Txn()),
+                      std::memory_order_release);
...
-    uint64_t writer = writer_.load(std::memory_order_relaxed);
+    uint64_t writer = writer_.load(std::memory_order_acquire);
...
-    writer_.store(0, std::memory_order_relaxed);
+    writer_.store(0, std::memory_order_release);

Also applies to: 184-200, 207-235

🤖 Prompt for AI Agents
In src/cc/reader_writer_cntl.cpp around lines 90-115 (also apply same fix to
184-200 and 207-235): the issue is that all loads/stores of writer_ use
memory_order_relaxed which can allow a reader to miss the writer pointer and
leave the control block in PendingWriter indefinitely; change the
synchronization to use release stores and acquire loads so the pointer/txn
becomes visible before state transitions. Concretely: change loads of writer_
that drive state transitions to std::memory_order_acquire, change stores of
writer_ (and txn pointer stores in AddWriter/FinishWriter branches) to
std::memory_order_release, and keep compare_exchange operations with
std::memory_order_acq_rel on success (and std::memory_order_acquire on failure
if two-order parameters are used) so the hand-off has proper happens-before
semantics; apply these exact ordering changes in FinishReader, both AddWriter
branches, FinishWriter, and any txn stores referenced in the noted line ranges.

@MrGuin MrGuin merged commit 3073870 into main Nov 7, 2025
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants