1#![cfg_attr(not(any(feature = "std", feature = "daemon", test)), no_std)]
2
3pub mod utils;
4pub mod componant;
5pub mod core;
6
7#[cfg(feature = "std")]
8use ::core::sync::atomic::{AtomicBool, Ordering};
9#[cfg(feature = "std")]
10use crate::componant::tls::{TlsRegistry, TlsHandle};
11#[cfg(feature = "std")]
12use crate::componant::daemon::DaemonMessage;
13
14#[cfg(feature = "std")]
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum ThreadCount {
17 Pool(usize),
18 Pin(usize),
19 Mixed(usize, usize),
20}
21
22#[cfg(feature = "std")]
23#[repr(C, align(64))]
26pub struct DualCacheFF<
27 K,
28 V,
29 P,
30 const CAP2: usize,
31 const CAP1: usize,
32 const CAP0: usize,
33 const TOTAL_CAP: usize,
34 const MAX_THREADS: usize,
35 const TLS_CAP: usize,
36 const TLS_INDEX_CAP: usize,
37>
38where
39 P: crate::componant::config::CachePolicy + Send + Sync,
40{
41 core: crate::core::DualCacheCore<K, V, P, CAP2, CAP1, CAP0, TOTAL_CAP>,
42 pub daemon_mode: AtomicBool,
43 #[cfg(feature = "std")]
44 pub cata_mode: AtomicBool,
45 pub tls_registry: TlsRegistry<K, V, MAX_THREADS, TLS_CAP, TLS_INDEX_CAP>,
46 #[cfg(feature = "std")]
47 #[allow(clippy::type_complexity)]
48 pub global_tx: std::sync::RwLock<Option<::std::sync::Arc<no_std_tool::collections::mpsc_queue::BoundedQueue<DaemonMessage<K, V>, 65536>>>>,
49 #[cfg(feature = "std")]
50 pub daemon_handle: std::sync::RwLock<Option<crate::componant::daemon::Daemon>>,
51}
52
53#[cfg(feature = "std")]
54impl<
55 K,
56 V,
57 P,
58 const CAP2: usize,
59 const CAP1: usize,
60 const CAP0: usize,
61 const TOTAL_CAP: usize,
62 const MAX_THREADS: usize,
63 const TLS_CAP: usize,
64 const TLS_INDEX_CAP: usize,
65> Default for DualCacheFF<K, V, P, CAP2, CAP1, CAP0, TOTAL_CAP, MAX_THREADS, TLS_CAP, TLS_INDEX_CAP>
66where
67 K: Clone + Eq + ::core::hash::Hash + Send + Sync + 'static,
68 V: Clone + Send + Sync + 'static,
69 P: crate::componant::config::CachePolicy + Send + Sync + 'static,
70 {
71 fn default() -> Self {
72 Self::new(P::Evict::default())
73 }
74}
75
76#[cfg(feature = "std")]
77impl<
78 K,
79 V,
80 P,
81 const CAP2: usize,
82 const CAP1: usize,
83 const CAP0: usize,
84 const TOTAL_CAP: usize,
85 const MAX_THREADS: usize,
86 const TLS_CAP: usize,
87 const TLS_INDEX_CAP: usize,
88> DualCacheFF<K, V, P, CAP2, CAP1, CAP0, TOTAL_CAP, MAX_THREADS, TLS_CAP, TLS_INDEX_CAP>
89where
90 K: Clone + Eq + ::core::hash::Hash + Send + Sync + 'static,
91 V: Clone + Send + Sync + 'static,
92 P: crate::componant::config::CachePolicy + Send + Sync + 'static,
93{
94 pub const fn new(eviction: P::Evict) -> Self {
95 Self {
96 core: crate::core::DualCacheCore::new(eviction),
97 daemon_mode: AtomicBool::new(false),
98 #[cfg(feature = "std")]
99 cata_mode: AtomicBool::new(false),
100 tls_registry: TlsRegistry::new(),
101 #[cfg(feature = "std")]
102 global_tx: std::sync::RwLock::new(None),
103 #[cfg(feature = "std")]
104 daemon_handle: std::sync::RwLock::new(None),
105 }
106 }
107
108 #[cfg(feature = "std")]
110 pub fn set_cata_tuning(&'static self, on: bool) {
111 if on && !self.cata_mode.swap(true, std::sync::atomic::Ordering::SeqCst) {
112 crate::componant::cata::spawn_demiurge(self);
113 } else if !on {
114 self.cata_mode.store(false, std::sync::atomic::Ordering::SeqCst);
115 }
116 }
117
118 #[cfg(feature = "std")]
121 pub fn set_daemon_mode(&'static self, on: bool) {
122 self.daemon_mode.store(on, Ordering::SeqCst);
123
124 if on {
125 let tx = unsafe { ::std::sync::Arc::<no_std_tool::collections::mpsc_queue::BoundedQueue<DaemonMessage<K, V>, 65536>>::new_zeroed().assume_init() };
126 let rx = tx.clone();
127 let mut broadcast_txs = std::vec::Vec::with_capacity(self.tls_registry.max_threads());
128
129 for i in 0..self.tls_registry.max_threads() {
130 let dummy_handle = TlsHandle { id: i, qsbr_node: ::core::ptr::null_mut() };
131 let block = self.tls_registry.get_block_mut(&dummy_handle);
132 block.tx = Some(tx.clone());
133
134 let hit_queue = unsafe { ::std::sync::Arc::<no_std_tool::collections::mpsc_queue::BoundedQueue<(usize, u8), 1024>>::new_zeroed().assume_init() };
135 block.hit_rx = Some(hit_queue.clone());
136 broadcast_txs.push(hit_queue);
137 }
138
139 let daemon_node = {
140 let node = std::boxed::Box::into_raw(std::boxed::Box::new(crate::componant::qsbr::ThreadStateNode::new()));
141 crate::componant::qsbr::register_node(node);
142 node
143 };
144 let daemon = crate::componant::daemon::Daemon::spawn(&self.core, rx, broadcast_txs, daemon_node);
145 if let Ok(mut handle_guard) = self.daemon_handle.write() {
146 *handle_guard = Some(daemon);
147 }
148 if let Ok(mut gtx) = self.global_tx.write() {
149 *gtx = Some(tx.clone());
150 }
151 } else {
152 if let Ok(mut gtx) = self.global_tx.write() {
153 *gtx = None;
154 }
155 self.tls_registry.clear_channels();
156 if let Ok(mut handle_guard) = self.daemon_handle.write()
157 && let Some(mut daemon) = handle_guard.take()
158 {
159 daemon.join();
160 }
161 }
162 }
163
164 pub fn register_thread(&self) -> TlsHandle {
166 let handle = self.tls_registry.register_thread();
167
168 #[cfg(feature = "std")]
169 if let Ok(gtx) = self.global_tx.read()
170 && let Some(ref global_tx) = *gtx {
171 let block = self.tls_registry.get_block_mut(&handle);
172 block.tx = Some(global_tx.clone());
173 }
174
175 handle
176 }
177
178 pub fn get(&self, key: &K, handle: &TlsHandle) -> Option<V> {
179 let block = self.tls_registry.get_block_mut(handle);
180 block.op_count = block.op_count.wrapping_add(1);
181
182 let op_count = block.op_count as u32;
183
184 #[cfg(feature = "std")]
185 if op_count & 63 == 0 {
186 let global = crate::componant::qsbr::get_global_epoch();
187 unsafe {
188 let node = &mut *handle.qsbr_node;
189 node.epoch.store(global, ::core::sync::atomic::Ordering::Relaxed);
190 node.active.store(true, ::core::sync::atomic::Ordering::Relaxed);
191 }
192 }
193
194 let guard = ::core::mem::ManuallyDrop::new(unsafe { crate::componant::qsbr::Guard::unpinned(handle.qsbr_node) });
195 let hash = self.core.hash_key(key);
196
197 if let Some(val) = self.core.get_t0(hash, key, &guard, op_count) {
199 block.warmup_state = block.warmup_state.saturating_add(10);
200 block.cache.insert_fast_pass(hash, key.clone(), val.clone());
201 return Some(val.clone());
202 }
203
204 if let Some(val) = self.core.get_t1(hash, key, &guard, op_count) {
206 block.cache.insert(hash, key.clone(), val.clone());
207 return Some(val.clone());
208 }
209
210 let (val_opt, promote, _sync) = block.cache.get(hash, key);
212 if let Some(val) = val_opt {
213 if promote {
214 self.core.put_t0(key.clone(), val.clone(), handle.qsbr_node);
215 }
216 #[cfg(feature = "std")]
217 if _sync > 0 {
218 if block.hit_batch_len < 32 {
219 block.hit_batch[block.hit_batch_len as usize] = (hash, _sync);
220 block.hit_batch_len += 1;
221 }
222 if block.hit_batch_len == 32 {
223 if let Some(ref tx) = block.tx {
224 let mut batch = [(0, 0); 32];
225 batch.copy_from_slice(&block.hit_batch);
226 let _ = tx.push(crate::componant::daemon::DaemonMessage::HitBatch(batch, 32));
227 }
228 block.hit_batch_len = 0;
229 }
230 }
231 return Some(val.clone());
232 }
233
234 if let Some(val) = self.core.get_t2(hash, key, &guard, op_count) {
236 block.warmup_state = block.warmup_state.saturating_sub(10);
237 block.cache.insert(hash, key.clone(), val.0.clone());
238 return Some(val.0.clone());
239 }
240 None
241 }
242
243 pub fn insert(&self, key: K, value: V, handle: &TlsHandle) {
244 let block = self.tls_registry.get_block_mut(handle);
245 block.op_count = block.op_count.wrapping_add(1);
246 if crate::utils::unlikely(block.op_count.is_multiple_of(64)) {
247 self.core.try_reclaim(handle.qsbr_node);
248 }
249
250 let hash = self.core.hash_key(&key);
251
252 if block.warmup_state > 50 {
253 block.cache.insert_fast_pass(hash, key.clone(), value.clone());
254 self.core.put_t0(key, value, handle.qsbr_node);
255 block.warmup_state = block.warmup_state.saturating_sub(20);
256 } else {
257 if block.cache.insert(hash, key.clone(), value.clone()) {
258 self.core.put(key, value, handle.qsbr_node);
259 }
260 }
261 }
262
263 pub fn warmup(&self, key: K, value: V, handle: &TlsHandle) {
267 let block = self.tls_registry.get_block_mut(handle);
268 block.op_count = block.op_count.wrapping_add(1);
269 if crate::utils::unlikely(block.op_count.is_multiple_of(64)) {
270 self.core.try_reclaim(handle.qsbr_node);
271 }
272
273 let hash = self.core.hash_key(&key);
274 block.cache.insert_fast_pass(hash, key.clone(), value.clone());
275 self.core.put_t0(key, value, handle.qsbr_node);
276 }
277}
278
279#[cfg(feature = "std")]
280unsafe impl<
281 K,
282 V,
283 P,
284 const CAP2: usize,
285 const CAP1: usize,
286 const CAP0: usize,
287 const TOTAL_CAP: usize,
288 const MAX_THREADS: usize,
289 const TLS_CAP: usize,
290 const TLS_INDEX_CAP: usize,
291> Send for DualCacheFF<K, V, P, CAP2, CAP1, CAP0, TOTAL_CAP, MAX_THREADS, TLS_CAP, TLS_INDEX_CAP>
292where
293 P: crate::componant::config::CachePolicy + Send + Sync,
294{}
295
296#[cfg(feature = "std")]
297unsafe impl<
298 K,
299 V,
300 P,
301 const CAP2: usize,
302 const CAP1: usize,
303 const CAP0: usize,
304 const TOTAL_CAP: usize,
305 const MAX_THREADS: usize,
306 const TLS_CAP: usize,
307 const TLS_INDEX_CAP: usize,
308> Sync for DualCacheFF<K, V, P, CAP2, CAP1, CAP0, TOTAL_CAP, MAX_THREADS, TLS_CAP, TLS_INDEX_CAP>
309where
310 P: crate::componant::config::CachePolicy + Send + Sync,
311{}
312
313
314#[cfg(feature = "std")]
315impl<
316 K, V, P,
317 const CAP2: usize, const CAP1: usize, const CAP0: usize, const TOTAL_CAP: usize,
318 const MAX_THREADS: usize, const TLS_CAP: usize, const TLS_INDEX_CAP: usize
319> DualCacheFF<K, V, P, CAP2, CAP1, CAP0, TOTAL_CAP, MAX_THREADS, TLS_CAP, TLS_INDEX_CAP>
320where
321 K: Clone + Eq,
322 V: Clone,
323 P: crate::componant::config::CachePolicy + Send + Sync,
324{
325 pub fn get_metrics(&self) -> (u64, u64) {
326 self.tls_registry.get_metrics()
327 }
328}
329
330#[cfg(feature = "std")]
331impl<
332 K, V, P,
333 const T0_CAP: usize, const T1_CAP: usize, const T2_CAP: usize, const TOTAL_CAP: usize,
334 const MAX_THREADS: usize, const TLS_CAP: usize, const TLS_INDEX_CAP: usize
335> Drop for DualCacheFF<K, V, P, T0_CAP, T1_CAP, T2_CAP, TOTAL_CAP, MAX_THREADS, TLS_CAP, TLS_INDEX_CAP>
336where
337 P: crate::componant::config::CachePolicy + Send + Sync,
338{
339 fn drop(&mut self) {
340 self.daemon_mode.store(false, ::core::sync::atomic::Ordering::SeqCst);
343 self.cata_mode.store(false, ::core::sync::atomic::Ordering::SeqCst);
344
345 if let Ok(mut gtx) = self.global_tx.write() {
347 *gtx = None;
348 }
349 self.tls_registry.clear_channels();
350
351 if let Ok(mut handle_guard) = self.daemon_handle.write()
353 && let Some(mut daemon) = handle_guard.take()
354 {
355 daemon.join();
356 }
357
358 }
360}
361
362#[cfg(test)]
363mod tests {
364 use super::*;
365 use std::thread;
366
367 #[test]
368 fn test_static_global_cache() {
369 static GLOBAL_CACHE: DualCacheFF<u64, u64, crate::componant::config::DefaultExponentialPolicy, 256, 1024, 2048, 1024, 10, 256, 512> = DualCacheFF::new(crate::componant::policy::DefaultEvictionPolicy::new());
370 let handle = GLOBAL_CACHE.register_thread();
371 GLOBAL_CACHE.insert(1, 100, &handle);
372 GLOBAL_CACHE.insert(1, 100, &handle);
373 assert_eq!(GLOBAL_CACHE.get(&1, &handle), Some(100));
374 }
375
376 #[test]
377 fn test_daemon_off_sync() {
378 static CACHE: DualCacheFF<u64, u64, crate::componant::config::DefaultExponentialPolicy, 256, 1024, 2048, 4096, 10, 256, 512> = DualCacheFF::new(crate::componant::policy::DefaultEvictionPolicy::new());
379 let handle = CACHE.register_thread();
380
381 CACHE.insert(1, 100, &handle);
383 CACHE.insert(1, 100, &handle);
384 assert_eq!(CACHE.get(&1, &handle), Some(100));
385
386 CACHE.insert(2, 200, &handle);
388 CACHE.insert(2, 200, &handle);
389 assert_eq!(CACHE.get(&2, &handle), Some(200));
390 }
391
392 #[cfg(feature = "std")]
393 #[test]
394 fn test_daemon_on_async() {
395 use std::time::Duration;
396
397 static CACHE: DualCacheFF<u64, u64, crate::componant::config::DefaultExponentialPolicy, 8, 16, 64, 88, 10, 256, 512> = DualCacheFF::new(crate::componant::policy::DefaultEvictionPolicy::new());
398
399 CACHE.set_daemon_mode(true);
401
402 let handle = CACHE.register_thread();
403
404 CACHE.insert(10, 1000, &handle);
406 CACHE.insert(10, 1000, &handle);
407
408 for i in 100..175 {
411 CACHE.insert(i, i * 10, &handle);
412 CACHE.insert(i, i * 10, &handle);
413 }
414
415 for _ in 0..5 {
417 let _ = CACHE.get(&10, &handle);
418 }
419
420 if let Ok(gtx) = CACHE.global_tx.read() {
422 if let Some(ref tx) = *gtx {
423 let _ = tx.push(crate::componant::daemon::DaemonMessage::SetPollInterval(5));
424
425 let ack = crate::componant::daemon::OneshotAck::new();
426 let _ = tx.push(crate::componant::daemon::DaemonMessage::Sync(ack.clone()));
427 ack.wait();
428 }
429 }
430
431 thread::sleep(Duration::from_millis(50));
433
434 assert_eq!(CACHE.get(&10, &handle), Some(1000));
436
437 CACHE.set_daemon_mode(false);
439 thread::sleep(Duration::from_millis(50));
440 }
441
442 #[cfg(feature = "std")]
443 #[test]
444 fn test_extensive_coverage() {
445 use std::time::Duration;
446
447 static CACHE: DualCacheFF<u64, u64, crate::componant::config::DefaultExponentialPolicy, 256, 1024, 2048, 4096, 10, 256, 512> = DualCacheFF::new(crate::componant::policy::DefaultEvictionPolicy::new());
448 let handle = CACHE.register_thread();
449
450 for i in 0..100 {
452 CACHE.insert(i, i * 10, &handle);
453 CACHE.insert(i, i * 10, &handle); CACHE.get(&i, &handle);
455 }
456
457 for _ in 0..300 {
459 CACHE.get(&10, &handle);
460 }
461
462 CACHE.set_daemon_mode(true);
464
465 for i in 100..200 {
467 CACHE.insert(i, i * 10, &handle);
468 CACHE.insert(i, i * 10, &handle); for _ in 0..100 {
471 CACHE.get(&i, &handle);
472 }
473 }
474 std::thread::sleep(Duration::from_millis(50));
476
477 if let Ok(gtx) = CACHE.global_tx.read()
479 && let Some(ref tx) = *gtx
480 {
481 let _ = tx.push(crate::componant::daemon::DaemonMessage::Promote(999, 999, 9990, 0));
482 let _ = tx.push(crate::componant::daemon::DaemonMessage::Promote(888, 888, 8880, 2));
483
484 let mut arr = [(0usize, 0u8); 32];
486 arr[0] = (123, 10);
487 arr[1] = (123, 5); arr[2] = (456, 1);
489 let _ = tx.push(crate::componant::daemon::DaemonMessage::HitBatch(arr, 3));
490 }
491 std::thread::sleep(Duration::from_millis(50));
492
493 let handle2 = CACHE.register_thread();
494 for i in 100..200 {
495 CACHE.get(&i, &handle2);
497 }
498
499 for i in 1000..2000 {
501 CACHE.insert(i, i * 10, &handle);
502 }
503
504 for i in 1000..2000 {
508 CACHE.get(&i, &handle2);
509 }
510
511 let warmup = CACHE.tls_registry.get_block_mut(&handle2).warmup_state;
512 println!("Warmup state for handle2 after 1000 gets: {}", warmup);
513
514 for i in 2000..3000 {
517 CACHE.insert(i, i * 10, &handle2);
518 CACHE.insert(i, i * 10, &handle2); }
520
521 for _ in 1..9 {
523 let _ = CACHE.register_thread();
524 }
525 let res = std::panic::catch_unwind(|| {
527 let _ = CACHE.register_thread(); });
529 assert!(res.is_err());
530
531 if let Ok(gtx) = CACHE.global_tx.read() {
533 if let Some(ref tx) = *gtx {
534 let _ = tx.push(crate::componant::daemon::DaemonMessage::Promote(123, 123, 123, 0));
535
536 let _ = tx.push(crate::componant::daemon::DaemonMessage::SetPollInterval(5));
538
539 let ack = crate::componant::daemon::OneshotAck::new();
540 let _ = tx.push(crate::componant::daemon::DaemonMessage::Sync(ack.clone()));
541 ack.wait();
542
543 }
545 } thread::sleep(Duration::from_millis(50));
547
548 CACHE.set_daemon_mode(false);
550
551 thread::sleep(Duration::from_millis(50));
553
554 CACHE.core.try_reclaim(handle.qsbr_node);
556 CACHE.core.try_reclaim(handle.qsbr_node);
557 }
558}