Skip to content

Add ChainBuilder to support chaining work requests#92

Open
aryeyur wants to merge 1 commit into
jonhoo:mainfrom
aryeyur:aryeyur/chain_ops
Open

Add ChainBuilder to support chaining work requests#92
aryeyur wants to merge 1 commit into
jonhoo:mainfrom
aryeyur:aryeyur/chain_ops

Conversation

@aryeyur

@aryeyur aryeyur commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

No description provided.

@aryeyur

aryeyur commented Jun 14, 2026

Copy link
Copy Markdown
Contributor Author

Hey 👋

Would it be possible to look into this PR?

It adds support for chaining RDMA operations.

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

Thank you for the PR, please see the comment for discussion

Comment thread ibverbs/src/lib.rs
}

/// A builder to construct and post a dynamically sized chain of work requests to the Send Queue.
pub struct ChainBuilder<'qp, 'buf> {

@xmakro xmakro Jun 16, 2026

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.

The ChainBuilder only needs to know the QueuePair during post, so we could disentangle them until that point. This avoids the QP lifetime and allows for example creating two ChainBuilders at the same time, and posting them later with the same QueuePair. So ChainBuilder just becomes a helper around &mut [ibv_send_wr].

If we go this route, then that raises the question if we need a ChainBuilder at all, or if we can have the helper only around ibv_send_wr, with an API looking like:

#[repr(transparent)]
pub struct WorkRequest<'a> {
    wr: ffi::ibv_send_wr,
    _local: PhantomData<&'a [LocalMemorySlice]>,   // keeps the sg_list borrow alive
}

impl<'a> WorkRequest<'a> {
    pub fn send (local: &'a [LocalMemorySlice], wr_id: u64, imm: Option<u32>) -> Self;
    pub fn write(local: &'a [LocalMemorySlice], remote: RemoteMemorySlice, wr_id: u64) -> Self;
    pub fn read (local: &'a [LocalMemorySlice], remote: RemoteMemorySlice, wr_id: u64) -> Self;
}

on the QueuePair:

pub unsafe fn post(&mut self, mut wrs: impl AsMut<[WorkRequest<'_>]>) -> io::Result<()>;

usage:

qp.post([
    WorkRequest::write(&locals[0], remotes[0].clone(), 1, None),
    WorkRequest::write(&locals[1], remotes[1].clone(), 2, None),
    WorkRequest::send(&notify, 3, None).signaled(),
])?;

// dynamic / reused buffer,
qp.post(&mut wrs)?;

Then we can also do things like:

WorkRequest::write(..).signaled(), .fenced()

What do you think? This API should have zero overhead, so we can redirect the existing single post_send/post_recv API to it.

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