Skip to content

Cluster Bus IO offload#3438

Open
hpatro wants to merge 1 commit into
valkey-io:unstablefrom
hpatro:cluster-io-offload
Open

Cluster Bus IO offload#3438
hpatro wants to merge 1 commit into
valkey-io:unstablefrom
hpatro:cluster-io-offload

Conversation

@hpatro

@hpatro hpatro commented Apr 2, 2026

Copy link
Copy Markdown
Contributor

Fixes: #3361

Cluster Bus I/O Offload

Overview

Cluster bus read, write, and TLS accept work can run on the shared I/O thread
pool, while all cluster state mutation stays on the main thread.

Jobs flow through:

  • io_shared_inbox (SPMC): main thread -> I/O workers
  • io_shared_outbox (MPSC): I/O workers -> main thread

If the pool is inactive or enqueue fails, the caller falls back to synchronous
I/O on the main thread and increments stat_cluster_io_sync_fallbacks.

Architecture

+---------------------------+       +-------------------------------+       +---------------------------+
|       Main Thread         |       |        Shared Queues          |       |     I/O Thread Pool       |
|                           |       |                               |       |                           |
| clusterReadOffloadHandler |------>| io_shared_inbox (SPMC)        |------>| clusterReadJob            |
| clusterWriteHandler       |       |                               |       | clusterWriteJob           |
| clusterAcceptHandler      |       |                               |       | clusterAcceptJob          |
| clusterSendMessage        |       +-------------------------------+       +---------------------------+
|                           |
| processIOThreadsResponses |<------ io_shared_outbox (MPSC) <------ sendToMainThread(...)
| clusterHandle*Completion  |
| clusterProcessPacket      |
| freeClusterLink           |
+---------------------------+

Key Design Decisions

  1. Reuse the existing shared SPMC/MPSC queues; no cluster-specific threading primitives.
  2. I/O threads do transport work only: connRead, connWrite, connAccept, framing, and result publication.
  3. Main thread alone applies cluster packets and mutates cluster state.
  4. Write offload uses a single canonical send_msg_queue plus a snapshot boundary:
    io_last_send_block, io_head_offset, and io_nodes_sent.
  5. Read offload uses rcvbuf snapshot boundaries: io_rcvbuf_snapshot_len and io_rcvbuf_snapshot_packets.
  6. Read completion drains the queued rcvbuf snapshot fully; there is no bounded packet/time budget.
  7. Link teardown is deferred with io_refs and async_close.
  8. Accept offload is serialized per connection with CONN_FLAG_ACCEPT_OFFLOAD_PENDING.
  9. ConnOwnerKind lets generic connection/TLS code distinguish client-owned and cluster-owned connections safely.

Data Flow: Read Path

[MAIN dispatch] clusterReadOffloadHandler
    |
    | drain queued snapshot
    | trySendClusterReadToIOThreads()
    v
[QUEUE] io_shared_inbox
    | JOB_REQ_CLUSTER_READ
    v
[IO worker] clusterReadJob
    | connRead() into rcvbuf
    | grow rcvbuf if needed
    | snapshot complete packet prefix
    | set io_rcvbuf_snapshot_len / packets
    | set io_result
    v
[QUEUE] io_shared_outbox
    | JOB_RES_CLUSTER_READ
    v
[MAIN completion] clusterHandleReadCompletion
    | set io_read_state = IDLE
    | io_refs--
    | reconcile memory
    | drain queued rcvbuf snapshot fully
    | shrink/free as needed

If dispatch returns C_ERR, the main thread falls back to clusterReadHandler(conn).

Data Flow: Write Path

[MAIN dispatch] clusterSendMessage / clusterWriteHandler
    |
    | append to send_msg_queue
    | snapshot io_last_send_block / io_head_offset
    | trySendClusterWriteToIOThreads()
    v
[QUEUE] io_shared_inbox
    | JOB_REQ_CLUSTER_WRITE
    v
[IO worker] clusterWriteJob
    | write from queue head
    | stop at io_last_send_block
    | set io_nodes_sent
    | set io_head_offset
    | set io_result
    v
