use parking_lot::Mutex;
use std::collections::HashSet;
use std::sync::Arc;
use tracing::info;
#[derive(Debug, Default)]
pub struct StringPool {
strings: Mutex<HashSet<Arc<str>>>,
}
impl StringPool {
pub fn new() -> Self {
Self::default()
}
pub fn with_capacity(capacity: usize) -> Self {
info!(capacity, "StringPool initialized");
Self {
strings: Mutex::new(HashSet::with_capacity(capacity)),
}
}
pub fn intern(&self, s: &str) -> Arc<str> {
let mut strings = self.strings.lock();
if let Some(existing) = strings.get(s) {
return Arc::clone(existing);
}
let arc: Arc<str> = Arc::from(s);
strings.insert(Arc::clone(&arc));
arc
}
pub fn len(&self) -> usize {
self.strings.lock().len()
}
pub fn is_empty(&self) -> bool {
self.strings.lock().is_empty()
}
pub fn clear(&self) {
self.strings.lock().clear();
}
pub fn stats(&self) -> PoolStats {
let strings = self.strings.lock();
let count = strings.len();
let total_bytes: usize = strings.iter().map(|s| s.len()).sum();
PoolStats {
count,
total_bytes,
avg_bytes: if count > 0 { total_bytes / count } else { 0 },
}
}
}
#[derive(Debug, Clone, Default)]
pub struct PoolStats {
pub count: usize,
pub total_bytes: usize,
pub avg_bytes: usize,
}
#[derive(Debug, Clone, PartialEq)]
pub enum CompactFilter {
EqInt {
field: Arc<str>,
value: i64,
},
EqBool {
field: Arc<str>,
value: bool,
},
EqStr {
field: Arc<str>,
value: Arc<str>,
},
IsNull {
field: Arc<str>,
},
IsNotNull {
field: Arc<str>,
},
GtInt {
field: Arc<str>,
value: i64,
},
LtInt {
field: Arc<str>,
value: i64,
},
And(Box<CompactFilter>, Box<CompactFilter>),
Or(Box<CompactFilter>, Box<CompactFilter>),
}
impl CompactFilter {
#[inline]
pub fn eq_int(field: impl Into<Arc<str>>, value: i64) -> Self {
Self::EqInt {
field: field.into(),
value,
}
}
#[inline]
pub fn eq_bool(field: impl Into<Arc<str>>, value: bool) -> Self {
Self::EqBool {
field: field.into(),
value,
}
}
#[inline]
pub fn eq_str(field: impl Into<Arc<str>>, value: impl Into<Arc<str>>) -> Self {
Self::EqStr {
field: field.into(),
value: value.into(),
}
}
#[inline]
pub fn is_null(field: impl Into<Arc<str>>) -> Self {
Self::IsNull {
field: field.into(),
}
}
#[inline]
pub fn is_not_null(field: impl Into<Arc<str>>) -> Self {
Self::IsNotNull {
field: field.into(),
}
}
#[inline]
pub fn gt_int(field: impl Into<Arc<str>>, value: i64) -> Self {
Self::GtInt {
field: field.into(),
value,
}
}
#[inline]
pub fn lt_int(field: impl Into<Arc<str>>, value: i64) -> Self {
Self::LtInt {
field: field.into(),
value,
}
}
#[inline]
pub fn and(self, other: Self) -> Self {
Self::And(Box::new(self), Box::new(other))
}
#[inline]
pub fn or(self, other: Self) -> Self {
Self::Or(Box::new(self), Box::new(other))
}
pub fn to_sql_postgres(&self, param_offset: &mut usize) -> String {
match self {
Self::EqInt { field, .. } => {
*param_offset += 1;
format!("{} = ${}", field, *param_offset)
}
Self::EqBool { field, .. } => {
*param_offset += 1;
format!("{} = ${}", field, *param_offset)
}
Self::EqStr { field, .. } => {
*param_offset += 1;
format!("{} = ${}", field, *param_offset)
}
Self::IsNull { field } => format!("{} IS NULL", field),
Self::IsNotNull { field } => format!("{} IS NOT NULL", field),
Self::GtInt { field, .. } => {
*param_offset += 1;
format!("{} > ${}", field, *param_offset)
}
Self::LtInt { field, .. } => {
*param_offset += 1;
format!("{} < ${}", field, *param_offset)
}
Self::And(left, right) => {
let left_sql = left.to_sql_postgres(param_offset);
let right_sql = right.to_sql_postgres(param_offset);
format!("({} AND {})", left_sql, right_sql)
}
Self::Or(left, right) => {
let left_sql = left.to_sql_postgres(param_offset);
let right_sql = right.to_sql_postgres(param_offset);
format!("({} OR {})", left_sql, right_sql)
}
}
}
pub fn size_bytes(&self) -> usize {
match self {
Self::EqInt { .. } | Self::GtInt { .. } | Self::LtInt { .. } => 24, Self::EqBool { .. } => 17, Self::EqStr { field, value } => 16 + field.len() + value.len(),
Self::IsNull { .. } | Self::IsNotNull { .. } => 16, Self::And(l, r) | Self::Or(l, r) => 16 + l.size_bytes() + r.size_bytes(),
}
}
}
#[derive(Debug, Default)]
pub struct BufferPool {
buffers: Mutex<Vec<String>>,
default_capacity: usize,
}
impl BufferPool {
pub fn new() -> Self {
Self {
buffers: Mutex::new(Vec::new()),
default_capacity: 256,
}
}
pub fn with_capacity(default_capacity: usize) -> Self {
info!(default_capacity, "BufferPool initialized");
Self {
buffers: Mutex::new(Vec::new()),
default_capacity,
}
}
pub fn get(&self) -> PooledBuffer<'_> {
let buffer = self
.buffers
.lock()
.pop()
.unwrap_or_else(|| String::with_capacity(self.default_capacity));
PooledBuffer { buffer, pool: self }
}
fn return_buffer(&self, mut buffer: String) {
buffer.clear();
if buffer.capacity() <= 4096 {
self.buffers.lock().push(buffer);
}
}
pub fn available(&self) -> usize {
self.buffers.lock().len()
}
pub fn clear(&self) {
self.buffers.lock().clear();
}
}
pub struct PooledBuffer<'a> {
buffer: String,
pool: &'a BufferPool,
}
impl<'a> PooledBuffer<'a> {
pub fn as_mut_str(&mut self) -> &mut String {
&mut self.buffer
}
pub fn take(mut self) -> String {
std::mem::take(&mut self.buffer)
}
}
impl<'a> std::ops::Deref for PooledBuffer<'a> {
type Target = String;
fn deref(&self) -> &Self::Target {
&self.buffer
}
}
impl<'a> std::ops::DerefMut for PooledBuffer<'a> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.buffer
}
}
impl<'a> Drop for PooledBuffer<'a> {
fn drop(&mut self) {
if !self.buffer.is_empty() || self.buffer.capacity() > 0 {
let buffer = std::mem::take(&mut self.buffer);
self.pool.return_buffer(buffer);
}
}
}
#[derive(Debug, Clone, Default)]
pub struct MemoryStats {
pub allocations: u64,
pub deallocations: u64,
pub current_bytes: usize,
pub peak_bytes: usize,
pub total_bytes: usize,
}
impl MemoryStats {
pub fn new() -> Self {
Self::default()
}
pub fn record_alloc(&mut self, bytes: usize) {
self.allocations += 1;
self.current_bytes += bytes;
self.total_bytes += bytes;
if self.current_bytes > self.peak_bytes {
self.peak_bytes = self.current_bytes;
}
}
pub fn record_dealloc(&mut self, bytes: usize) {
self.deallocations += 1;
self.current_bytes = self.current_bytes.saturating_sub(bytes);
}
pub fn net_allocations(&self) -> i64 {
self.allocations as i64 - self.deallocations as i64
}
}
pub static GLOBAL_STRING_POOL: std::sync::LazyLock<StringPool> = std::sync::LazyLock::new(|| {
let pool = StringPool::with_capacity(128);
for name in COMMON_FIELD_NAMES {
pool.intern(name);
}
pool
});
pub static GLOBAL_BUFFER_POOL: std::sync::LazyLock<BufferPool> =
std::sync::LazyLock::new(|| BufferPool::with_capacity(256));
const COMMON_FIELD_NAMES: &[&str] = &[
"id",
"uuid",
"name",
"email",
"username",
"password",
"title",
"description",
"content",
"body",
"status",
"type",
"role",
"active",
"enabled",
"deleted",
"verified",
"published",
"count",
"score",
"priority",
"order",
"position",
"age",
"amount",
"price",
"quantity",
"user_id",
"post_id",
"comment_id",
"category_id",
"parent_id",
"author_id",
"owner_id",
"created_at",
"updated_at",
"deleted_at",
"published_at",
"expires_at",
"starts_at",
"ends_at",
"last_login_at",
"verified_at",
"slug",
"url",
"path",
"key",
"value",
"token",
"code",
"version",
];
#[inline]
pub fn intern(s: &str) -> Arc<str> {
GLOBAL_STRING_POOL.intern(s)
}
#[inline]
pub fn get_buffer() -> PooledBuffer<'static> {
GLOBAL_BUFFER_POOL.get()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_string_pool_interning() {
let pool = StringPool::new();
let s1 = pool.intern("hello");
let s2 = pool.intern("hello");
assert!(Arc::ptr_eq(&s1, &s2));
assert_eq!(pool.len(), 1);
}
#[test]
fn test_string_pool_different_strings() {
let pool = StringPool::new();
let s1 = pool.intern("hello");
let s2 = pool.intern("world");
assert!(!Arc::ptr_eq(&s1, &s2));
assert_eq!(pool.len(), 2);
}
#[test]
fn test_compact_filter_eq_int() {
let filter = CompactFilter::eq_int(Arc::from("id"), 42);
let mut offset = 0;
let sql = filter.to_sql_postgres(&mut offset);
assert_eq!(sql, "id = $1");
assert_eq!(offset, 1);
}
#[test]
fn test_compact_filter_and() {
let filter = CompactFilter::eq_int(Arc::from("id"), 42)
.and(CompactFilter::eq_bool(Arc::from("active"), true));
let mut offset = 0;
let sql = filter.to_sql_postgres(&mut offset);
assert_eq!(sql, "(id = $1 AND active = $2)");
assert_eq!(offset, 2);
}
#[test]
fn test_compact_filter_is_null() {
let filter = CompactFilter::is_null(Arc::from("deleted_at"));
let mut offset = 0;
let sql = filter.to_sql_postgres(&mut offset);
assert_eq!(sql, "deleted_at IS NULL");
assert_eq!(offset, 0); }
#[test]
fn test_buffer_pool() {
let pool = BufferPool::new();
{
let mut buffer = pool.get();
buffer.push_str("hello");
assert_eq!(&*buffer, "hello");
}
assert_eq!(pool.available(), 1);
{
let buffer = pool.get();
assert!(buffer.is_empty()); }
}
#[test]
fn test_global_intern() {
let s1 = intern("id");
let s2 = intern("id");
assert!(Arc::ptr_eq(&s1, &s2));
}
#[test]
fn test_memory_stats() {
let mut stats = MemoryStats::new();
stats.record_alloc(100);
stats.record_alloc(200);
assert_eq!(stats.current_bytes, 300);
assert_eq!(stats.peak_bytes, 300);
stats.record_dealloc(100);
assert_eq!(stats.current_bytes, 200);
assert_eq!(stats.peak_bytes, 300); }
}