cartel_sqlite/settings/
memory.rs1use 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 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 pub backing_bytes: usize,
122 pub control_bytes: usize,
124 pub sqlite_bytes: usize,
126 pub sqlite_capacity: usize,
128 pub result_bytes: usize,
130 pub statements: Statements,
132 pub lookaside_bytes: usize,
134 pub targets: Targets,
136}
137
138#[derive(Clone, Copy, PartialEq, Eq)]
139pub struct Statements {
140 pub catalog: crate::Shape,
142 pub items: usize,
144 pub sql_bytes: usize,
146 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 pub statements: usize,
170 pub pager: usize,
172 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}