[QUEUE] io_shared_outbox
    | JOB_RES_CLUSTER_WRITE
    v
[MAIN completion] clusterHandleWriteCompletion
    | set io_write_state = IDLE
    | io_refs--
    | pop sent nodes
    | apply head_msg_send_offset
    | reinstall handler or free on error

Important note:

  • New messages appended while a write job is in flight stay on send_msg_queue,
    but the worker stops at io_last_send_block, so those new nodes are picked up
    by a later dispatch.

If dispatch returns C_ERR, clusterWriteHandler(conn) falls back to the synchronous connWrite() loop.

Data Flow: Accept Path (TLS)

[MAIN dispatch] clusterAcceptHandler
    |
    | create accepted conn
    | set owner kind
    | allow accept offload
    | trySendClusterAcceptToIOThreads()
    v
[QUEUE] io_shared_inbox
    | JOB_REQ_CLUSTER_ACCEPT
    v
[IO worker] clusterAcceptJob
    | connAccept(conn, NULL)
    v
[QUEUE] io_shared_outbox
    | JOB_RES_CLUSTER_ACCEPT
    v
[MAIN completion] clusterHandleAcceptCompletion
    | clear ACCEPT_OFFLOAD_PENDING
    | finalize conn state / refs
    | if ACCEPTING: return
    | else clusterConnAcceptHandler()
    | create clusterLink on success

Important note:

  • TLS retries can re-enter the generic accept offload path. Cluster-owned
    connections are routed back to trySendClusterAcceptToIOThreads, and the
    pending flag ensures only one accept job is in flight for that connection.

If dispatch returns C_ERR, the main thread falls back to connAccept(conn, clusterConnAcceptHandler).

clusterLink I/O State

IDLE --dispatch read-->  READ_PENDING  --read completion-->  IDLE
IDLE --dispatch write--> WRITE_PENDING --write completion--> IDLE

If freeClusterLink() sees io_refs > 0:
  detach link from node
  remove handlers
  set async_close = 1
  defer final free until the last completion drops io_refs to 0

Read and write jobs are mutually exclusive per link.

Follow-Up

  • Read completion currently drains the queued rcvbuf snapshot in one pass on the main thread and compacts the buffer after each packet. (might be fine for time being)
  • Current behavior on CLUSTER_IO_BAD_HEADER / CLUSTER_IO_BAD_LENGTH is to close the link immediately, even if the same offloaded read also contained a valid packet prefix in the queued snapshot. This is accepted for now as an invalid-peer path, but if we ever need sync/offload parity here, read completion should drain the valid prefix before tearing the link down.
  • Create separate queue for cluster io jobs to avoid contention with client io jobs. This will allow us to prioritize different type of jobs and drain at different rate.

@hpatro hpatro marked this pull request as draft April 2, 2026 20:41
@hpatro

hpatro commented Apr 2, 2026

Copy link
Copy Markdown
Contributor Author

This PR is based off #3324. So, we would need to get that change into avoid lot of refactoring on this PR.

@hpatro hpatro changed the title Cluster IO offload Cluster Bus IO offload Apr 2, 2026

@roshkhatri roshkhatri left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This review is posted by AI

Review: Cluster Bus I/O Offload

Overall the architecture is sound — separating transport I/O from state mutation is the right design, and reusing the shared queues avoids unnecessary complexity. The design document is excellent.

I found a few issues worth addressing, detailed in inline comments below. The two most important are:

  1. rcvbuf_len mixed atomic/non-atomic access — undefined behavior in C11
  2. drainIOThreadsQueue deadlock — main thread can deadlock when the MPSC outbox is full

The MPSC reservation concern with pthread_cancel is lower probability but worth considering a cooperative shutdown model.

Comment thread src/cluster_legacy.c
break;
}
/* Real read error. */
result = CLUSTER_IO_READ_ERROR;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🔴 Thread Safety — rcvbuf_len mixed atomic/non-atomic access is UB

rcvbuf_len is declared atomic_size_t in clusterLink, but here in the I/O thread worker it's modified with a plain +=:

link->rcvbuf_len += nread;

