reifydb_core/value/column/pool/
mod.rs

1// Copyright (c) reifydb.com 2025
2// This file is licensed under the AGPL-3.0-or-later, see license.md file
3
4//! Container pooling infrastructure for efficient memory management during
5//! expression evaluation.
6//!
7//! This module provides pooling for all container types to avoid frequent
8//! allocations and deallocations during column operations. Each container
9//! type has its own pool that manages reusable instances.
10
11mod allocator;
12mod capacity;
13pub mod config;
14mod guard;
15pub mod lazy;
16pub mod scoped;
17mod stats;
18#[cfg(test)]
19pub mod testing;
20pub mod thread_local;
21
22use std::{collections::HashMap, ops::Deref, rc::Rc};
23
24pub use config::{PoolConfig, init_default_thread_pools, init_test_pools, init_thread_pools};
25pub use guard::PooledGuard;
26pub use lazy::{ensure_thread_pools, get_or_init_pools, thread_pools_lazy};
27use reifydb_type::{Date, DateTime, Duration, Time, Uuid4, Uuid7};
28pub use scoped::{ScopedPools, with_default_pools, with_scoped_pools, with_test_pools};
29pub use thread_local::{get_thread_pools, has_thread_pools, thread_pools};
30
31use crate::value::{
32	column::pool::{
33		allocator::{PoolAllocator, StdPoolAllocator},
34		stats::PoolStats,
35	},
36	container::*,
37};
38
39#[derive(Clone)]
40pub struct Pools(Rc<PoolsInner>);
41
42impl Deref for Pools {
43	type Target = PoolsInner;
44
45	fn deref(&self) -> &Self::Target {
46		&self.0
47	}
48}
49
50pub struct PoolsInner {
51	bool_pool: StdPoolAllocator<BoolContainer>,
52	string_pool: StdPoolAllocator<Utf8Container>,
53	blob_pool: StdPoolAllocator<BlobContainer>,
54	row_number_pool: StdPoolAllocator<RowNumberContainer>,
55	undefined_pool: StdPoolAllocator<UndefinedContainer>,
56
57	// Numeric pools for all types
58	i8_pool: StdPoolAllocator<NumberContainer<i8>>,
59	i16_pool: StdPoolAllocator<NumberContainer<i16>>,
60	i32_pool: StdPoolAllocator<NumberContainer<i32>>,
61	i64_pool: StdPoolAllocator<NumberContainer<i64>>,
62	i128_pool: StdPoolAllocator<NumberContainer<i128>>,
63	u8_pool: StdPoolAllocator<NumberContainer<u8>>,
64	u16_pool: StdPoolAllocator<NumberContainer<u16>>,
65	u32_pool: StdPoolAllocator<NumberContainer<u32>>,
66	u64_pool: StdPoolAllocator<NumberContainer<u64>>,
67	u128_pool: StdPoolAllocator<NumberContainer<u128>>,
68	f32_pool: StdPoolAllocator<NumberContainer<f32>>,
69	f64_pool: StdPoolAllocator<NumberContainer<f64>>,
70
71	// Temporal pools
72	date_pool: StdPoolAllocator<TemporalContainer<Date>>,
73	datetime_pool: StdPoolAllocator<TemporalContainer<DateTime>>,
74	time_pool: StdPoolAllocator<TemporalContainer<Time>>,
75	duration_pool: StdPoolAllocator<TemporalContainer<Duration>>,
76
77	// UUID pools
78	uuid4_pool: StdPoolAllocator<UuidContainer<Uuid4>>,
79	uuid7_pool: StdPoolAllocator<UuidContainer<Uuid7>>,
80}
81
82impl Default for Pools {
83	fn default() -> Self {
84		Self::new(16) // Default max pool size of 16 containers per bucket
85	}
86}
87
88impl Pools {
89	pub fn new(max_pool_size: usize) -> Self {
90		Self(Rc::new(PoolsInner {
91			bool_pool: StdPoolAllocator::new(max_pool_size),
92			string_pool: StdPoolAllocator::new(max_pool_size),
93			blob_pool: StdPoolAllocator::new(max_pool_size),
94			row_number_pool: StdPoolAllocator::new(max_pool_size),
95			undefined_pool: StdPoolAllocator::new(max_pool_size),
96
97			i8_pool: StdPoolAllocator::new(max_pool_size),
98			i16_pool: StdPoolAllocator::new(max_pool_size),
99			i32_pool: StdPoolAllocator::new(max_pool_size),
100			i64_pool: StdPoolAllocator::new(max_pool_size),
101			i128_pool: StdPoolAllocator::new(max_pool_size),
102			u8_pool: StdPoolAllocator::new(max_pool_size),
103			u16_pool: StdPoolAllocator::new(max_pool_size),
104			u32_pool: StdPoolAllocator::new(max_pool_size),
105			u64_pool: StdPoolAllocator::new(max_pool_size),
106			u128_pool: StdPoolAllocator::new(max_pool_size),
107			f32_pool: StdPoolAllocator::new(max_pool_size),
108			f64_pool: StdPoolAllocator::new(max_pool_size),
109
110			date_pool: StdPoolAllocator::new(max_pool_size),
111			datetime_pool: StdPoolAllocator::new(max_pool_size),
112			time_pool: StdPoolAllocator::new(max_pool_size),
113			duration_pool: StdPoolAllocator::new(max_pool_size),
114
115			uuid4_pool: StdPoolAllocator::new(max_pool_size),
116			uuid7_pool: StdPoolAllocator::new(max_pool_size),
117		}))
118	}
119
120	// Accessors for each pool type
121	pub fn bool_pool(&self) -> &StdPoolAllocator<BoolContainer> {
122		&self.bool_pool
123	}
124	pub fn string_pool(&self) -> &StdPoolAllocator<Utf8Container> {
125		&self.string_pool
126	}
127	pub fn blob_pool(&self) -> &StdPoolAllocator<BlobContainer> {
128		&self.blob_pool
129	}
130	pub fn row_number_pool(&self) -> &StdPoolAllocator<RowNumberContainer> {
131		&self.row_number_pool
132	}
133	pub fn undefined_pool(&self) -> &StdPoolAllocator<UndefinedContainer> {
134		&self.undefined_pool
135	}
136
137	pub fn i8_pool(&self) -> &StdPoolAllocator<NumberContainer<i8>> {
138		&self.i8_pool
139	}
140	pub fn i16_pool(&self) -> &StdPoolAllocator<NumberContainer<i16>> {
141		&self.i16_pool
142	}
143	pub fn i32_pool(&self) -> &StdPoolAllocator<NumberContainer<i32>> {
144		&self.i32_pool
145	}
146	pub fn i64_pool(&self) -> &StdPoolAllocator<NumberContainer<i64>> {
147		&self.i64_pool
148	}
149	pub fn i128_pool(&self) -> &StdPoolAllocator<NumberContainer<i128>> {
150		&self.i128_pool
151	}
152	pub fn u8_pool(&self) -> &StdPoolAllocator<NumberContainer<u8>> {
153		&self.u8_pool
154	}
155	pub fn u16_pool(&self) -> &StdPoolAllocator<NumberContainer<u16>> {
156		&self.u16_pool
157	}
158	pub fn u32_pool(&self) -> &StdPoolAllocator<NumberContainer<u32>> {
159		&self.u32_pool
160	}
161	pub fn u64_pool(&self) -> &StdPoolAllocator<NumberContainer<u64>> {
162		&self.u64_pool
163	}
164	pub fn u128_pool(&self) -> &StdPoolAllocator<NumberContainer<u128>> {
165		&self.u128_pool
166	}
167	pub fn f32_pool(&self) -> &StdPoolAllocator<NumberContainer<f32>> {
168		&self.f32_pool
169	}
170	pub fn f64_pool(&self) -> &StdPoolAllocator<NumberContainer<f64>> {
171		&self.f64_pool
172	}
173
174	pub fn date_pool(&self) -> &StdPoolAllocator<TemporalContainer<Date>> {
175		&self.date_pool
176	}
177	pub fn datetime_pool(&self) -> &StdPoolAllocator<TemporalContainer<DateTime>> {
178		&self.datetime_pool
179	}
180	pub fn time_pool(&self) -> &StdPoolAllocator<TemporalContainer<Time>> {
181		&self.time_pool
182	}
183	pub fn duration_pool(&self) -> &StdPoolAllocator<TemporalContainer<Duration>> {
184		&self.duration_pool
185	}
186
187	pub fn uuid4_pool(&self) -> &StdPoolAllocator<UuidContainer<Uuid4>> {
188		&self.uuid4_pool
189	}
190	pub fn uuid7_pool(&self) -> &StdPoolAllocator<UuidContainer<Uuid7>> {
191		&self.uuid7_pool
192	}
193
194	/// Clear all pools
195	pub fn clear_all(&self) {
196		self.bool_pool.clear();
197		self.string_pool.clear();
198		self.blob_pool.clear();
199		self.row_number_pool.clear();
200		self.undefined_pool.clear();
201
202		self.i8_pool.clear();
203		self.i16_pool.clear();
204		self.i32_pool.clear();
205		self.i64_pool.clear();
206		self.i128_pool.clear();
207		self.u8_pool.clear();
208		self.u16_pool.clear();
209		self.u32_pool.clear();
210		self.u64_pool.clear();
211		self.u128_pool.clear();
212		self.f32_pool.clear();
213		self.f64_pool.clear();
214
215		self.date_pool.clear();
216		self.datetime_pool.clear();
217		self.time_pool.clear();
218		self.duration_pool.clear();
219
220		self.uuid4_pool.clear();
221		self.uuid7_pool.clear();
222	}
223
224	/// Get statistics for all pools
225	pub fn all_stats(&self) -> HashMap<String, PoolStats> {
226		let mut stats = HashMap::new();
227
228		stats.insert("bool".to_string(), self.bool_pool.stats());
229		stats.insert("string".to_string(), self.string_pool.stats());
230		stats.insert("blob".to_string(), self.blob_pool.stats());
231		stats.insert("row_number".to_string(), self.row_number_pool.stats());
232		stats.insert("undefined".to_string(), self.undefined_pool.stats());
233
234		stats.insert("i8".to_string(), self.i8_pool.stats());
235		stats.insert("i16".to_string(), self.i16_pool.stats());
236		stats.insert("i32".to_string(), self.i32_pool.stats());
237		stats.insert("i64".to_string(), self.i64_pool.stats());
238		stats.insert("i128".to_string(), self.i128_pool.stats());
239		stats.insert("u8".to_string(), self.u8_pool.stats());
240		stats.insert("u16".to_string(), self.u16_pool.stats());
241		stats.insert("u32".to_string(), self.u32_pool.stats());
242		stats.insert("u64".to_string(), self.u64_pool.stats());
243		stats.insert("u128".to_string(), self.u128_pool.stats());
244		stats.insert("f32".to_string(), self.f32_pool.stats());
245		stats.insert("f64".to_string(), self.f64_pool.stats());
246
247		stats.insert("date".to_string(), self.date_pool.stats());
248		stats.insert("datetime".to_string(), self.datetime_pool.stats());
249		stats.insert("time".to_string(), self.time_pool.stats());
250		stats.insert("duration".to_string(), self.duration_pool.stats());
251
252		stats.insert("uuid4".to_string(), self.uuid4_pool.stats());
253		stats.insert("uuid7".to_string(), self.uuid7_pool.stats());
254
255		stats
256	}
257}
258
259#[cfg(test)]
260mod tests {
261	use super::*;
262
263	#[test]
264	fn test_container_pools() {
265		let pools = Pools::new(4);
266
267		// Test different pool types
268		let bool_container = pools.bool_pool().acquire(10);
269		let string_container = pools.string_pool().acquire(20);
270		let i32_container = pools.i32_pool().acquire(30);
271
272		pools.bool_pool().release(bool_container);
273		pools.string_pool().release(string_container);
274		pools.i32_pool().release(i32_container);
275
276		let all_stats = pools.all_stats();
277		assert_eq!(all_stats["bool"].available, 1);
278		assert_eq!(all_stats["string"].available, 1);
279		assert_eq!(all_stats["i32"].available, 1);
280	}
281
282	#[test]
283	fn test_clear_pools() {
284		let pools = Pools::new(4);
285
286		let container = pools.bool_pool().acquire(10);
287		pools.bool_pool().release(container);
288
289		assert_eq!(pools.bool_pool().stats().available, 1);
290
291		pools.clear_all();
292
293		assert_eq!(pools.bool_pool().stats().available, 0);
294	}
295}