mod vfs;
use crate::{
catalogs, conn,
runtime::{self, Error, heap},
sys,
};
use o3::alloc;
use std::{mem, ptr};
#[repr(C, align(64))]
struct Unit {
bytes: [mem::MaybeUninit<u8>; Span::ALIGNMENT],
}
pub(crate) struct Memory {
_memory: alloc::array::Block<mem::MaybeUninit<Unit>, usize>,
}
pub(crate) struct Span {
base: ptr::NonNull<u8>,
bytes: usize,
}
#[must_use]
pub struct Permit(pub(super) ());
struct Setup(Permit);
impl Permit {
pub unsafe fn exclusive() -> Self {
Self(())
}
pub(super) fn initialize(self) -> Result<Self, Error> {
if unsafe {
libsqlite3_sys::sqlite3_compileoption_used(c"ENABLE_MEMORY_MANAGEMENT".as_ptr())
} != 0
{
return Err(Error::GlobalCache);
}
if unsafe {
libsqlite3_sys::sqlite3_compileoption_used(c"DISABLE_PAGECACHE_OVERFLOW_STATS".as_ptr())
} == 0
{
return Err(Error::CacheStats);
}
if unsafe { libsqlite3_sys::sqlite3_compileoption_used(c"ENABLE_STMTVTAB".as_ptr()) } != 0 {
return Err(Error::StatementVtab);
}
if unsafe { libsqlite3_sys::sqlite3_compileoption_used(c"OMIT_WSD".as_ptr()) } != 0 {
return Err(Error::WritableStatic);
}
if unsafe { libsqlite3_sys::sqlite3_compileoption_used(c"ENABLE_SQLLOG".as_ptr()) } != 0 {
return Err(Error::StatementLog);
}
Setup(self).initialize()
}
}
impl Setup {
fn initialize(self) -> Result<Permit, Error> {
use heap::raw;
use vfs::Vfs;
let code =
unsafe { libsqlite3_sys::sqlite3_config(libsqlite3_sys::SQLITE_CONFIG_MULTITHREAD) };
if code != libsqlite3_sys::SQLITE_OK {
return Err(Error::Threading(sys::Code::new(code)));
}
unsafe {
libsqlite3_sys::sqlite3_config(libsqlite3_sys::SQLITE_CONFIG_URI, 0);
libsqlite3_sys::sqlite3_config(libsqlite3_sys::SQLITE_CONFIG_MEMSTATUS, 0);
libsqlite3_sys::sqlite3_config(libsqlite3_sys::SQLITE_CONFIG_LOOKASIDE, 0, 0);
libsqlite3_sys::sqlite3_config(
libsqlite3_sys::SQLITE_CONFIG_PAGECACHE,
ptr::null_mut::<std::ffi::c_void>(),
0,
20,
);
}
let cache = libsqlite3_sys::sqlite3_pcache_methods2 {
iVersion: 1,
pArg: ptr::null_mut(),
xInit: None,
xShutdown: None,
xCreate: None,
xCachesize: None,
xPagecount: None,
xFetch: None,
xUnpin: None,
xRekey: None,
xTruncate: None,
xDestroy: None,
xShrink: None,
};
unsafe {
libsqlite3_sys::sqlite3_config(libsqlite3_sys::SQLITE_CONFIG_PCACHE2, &raw const cache);
}
let hooks = raw::methods();
unsafe {
libsqlite3_sys::sqlite3_config(libsqlite3_sys::SQLITE_CONFIG_MALLOC, &raw const hooks);
}
raw::foreign(|| {
let code = unsafe { libsqlite3_sys::sqlite3_initialize() };
let result = if code == libsqlite3_sys::SQLITE_OK {
unsafe { Vfs::install() }
} else {
Err(Error::Initialization(sys::Code::new(code)))
};
if result.is_err() {
unsafe { libsqlite3_sys::sqlite3_shutdown() };
}
result
})?;
Ok(self.0)
}
}
impl Memory {
pub(in crate::runtime) fn new<I: catalogs::Catalog>(
layout: &runtime::Layout<'_, I>,
) -> Result<(Self, heap::raw::Span, Span, Span, Span, Span), runtime::Error> {
let (sqlite, collect_bytes, statement_bytes, lookaside_bytes) = layout.dimensions();
let phase = conn::raw::Vacant::<'_, '_, I>::LAYOUT;
let prefix = phase.size().next_multiple_of(Span::ALIGNMENT);
let collect = prefix + heap::layout::Layout::PREFIX_BYTES + sqlite.bytes();
let stmts = collect + collect_bytes.next_multiple_of(Span::ALIGNMENT);
let aside = stmts + statement_bytes;
let bytes = aside + lookaside_bytes.next_multiple_of(Span::ALIGNMENT);
let units = bytes / Span::ALIGNMENT;
let mut memory =
alloc::array::Block::try_new(units, ()).map_err(runtime::Error::Allocation)?;
let base = unsafe { ptr::NonNull::new_unchecked(memory.as_mut_ptr().cast()) };
let start = Span::new(base, prefix, collect - prefix).base();
let collect = Span::new(base, collect, collect_bytes);
let stmts = Span::new(base, stmts, aside - stmts);
let aside = Span::new(base, aside, bytes - aside);
let phase = Span::new(base, 0, phase.size());
let sqlite = unsafe { heap::raw::Span::new(start, sqlite) };
Ok((
Self { _memory: memory },
sqlite,
collect,
stmts,
aside,
phase,
))
}
}
impl Span {
pub(crate) const ALIGNMENT: usize = 64;
fn new(base: ptr::NonNull<u8>, start: usize, bytes: usize) -> Self {
let base = unsafe { ptr::NonNull::new_unchecked(base.as_ptr().add(start)) };
Self { base, bytes }
}
pub(crate) const fn into_parts(self) -> (ptr::NonNull<u8>, usize) {
(self.base, self.bytes)
}
pub(crate) const fn as_mut_ptr(&mut self) -> *mut u8 {
self.base.as_ptr()
}
pub(crate) const fn len(&self) -> usize {
self.bytes
}
pub(crate) const fn base(&self) -> ptr::NonNull<u8> {
self.base
}
}
const _: () = {
assert!(mem::size_of::<Unit>() == Span::ALIGNMENT);
assert!(mem::align_of::<Unit>() == Span::ALIGNMENT);
};