Meanwhile the main thread reads it with atomic_load_explicit in freeClusterLinkOnBufferLimitReached, and as a plain variable in clusterReadHandler.

In C11, mixing atomic and non-atomic access to the same _Atomic variable is undefined behavior. This may work on x86 but could break on ARM or with aggressive compiler optimizations.

Suggested fix: Use atomic_store_explicit/atomic_load_explicit consistently everywhere rcvbuf_len is accessed, or keep it non-atomic and use rcvbuf_alloc as a conservative upper bound in the buffer limit check when a read job is in flight.

Comment thread src/io_threads.c
#endif
if (server.io_threads_num == 1) return;
serverAssert(inMainThread());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🟡 Deadlock — drainIOThreadsQueue doesn't drain the MPSC outbox

This function spins waiting for io_jobs_finished to catch up to io_jobs_submitted. But I/O threads increment io_jobs_finished only after processing a job — and if they can't push their completion result to the full MPSC outbox (io_shared_outbox), they get stuck in flushPendingIOResponses retrying.

Since this function never calls processIOThreadsResponses(), nobody drains the outbox, and we have a classic deadlock: main thread waits for workers, workers wait for outbox space.

Suggested fix:

void drainIOThreadsQueue(void) {
    serverAssert(inMainThread());
    commitIOJobs();
    while (getPendingIOThreadsJobs()) {
        processIOThreadsResponses();  // drain outbox to unblock workers
        atomic_thread_fence(memory_order_acquire);
    }
}

Note: updateIOThreads has a partial guard (pending > MPSC_QUEUE_SIZE check), but that doesn't cover all paths that call drainIOThreadsQueue.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good to highlight this issue and the one below on #3324 the PR which introduces this change.

