mirror of
https://github.com/aljazceru/turso.git
synced 2026-02-23 00:45:37 +01:00
Fix ordering and implement Deref
This commit is contained in:
@@ -27,7 +27,7 @@ impl Database {
|
||||
// ensure db header is there
|
||||
io.run_once().unwrap();
|
||||
|
||||
let page_size = db_header.lock().get_mut().page_size;
|
||||
let page_size = db_header.lock().page_size;
|
||||
|
||||
let wal_path = format!("{}-wal", path);
|
||||
let wal_shared = WalFileShared::open_shared(&io, wal_path.as_str(), page_size).unwrap();
|
||||
|
||||
@@ -1,34 +1,43 @@
|
||||
use std::{
|
||||
cell::UnsafeCell,
|
||||
ops::{Deref, DerefMut},
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FastLock<T> {
|
||||
pub struct SpinLock<T> {
|
||||
lock: AtomicBool,
|
||||
value: UnsafeCell<T>,
|
||||
}
|
||||
|
||||
pub struct FastLockGuard<'a, T> {
|
||||
lock: &'a FastLock<T>,
|
||||
pub struct SpinLockGuard<'a, T> {
|
||||
lock: &'a SpinLock<T>,
|
||||
}
|
||||
|
||||
impl<'a, T> FastLockGuard<'a, T> {
|
||||
pub fn get_mut(&self) -> &mut T {
|
||||
self.lock.get_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Drop for FastLockGuard<'a, T> {
|
||||
impl<'a, T> Drop for SpinLockGuard<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
self.lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: Send> Send for FastLock<T> {}
|
||||
unsafe impl<T> Sync for FastLock<T> {}
|
||||
impl<T> Deref for SpinLockGuard<'_, T> {
|
||||
type Target = T;
|
||||
|
||||
impl<T> FastLock<T> {
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { &*self.lock.value.get() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DerefMut for SpinLockGuard<'_, T> {
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
unsafe { &mut *self.lock.value.get() }
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: Send> Send for SpinLock<T> {}
|
||||
unsafe impl<T> Sync for SpinLock<T> {}
|
||||
|
||||
impl<T> SpinLock<T> {
|
||||
pub fn new(value: T) -> Self {
|
||||
Self {
|
||||
lock: AtomicBool::new(false),
|
||||
@@ -36,26 +45,15 @@ impl<T> FastLock<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lock(&self) -> FastLockGuard<T> {
|
||||
while self
|
||||
.lock
|
||||
.compare_exchange(false, true, Ordering::Acquire, Ordering::Acquire)
|
||||
.is_err()
|
||||
{
|
||||
pub fn lock(&self) -> SpinLockGuard<T> {
|
||||
while self.lock.swap(true, Ordering::Acquire) {
|
||||
std::thread::yield_now();
|
||||
}
|
||||
FastLockGuard { lock: self }
|
||||
SpinLockGuard { lock: self }
|
||||
}
|
||||
|
||||
pub fn unlock(&self) {
|
||||
assert!(self
|
||||
.lock
|
||||
.compare_exchange(true, false, Ordering::Acquire, Ordering::Acquire)
|
||||
.is_ok());
|
||||
}
|
||||
|
||||
pub fn get_mut(&self) -> &mut T {
|
||||
unsafe { self.value.get().as_mut().unwrap() }
|
||||
self.lock.store(false, Ordering::Release);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,24 +61,23 @@ impl<T> FastLock<T> {
|
||||
mod tests {
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::FastLock;
|
||||
use super::SpinLock;
|
||||
|
||||
#[test]
|
||||
fn test_fast_lock_multiple_thread_sum() {
|
||||
let lock = Arc::new(FastLock::new(0));
|
||||
let lock = Arc::new(SpinLock::new(0));
|
||||
let mut threads = vec![];
|
||||
const NTHREADS: usize = 1000;
|
||||
for _ in 0..NTHREADS {
|
||||
let lock = lock.clone();
|
||||
threads.push(std::thread::spawn(move || {
|
||||
lock.lock();
|
||||
let value = lock.get_mut();
|
||||
*value += 1;
|
||||
let mut guard = lock.lock();
|
||||
*guard += 1;
|
||||
}));
|
||||
}
|
||||
for thread in threads {
|
||||
thread.join().unwrap();
|
||||
}
|
||||
assert_eq!(*lock.get_mut(), NTHREADS);
|
||||
assert_eq!(*lock.lock(), NTHREADS);
|
||||
}
|
||||
}
|
||||
|
||||
14
core/lib.rs
14
core/lib.rs
@@ -26,7 +26,7 @@ static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
|
||||
|
||||
use ext::list_vfs_modules;
|
||||
use fallible_iterator::FallibleIterator;
|
||||
use fast_lock::FastLock;
|
||||
use fast_lock::SpinLock;
|
||||
use limbo_ext::{ResultCode, VTabKind, VTabModuleImpl};
|
||||
use limbo_sqlite3_parser::{ast, ast::Cmd, lexer::sql::Parser};
|
||||
use parking_lot::RwLock;
|
||||
@@ -36,7 +36,7 @@ use std::cell::Cell;
|
||||
use std::collections::HashMap;
|
||||
use std::num::NonZero;
|
||||
use std::ops::Deref;
|
||||
use std::sync::{Arc, Mutex, OnceLock};
|
||||
use std::sync::{Arc, OnceLock};
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
use storage::btree::btree_init_page;
|
||||
#[cfg(feature = "fs")]
|
||||
@@ -90,7 +90,7 @@ pub struct Database {
|
||||
mv_store: Option<Rc<MvStore>>,
|
||||
schema: Arc<RwLock<Schema>>,
|
||||
// TODO: make header work without lock
|
||||
header: Arc<FastLock<DatabaseHeader>>,
|
||||
header: Arc<SpinLock<DatabaseHeader>>,
|
||||
page_io: Arc<dyn DatabaseStorage>,
|
||||
io: Arc<dyn IO>,
|
||||
page_size: u16,
|
||||
@@ -114,7 +114,7 @@ impl Database {
|
||||
let wal_path = format!("{}-wal", path);
|
||||
let db_header = Pager::begin_open(page_io.clone())?;
|
||||
io.run_once()?;
|
||||
let page_size = db_header.lock().get_mut().page_size;
|
||||
let page_size = db_header.lock().page_size;
|
||||
let wal_shared = WalFileShared::open_shared(&io, wal_path.as_str(), page_size)?;
|
||||
Self::open(io, page_io, wal_shared, enable_mvcc)
|
||||
}
|
||||
@@ -129,7 +129,7 @@ impl Database {
|
||||
let db_header = Pager::begin_open(page_io.clone())?;
|
||||
io.run_once()?;
|
||||
DATABASE_VERSION.get_or_init(|| {
|
||||
let version = db_header.lock().get_mut().version_number;
|
||||
let version = db_header.lock().version_number;
|
||||
version.to_string()
|
||||
});
|
||||
let mv_store = if enable_mvcc {
|
||||
@@ -141,7 +141,7 @@ impl Database {
|
||||
None
|
||||
};
|
||||
let shared_page_cache = Arc::new(RwLock::new(DumbLruPageCache::new(10)));
|
||||
let page_size = db_header.lock().get_mut().page_size;
|
||||
let page_size = db_header.lock().page_size;
|
||||
let header = db_header;
|
||||
let schema = Arc::new(RwLock::new(Schema::new()));
|
||||
let db = Database {
|
||||
@@ -282,7 +282,7 @@ pub struct Connection {
|
||||
_db: Arc<Database>,
|
||||
pager: Rc<Pager>,
|
||||
schema: Arc<RwLock<Schema>>,
|
||||
header: Arc<FastLock<DatabaseHeader>>,
|
||||
header: Arc<SpinLock<DatabaseHeader>>,
|
||||
auto_commit: RefCell<bool>,
|
||||
mv_transactions: RefCell<Vec<crate::mvcc::database::TxID>>,
|
||||
transaction_state: RefCell<TransactionState>,
|
||||
|
||||
@@ -1960,8 +1960,7 @@ impl BTreeCursor {
|
||||
}
|
||||
OverflowState::ProcessPage { next_page } => {
|
||||
if next_page < 2
|
||||
|| next_page as usize
|
||||
> self.pager.db_header.lock().get_mut().database_size as usize
|
||||
|| next_page as usize > self.pager.db_header.lock().database_size as usize
|
||||
{
|
||||
self.overflow_state = None;
|
||||
return Err(LimboError::Corrupt("Invalid overflow page number".into()));
|
||||
@@ -3037,7 +3036,7 @@ mod tests {
|
||||
use test_log::test;
|
||||
|
||||
use super::*;
|
||||
use crate::fast_lock::FastLock;
|
||||
use crate::fast_lock::SpinLock;
|
||||
use crate::io::{Buffer, Completion, MemoryIO, OpenFlags, IO};
|
||||
use crate::storage::database::FileStorage;
|
||||
use crate::storage::page_cache::DumbLruPageCache;
|
||||
@@ -3051,7 +3050,6 @@ mod tests {
|
||||
use std::panic;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use tempfile::TempDir;
|
||||
|
||||
@@ -3333,7 +3331,7 @@ mod tests {
|
||||
|
||||
let page_cache = Arc::new(parking_lot::RwLock::new(DumbLruPageCache::new(10)));
|
||||
let pager = {
|
||||
let db_header = Arc::new(FastLock::new(db_header.clone()));
|
||||
let db_header = Arc::new(SpinLock::new(db_header.clone()));
|
||||
Pager::finish_open(db_header, page_io, wal, io, page_cache, buffer_pool).unwrap()
|
||||
};
|
||||
let pager = Rc::new(pager);
|
||||
@@ -3565,12 +3563,12 @@ mod tests {
|
||||
}
|
||||
|
||||
#[allow(clippy::arc_with_non_send_sync)]
|
||||
fn setup_test_env(database_size: u32) -> (Rc<Pager>, Arc<FastLock<DatabaseHeader>>) {
|
||||
fn setup_test_env(database_size: u32) -> (Rc<Pager>, Arc<SpinLock<DatabaseHeader>>) {
|
||||
let page_size = 512;
|
||||
let mut db_header = DatabaseHeader::default();
|
||||
db_header.page_size = page_size;
|
||||
db_header.database_size = database_size;
|
||||
let db_header = Arc::new(FastLock::new(db_header));
|
||||
let db_header = Arc::new(SpinLock::new(db_header));
|
||||
|
||||
let buffer_pool = Rc::new(BufferPool::new(10));
|
||||
|
||||
@@ -3590,7 +3588,7 @@ mod tests {
|
||||
{
|
||||
let mut buf_mut = buf.borrow_mut();
|
||||
let buf_slice = buf_mut.as_mut_slice();
|
||||
sqlite3_ondisk::write_header_to_buf(buf_slice, &db_header.lock().get_mut());
|
||||
sqlite3_ondisk::write_header_to_buf(buf_slice, &db_header.lock());
|
||||
}
|
||||
|
||||
let write_complete = Box::new(|_| {});
|
||||
@@ -3640,7 +3638,7 @@ mod tests {
|
||||
let drop_fn = Rc::new(|_buf| {});
|
||||
#[allow(clippy::arc_with_non_send_sync)]
|
||||
let buf = Arc::new(RefCell::new(Buffer::allocate(
|
||||
db_header.lock().get_mut().page_size as usize,
|
||||
db_header.lock().page_size as usize,
|
||||
drop_fn,
|
||||
)));
|
||||
let write_complete = Box::new(|_| {});
|
||||
@@ -3680,20 +3678,20 @@ mod tests {
|
||||
first_overflow_page: Some(2), // Point to first overflow page
|
||||
});
|
||||
|
||||
let initial_freelist_pages = db_header.lock().get_mut().freelist_pages;
|
||||
let initial_freelist_pages = db_header.lock().freelist_pages;
|
||||
// Clear overflow pages
|
||||
let clear_result = cursor.clear_overflow_pages(&leaf_cell)?;
|
||||
match clear_result {
|
||||
CursorResult::Ok(_) => {
|
||||
// Verify proper number of pages were added to freelist
|
||||
assert_eq!(
|
||||
db_header.lock().get_mut().freelist_pages,
|
||||
db_header.lock().freelist_pages,
|
||||
initial_freelist_pages + 3,
|
||||
"Expected 3 pages to be added to freelist"
|
||||
);
|
||||
|
||||
// If this is first trunk page
|
||||
let trunk_page_id = db_header.lock().get_mut().freelist_trunk_page;
|
||||
let trunk_page_id = db_header.lock().freelist_trunk_page;
|
||||
if trunk_page_id > 0 {
|
||||
// Verify trunk page structure
|
||||
let trunk_page = cursor.pager.read_page(trunk_page_id as usize)?;
|
||||
@@ -3735,7 +3733,7 @@ mod tests {
|
||||
first_overflow_page: None,
|
||||
});
|
||||
|
||||
let initial_freelist_pages = db_header.lock().get_mut().freelist_pages;
|
||||
let initial_freelist_pages = db_header.lock().freelist_pages;
|
||||
|
||||
// Try to clear non-existent overflow pages
|
||||
let clear_result = cursor.clear_overflow_pages(&leaf_cell)?;
|
||||
@@ -3743,14 +3741,14 @@ mod tests {
|
||||
CursorResult::Ok(_) => {
|
||||
// Verify freelist was not modified
|
||||
assert_eq!(
|
||||
db_header.lock().get_mut().freelist_pages,
|
||||
db_header.lock().freelist_pages,
|
||||
initial_freelist_pages,
|
||||
"Freelist should not change when no overflow pages exist"
|
||||
);
|
||||
|
||||
// Verify trunk page wasn't created
|
||||
assert_eq!(
|
||||
db_header.lock().get_mut().freelist_trunk_page,
|
||||
db_header.lock().freelist_trunk_page,
|
||||
0,
|
||||
"No trunk page should be created when no overflow pages exist"
|
||||
);
|
||||
@@ -3769,7 +3767,7 @@ mod tests {
|
||||
let (pager, db_header) = setup_test_env(initial_size);
|
||||
let mut cursor = BTreeCursor::new(None, pager.clone(), 2);
|
||||
assert_eq!(
|
||||
db_header.lock().get_mut().database_size,
|
||||
db_header.lock().database_size,
|
||||
initial_size,
|
||||
"Database should initially have 3 pages"
|
||||
);
|
||||
@@ -3829,18 +3827,18 @@ mod tests {
|
||||
|
||||
// Verify structure before destruction
|
||||
assert_eq!(
|
||||
db_header.lock().get_mut().database_size,
|
||||
db_header.lock().database_size,
|
||||
5, // We should have pages 0-4
|
||||
"Database should have 4 pages total"
|
||||
);
|
||||
|
||||
// Track freelist state before destruction
|
||||
let initial_free_pages = db_header.lock().get_mut().freelist_pages;
|
||||
let initial_free_pages = db_header.lock().freelist_pages;
|
||||
assert_eq!(initial_free_pages, 0, "should start with no free pages");
|
||||
|
||||
run_until_done(|| cursor.btree_destroy(), pager.deref())?;
|
||||
|
||||
let pages_freed = db_header.lock().get_mut().freelist_pages - initial_free_pages;
|
||||
let pages_freed = db_header.lock().freelist_pages - initial_free_pages;
|
||||
assert_eq!(pages_freed, 3, "should free 3 pages (root + 2 leaves)");
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::fast_lock::FastLock;
|
||||
use crate::fast_lock::SpinLock;
|
||||
use crate::result::LimboResult;
|
||||
use crate::storage::buffer_pool::BufferPool;
|
||||
use crate::storage::database::DatabaseStorage;
|
||||
@@ -10,7 +10,7 @@ use std::cell::{RefCell, UnsafeCell};
|
||||
use std::collections::HashSet;
|
||||
use std::rc::Rc;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::Arc;
|
||||
use tracing::trace;
|
||||
|
||||
use super::page_cache::{DumbLruPageCache, PageCacheKey};
|
||||
@@ -163,7 +163,7 @@ pub struct Pager {
|
||||
/// I/O interface for input/output operations.
|
||||
pub io: Arc<dyn crate::io::IO>,
|
||||
dirty_pages: Rc<RefCell<HashSet<usize>>>,
|
||||
pub db_header: Arc<FastLock<DatabaseHeader>>,
|
||||
pub db_header: Arc<SpinLock<DatabaseHeader>>,
|
||||
|
||||
flush_info: RefCell<FlushInfo>,
|
||||
checkpoint_state: RefCell<CheckpointState>,
|
||||
@@ -173,13 +173,13 @@ pub struct Pager {
|
||||
|
||||
impl Pager {
|
||||
/// Begins opening a database by reading the database header.
|
||||
pub fn begin_open(page_io: Arc<dyn DatabaseStorage>) -> Result<Arc<FastLock<DatabaseHeader>>> {
|
||||
pub fn begin_open(page_io: Arc<dyn DatabaseStorage>) -> Result<Arc<SpinLock<DatabaseHeader>>> {
|
||||
sqlite3_ondisk::begin_read_database_header(page_io)
|
||||
}
|
||||
|
||||
/// Completes opening a database by initializing the Pager with the database header.
|
||||
pub fn finish_open(
|
||||
db_header_ref: Arc<FastLock<DatabaseHeader>>,
|
||||
db_header_ref: Arc<SpinLock<DatabaseHeader>>,
|
||||
page_io: Arc<dyn DatabaseStorage>,
|
||||
wal: Rc<RefCell<dyn Wal>>,
|
||||
io: Arc<dyn crate::io::IO>,
|
||||
@@ -232,7 +232,7 @@ impl Pager {
|
||||
/// In other words, if the page size is 512, then the reserved space size cannot exceed 32.
|
||||
pub fn usable_space(&self) -> usize {
|
||||
let db_header = self.db_header.lock();
|
||||
(db_header.get_mut().page_size - db_header.get_mut().reserved_space as u16) as usize
|
||||
(db_header.page_size - db_header.reserved_space as u16) as usize
|
||||
}
|
||||
|
||||
pub fn begin_read_tx(&self) -> Result<LimboResult> {
|
||||
@@ -352,7 +352,7 @@ impl Pager {
|
||||
trace!("cacheflush {:?}", state);
|
||||
match state {
|
||||
FlushState::Start => {
|
||||
let db_size = self.db_header.lock().get_mut().database_size;
|
||||
let db_size = self.db_header.lock().database_size;
|
||||
for page_id in self.dirty_pages.borrow().iter() {
|
||||
let mut cache = self.page_cache.write();
|
||||
let page_key =
|
||||
@@ -503,7 +503,7 @@ impl Pager {
|
||||
const TRUNK_PAGE_NEXT_PAGE_OFFSET: usize = 0; // Offset to next trunk page pointer
|
||||
const TRUNK_PAGE_LEAF_COUNT_OFFSET: usize = 4; // Offset to leaf count
|
||||
|
||||
if page_id < 2 || page_id > self.db_header.lock().get_mut().database_size as usize {
|
||||
if page_id < 2 || page_id > self.db_header.lock().database_size as usize {
|
||||
return Err(LimboError::Corrupt(format!(
|
||||
"Invalid page number {} for free operation",
|
||||
page_id
|
||||
@@ -518,9 +518,9 @@ impl Pager {
|
||||
None => self.read_page(page_id)?,
|
||||
};
|
||||
|
||||
self.db_header.lock().get_mut().freelist_pages += 1;
|
||||
self.db_header.lock().freelist_pages += 1;
|
||||
|
||||
let trunk_page_id = self.db_header.lock().get_mut().freelist_trunk_page;
|
||||
let trunk_page_id = self.db_header.lock().freelist_trunk_page;
|
||||
|
||||
if trunk_page_id != 0 {
|
||||
// Add as leaf to current trunk
|
||||
@@ -558,7 +558,7 @@ impl Pager {
|
||||
// Zero leaf count
|
||||
contents.write_u32(TRUNK_PAGE_LEAF_COUNT_OFFSET, 0);
|
||||
// Update page 1 to point to new trunk
|
||||
self.db_header.lock().get_mut().freelist_trunk_page = page_id as u32;
|
||||
self.db_header.lock().freelist_trunk_page = page_id as u32;
|
||||
// Clear flags
|
||||
page.clear_uptodate();
|
||||
page.clear_loaded();
|
||||
@@ -572,8 +572,8 @@ impl Pager {
|
||||
#[allow(clippy::readonly_write_lock)]
|
||||
pub fn allocate_page(&self) -> Result<PageRef> {
|
||||
let header = &self.db_header;
|
||||
let header = header.lock();
|
||||
header.get_mut().database_size += 1;
|
||||
let mut header = header.lock();
|
||||
header.database_size += 1;
|
||||
{
|
||||
// update database size
|
||||
// read sync for now
|
||||
@@ -587,16 +587,12 @@ impl Pager {
|
||||
self.add_dirty(1);
|
||||
|
||||
let contents = first_page_ref.get().contents.as_ref().unwrap();
|
||||
contents.write_database_header(&header.get_mut());
|
||||
contents.write_database_header(&header);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let page = allocate_page(
|
||||
header.get_mut().database_size as usize,
|
||||
&self.buffer_pool,
|
||||
0,
|
||||
);
|
||||
let page = allocate_page(header.database_size as usize, &self.buffer_pool, 0);
|
||||
{
|
||||
// setup page and add to cache
|
||||
page.set_dirty();
|
||||
@@ -619,7 +615,7 @@ impl Pager {
|
||||
|
||||
pub fn usable_size(&self) -> usize {
|
||||
let db_header = self.db_header.lock();
|
||||
(db_header.get_mut().page_size - db_header.get_mut().reserved_space as u16) as usize
|
||||
(db_header.page_size - db_header.reserved_space as u16) as usize
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
//! https://www.sqlite.org/fileformat.html
|
||||
|
||||
use crate::error::LimboError;
|
||||
use crate::fast_lock::FastLock;
|
||||
use crate::fast_lock::SpinLock;
|
||||
use crate::io::{Buffer, Completion, ReadCompletion, SyncCompletion, WriteCompletion};
|
||||
use crate::storage::buffer_pool::BufferPool;
|
||||
use crate::storage::database::DatabaseStorage;
|
||||
@@ -53,7 +53,7 @@ use parking_lot::RwLock;
|
||||
use std::cell::RefCell;
|
||||
use std::pin::Pin;
|
||||
use std::rc::Rc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::Arc;
|
||||
use tracing::trace;
|
||||
|
||||
use super::pager::PageRef;
|
||||
@@ -245,11 +245,11 @@ impl Default for DatabaseHeader {
|
||||
|
||||
pub fn begin_read_database_header(
|
||||
page_io: Arc<dyn DatabaseStorage>,
|
||||
) -> Result<Arc<FastLock<DatabaseHeader>>> {
|
||||
) -> Result<Arc<SpinLock<DatabaseHeader>>> {
|
||||
let drop_fn = Rc::new(|_buf| {});
|
||||
#[allow(clippy::arc_with_non_send_sync)]
|
||||
let buf = Arc::new(RefCell::new(Buffer::allocate(512, drop_fn)));
|
||||
let result = Arc::new(FastLock::new(DatabaseHeader::default()));
|
||||
let result = Arc::new(SpinLock::new(DatabaseHeader::default()));
|
||||
let header = result.clone();
|
||||
let complete = Box::new(move |buf: Arc<RefCell<Buffer>>| {
|
||||
let header = header.clone();
|
||||
@@ -262,12 +262,11 @@ pub fn begin_read_database_header(
|
||||
|
||||
fn finish_read_database_header(
|
||||
buf: Arc<RefCell<Buffer>>,
|
||||
header: Arc<FastLock<DatabaseHeader>>,
|
||||
header: Arc<SpinLock<DatabaseHeader>>,
|
||||
) -> Result<()> {
|
||||
let buf = buf.borrow();
|
||||
let buf = buf.as_slice();
|
||||
let header = header.lock();
|
||||
let header = header.get_mut();
|
||||
let mut header = header.lock();
|
||||
header.magic.copy_from_slice(&buf[0..16]);
|
||||
header.page_size = u16::from_be_bytes([buf[16], buf[17]]);
|
||||
header.write_version = buf[18];
|
||||
|
||||
@@ -24,7 +24,7 @@ pub(crate) mod select;
|
||||
pub(crate) mod subquery;
|
||||
pub(crate) mod transaction;
|
||||
|
||||
use crate::fast_lock::FastLock;
|
||||
use crate::fast_lock::SpinLock;
|
||||
use crate::schema::Schema;
|
||||
use crate::storage::pager::Pager;
|
||||
use crate::storage::sqlite3_ondisk::DatabaseHeader;
|
||||
@@ -39,14 +39,14 @@ use limbo_sqlite3_parser::ast::{self, fmt::ToTokens, CreateVirtualTable, Delete,
|
||||
use select::translate_select;
|
||||
use std::fmt::Display;
|
||||
use std::rc::{Rc, Weak};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::Arc;
|
||||
use transaction::{translate_tx_begin, translate_tx_commit};
|
||||
|
||||
/// Translate SQL statement into bytecode program.
|
||||
pub fn translate(
|
||||
schema: &Schema,
|
||||
stmt: ast::Stmt,
|
||||
database_header: Arc<FastLock<DatabaseHeader>>,
|
||||
database_header: Arc<SpinLock<DatabaseHeader>>,
|
||||
pager: Rc<Pager>,
|
||||
connection: Weak<Connection>,
|
||||
syms: &SymbolTable,
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
use limbo_sqlite3_parser::ast;
|
||||
use limbo_sqlite3_parser::ast::PragmaName;
|
||||
use std::rc::Rc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::fast_lock::FastLock;
|
||||
use crate::fast_lock::SpinLock;
|
||||
use crate::schema::Schema;
|
||||
use crate::storage::sqlite3_ondisk::{DatabaseHeader, MIN_PAGE_CACHE_SIZE};
|
||||
use crate::storage::wal::CheckpointMode;
|
||||
@@ -39,7 +39,7 @@ pub fn translate_pragma(
|
||||
schema: &Schema,
|
||||
name: &ast::QualifiedName,
|
||||
body: Option<ast::PragmaBody>,
|
||||
database_header: Arc<FastLock<DatabaseHeader>>,
|
||||
database_header: Arc<SpinLock<DatabaseHeader>>,
|
||||
pager: Rc<Pager>,
|
||||
) -> crate::Result<ProgramBuilder> {
|
||||
let mut program = ProgramBuilder::new(ProgramBuilderOpts {
|
||||
@@ -116,7 +116,7 @@ fn update_pragma(
|
||||
pragma: PragmaName,
|
||||
schema: &Schema,
|
||||
value: ast::Expr,
|
||||
header: Arc<FastLock<DatabaseHeader>>,
|
||||
header: Arc<SpinLock<DatabaseHeader>>,
|
||||
pager: Rc<Pager>,
|
||||
program: &mut ProgramBuilder,
|
||||
) -> crate::Result<()> {
|
||||
@@ -167,18 +167,14 @@ fn query_pragma(
|
||||
pragma: PragmaName,
|
||||
schema: &Schema,
|
||||
value: Option<ast::Expr>,
|
||||
database_header: Arc<FastLock<DatabaseHeader>>,
|
||||
database_header: Arc<SpinLock<DatabaseHeader>>,
|
||||
program: &mut ProgramBuilder,
|
||||
) -> crate::Result<()> {
|
||||
let register = program.alloc_register();
|
||||
match pragma {
|
||||
PragmaName::CacheSize => {
|
||||
program.emit_int(
|
||||
database_header
|
||||
.lock()
|
||||
.get_mut()
|
||||
.default_page_cache_size
|
||||
.into(),
|
||||
database_header.lock().default_page_cache_size.into(),
|
||||
register,
|
||||
);
|
||||
program.emit_result_row(register, 1);
|
||||
@@ -266,7 +262,7 @@ fn query_pragma(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_cache_size(value: i64, header: Arc<FastLock<DatabaseHeader>>, pager: Rc<Pager>) {
|
||||
fn update_cache_size(value: i64, header: Arc<SpinLock<DatabaseHeader>>, pager: Rc<Pager>) {
|
||||
let mut cache_size_unformatted: i64 = value;
|
||||
let mut cache_size = if cache_size_unformatted < 0 {
|
||||
let kb = cache_size_unformatted.abs() * 1024;
|
||||
@@ -282,12 +278,12 @@ fn update_cache_size(value: i64, header: Arc<FastLock<DatabaseHeader>>, pager: R
|
||||
}
|
||||
|
||||
// update in-memory header
|
||||
header.lock().get_mut().default_page_cache_size = cache_size_unformatted
|
||||
header.lock().default_page_cache_size = cache_size_unformatted
|
||||
.try_into()
|
||||
.unwrap_or_else(|_| panic!("invalid value, too big for a i32 {}", value));
|
||||
|
||||
// update in disk
|
||||
let header_copy = header.lock().get_mut().clone();
|
||||
let header_copy = header.lock().clone();
|
||||
pager.write_database_header(&header_copy);
|
||||
|
||||
// update cache size
|
||||
|
||||
@@ -2,11 +2,11 @@ use std::{
|
||||
cell::Cell,
|
||||
collections::HashMap,
|
||||
rc::{Rc, Weak},
|
||||
sync::{Arc, Mutex},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
fast_lock::FastLock,
|
||||
fast_lock::SpinLock,
|
||||
parameters::Parameters,
|
||||
schema::{BTreeTable, Index, PseudoTable},
|
||||
storage::sqlite3_ondisk::DatabaseHeader,
|
||||
@@ -436,7 +436,7 @@ impl ProgramBuilder {
|
||||
|
||||
pub fn build(
|
||||
mut self,
|
||||
database_header: Arc<FastLock<DatabaseHeader>>,
|
||||
database_header: Arc<SpinLock<DatabaseHeader>>,
|
||||
connection: Weak<Connection>,
|
||||
change_cnt_on: bool,
|
||||
) -> Program {
|
||||
|
||||
@@ -25,7 +25,7 @@ pub mod sorter;
|
||||
|
||||
use crate::error::{LimboError, SQLITE_CONSTRAINT_PRIMARYKEY};
|
||||
use crate::ext::ExtValue;
|
||||
use crate::fast_lock::FastLock;
|
||||
use crate::fast_lock::SpinLock;
|
||||
use crate::function::{AggFunc, ExtFunc, FuncCtx, MathFunc, MathFuncArity, ScalarFunc, VectorFunc};
|
||||
use crate::functions::datetime::{
|
||||
exec_date, exec_datetime_full, exec_julianday, exec_strftime, exec_time, exec_unixepoch,
|
||||
@@ -76,7 +76,7 @@ use std::ffi::c_void;
|
||||
use std::num::NonZero;
|
||||
use std::ops::Deref;
|
||||
use std::rc::{Rc, Weak};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::Arc;
|
||||
use tracing::instrument;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
@@ -333,7 +333,7 @@ pub struct Program {
|
||||
pub max_registers: usize,
|
||||
pub insns: Vec<Insn>,
|
||||
pub cursor_ref: Vec<(Option<String>, CursorType)>,
|
||||
pub database_header: Arc<FastLock<DatabaseHeader>>,
|
||||
pub database_header: Arc<SpinLock<DatabaseHeader>>,
|
||||
pub comments: Option<HashMap<InsnReference, &'static str>>,
|
||||
pub parameters: crate::parameters::Parameters,
|
||||
pub connection: Weak<Connection>,
|
||||
@@ -3074,7 +3074,7 @@ impl Program {
|
||||
}
|
||||
// SQLite returns "0" on an empty database, and 2 on the first insertion,
|
||||
// so we'll mimic that behavior.
|
||||
let mut pages = pager.db_header.lock().get_mut().database_size.into();
|
||||
let mut pages = pager.db_header.lock().database_size.into();
|
||||
if pages == 1 {
|
||||
pages = 0;
|
||||
}
|
||||
@@ -3108,7 +3108,7 @@ impl Program {
|
||||
todo!("temp databases not implemented yet");
|
||||
}
|
||||
let cookie_value = match cookie {
|
||||
Cookie::UserVersion => pager.db_header.lock().get_mut().user_version.into(),
|
||||
Cookie::UserVersion => pager.db_header.lock().user_version.into(),
|
||||
cookie => todo!("{cookie:?} is not yet implement for ReadCookie"),
|
||||
};
|
||||
state.registers[*dest] = OwnedValue::Integer(cookie_value);
|
||||
|
||||
Reference in New Issue
Block a user