wireshift_core/buffer/
pool.rs1use crossbeam_queue::ArrayQueue;
2use std::sync::Arc;
3
4use super::{allocate_overflow_buffer, allocate_reusable_buffer, Buffer, Owned, PooledBuffer};
5use crate::error::{Error, Result};
6
7#[derive(Debug)]
8pub(crate) struct BufferPoolInner {
9 pub(crate) capacity: usize,
10 pub(crate) max_buffers: usize,
11 pub(crate) overflow_on_exhaustion: bool,
12 pub(crate) free: ArrayQueue<PooledBuffer>,
13}
14
15impl Drop for BufferPoolInner {
16 fn drop(&mut self) {
17 while let Some(buffer) = self.free.pop() {
18 buffer.deallocate();
19 }
20 }
21}
22
23#[derive(Clone, Debug)]
34pub struct BufferPool {
35 inner: Arc<BufferPoolInner>,
36}
37
38impl BufferPool {
39 pub fn new(capacity: usize, max_buffers: usize) -> Result<Self> {
41 Self::with_overflow_strategy(capacity, max_buffers, false)
42 }
43
44 pub fn registered() -> Result<Self> {
49 Self::with_overflow_strategy(
50 super::REGISTERED_BUFFER_CAPACITY,
51 super::REGISTERED_BUFFER_COUNT,
52 true,
53 )
54 }
55
56 fn with_overflow_strategy(
57 capacity: usize,
58 max_buffers: usize,
59 overflow_on_exhaustion: bool,
60 ) -> Result<Self> {
61 if capacity == 0 {
62 return Err(Error::validation(
63 "buffer capacity must be greater than zero",
64 "construct the pool with a non-zero buffer capacity",
65 ));
66 }
67 if max_buffers == 0 {
68 return Err(Error::validation(
69 "max_buffers must be greater than zero",
70 "construct the pool with at least one reusable buffer",
71 ));
72 }
73 let free = ArrayQueue::new(max_buffers);
74 for _ in 0..max_buffers {
75 let buffer = allocate_reusable_buffer(capacity)?;
76 if let Err(buffer) = free.push(buffer) {
77 buffer.deallocate();
78 return Err(Error::resource_exhausted(
79 "failed to initialize buffer pool free queue",
80 "increase the max_buffers capacity to fit all allocations",
81 ));
82 }
83 }
84 Ok(Self {
85 inner: Arc::new(BufferPoolInner {
86 capacity,
87 max_buffers,
88 overflow_on_exhaustion,
89 free,
90 }),
91 })
92 }
93
94 pub fn acquire(&self) -> Result<Buffer<Owned>> {
96 if let Some(buffer) = self.inner.free.pop() {
97 return Ok(Buffer::new(self.inner.clone(), buffer, 0));
98 }
99 if !self.inner.overflow_on_exhaustion {
100 return Err(Error::resource_exhausted(
101 format!(
102 "buffer pool exhausted (capacity: {}, max_buffers: {})",
103 self.inner.capacity, self.inner.max_buffers
104 ),
105 "release completed buffers back to the pool or increase max_buffers",
106 ));
107 }
108 Ok(Buffer::new(
109 self.inner.clone(),
110 allocate_overflow_buffer(self.inner.capacity),
111 0,
112 ))
113 }
114
115 #[must_use]
117 pub fn capacity(&self) -> usize {
118 self.inner.capacity
119 }
120
121 #[must_use]
123 pub fn max_buffers(&self) -> usize {
124 self.inner.max_buffers
125 }
126}