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}