Comment thread src/queues.c
/* Reserve a slot (or use existing reservation) */
if (!ticket->has_reservation) {
tail = atomic_fetch_add_explicit(&q->tail, 1, memory_order_relaxed);
} else {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🟡 MPSC reservation can permanently block dequeue if producer thread is cancelled

When the queue is full, mpscEnqueue reserves a slot (increments tail) but doesn't write data. The ticket saves the index for retry. However, mpscDequeueBatch stops at the first NULL slot:

if (!data) break;

If a producer thread is killed via pthread_cancel after reserving a slot but before writing data, that NULL slot permanently blocks all subsequent dequeues.

In practice the window is narrow since pthread_cancel fires at cancellation points (top of the I/O loop), not mid-enqueue. But it's a latent risk.

Suggested fix: Consider cooperative shutdown (atomic flag + clean exit) instead of pthread_cancel. This eliminates the problem and is generally safer for lock-free data structures.

@sarthakaggarwal97 sarthakaggarwal97 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.

Automated review found no actionable issues in this pass. It is not approving automatically.

@hpatro

hpatro commented Apr 15, 2026

Copy link
Copy Markdown
Contributor Author

Got unstable merged into this branch.

@hpatro hpatro force-pushed the cluster-io-offload branch from 6e20b2f to 61ddd4f Compare April 21, 2026 20:51
@hpatro hpatro marked this pull request as ready for review April 23, 2026 21:05
@hpatro hpatro requested review from madolson and zuiderkwast May 20, 2026 13:30
@hpatro hpatro added this to Valkey 10 Jun 2, 2026
@github-project-automation github-project-automation Bot moved this to Todo in Valkey 10 Jun 2, 2026
@hpatro hpatro added the major-decision-pending Major decision pending by TSC team label Jun 2, 2026
@hpatro

hpatro commented Jun 2, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Cluster bus reads, writes, and TLS accepts now offload to I/O threads with snapshot-based receive handling, deferred cluster-link teardown, ownership tracking, and updated cluster stats. Tests and docs were updated to cover the new offload paths and metrics.

Changes

Cluster Bus I/O Offload

Layer / File(s) Summary
Contracts and queue tags
design-docs/io-threads.md, src/cluster_legacy.h, src/connection.h, src/io_threads.h
Defines the cluster link I/O state, owner classification, job/result tags, exported job APIs, and the documented cluster bus offload flow.
I/O thread dispatch plumbing
src/cluster_legacy.c, src/io_threads.c
Adds cluster job queue routing, pending-response accounting, producer helpers, queue reset helpers, and completion dispatch in the shared I/O thread engine.
Cluster link read/write execution
src/cluster_legacy.c, src/unit/test_cluster_io_offload.cpp
Implements receive-buffer snapshots, read/write handler offload decisions, deferred link teardown, liveness and buffer accounting, shared worker completions, and read/write-focused unit coverage.
Accept offload and runtime observability
src/cluster_legacy.c, src/server.c, src/server.h, src/socket.c, tests/unit/cluster/cluster-io-offload.tcl, tests/unit/io-threads.tcl, src/unit/test_cluster_io_offload.cpp
Marks cluster-owned connections, routes TLS accept offload, updates server and socket observability, and adds cluster and I/O-thread tests for metrics and churn.

Sequence Diagram(s)

Cluster write offload

sequenceDiagram
  participant clusterWriteHandler
  participant trySendClusterWriteToIOThreads
  participant clusterWriteJob
  participant processIOThreadsResponses
  participant clusterHandleWriteCompletion
  clusterWriteHandler->>trySendClusterWriteToIOThreads: enqueue cluster write job
  trySendClusterWriteToIOThreads->>clusterWriteJob: JOB_REQ_CLUSTER_WRITE
  clusterWriteJob->>processIOThreadsResponses: JOB_RES_CLUSTER_WRITE
  processIOThreadsResponses->>clusterHandleWriteCompletion: invoke completion
Loading

TLS accept offload

sequenceDiagram
  participant clusterAcceptHandler
  participant trySendClusterAcceptToIOThreads
  participant clusterAcceptJob
  participant processIOThreadsResponses
  participant clusterHandleAcceptCompletion
  participant clusterConnAcceptHandler
  clusterAcceptHandler->>trySendClusterAcceptToIOThreads: enqueue cluster accept job
  trySendClusterAcceptToIOThreads->>clusterAcceptJob: JOB_REQ_CLUSTER_ACCEPT
  clusterAcceptJob->>processIOThreadsResponses: JOB_RES_CLUSTER_ACCEPT
  processIOThreadsResponses->>clusterHandleAcceptCompletion: invoke completion
  clusterHandleAcceptCompletion->>clusterConnAcceptHandler: finalize accepted cluster link
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~90+ minutes

Possibly related issues

Possibly related PRs

  • valkey-io/valkey#4022 — Updates the I/O-thread design documentation that this PR expands with the new Cluster Bus I/O section.

Suggested reviewers

  • madolson
  • zuiderkwast
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 38.20% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed Title is concise, clear, and matches the main change: cluster bus I/O offload.
Description check ✅ Passed The description is directly about cluster bus I/O offload and matches the changeset.
Linked Issues check ✅ Passed The code and tests implement the linked cluster bus offload requirements for read, write, accept, fallback, and shared queues.
Out of Scope Changes check ✅ Passed The added docs and tests support the same feature set and no unrelated code changes stand out.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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.

@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: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/cluster_legacy.c`:
- Around line 4725-4756: When clusterSnapshotPackets() encounters a bad trailing
header or length after successfully parsing one or more valid messages, ensure
the function records the parsed prefix before returning: set *snapshot_len =
offset (the byte length of the valid prefix) and leave *packet_count reflecting
parsed packets, then set *result to CLUSTER_IO_BAD_HEADER or
CLUSTER_IO_BAD_LENGTH and return; do not return early without publishing
snapshot_len/packet_count. Update the error branches that currently "return" on
memcmp(hdr->sig...) and totlen < minlen to first assign *snapshot_len = offset
and then set *result appropriately before returning so the synchronous path can
process the complete messages already parsed.
- Around line 8827-8875: clusterWriteJob (and the analogous threaded-write block
around lines 8964-9030) never updates cluster byte counters for successful
writes; update these threaded paths to account for bytes actually written by
calling clusterBusAddNetworkBytesByType() (which updates
cluster_stats_bytes_sent and per-type counters) whenever nwritten > 0,
accounting for partial writes by passing the number of bytes written for that
message fragment and the message's type (use msg/meta from
clusterMsgSendBlock/clusterMsg to determine the bus type). Ensure io_head_offset
and io_nodes_sent semantics remain correct when accounting bytes for partial and
full sends, and preserve existing sendToMainThread(link, JOB_RES_CLUSTER_WRITE)
behavior.

In `@src/unit/test_cluster_io_offload.cpp`:
- Around line 151-157: The helper makeConn() currently sets fc->conn.owner_kind
= CONN_OWNER_CLUSTER_LINK which makes accept-path tests start with a
cluster-owned connection; change makeConn() to accept an optional owner_kind
parameter (or create a separate makePreLinkConn()) and default to the pre-link
owner kind used in production for accept flow tests, then update the accept-path
tests to call the new parameterized helper or use the new makePreLinkConn() so
those tests begin with the correct non-cluster owner state instead of
CONN_OWNER_CLUSTER_LINK.
- Around line 398-406: The test leaves a synthetic accept dispatch referenced by
the shared I/O queue; after asserting the pending flag in
TEST_F(ClusterIOOffloadTest, AcceptDispatchSetsPendingFlag) you must unwind that
in-flight state to avoid a stale connection pointer during TearDown — mirror the
write-dispatch test by clearing the synthetic dispatch before returning: call
the test-only cleanup routine (testOnlyFreeIOThreadQueues()) to remove the
queued reference for the FakeConn created by makeConn() and ensure
CONN_FLAG_ACCEPT_OFFLOAD_PENDING is cleared on fc->conn (or otherwise released)
so owned_conns teardown won’t encounter a stale connection.

In `@tests/unit/cluster/cluster-io-offload.tcl`:
- Around line 17-49: Both tests mutate node 0 config but only restore on the
success path; wrap each test body (the code that calls R 0 config set ...,
wait_for_condition, and wait_for_cluster_state ok) in a try { ... } finally {
... } (or a catch/restore pattern) so the original values captured in oldlimit
and old_threads are always restored via R 0 config set <oldvalue> and cluster
state checked in the finally block; reference the test names ("buffer-limit
enforcement increments stat..." and "disabling io threads on one node causes
sync fallback"), the R 0 config set/get commands, wait_for_condition, and
wait_for_cluster_state ok when placing the restore logic.

In `@tests/unit/io-threads.tcl`:
- Around line 118-123: Remove the lifetime-bound assertion that checks the
cumulative used_active_time against the total sleep window (the assert using
used_active_time < ($sleep_time_ms/1000)); this check is flaky because
initial_active_times can already be large—keep the existing per-thread delta
check that computes used_active_time - $initial_active_times($i) and any
assertions using initial_active_times and getInfoProperty, so only drop the
cumulative assertion and rely on the delta-based assertion to validate
post-sleep activity.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 77bd46be-935a-438c-93c2-66fd0dc02015

📥 Commits

Reviewing files that changed from the base of the PR and between fc00f7b and 61ddd4f.

📒 Files selected for processing (12)
  • design-docs/cluster-io-offload.md
  • src/cluster_legacy.c
  • src/cluster_legacy.h
  • src/connection.h
  • src/io_threads.c
  • src/io_threads.h
  • src/server.c
  • src/server.h
  • src/socket.c
  • src/unit/test_cluster_io_offload.cpp
  • tests/unit/cluster/cluster-io-offload.tcl
  • tests/unit/io-threads.tcl

Comment thread src/cluster_legacy.c
Comment thread src/cluster_legacy.c
Comment thread src/unit/test_cluster_io_offload.cpp Outdated
Comment thread src/unit/test_cluster_io_offload.cpp
Comment thread tests/unit/cluster/cluster-io-offload.tcl Outdated
Comment on lines +71 to +79
test "cluster_io_accepts_offloaded increments under tls reconnect churn" {
wait_for_condition 500 10 {
[getInfoProperty [R 0 info stats] cluster_io_accepts_offloaded] > 0 || \
[getInfoProperty [R 1 info stats] cluster_io_accepts_offloaded] > 0 || \
[getInfoProperty [R 2 info stats] cluster_io_accepts_offloaded] > 0
} else {
fail "cluster_io_accepts_offloaded did not increase"
}
}

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 | 🟡 Minor | ⚡ Quick win

Make the TLS accept-offload check self-contained.

This test never triggers reconnect churn itself or captures a pre-churn baseline; it just checks whether cluster_io_accepts_offloaded is already non-zero. That can pass because of the previous restart test or even initial cluster boot, so it does not actually verify "under tls reconnect churn". Reset the relevant stats, induce the reconnects in this test, then assert the counter increased from the saved baseline.

As per coding guidelines: "Tests should not depend on execution order (test isolation)" and "Keep tests simple and focused on one scenario (test readability)".

Comment thread tests/unit/io-threads.tcl Outdated

@zuiderkwast zuiderkwast 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.

Sorry for delay. I didn't get to finish the review yet so I'm just posting my pending comments now.

Maybe we don't need to add so many INFO fields? INFO is already bloated. I guess you needed them for developing/debugging.

Btw, we already count these reads in io_threaded_reads_processed and in the existing cluster message counters, so maybe we just need to add a "reads in main thread" counter? (And the same for writes)

Comment thread src/connection.h Outdated
Comment thread src/server.c Outdated
Comment thread design-docs/cluster-io-offload.md Outdated
Comment thread design-docs/cluster-io-offload.md Outdated
hpatro added a commit to hpatro/valkey that referenced this pull request Jun 25, 2026
The main-thread fallback path uses connWrite/connRead, which are
non-blocking. "Synchronous" implies blocking I/O, which is not what
happens. Per zuiderkwast's review feedback on PR valkey-io#3438.
@codecov

codecov Bot commented Jun 25, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.63180% with 60 lines in your changes missing coverage. Please review.
✅ Project coverage is 76.80%. Comparing base (689906a) to head (16d11d2).

Files with missing lines Patch % Lines
src/io_threads.c 77.95% 28 Missing ⚠️
src/cluster_legacy.c 92.06% 23 Missing ⚠️
src/unit/test_cluster_io_offload.cpp 96.80% 9 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##           unstable    #3438      +/-   ##
============================================
+ Coverage     76.73%   76.80%   +0.07%     
============================================
  Files           162      163       +1     
  Lines         81029    81712     +683     
============================================
+ Hits          62175    62759     +584     
- Misses        18854    18953      +99     
Files with missing lines Coverage Δ
src/connection.h 90.47% <100.00%> (+2.35%) ⬆️
src/server.c 89.51% <100.00%> (-0.02%) ⬇️
src/server.h 100.00% <ø> (ø)
src/socket.c 93.95% <100.00%> (+0.54%) ⬆️
src/unit/test_cluster_io_offload.cpp 96.80% <96.80%> (ø)
src/cluster_legacy.c 88.75% <92.06%> (+0.54%) ⬆️
src/io_threads.c 76.48% <77.95%> (+0.43%) ⬆️

... and 21 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Use I/O threads for cluster bus reads, writes, and TLS accepts,
mirroring the client I/O threading model. Splits packet framing from
application, adds deferred link teardown with io_refs for safe
concurrent I/O, dual send queues, and a framed packet queue on
clusterLink. Adds observability counters (CLUSTER INFO).

Signed-off-by: Harkrishn Patro <h_patro@apple.com>
@hpatro hpatro force-pushed the cluster-io-offload branch from b4fdc03 to 16d11d2 Compare June 29, 2026 15:25
@hpatro

hpatro commented Jun 29, 2026

Copy link
Copy Markdown
Contributor Author

Squashed the changes.

@hpatro hpatro requested a review from zuiderkwast June 29, 2026 16:48
@hpatro

hpatro commented Jun 29, 2026

Copy link
Copy Markdown
Contributor Author

@zuiderkwast The CI is green, if you want to take a pass again.

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

Labels

major-decision-pending Major decision pending by TSC team

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

Cluster Bus I/O Offload

4 participants