Skip to main content

cartel_sqlite/settings/
memory.rs

1use crate::{
2    api::stmt,
3    catalogs, config, conn,
4    runtime::{Error, heap::layout::Layout, raw},
5};
6
7#[derive(Clone, Copy, PartialEq, Eq)]
8pub struct Memory {
9    pub sqlite_bytes: usize,
10    pub results: Results,
11    pub statement_bytes: usize,
12    pub cache: Cache,
13    pub lookaside: Lookaside,
14}
15
16impl Memory {
17    /// Computes the exact worker backing reservation for a catalog.
18    pub fn reservation<I: crate::Catalog>(self) -> Option<Reservation> {
19        self.admit::<I>().ok().map(|(plan, _)| plan)
20    }
21
22    pub(crate) fn admit<I: crate::Catalog>(self) -> Result<(Reservation, Layout), Error> {
23        let sqlite = Layout::new(self.sqlite_bytes).ok_or(Error::SqliteBytes)?;
24        let shape = catalogs::Shape::of::<I>();
25        let stmts = Statements::new(shape).ok_or(Error::CapacityOverflow)?;
26        let results = round(self.results.bytes).ok_or(Error::CapacityOverflow)?;
27        let aside = round(self.lookaside.bytes()).ok_or(Error::CapacityOverflow)?;
28        let phase = conn::raw::Vacant::<'_, '_, I>::LAYOUT;
29        if phase.align() > raw::Span::ALIGNMENT {
30            return Err(Error::Layout);
31        }
32        let phase = round(phase.size()).ok_or(Error::CapacityOverflow)?;
33        let arena = sqlite.backing().ok_or(Error::CapacityOverflow)?;
34        let retain = phase.checked_add(arena).ok_or(Error::CapacityOverflow)?;
35        let backing = retain
36            .checked_add(results)
37            .and_then(|bytes| bytes.checked_add(stmts.slots_bytes))
38            .and_then(|bytes| bytes.checked_add(aside))
39            .ok_or(Error::CapacityOverflow)?;
40        let targets =
41            Targets::new(self.cache, self.statement_bytes).ok_or(Error::CapacityOverflow)?;
42        Ok((
43            Reservation {
44                backing_bytes: backing,
45                control_bytes: retain - self.sqlite_bytes,
46                sqlite_bytes: self.sqlite_bytes,
47                sqlite_capacity: sqlite.capacity(),
48                result_bytes: results,
49                statements: stmts,
50                lookaside_bytes: aside,
51                targets,
52            },
53            sqlite,
54        ))
55    }
56}
57
58fn round(bytes: usize) -> Option<usize> {
59    Some(bytes.checked_add(63)? / 64 * 64)
60}
61
62#[derive(Clone, Copy, PartialEq, Eq)]
63pub struct Results {
64    pub rows: usize,
65    pub bytes: usize,
66}
67
68#[derive(Clone, Copy, PartialEq, Eq)]
69pub struct Cache {
70    pub main_bytes: usize,
71    pub temporary_bytes: usize,
72}
73
74#[derive(Clone, Copy, PartialEq, Eq)]
75pub struct Lookaside {
76    slot_bytes: u16,
77    slots: u16,
78}
79
80impl Lookaside {
81    pub const DISABLED: Self = Self {
82        slot_bytes: 0,
83        slots: 0,
84    };
85
86    pub const fn try_new(bytes: u16, slots: u16) -> Option<Self> {
87        if bytes as usize <= size_of::<usize>()
88            || !bytes.is_multiple_of(8)
89            || slots == 0
90            || bytes as u32 * slots as u32 > 0x7fff0000
91        {
92            return None;
93        }
94        Some(Self {
95            slot_bytes: bytes,
96            slots,
97        })
98    }
99
100    pub const fn slot_bytes(self) -> usize {
101        self.slot_bytes as usize
102    }
103
104    pub const fn slots(self) -> usize {
105        self.slots as usize
106    }
107
108    pub const fn bytes(self) -> usize {
109        const { assert!(usize::BITS >= 2 * u16::BITS) };
110        self.slot_bytes() * self.slots()
111    }
112
113    pub(crate) const fn sqlite_parts(self) -> (i32, i32) {
114        (self.slot_bytes as i32, self.slots as i32)
115    }
116}
117
118#[derive(Clone, Copy, PartialEq, Eq)]
119pub struct Reservation {
120    /// Total bytes in the worker's single aligned backing allocation.
121    pub backing_bytes: usize,
122    /// Connection state, intrusive ownership and allocator control in the same allocation.
123    pub control_bytes: usize,
124    /// Physical partition reserved for SQLite's allocator.
125    pub sqlite_bytes: usize,
126    /// Usable SQLite allocation capacity after allocator metadata.
127    pub sqlite_capacity: usize,
128    /// Aligned retained-result arena bytes.
129    pub result_bytes: usize,
130    /// Validated prepared-statement layout.
131    pub statements: Statements,
132    /// Aligned per-connection lookaside bytes.
133    pub lookaside_bytes: usize,
134    /// Logical targets charged to SQLite's allocator partition.
135    pub targets: Targets,
136}
137
138#[derive(Clone, Copy, PartialEq, Eq)]
139pub struct Statements {
140    /// Validated compile-time catalog shape.
141    pub catalog: crate::Shape,
142    /// Prepared catalog and internal control statement slots.
143    pub items: usize,
144    /// Maximum SQL bytes across catalog and internal control statements.
145    pub sql_bytes: usize,
146    /// Aligned prepared-statement registry bytes.
147    pub slots_bytes: usize,
148}
149
150impl Statements {
151    fn new(catalog: crate::Shape) -> Option<Self> {
152        let items = catalog
153            .statements
154            .checked_add(config::CONTROL_STATEMENT_ITEMS)?;
155        let sql = catalog.max_sql_bytes.max(stmt::Control::MAX_SQL_BYTES);
156        let bytes = stmt::bytes(items)?;
157        Some(Self {
158            catalog,
159            items,
160            sql_bytes: sql,
161            slots_bytes: bytes,
162        })
163    }
164}
165
166#[derive(Clone, Copy, PartialEq, Eq)]
167pub struct Targets {
168    /// SQLite-reported prepared-program bytes.
169    pub statements: usize,
170    /// Main plus temporary page-cache bytes.
171    pub pager: usize,
172    /// Statements plus page-cache bytes.
173    pub retained: usize,
174}
175
176impl Targets {
177    fn new(cache: Cache, stmts: usize) -> Option<Self> {
178        let pager = cache.main_bytes.checked_add(cache.temporary_bytes)?;
179        let retained = pager.checked_add(stmts)?;
180        Some(Self {
181            statements: stmts,
182            pager,
183            retained,
184        })
185    }
186}