FixedBufPool

Struct FixedBufPool 

Source
pub struct FixedBufPool<T: IoBufMut> { /* private fields */ }
Expand description

A dynamic collection of I/O buffers pre-registered with the kernel.

FixedBufPool allows the application to manage a collection of buffers allocated in memory, that can be registered in the current tokio-uring context using the register method. Unlike FixedBufRegistry, individual buffers are not retrieved by index; instead, an available buffer matching a specified capacity can be retrieved with the try_next method. In asynchronous contexts, the next method can be used to wait until such a buffer becomes available. This allows some flexibility in managing sets of buffers with different capacity tiers. The need to maintain lists of free buffers, however, imposes additional runtime overhead.

A FixedBufPool value is a lightweight handle for a collection of allocated buffers. Cloning of a FixedBufPool creates a new reference to the same collection of buffers.

The buffers of the collection are not deallocated until:

  • all FixedBufPool references to the collection have been dropped;
  • all FixedBuf handles to individual buffers in the collection have been dropped, including the buffer handles owned by any I/O operations in flight;
  • The tokio-uring Runtime the buffers are registered with has been dropped.

§Examples

use tokio_uring::buf::fixed::FixedBufPool;
use tokio_uring::buf::IoBuf;
use std::iter;
use std::mem;

tokio_uring::start(async {
    let pool = FixedBufPool::new(
         iter::once(Vec::with_capacity(BUF_SIZE_LARGE))
             .chain(iter::repeat_with(|| Vec::with_capacity(BUF_SIZE_SMALL)).take(2))
     );

    pool.register()?;

    let buf = pool.try_next(BUF_SIZE_LARGE).unwrap();
    assert_eq!(buf.bytes_total(), BUF_SIZE_LARGE);
    let next = pool.try_next(BUF_SIZE_LARGE);
    assert!(next.is_none());
    let buf1 = pool.try_next(BUF_SIZE_SMALL).unwrap();
    assert_eq!(buf1.bytes_total(), BUF_SIZE_SMALL);
    let buf2 = pool.try_next(BUF_SIZE_SMALL).unwrap();
    assert_eq!(buf2.bytes_total(), BUF_SIZE_SMALL);
    let next = pool.try_next(BUF_SIZE_SMALL);
    assert!(next.is_none());
    mem::drop(buf);
    let buf = pool.try_next(BUF_SIZE_LARGE).unwrap();
    assert_eq!(buf.bytes_total(), BUF_SIZE_LARGE);

    Ok(())
})

Implementations§

Source§

impl<T: IoBufMut> FixedBufPool<T>

Source

pub fn new(bufs: impl IntoIterator<Item = T>) -> Self

Creates a new collection of buffers from the provided allocated vectors.

The buffers are assigned 0-based indices in the order of the iterable input parameter. The returned collection takes up to UIO_MAXIOV buffers from the input. Any items in excess of that amount are silently dropped, unless the input iterator produces the vectors lazily.

§Examples

When providing uninitialized vectors for the collection, take care to not replicate a vector with .clone() as that does not preserve the capacity and the resulting buffer pointer will be rejected by the kernel. This means that the following use of iter::repeat would not work:

use tokio_uring::buf::fixed::FixedBufPool;
use std::iter;

let pool = FixedBufPool::new(
    iter::repeat(Vec::with_capacity(BUF_SIZE)).take(NUM_BUFFERS)
);

tokio_uring::start(async {
    pool.register()?;
    // ...
    Ok(())
})

Instead, create the vectors with requested capacity directly:

use tokio_uring::buf::fixed::FixedBufPool;
use std::iter;

let pool = FixedBufPool::new(
    iter::repeat_with(|| Vec::with_capacity(BUF_SIZE)).take(NUM_BUFFERS)
);

tokio_uring::start(async {
    pool.register()?;
    // ...
    Ok(())
})
Source

pub fn register(&self) -> Result<()>

Registers the buffers with the kernel.

This method must be called in the context of a tokio-uring runtime. The registration persists for the lifetime of the runtime, unless revoked by the unregister method. Dropping the FixedBufPool instance this method has been called on does not revoke the registration or deallocate the buffers.

This call can be blocked in the kernel to complete any operations in-flight on the same io-uring instance. The application is recommended to register buffers before starting any I/O operations.

§Errors

If a collection of buffers is currently registered in the context of the tokio-uring runtime this call is made in, the function returns an error.

Source

pub fn unregister(&self) -> Result<()>

Unregisters this collection of buffers.

This method must be called in the context of a tokio-uring runtime, where the buffers should have been previously registered.

This operation invalidates any FixedBuf handles checked out from this registry instance. Continued use of such handles in I/O operations may result in an error.

§Errors

If another collection of buffers is currently registered in the context of the tokio-uring runtime this call is made in, the function returns an error. Calling unregister when no FixedBufPool is currently registered on this runtime also returns an error.

Source

pub fn try_next(&self, cap: usize) -> Option<FixedBuf>

Returns a buffer of requested capacity from this pool that is not currently owned by any other FixedBuf handle. If no such free buffer is available, returns None.

The buffer is released to be available again once the returned FixedBuf handle has been dropped. An I/O operation using the buffer takes ownership of it and returns it once completed, preventing shared use of the buffer while the operation is in flight.

An application should not rely on any particular order in which available buffers are retrieved.

Source

pub async fn next(&self, cap: usize) -> FixedBuf

Resolves to a buffer of requested capacity when it is or becomes available in this pool. This may happen when a FixedBuf handle owning a buffer of the same capacity is dropped.

If no matching buffers are available and none are being released, this asynchronous function will never resolve. Applications should take care to wait on the returned future concurrently with some tasks that will complete I/O operations owning the buffers, or back it up with a timeout using, for example, tokio::util::timeout.

Trait Implementations§

Source§

impl<T: Clone + IoBufMut> Clone for FixedBufPool<T>

Source§

fn clone(&self) -> FixedBufPool<T>

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more

Auto Trait Implementations§

§

impl<T> Freeze for FixedBufPool<T>

§

impl<T> !RefUnwindSafe for FixedBufPool<T>

§

impl<T> !Send for FixedBufPool<T>

§

impl<T> !Sync for FixedBufPool<T>

§

impl<T> Unpin for FixedBufPool<T>

§

impl<T> !UnwindSafe for FixedBufPool<T>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.