flatbuffers_pool/
pool.rs

1//! `parking_log::Mutex<Vec>` based flatbuffer builder pool
2use std::{
3    ops::{Deref, DerefMut},
4    sync::atomic::{AtomicBool, Ordering},
5    sync::{Arc, Weak},
6};
7
8use flatbuffers::FlatBufferBuilder;
9use once_cell::sync::Lazy;
10use parking_lot::Mutex;
11
12/// `FlatBufferBuilder` pool.
13///
14/// # Examples
15///
16/// ```
17/// use flatbuffers_pool::FlatBufferBuilderPool;
18///
19/// let mut b = FlatBufferBuilderPool::get();
20/// let name = b.create_string("something fun");
21/// b.finish(name, None);
22/// ```
23pub struct FlatBufferBuilderPool {
24    /// Initial local pool size.
25    init: usize,
26
27    /// Maximum local pool size.
28    max: usize,
29
30    /// Flatbuffer buffer capacity of the local pool buffer.
31    buffer_capacity: usize,
32}
33
34static mut INIT_POOL_SIZE: usize = 32;
35static mut MAX_POOL_SIZE: usize = 1_024;
36static mut BUFFER_CAPACITY: usize = 64;
37
38impl FlatBufferBuilderPool {
39    /// Get the `FlatBufferBuilder` from the global pool.
40    ///
41    /// # Examples
42    ///
43    /// ```
44    /// use flatbuffers_pool::FlatBufferBuilderPool;
45    ///
46    /// let mut b = FlatBufferBuilderPool::get();
47    /// let name = b.create_string("something fun");
48    /// b.finish(name, None);
49    /// ```
50    #[inline]
51    pub fn get() -> GlobalBuilder {
52        let mut pool = POOL.lock();
53        match pool.pop() {
54            Some(builder) => builder,
55            None => GlobalBuilder::new(),
56        }
57    }
58
59    /// Change the initial global pool size.
60    ///
61    /// It should be called before calling the first `get`
62    /// function otherwise the change won't applicable.
63    ///
64    /// # Examples
65    ///
66    /// ```
67    /// use flatbuffers_pool::FlatBufferBuilderPool;
68    ///
69    /// FlatBufferBuilderPool::init_global_pool_size(0);
70    /// let mut b = FlatBufferBuilderPool::get();
71    /// let name = b.create_string("something fun");
72    /// b.finish(name, None);
73    /// ```
74    #[inline]
75    pub fn init_global_pool_size(size: usize) {
76        unsafe {
77            INIT_POOL_SIZE = size;
78            if MAX_POOL_SIZE < size {
79                MAX_POOL_SIZE = size;
80            }
81        }
82    }
83
84    /// Change the maximum global pool size.
85    ///
86    /// It should be called before calling the first `get`
87    /// function otherwise the change won't applicable.
88    ///
89    /// # Examples
90    ///
91    /// ```
92    /// use flatbuffers_pool::FlatBufferBuilderPool;
93    ///
94    /// FlatBufferBuilderPool::max_global_pool_size(4);
95    /// let mut b = FlatBufferBuilderPool::get();
96    /// let name = b.create_string("something fun");
97    /// b.finish(name, None);
98    /// ```
99    #[inline]
100    pub fn max_global_pool_size(size: usize) {
101        unsafe {
102            MAX_POOL_SIZE = size;
103            if INIT_POOL_SIZE > size {
104                INIT_POOL_SIZE = size;
105            }
106        }
107    }
108
109    /// Change the initial `FlatBufferBuilder` buffer size.
110    ///
111    /// The value only applicable for the newly allocated
112    /// `FlatBufferBuilder` instances.
113    ///
114    /// # Examples
115    ///
116    /// ```
117    /// use flatbuffers_pool::FlatBufferBuilderPool;
118    ///
119    /// FlatBufferBuilderPool::global_buffer_capacity(64);
120    /// let mut b = FlatBufferBuilderPool::get();
121    /// let name = b.create_string("something fun");
122    /// b.finish(name, None);
123    /// ```
124    #[inline]
125    pub fn global_buffer_capacity(capacity: usize) {
126        unsafe {
127            BUFFER_CAPACITY = capacity;
128        }
129    }
130}
131
132/// `GlobalBuilder` encapsulates the `FlatBufferBuilder` instance
133/// for the global pool.
134pub struct GlobalBuilder(Option<FlatBufferBuilder<'static>>);
135
136impl GlobalBuilder {
137    #[inline]
138    fn new() -> Self {
139        Self::default()
140    }
141
142    #[inline]
143    fn buffer_capacity() -> usize {
144        unsafe { BUFFER_CAPACITY }
145    }
146}
147
148impl Default for GlobalBuilder {
149    #[inline]
150    fn default() -> Self {
151        Self(Some(FlatBufferBuilder::new_with_capacity(
152            Self::buffer_capacity(),
153        )))
154    }
155}
156
157impl Deref for GlobalBuilder {
158    type Target = FlatBufferBuilder<'static>;
159    #[inline]
160    fn deref(&self) -> &Self::Target {
161        self.0.as_ref().unwrap()
162    }
163}
164
165impl DerefMut for GlobalBuilder {
166    #[inline]
167    fn deref_mut(&mut self) -> &mut Self::Target {
168        self.0.as_mut().unwrap()
169    }
170}
171
172impl Drop for GlobalBuilder {
173    fn drop(&mut self) {
174        if let Some(mut builder) = self.0.take() {
175            // resetting the builder outside of the lock
176            // to reduce the pool manipulation contention.
177            builder.reset();
178            let max = unsafe { MAX_POOL_SIZE };
179            let mut pool = POOL.lock();
180            if pool.len() < max {
181                pool.push(GlobalBuilder(Some(builder)))
182            }
183        }
184    }
185}
186
187static POOL: Lazy<Mutex<Vec<GlobalBuilder>>> = Lazy::new(|| {
188    let (init, max) = unsafe { (INIT_POOL_SIZE, MAX_POOL_SIZE) };
189    let mut pool = Vec::with_capacity(max);
190    for _ in { 0..init } {
191        pool.push(GlobalBuilder::new());
192    }
193    Mutex::new(pool)
194});
195
196impl FlatBufferBuilderPool {
197    /// Create a local `FlatBufferBuilder` pool instance.
198    ///
199    /// # Examples
200    ///
201    /// ```
202    /// use flatbuffers_pool::FlatBufferBuilderPool;
203    ///
204    /// // Get the builder from the local pool.
205    /// let mut pool = FlatBufferBuilderPool::new().build();
206    /// let mut b = pool.get();
207    /// let name = b.create_string("something fun");
208    /// b.finish(name, None);
209    /// ```
210    pub fn new() -> Self {
211        Self::default()
212    }
213
214    /// Change the initial local pool size.
215    ///
216    /// It should be called before calling the first `get`
217    /// function otherwise the change won't applicable.
218    ///
219    /// # Examples
220    ///
221    /// ```
222    /// use flatbuffers_pool::FlatBufferBuilderPool;
223    ///
224    /// // Get the builder from the local pool.
225    /// let pool = FlatBufferBuilderPool::new()
226    ///     .init_pool_size(0)
227    ///     .build();
228    /// let mut b = pool.get();
229    /// let name = b.create_string("something fun");
230    /// b.finish(name, None);
231    /// ```
232    #[inline]
233    pub fn init_pool_size(mut self, size: usize) -> Self {
234        self.init = size;
235        if self.max < size {
236            self.max = size;
237        }
238        self
239    }
240
241    /// Change the maximum local pool size.
242    ///
243    /// It should be called before calling the first `get`
244    /// function otherwise the change won't applicable.
245    ///
246    /// # Examples
247    ///
248    /// ```
249    /// use flatbuffers_pool::FlatBufferBuilderPool;
250    ///
251    /// // Get the builder from the local pool.
252    /// let pool = FlatBufferBuilderPool::new()
253    ///     .max_pool_size(4)
254    ///     .build();
255    /// let mut b = pool.get();
256    /// let name = b.create_string("something fun");
257    /// b.finish(name, None);
258    /// ```
259    #[inline]
260    pub fn max_pool_size(mut self, size: usize) -> Self {
261        self.max = size;
262        if self.init > size {
263            self.init = size;
264        }
265        self
266    }
267
268    /// Change the initial `FlatBufferBuilder` buffer size.
269    ///
270    /// The value only applicable for the newly allocated
271    /// `FlatBufferBuilder` instances.
272    ///
273    /// # Examples
274    ///
275    /// ```
276    /// use flatbuffers_pool::FlatBufferBuilderPool;
277    ///
278    /// // Get the builder from the local pool.
279    /// let pool = FlatBufferBuilderPool::new()
280    ///     .buffer_capacity(64)
281    ///     .build();
282    /// let mut b = pool.get();
283    /// let name = b.create_string("something fun");
284    /// b.finish(name, None);
285    /// ```
286    #[inline]
287    pub fn buffer_capacity(mut self, capacity: usize) -> Self {
288        self.buffer_capacity = capacity;
289        self
290    }
291
292    /// Build a local `FlatBufferBuilder` pool.
293    ///
294    /// # Examples
295    ///
296    /// ```
297    /// use flatbuffers_pool::FlatBufferBuilderPool;
298    ///
299    /// // Get the builder from the local pool.
300    /// let pool = FlatBufferBuilderPool::new()
301    ///     .build();
302    /// let mut b = pool.get();
303    /// let name = b.create_string("something fun");
304    /// b.finish(name, None);
305    /// ```
306    pub fn build<'a>(&self) -> FlatBufferBuilderLocalPool<'a> {
307        let inner = Arc::new(Mutex::new(Vec::with_capacity(self.max)));
308        for _ in { 0..self.init } {
309            let builder = LocalBuilder::new(
310                Arc::downgrade(&inner),
311                self.max,
312                FlatBufferBuilder::new_with_capacity(self.buffer_capacity),
313            );
314            inner.lock().push(builder);
315        }
316        FlatBufferBuilderLocalPool::<'a> {
317            max: self.max,
318            buffer_capacity: self.buffer_capacity,
319            inner,
320        }
321    }
322}
323
324const LOCAL_INIT_POOL_SIZE: usize = 32;
325const LOCAL_MAX_POOL_SIZE: usize = 1_024;
326const LOCAL_BUFFER_CAPACITY: usize = 64;
327
328impl Default for FlatBufferBuilderPool {
329    fn default() -> Self {
330        Self {
331            init: LOCAL_INIT_POOL_SIZE,
332            max: LOCAL_MAX_POOL_SIZE,
333            buffer_capacity: LOCAL_BUFFER_CAPACITY,
334        }
335    }
336}
337
338/// Local `FlatBufferBuilder` pool.
339///
340/// # Examples
341///
342/// ```
343/// use flatbuffers_pool::FlatBufferBuilderPool;
344///
345/// // Get the builder from the global pool.
346/// let pool = FlatBufferBuilderPool::new().build();
347/// let mut b = pool.get();
348/// let name = b.create_string("something fun");
349/// b.finish(name, None);
350/// ```
351pub struct FlatBufferBuilderLocalPool<'a> {
352    /// Maximum local pool size.
353    max: usize,
354
355    /// Flatbuffer buffer capacity for the local pool.
356    buffer_capacity: usize,
357
358    /// Local pool.
359    inner: Arc<Mutex<Vec<LocalBuilder<'a>>>>,
360}
361
362impl<'a> FlatBufferBuilderLocalPool<'a> {
363    /// Get the `FlatBufferBuilder` from the local pool.
364    ///
365    /// # Examples
366    ///
367    /// ```
368    /// use flatbuffers_pool::FlatBufferBuilderPool;
369    ///
370    /// // Get the builder from the local pool.
371    /// let pool = FlatBufferBuilderPool::new().build();
372    /// let mut b = pool.get();
373    /// let name = b.create_string("something fun");
374    /// b.finish(name, None);
375    /// ```
376    #[inline]
377    pub fn get(&self) -> LocalBuilder<'a> {
378        let mut pool = self.inner.lock();
379        match pool.pop() {
380            Some(builder) => builder,
381            None => LocalBuilder::new(
382                Arc::downgrade(&self.inner),
383                self.max,
384                FlatBufferBuilder::new_with_capacity(self.buffer_capacity),
385            ),
386        }
387    }
388}
389
390impl<'a> Drop for FlatBufferBuilderLocalPool<'a> {
391    fn drop(&mut self) {
392        let mut pool = self.inner.lock();
393        while let Some(mut builder) = pool.pop() {
394            builder.drain();
395        }
396    }
397}
398
399/// `LocalBuilder` encapsulates the `FlatBufferBuilder` instance
400/// for the local pool.
401pub struct LocalBuilder<'a> {
402    /// Local pool.
403    pool: Weak<Mutex<Vec<LocalBuilder<'a>>>>,
404
405    /// Maximum local pool size.
406    max: usize,
407
408    /// Drained state.
409    drained: AtomicBool,
410
411    /// Actual builder.
412    inner: Option<FlatBufferBuilder<'a>>,
413}
414
415impl<'a> LocalBuilder<'a> {
416    fn new(pool: Weak<Mutex<Vec<Self>>>, max: usize, builder: FlatBufferBuilder<'a>) -> Self {
417        Self {
418            pool,
419            max,
420            drained: AtomicBool::new(false),
421            inner: Some(builder),
422        }
423    }
424    #[inline]
425    fn drain(&mut self) {
426        self.drained.store(true, Ordering::SeqCst);
427    }
428    #[inline]
429    fn is_drained(&self) -> bool {
430        self.drained.load(Ordering::SeqCst)
431    }
432}
433
434impl<'a> Deref for LocalBuilder<'a> {
435    type Target = FlatBufferBuilder<'a>;
436    #[inline]
437    fn deref(&self) -> &Self::Target {
438        self.inner.as_ref().unwrap()
439    }
440}
441
442impl<'a> DerefMut for LocalBuilder<'a> {
443    #[inline]
444    fn deref_mut(&mut self) -> &mut Self::Target {
445        self.inner.as_mut().unwrap()
446    }
447}
448
449impl<'a> Drop for LocalBuilder<'a> {
450    fn drop(&mut self) {
451        if self.is_drained() {
452            return;
453        }
454        if let Some(mut builder) = self.inner.take() {
455            builder.reset();
456            if let Some(pool) = &self.pool.upgrade() {
457                let mut pool = pool.lock();
458                if pool.len() < self.max {
459                    pool.push(LocalBuilder::new(self.pool.clone(), self.max, builder));
460                }
461            }
462        }
463    }
464}