compio_runtime/runtime/
buffer_pool.rs

1//! Buffer pool
2
3use std::{io, marker::PhantomData, mem::ManuallyDrop};
4
5pub use compio_driver::BorrowedBuffer;
6
7use crate::Runtime;
8
9/// Buffer pool
10///
11/// A buffer pool to allow user no need to specify a specific buffer to do the
12/// IO operation
13///
14/// Drop the `BufferPool` will release the buffer pool automatically
15#[derive(Debug)]
16pub struct BufferPool {
17    inner: ManuallyDrop<compio_driver::BufferPool>,
18    runtime_id: u64,
19
20    // make it !Send and !Sync, to prevent user send the buffer pool to other thread
21    _marker: PhantomData<*const ()>,
22}
23
24impl BufferPool {
25    /// Create buffer pool with given `buffer_size` and `buffer_len`
26    ///
27    /// # Notes
28    ///
29    /// If `buffer_len` is not power of 2, it will be upward with
30    /// [`u16::next_power_of_two`]
31    pub fn new(buffer_len: u16, buffer_size: usize) -> io::Result<Self> {
32        let (inner, runtime_id) = Runtime::with_current(|runtime| {
33            let buffer_pool = runtime.create_buffer_pool(buffer_len, buffer_size)?;
34            let runtime_id = runtime.id();
35
36            io::Result::Ok((buffer_pool, runtime_id))
37        })?;
38
39        Ok(Self {
40            inner: ManuallyDrop::new(inner),
41            runtime_id,
42            _marker: Default::default(),
43        })
44    }
45
46    /// Get the inner driver buffer pool reference
47    ///
48    /// # Notes
49    ///
50    /// You should not use this method unless you are writing your own IO opcode
51    pub fn try_inner(&self) -> io::Result<&compio_driver::BufferPool> {
52        let current_runtime_id = Runtime::with_current(|runtime| runtime.id());
53        if current_runtime_id == self.runtime_id {
54            Ok(&self.inner)
55        } else {
56            Err(io::Error::other("runtime and buffer pool mismatch"))
57        }
58    }
59}
60
61impl Drop for BufferPool {
62    fn drop(&mut self) {
63        let _ = Runtime::try_with_current(|runtime| {
64            if self.runtime_id != runtime.id() {
65                return;
66            }
67
68            unsafe {
69                // SAFETY: we own the inner
70                let inner = ManuallyDrop::take(&mut self.inner);
71
72                // SAFETY: the buffer pool is created by current thread runtime
73                let _ = runtime.release_buffer_pool(inner);
74            }
75        });
76    }
77}