use crate::api::{batches, stmt, work};
use crate::retry;
use crate::runtime::slot::{Opening, lease::Lease};
use crate::runtime::{self, Error, heap};
use crate::{catalogs, config, sys};
use heap::scopes::Scope;
use o3::mem::lease::Open;
use std::{mem, ptr};
pub(crate) struct Local<I: catalogs::Catalog> {
owned: Owned<I>,
arena: runtime::raw::Span,
work: work::Work,
lookaside: runtime::raw::Span,
lookaside_layout: crate::memory::Lookaside,
}
pub(super) struct Owned<I: catalogs::Catalog> {
connection: Option<crate::sys::Connection>,
statements: stmt::Storage<I>,
scope: Option<Scope>,
}
impl<I: catalogs::Catalog> Local<I> {
pub(crate) fn new(
memory: runtime::raw::Memory,
sqlite: heap::raw::Span,
collect: runtime::raw::Span,
stmts: runtime::raw::Span,
aside: runtime::raw::Span,
layout: crate::memory::Lookaside,
) -> Result<(Self, heap::raw::Local, heap::raw::Retained), Error> {
let stmts = stmt::Storage::new(stmts)?;
let (sqlite, retained) = heap::raw::Local::from_span(sqlite, memory);
Ok((
Self {
owned: Owned {
connection: None,
statements: stmts,
scope: None,
},
arena: collect,
work: work::Work::new(),
lookaside: aside,
lookaside_layout: layout,
},
sqlite,
retained,
))
}
pub(crate) fn lease<'slot, 'd: 'slot>(
&'slot mut self,
heap: heap::raw::Local,
retry: retry::raw::Loan<'slot, 'd>,
report: &'slot mut crate::open::Completion,
) -> Result<Vacant<'slot, 'd, I>, crate::Error> {
self.owned.scope = Some(Scope::enter(heap)?);
let arena = &mut self.arena;
let owned = ptr::NonNull::from(&mut self.owned);
let lease = Lease::new(owned, retry, &self.work, report);
Ok(Vacant {
connection: &mut self.owned.connection,
statements: &mut self.owned.statements,
arena,
lookaside: &mut self.lookaside,
lookaside_layout: self.lookaside_layout,
lease,
})
}
}
impl<I: catalogs::Catalog> Drop for Local<I> {
fn drop(&mut self) {
self.owned.retire(&self.work);
}
}
impl<I: catalogs::Catalog> Owned<I> {
pub(super) fn finish(&mut self) {
self.connection = None;
if let Some(scope) = self.scope.take() {
scope.finish();
}
}
fn retire(&mut self, work: &work::Work) {
if self.scope.is_some() {
if let Some(db) = &self.connection {
work.refresh(db);
}
self.statements.retire_all(work);
self.finish();
}
}
}
pub(crate) struct Vacant<'slot, 'd, I: catalogs::Catalog> {
connection: &'slot mut Option<crate::sys::Connection>,
statements: &'slot mut stmt::Storage<I>,
arena: batches::Arena<'slot>,
lookaside: &'slot mut runtime::raw::Span,
lookaside_layout: crate::memory::Lookaside,
lease: Lease<'slot, 'd, I, Open>,
}
impl<'slot, 'd, I: catalogs::Catalog> Vacant<'slot, 'd, I> {
pub(crate) fn open(self, db: sys::Connection) -> Result<Opening<'slot, 'd, I>, crate::Error> {
let config = self.lease.config();
let work = self.lease.work();
let guard = work.begin(config.work.open.progress)?;
work.progress(&db, config::Budget::PROGRESS_INTERVAL);
Ok(Opening {
guard,
connection: self.connection.insert(db),
statements: self.statements,
arena: self.arena,
lookaside: self.lookaside,
lookaside_layout: self.lookaside_layout,
lease: self.lease,
})
}
}
const _: () = {
let word = mem::size_of::<usize>();
assert!(mem::size_of::<Option<Scope>>() == word);
let fields = mem::size_of::<Option<crate::sys::Connection>>()
+ mem::size_of::<stmt::Storage<catalogs::Empty>>()
+ 2 * mem::size_of::<runtime::raw::Span>()
+ mem::size_of::<work::Work>()
+ mem::size_of::<Option<Scope>>()
+ mem::size_of::<crate::memory::Lookaside>();
let align = mem::align_of::<Local<catalogs::Empty>>();
assert!(mem::size_of::<Local<catalogs::Empty>>() == fields.next_multiple_of(align));
};