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(libsqlite3_sys::SQLITE_CONFIG_LOOKASIDE, 0, 0);
88 libsqlite3_sys::sqlite3_config(
89 libsqlite3_sys::SQLITE_CONFIG_PAGECACHE,
90 ptr::null_mut::<std::ffi::c_void>(),
91 0,
92 20,
93 );
94 }
95 let cache = libsqlite3_sys::sqlite3_pcache_methods2 {
96 iVersion: 1,
97 pArg: ptr::null_mut(),
98 xInit: None,
99 xShutdown: None,
100 xCreate: None,
101 xCachesize: None,
102 xPagecount: None,
103 xFetch: None,
104 xUnpin: None,
105 xRekey: None,
106 xTruncate: None,
107 xDestroy: None,
108 xShrink: None,
109 };
110 unsafe {
113 libsqlite3_sys::sqlite3_config(libsqlite3_sys::SQLITE_CONFIG_PCACHE2, &raw const cache);
114 }
115 let hooks = raw::Hooks::new();
116 unsafe {
119 libsqlite3_sys::sqlite3_config(libsqlite3_sys::SQLITE_CONFIG_MALLOC, hooks.as_ptr());
120 }
121 let scope = raw::Foreign::enter();
122 let code = unsafe { libsqlite3_sys::sqlite3_initialize() };
123 let result = if code == libsqlite3_sys::SQLITE_OK {
124 unsafe { Vfs::install() }
125 } else {
126 Err(Error::Initialization(sys::Code::new(code)))
127 };
128 if result.is_err() {
129 unsafe { libsqlite3_sys::sqlite3_shutdown() };
132 }
133 drop(scope);
134 result?;
135 Ok(self.0)
136 }
137}
138
139impl Memory {
140 pub(in crate::runtime) fn new(
142 sqlite: Layout,
143 collect: usize,
144 stmts: usize,
145 aside: usize,
146 phase: std::alloc::Layout,
147 ) -> Result<(Self, heap::raw::Span, Span, Span, Span, Span), runtime::Error> {
148 if phase.align() > Span::ALIGNMENT {
149 return Err(runtime::Error::Layout);
150 }
151 let phase_bytes = Self::round(phase.size())?;
152 let rounded = Self::round(collect)?;
153 let aside = Self::round(aside)?;
154 let arena = sqlite.backing().ok_or(runtime::Error::CapacityOverflow)?;
155 let control = local::State::<crate::catalogs::Empty>::RETENTION_BYTES;
156 let start = control
157 .checked_add(phase_bytes)
158 .ok_or(runtime::Error::CapacityOverflow)?;
159 let retain = start
160 .checked_add(arena)
161 .ok_or(runtime::Error::CapacityOverflow)?;
162 let bytes = retain
163 .checked_add(rounded)
164 .and_then(|total| total.checked_add(stmts))
165 .and_then(|total| total.checked_add(aside))
166 .ok_or(runtime::Error::CapacityOverflow)?;
167 let units = bytes.div_ceil(Span::ALIGNMENT);
168 let mut memory =
169 alloc::array::Block::try_new(units, ()).map_err(runtime::Error::Allocation)?;
170 let base = unsafe { ptr::NonNull::new_unchecked(memory.as_mut_ptr().cast()) };
172 let collect = Span::new(base, retain, collect);
173 let stmts = Span::new(base, retain + rounded, stmts);
174 let aside = Span::new(base, retain + rounded + stmts.len(), aside);
175 let phase = Span::new(base, control, phase.size());
176 let start = Span::new(base, start, arena).base();
177 let sqlite = unsafe { heap::raw::Span::new(start, sqlite) };
179 Ok((Self { memory }, sqlite, collect, stmts, aside, phase))
180 }
181
182 fn round(bytes: usize) -> Result<usize, runtime::Error> {
183 bytes
184 .checked_add(Span::ALIGNMENT - 1)
185 .map(|rounded| rounded / Span::ALIGNMENT * Span::ALIGNMENT)
186 .ok_or(runtime::Error::CapacityOverflow)
187 }
188
189 pub(in crate::runtime) fn base(&mut self) -> ptr::NonNull<u8> {
190 unsafe { ptr::NonNull::new_unchecked(self.memory.as_mut_ptr().cast()) }
192 }
193}
194
195impl Span {
196 pub(crate) const ALIGNMENT: usize = 64;
197
198 fn new(base: ptr::NonNull<u8>, start: usize, bytes: usize) -> Self {
199 let base = unsafe { ptr::NonNull::new_unchecked(base.as_ptr().add(start)) };
201 Self { base, bytes }
202 }
203
204 pub(crate) const fn into_parts(self) -> (ptr::NonNull<u8>, usize) {
205 (self.base, self.bytes)
206 }
207
208 pub(crate) const fn as_mut_ptr(&mut self) -> *mut u8 {
209 self.base.as_ptr()
210 }
211
212 pub(crate) const fn len(&self) -> usize {
213 self.bytes
214 }
215
216 pub(crate) const fn base(&self) -> ptr::NonNull<u8> {
217 self.base
218 }
219}
220
221const _: () = {
222 assert!(mem::size_of::<Unit>() == Span::ALIGNMENT);
223 assert!(mem::align_of::<Unit>() == Span::ALIGNMENT);
224};