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