Skip to main content

cartel_sqlite/runtime/
local.rs

1use crate::{
2    catalogs, config, conn, database, retry,
3    runtime::{self, heap, slot},
4};
5use dope_core::driver::storage;
6use heap::layout::Layout;
7use std::{cell, marker, mem, pin};
8
9/// Pinned SQLite resources owned by one generative driver domain.
10pub struct State<'d, I: catalogs::Catalog> {
11    retry: retry::raw::Configured<'d>,
12    slot: cell::UnsafeCell<slot::Local<I>>,
13    phase: runtime::raw::Span,
14    _retire: heap::raw::Retained,
15    proof: marker::PhantomData<(cell::Cell<&'d I>, marker::PhantomPinned)>,
16    value_bytes: i32,
17    statement_sql_bytes: i32,
18    // The idle heap token has no destructor or backing borrow after _retire drops.
19    database: cell::UnsafeCell<Option<(database::Target<'d>, heap::raw::Local)>>,
20}
21
22pub(super) struct Settings {
23    pub(super) config: config::Config,
24    pub(super) value_bytes: i32,
25    pub(super) statement_sql_bytes: i32,
26}
27
28impl<'d, I: catalogs::Catalog> State<'d, I> {
29    pub(in crate::runtime) fn new(
30        context: &mut storage::Context<'_, 'd>,
31        settings: Settings,
32        sqlite: Layout,
33        database: database::Target<'d>,
34        stmts: usize,
35        aside: crate::memory::Lookaside,
36    ) -> Result<Self, runtime::Error> {
37        let Settings {
38            config,
39            value_bytes: values,
40            statement_sql_bytes: sql,
41        } = settings;
42        let (memory, sqlite, collect, stmts, storage, phase) = runtime::raw::Memory::new(
43            sqlite,
44            config.result_bytes(),
45            stmts,
46            aside.bytes(),
47            conn::raw::Vacant::<'_, 'd, I>::LAYOUT,
48        )?;
49        let retry = retry::raw::Configured::new(config, || {
50            context
51                .timer()
52                .try_alarm()
53                .map_err(runtime::Error::TimerCapacity)
54        })?;
55        let (slot, heap, retained) =
56            slot::Local::new(memory, sqlite, collect, stmts, storage, aside)?;
57        Ok(Self {
58            retry,
59            slot: cell::UnsafeCell::new(slot),
60            phase,
61            _retire: retained,
62            proof: marker::PhantomData,
63            value_bytes: values,
64            statement_sql_bytes: sql,
65            database: cell::UnsafeCell::new(Some((database, heap))),
66        })
67    }
68
69    pub fn config(self: pin::Pin<&Self>) -> &config::Config {
70        self.get_ref().retry.config()
71    }
72
73    pub(crate) const fn sql_bytes(&self) -> i32 {
74        self.statement_sql_bytes
75    }
76
77    pub(crate) const fn value_bytes(&self) -> i32 {
78        self.value_bytes
79    }
80
81    pub(crate) fn try_lease<'local>(
82        self: pin::Pin<&'local Self>,
83        report: &'local mut crate::open::Completion,
84    ) -> Result<
85        (
86            database::Target<'d>,
87            slot::Vacant<'local, 'd, I>,
88            conn::raw::Vacant<'local, 'd, I>,
89        ),
90        crate::open::Error,
91    >
92    where
93        'd: 'local,
94    {
95        let report = report.admit()?;
96        let local = self.get_ref();
97        // SAFETY: this thread-bound take invokes no callbacks and retains no field borrow.
98        let (database, heap) = unsafe { &mut *local.database.get() }
99            .take()
100            .ok_or(crate::open::Error::AlreadyStarted)?;
101        // SAFETY: the target is consumed once and never restored, so it grants the
102        // sole retry loan. Config stays outside every mutable slot projection.
103        let retry = unsafe { local.retry.loan() };
104        // SAFETY: the same consumed target grants the only mutable local projection.
105        // Pin preserves both owners' addresses through their returned lease.
106        let slot = unsafe { &mut *local.slot.get() };
107        let lease = slot.lease(heap, retry, report)?;
108        // SAFETY: Memory reserved this exact catalog's phase layout. The consumed
109        // target grants its only initialization, and local retains the backing.
110        let phase = unsafe { conn::raw::Vacant::new(&local.phase) };
111        Ok((database, lease, phase))
112    }
113}
114
115const _: () = {
116    let fields = mem::size_of::<retry::raw::Configured<'_>>()
117        + mem::size_of::<cell::UnsafeCell<slot::Local<catalogs::Empty>>>()
118        + mem::size_of::<runtime::raw::Span>()
119        + mem::size_of::<heap::raw::Retained>()
120        + mem::size_of::<marker::PhantomData<(cell::Cell<&catalogs::Empty>, marker::PhantomPinned)>>(
121        )
122        + 2 * mem::size_of::<i32>()
123        + mem::size_of::<cell::UnsafeCell<Option<(database::Target<'_>, heap::raw::Local)>>>();
124    let align = mem::align_of::<State<'_, catalogs::Empty>>();
125    assert!(mem::size_of::<State<'_, catalogs::Empty>>() == fields.next_multiple_of(align));
126};