Skip to main content

qualia_core_db/inference/
thermal_wal.rs

1use bytemuck::{Pod, Zeroable};
2use memmap2::{MmapMut, MmapOptions};
3use std::fs::OpenOptions;
4use std::path::Path;
5
6#[repr(C)]
7#[derive(Copy, Clone, Debug, Pod, Zeroable)]
8pub struct ThermalEvictionRecord {
9    pub timestamp_ms: u64,
10    pub page_id: u32,
11    pub fast_entropy: f32,
12    pub top1_v: f32,
13    pub top2_v: f32,
14    pub reserved: [u8; 8], // align to 32 bytes
15}
16
17#[repr(C)]
18#[derive(Copy, Clone, Debug, Pod, Zeroable)]
19pub struct ThermalWalHeader {
20    pub magic: [u8; 4], // "WAL\0"
21    pub version: u32,
22    pub head: u32,          // index of next write
23    pub capacity: u32,      // total number of records
24    pub reserved: [u8; 48], // align to 64 bytes
25}
26
27pub struct ThermalWal {
28    mmap: MmapMut,
29    capacity: usize,
30    head: usize,
31}
32
33impl ThermalWal {
34    pub fn open(path: &Path, capacity_records: usize) -> std::io::Result<Self> {
35        let file_size = 64 + (capacity_records * 32);
36        let file = OpenOptions::new()
37            .read(true)
38            .write(true)
39            .create(true)
40            .open(path)?;
41        file.set_len(file_size as u64)?;
42
43        let mut mmap = unsafe { MmapOptions::new().map_mut(&file)? };
44
45        // initialize header if new
46        let header_ptr = mmap.as_mut_ptr() as *mut ThermalWalHeader;
47        let mut head = 0;
48        unsafe {
49            if (*header_ptr).magic != *b"WAL\0" {
50                (*header_ptr).magic = *b"WAL\0";
51                (*header_ptr).version = 1;
52                (*header_ptr).head = 0;
53                (*header_ptr).capacity = capacity_records as u32;
54            } else {
55                head = (*header_ptr).head as usize;
56            }
57        }
58
59        Ok(Self {
60            mmap,
61            capacity: capacity_records,
62            head,
63        })
64    }
65
66    pub fn append(&mut self, record: ThermalEvictionRecord) {
67        let offset = 64 + (self.head * 32);
68        let record_bytes = bytemuck::bytes_of(&record);
69        self.mmap[offset..offset + 32].copy_from_slice(record_bytes);
70
71        self.head = (self.head + 1) % self.capacity;
72        let header_ptr = self.mmap.as_mut_ptr() as *mut ThermalWalHeader;
73        unsafe {
74            (*header_ptr).head = self.head as u32;
75        }
76    }
77}