1use crate::{
2 api::stmt,
3 catalogs, config, conn,
4 runtime::{Error, heap::layout::Layout, local, 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 = local::State::<I>::RETENTION_BYTES
35 .checked_add(phase)
36 .and_then(|bytes| bytes.checked_add(arena))
37 .ok_or(Error::CapacityOverflow)?;
38 let backing = retain
39 .checked_add(results)
40 .and_then(|bytes| bytes.checked_add(stmts.slots_bytes))
41 .and_then(|bytes| bytes.checked_add(aside))
42 .ok_or(Error::CapacityOverflow)?;
43 let targets =
44 Targets::new(self.cache, self.statement_bytes).ok_or(Error::CapacityOverflow)?;
45 Ok((
46 Reservation {
47 backing_bytes: backing,
48 control_bytes: retain - self.sqlite_bytes,
49 sqlite_bytes: self.sqlite_bytes,
50 sqlite_capacity: sqlite.capacity(),
51 result_bytes: results,
52 statements: stmts,
53 lookaside_bytes: aside,
54 targets,
55 },
56 sqlite,
57 ))
58 }
59}
60
61fn round(bytes: usize) -> Option<usize> {
62 Some(bytes.checked_add(63)? / 64 * 64)
63}
64
65#[derive(Clone, Copy, PartialEq, Eq)]
66pub struct Results {
67 pub rows: usize,
68 pub bytes: usize,
69}
70
71#[derive(Clone, Copy, PartialEq, Eq)]
72pub struct Cache {
73 pub main_bytes: usize,
74 pub temporary_bytes: usize,
75}
76
77#[derive(Clone, Copy, PartialEq, Eq)]
78pub struct Lookaside {
79 slot_bytes: u16,
80 slots: u16,
81}
82
83impl Lookaside {
84 pub const DISABLED: Self = Self {
85 slot_bytes: 0,
86 slots: 0,
87 };
88
89 pub const fn try_new(bytes: u16, slots: u16) -> Option<Self> {
90 if bytes as usize <= size_of::<usize>()
91 || !bytes.is_multiple_of(8)
92 || slots == 0
93 || bytes as u32 * slots as u32 > 0x7fff0000
94 {
95 return None;
96 }
97 Some(Self {
98 slot_bytes: bytes,
99 slots,
100 })
101 }
102
103 pub const fn slot_bytes(self) -> usize {
104 self.slot_bytes as usize
105 }
106
107 pub const fn slots(self) -> usize {
108 self.slots as usize
109 }
110
111 pub const fn bytes(self) -> usize {
112 const { assert!(usize::BITS >= 2 * u16::BITS) };
113 self.slot_bytes() * self.slots()
114 }
115
116 pub(crate) const fn sqlite_parts(self) -> (i32, i32) {
117 (self.slot_bytes as i32, self.slots as i32)
118 }
119}
120
121#[derive(Clone, Copy, PartialEq, Eq)]
122pub struct Reservation {
123 pub backing_bytes: usize,
125 pub control_bytes: usize,
127 pub sqlite_bytes: usize,
129 pub sqlite_capacity: usize,
131 pub result_bytes: usize,
133 pub statements: Statements,
135 pub lookaside_bytes: usize,
137 pub targets: Targets,
139}
140
141#[derive(Clone, Copy, PartialEq, Eq)]
142pub struct Statements {
143 pub catalog: crate::Shape,
145 pub items: usize,
147 pub sql_bytes: usize,
149 pub slots_bytes: usize,
151}
152
153impl Statements {
154 fn new(catalog: crate::Shape) -> Option<Self> {
155 let items = catalog
156 .statements
157 .checked_add(config::CONTROL_STATEMENT_ITEMS)?;
158 let sql = catalog.max_sql_bytes.max(stmt::Control::MAX_SQL_BYTES);
159 let bytes = stmt::bytes(items)?;
160 Some(Self {
161 catalog,
162 items,
163 sql_bytes: sql,
164 slots_bytes: bytes,
165 })
166 }
167}
168
169#[derive(Clone, Copy, PartialEq, Eq)]
170pub struct Targets {
171 pub statements: usize,
173 pub pager: usize,
175 pub retained: usize,
177}
178
179impl Targets {
180 fn new(cache: Cache, stmts: usize) -> Option<Self> {
181 let pager = cache.main_bytes.checked_add(cache.temporary_bytes)?;
182 let retained = pager.checked_add(stmts)?;
183 Some(Self {
184 statements: stmts,
185 pager,
186 retained,
187 })
188 }
189}