cartel_sqlite/runtime/raw/
mod.rs1mod vfs;
2
3use crate::{
4 runtime::{self, Error, heap, local},
5 sys,
6};
7use heap::layout::Layout;
8use o3::alloc;
9use std::{mem, ptr};
10
11#[repr(C, align(64))]
12struct Unit {
13 bytes: [mem::MaybeUninit<u8>; Span::ALIGNMENT],
14}
15
16pub(crate) struct Memory {
17 memory: alloc::array::Block<mem::MaybeUninit<Unit>, usize>,
18}
19
20pub(crate) struct Span {
21 base: ptr::NonNull<u8>,
22 bytes: usize,
23}
24
25#[must_use]
31pub struct Permit(pub(super) ());
32
33struct Setup(Permit);
35
36impl Permit {
37 pub unsafe fn exclusive() -> Self {
41 Self(())
42 }
43
44 pub(super) fn initialize(self) -> Result<Self, Error> {
45 if unsafe {
46 libsqlite3_sys::sqlite3_compileoption_used(c"ENABLE_MEMORY_MANAGEMENT".as_ptr())
47 } != 0
48 {
49 return Err(Error::GlobalCache);
50 }
51 if unsafe {
52 libsqlite3_sys::sqlite3_compileoption_used(c"DISABLE_PAGECACHE_OVERFLOW_STATS".as_ptr())
53 } == 0
54 {
55 return Err(Error::CacheStats);
56 }
57 if unsafe { libsqlite3_sys::sqlite3_compileoption_used(c"ENABLE_STMTVTAB".as_ptr()) } != 0 {
58 return Err(Error::StatementVtab);
59 }
60 if unsafe { libsqlite3_sys::sqlite3_compileoption_used(c"OMIT_WSD".as_ptr()) } != 0 {
61 return Err(Error::WritableStatic);
62 }
63 if unsafe { libsqlite3_sys::sqlite3_compileoption_used(c"ENABLE_SQLLOG".as_ptr()) } != 0 {
64 return Err(Error::StatementLog);
65 }
66 Setup(self).initialize()
67 }
68}
69
70impl Setup {
71 fn initialize(self) -> Result<Permit, Error> {
72 use heap::raw;
73 use vfs::Vfs;
74
75 let code =
76 unsafe { libsqlite3_sys::sqlite3_config(libsqlite3_sys::SQLITE_CONFIG_MULTITHREAD) };
77 if code != libsqlite3_sys::SQLITE_OK {
78 return Err(Error::Threading(sys::Code::new(code)));
79 }
80 unsafe {
84 libsqlite3_sys::sqlite3_config(libsqlite3_sys::SQLITE_CONFIG_URI, 0);
85 libsqlite3_sys::sqlite3_config(libsqlite3_sys::SQLITE_CONFIG_MEMSTATUS, 0);
86 libsqlite3_sys::sqlite3_config(
87 libsqlite3_sys::SQLITE_CONFIG_PAGECACHE,
88 ptr::null_mut::<std::ffi::c_void>(),
89 0,
90 20,
91 );
92 }
93 let cache = libsqlite3_sys::sqlite3_pcache_methods2 {
94 iVersion: 1,
95 pArg: ptr::null_mut(),
96 xInit: None,
97 xShutdown: None,
98 xCreate: None,
99 xCachesize: None,
100 xPagecount: None,
101 xFetch: None,
102 xUnpin: None,
103 xRekey: None,
104 xTruncate: None,
105 xDestroy: None,
106 xShrink: None,
107 };
108 unsafe {
111 libsqlite3_sys::sqlite3_config(libsqlite3_sys::SQLITE_CONFIG_PCACHE2, &raw const cache);
112 }
113 let hooks = raw::Hooks::new();
114 unsafe {
117 libsqlite3_sys::sqlite3_config(libsqlite3_sys::SQLITE_CONFIG_MALLOC, hooks.as_ptr());
118 }
119 let scope = raw::Foreign::enter();
120 let code = unsafe { libsqlite3_sys::sqlite3_initialize() };
121 let result = if code == libsqlite3_sys::SQLITE_OK {
122 unsafe { Vfs::install() }
123 } else {
124 Err(Error::Initialization(sys::Code::new(code)))
125 };
126 if result.is_err() {
127 unsafe { libsqlite3_sys::sqlite3_shutdown() };
130 }
131 drop(scope);
132 result?;
133 Ok(self.0)
134 }
135}
136
137impl Memory {
138 pub(in crate::runtime) fn new(
140 sqlite: Layout,
141 collect: usize,
142 stmts: usize,
143 aside: usize,
144 phase: std::alloc::Layout,
145 ) -> Result<(Self, heap::raw::Span, Span, Span, Span, Span), runtime::Error> {
146 if phase.align() > Span::ALIGNMENT {
147 return Err(runtime::Error::Layout);
148 }
149 let phase_bytes = Self::round(phase.size())?;
150 let rounded = Self::round(collect)?;
151 let aside = Self::round(aside)?;
152 let arena = sqlite.backing().ok_or(runtime::Error::CapacityOverflow)?;
153 let control = local::State::<crate::catalogs::Empty>::RETENTION_BYTES;
154 let start = control
155 .checked_add(phase_bytes)
156 .ok_or(runtime::Error::CapacityOverflow)?;
157 let retain = start
158 .checked_add(arena)
159 .ok_or(runtime::Error::CapacityOverflow)?;
160 let bytes = retain
161 .checked_add(rounded)
162 .and_then(|total| total.checked_add(stmts))
163 .and_then(|total| total.checked_add(aside))
164 .ok_or(runtime::Error::CapacityOverflow)?;
165 let units = bytes.div_ceil(Span::ALIGNMENT);
166 let mut memory =
167 alloc::array::Block::try_new(units, ()).map_err(runtime::Error::Allocation)?;
168 let base = unsafe { ptr::NonNull::new_unchecked(memory.as_mut_ptr().cast()) };
170 let collect = Span::new(base, retain, collect);
171 let stmts = Span::new(base, retain + rounded, stmts);
172 let aside = Span::new(base, retain + rounded + stmts.len(), aside);
173 let phase = Span::new(base, control, phase.size());
174 let start = Span::new(base, start, arena).base();
175 let sqlite = unsafe { heap::raw::Span::new(start, sqlite) };
177 Ok((Self { memory }, sqlite, collect, stmts, aside, phase))
178 }
179
180 fn round(bytes: usize) -> Result<usize, runtime::Error> {
181 bytes
182 .checked_add(Span::ALIGNMENT - 1)
183 .map(|rounded| rounded / Span::ALIGNMENT * Span::ALIGNMENT)
184 .ok_or(runtime::Error::CapacityOverflow)
185 }
186
187 pub(in crate::runtime) fn base(&mut self) -> ptr::NonNull<u8> {
188 unsafe { ptr::NonNull::new_unchecked(self.memory.as_mut_ptr().cast()) }
190 }
191}
192
193impl Span {
194 pub(crate) const ALIGNMENT: usize = 64;
195
196 fn new(base: ptr::NonNull<u8>, start: usize, bytes: usize) -> Self {
197 let base = unsafe { ptr::NonNull::new_unchecked(base.as_ptr().add(start)) };
199 Self { base, bytes }
200 }
201
202 pub(crate) const fn into_parts(self) -> (ptr::NonNull<u8>, usize) {
203 (self.base, self.bytes)
204 }
205
206 pub(crate) const fn as_mut_ptr(&mut self) -> *mut u8 {
207 self.base.as_ptr()
208 }
209
210 pub(crate) const fn len(&self) -> usize {
211 self.bytes
212 }
213
214 pub(crate) const fn base(&self) -> ptr::NonNull<u8> {
215 self.base
216 }
217}
218
219const _: () = {
220 assert!(mem::size_of::<Unit>() == Span::ALIGNMENT);
221 assert!(mem::align_of::<Unit>() == Span::ALIGNMENT);
222};