Skip to main content

dualcache_ff/tls/
std_tls.rs

1use super::TlsProvider;
2use crate::sync::atomic::{AtomicUsize, Ordering};
3use crate::sync::index_types::TickType;
4use core::cell::{Cell, RefCell};
5use std::sync::Mutex;
6use alloc::vec::Vec;
7
8struct IdAllocator {
9    free_list: Mutex<Vec<usize>>,
10    next_id: AtomicUsize,
11}
12
13static ALLOCATOR: IdAllocator = IdAllocator {
14    free_list: Mutex::new(Vec::new()),
15    next_id: AtomicUsize::new(0),
16};
17
18struct ThreadIdGuard {
19    id: usize,
20}
21
22impl Drop for ThreadIdGuard {
23    fn drop(&mut self) {
24        if let Ok(mut list) = ALLOCATOR.free_list.lock() {
25            list.push(self.id);
26        }
27    }
28}
29
30thread_local! {
31    static WORKER_ID: usize = {
32        let id = if let Ok(mut list) = ALLOCATOR.free_list.lock() {
33            list.pop().unwrap_or_else(|| ALLOCATOR.next_id.fetch_add(1, Ordering::Relaxed))
34        } else {
35            ALLOCATOR.next_id.fetch_add(1, Ordering::Relaxed)
36        };
37        
38        GUARD.with(|g| {
39            *g.borrow_mut() = Some(ThreadIdGuard { id });
40        });
41        id
42    };
43
44    static GUARD: RefCell<Option<ThreadIdGuard>> = const { RefCell::new(None) };
45
46    /// Hit index buffer: batches 64 Cache-hit global indices before sending
47    /// to Daemon via the hit queue.
48    static HIT_BUF: RefCell<([usize; 64], usize)> = const { RefCell::new(([0; 64], 0)) };
49
50    /// TLS probation filter: prevents single-hit items from reaching the
51    /// Arena. A 4 KB sketch that decays periodically.
52    static L1_FILTER: RefCell<([u8; 4096], usize)> = const { RefCell::new(([0; 4096], 0)) };
53
54    /// Task 6 — last daemon_tick observed at TLS flush time.
55    /// When `daemon_tick - LAST_FLUSH_TICK >= flush_tick_threshold`, the
56    /// Worker force-drains its TLS buffer even if it is not full.
57    static LAST_FLUSH_TICK: Cell<TickType> = const { Cell::new(0) };
58
59    /// Intelligent warmup state. 0 = full fast pass. >= 100 = normal mode.
60    static WARMUP_STATE: Cell<u8> = const { Cell::new(0) };
61}
62
63#[derive(Clone)]
64pub struct DefaultTls;
65
66impl TlsProvider for DefaultTls {
67    #[inline(always)]
68    fn get_worker_id(&self) -> Option<usize> {
69        Some(WORKER_ID.with(|id| *id))
70    }
71
72    #[inline(always)]
73    fn with_hit_buf(&self, f: &mut dyn FnMut(&mut ([usize; 64], usize))) {
74        HIT_BUF.with(|buf| {
75            f(&mut *buf.borrow_mut());
76        });
77    }
78
79    #[inline(always)]
80    fn with_l1_filter(&self, f: &mut dyn FnMut(&mut ([u8; 4096], usize))) {
81        L1_FILTER.with(|filter| {
82            f(&mut *filter.borrow_mut());
83        });
84    }
85
86    #[inline(always)]
87    fn with_last_flush_tick(&self, f: &mut dyn FnMut(&mut TickType)) {
88        LAST_FLUSH_TICK.with(|cell| {
89            let mut val = cell.get();
90            f(&mut val);
91            cell.set(val);
92        });
93    }
94
95    #[inline(always)]
96    fn with_warmup_state(&self, f: &mut dyn FnMut(&mut u8)) {
97        WARMUP_STATE.with(|cell| {
98            let mut val = cell.get();
99            f(&mut val);
100            cell.set(val);
101        });
102    }
103}