mirror of
https://github.com/aljazceru/turso.git
synced 2026-01-02 07:54:19 +01:00
Merge 'Fix: ensure PRAGMA cache_size changes persist only for current session' from meteorgan
According to [the document](https://www.sqlite.org/pragma.html#pragma_cache_size): ``` When you change the cache size using the cache_size pragma, the change only endures for the current session. The cache size reverts to the default value when the database is closed and reopened. ``` so, we shouldn't persist cache_size to database header. this PR also addresses two minor issues: 1. Sets the default cache_size to -2000 to align with SQLite's default 2. Uses the actual page size to calculate the cache size. Reviewed-by: Pere Diaz Bou <pere-altea@homail.com> Closes #1672
This commit is contained in:
@@ -240,6 +240,7 @@ impl Database {
|
||||
syms: RefCell::new(SymbolTable::new()),
|
||||
total_changes: Cell::new(0),
|
||||
_shared_cache: false,
|
||||
cache_size: Cell::new(self.header.lock().default_page_cache_size),
|
||||
});
|
||||
if let Err(e) = conn.register_builtins() {
|
||||
return Err(LimboError::ExtensionError(e));
|
||||
@@ -339,6 +340,7 @@ pub struct Connection {
|
||||
total_changes: Cell<i64>,
|
||||
syms: RefCell<SymbolTable>,
|
||||
_shared_cache: bool,
|
||||
cache_size: Cell<i32>,
|
||||
}
|
||||
|
||||
impl Connection {
|
||||
@@ -595,6 +597,13 @@ impl Connection {
|
||||
self.total_changes.get()
|
||||
}
|
||||
|
||||
pub fn get_cache_size(&self) -> i32 {
|
||||
self.cache_size.get()
|
||||
}
|
||||
pub fn set_cache_size(&self, size: i32) {
|
||||
self.cache_size.set(size);
|
||||
}
|
||||
|
||||
#[cfg(feature = "fs")]
|
||||
pub fn open_new(&self, path: &str, vfs: &str) -> Result<(Arc<dyn IO>, Arc<Database>)> {
|
||||
Database::open_with_vfs(&self._db, path, vfs)
|
||||
|
||||
@@ -251,7 +251,7 @@ impl Default for DatabaseHeader {
|
||||
freelist_pages: 0,
|
||||
schema_cookie: 0,
|
||||
schema_format: 4, // latest format, new sqlite3 databases use this format
|
||||
default_page_cache_size: 500, // pages
|
||||
default_page_cache_size: DEFAULT_CACHE_SIZE,
|
||||
vacuum_mode_largest_root_page: 0,
|
||||
text_encoding: 1, // utf-8
|
||||
user_version: 0,
|
||||
|
||||
@@ -88,6 +88,7 @@ pub fn translate(
|
||||
body.map(|b| *b),
|
||||
database_header.clone(),
|
||||
pager,
|
||||
connection.clone(),
|
||||
program,
|
||||
)?,
|
||||
stmt => translate_inner(schema, stmt, syms, query_mode, program)?,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
use limbo_sqlite3_parser::ast;
|
||||
use limbo_sqlite3_parser::ast::PragmaName;
|
||||
use std::rc::Rc;
|
||||
use std::rc::{Rc, Weak};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::fast_lock::SpinLock;
|
||||
@@ -33,6 +33,7 @@ pub fn translate_pragma(
|
||||
body: Option<ast::PragmaBody>,
|
||||
database_header: Arc<SpinLock<DatabaseHeader>>,
|
||||
pager: Rc<Pager>,
|
||||
connection: Weak<crate::Connection>,
|
||||
mut program: ProgramBuilder,
|
||||
) -> crate::Result<ProgramBuilder> {
|
||||
let opts = ProgramBuilderOpts {
|
||||
@@ -56,7 +57,14 @@ pub fn translate_pragma(
|
||||
|
||||
match body {
|
||||
None => {
|
||||
query_pragma(pragma, schema, None, database_header.clone(), &mut program)?;
|
||||
query_pragma(
|
||||
pragma,
|
||||
schema,
|
||||
None,
|
||||
database_header.clone(),
|
||||
connection,
|
||||
&mut program,
|
||||
)?;
|
||||
}
|
||||
Some(ast::PragmaBody::Equals(value)) => match pragma {
|
||||
PragmaName::TableInfo => {
|
||||
@@ -65,6 +73,7 @@ pub fn translate_pragma(
|
||||
schema,
|
||||
Some(value),
|
||||
database_header.clone(),
|
||||
connection,
|
||||
&mut program,
|
||||
)?;
|
||||
}
|
||||
@@ -76,6 +85,7 @@ pub fn translate_pragma(
|
||||
value,
|
||||
database_header.clone(),
|
||||
pager,
|
||||
connection,
|
||||
&mut program,
|
||||
)?;
|
||||
}
|
||||
@@ -87,6 +97,7 @@ pub fn translate_pragma(
|
||||
schema,
|
||||
Some(value),
|
||||
database_header.clone(),
|
||||
connection,
|
||||
&mut program,
|
||||
)?;
|
||||
}
|
||||
@@ -109,36 +120,51 @@ fn update_pragma(
|
||||
value: ast::Expr,
|
||||
header: Arc<SpinLock<DatabaseHeader>>,
|
||||
pager: Rc<Pager>,
|
||||
connection: Weak<crate::Connection>,
|
||||
program: &mut ProgramBuilder,
|
||||
) -> crate::Result<()> {
|
||||
match pragma {
|
||||
PragmaName::CacheSize => {
|
||||
let cache_size = match value {
|
||||
ast::Expr::Literal(ast::Literal::Numeric(numeric_value)) => {
|
||||
numeric_value.parse::<i64>()?
|
||||
}
|
||||
ast::Expr::Unary(ast::UnaryOperator::Negative, expr) => match *expr {
|
||||
ast::Expr::Literal(ast::Literal::Numeric(numeric_value)) => {
|
||||
-numeric_value.parse::<i64>()?
|
||||
}
|
||||
_ => bail_parse_error!("Not a valid value"),
|
||||
},
|
||||
_ => bail_parse_error!("Not a valid value"),
|
||||
let cache_size = match parse_signed_number(&value)? {
|
||||
Value::Integer(size) => size,
|
||||
Value::Float(size) => size as i64,
|
||||
_ => bail_parse_error!("Invalid value for cache size pragma"),
|
||||
};
|
||||
update_cache_size(cache_size, header, pager)?;
|
||||
update_cache_size(cache_size, header, pager, connection)?;
|
||||
Ok(())
|
||||
}
|
||||
PragmaName::JournalMode => {
|
||||
query_pragma(PragmaName::JournalMode, schema, None, header, program)?;
|
||||
query_pragma(
|
||||
PragmaName::JournalMode,
|
||||
schema,
|
||||
None,
|
||||
header,
|
||||
connection,
|
||||
program,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
PragmaName::LegacyFileFormat => Ok(()),
|
||||
PragmaName::WalCheckpoint => {
|
||||
query_pragma(PragmaName::WalCheckpoint, schema, None, header, program)?;
|
||||
query_pragma(
|
||||
PragmaName::WalCheckpoint,
|
||||
schema,
|
||||
None,
|
||||
header,
|
||||
connection,
|
||||
program,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
PragmaName::PageCount => {
|
||||
query_pragma(PragmaName::PageCount, schema, None, header, program)?;
|
||||
query_pragma(
|
||||
PragmaName::PageCount,
|
||||
schema,
|
||||
None,
|
||||
header,
|
||||
connection,
|
||||
program,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
PragmaName::UserVersion => {
|
||||
@@ -178,13 +204,14 @@ fn query_pragma(
|
||||
schema: &Schema,
|
||||
value: Option<ast::Expr>,
|
||||
database_header: Arc<SpinLock<DatabaseHeader>>,
|
||||
connection: Weak<crate::Connection>,
|
||||
program: &mut ProgramBuilder,
|
||||
) -> crate::Result<()> {
|
||||
let register = program.alloc_register();
|
||||
match pragma {
|
||||
PragmaName::CacheSize => {
|
||||
program.emit_int(
|
||||
database_header.lock().default_page_cache_size.into(),
|
||||
connection.upgrade().unwrap().get_cache_size() as i64,
|
||||
register,
|
||||
);
|
||||
program.emit_result_row(register, 1);
|
||||
@@ -287,30 +314,25 @@ fn update_cache_size(
|
||||
value: i64,
|
||||
header: Arc<SpinLock<DatabaseHeader>>,
|
||||
pager: Rc<Pager>,
|
||||
connection: Weak<crate::Connection>,
|
||||
) -> crate::Result<()> {
|
||||
let mut cache_size_unformatted: i64 = value;
|
||||
let mut cache_size = if cache_size_unformatted < 0 {
|
||||
let kb = cache_size_unformatted.abs() * 1024;
|
||||
kb / 512 // assume 512 page size for now
|
||||
let page_size = header.lock().get_page_size();
|
||||
kb / page_size as i64
|
||||
} else {
|
||||
value
|
||||
} as usize;
|
||||
|
||||
if cache_size < MIN_PAGE_CACHE_SIZE {
|
||||
// update both in memory and stored disk value
|
||||
cache_size = MIN_PAGE_CACHE_SIZE;
|
||||
cache_size_unformatted = MIN_PAGE_CACHE_SIZE as i64;
|
||||
}
|
||||
|
||||
let mut header_guard = header.lock();
|
||||
|
||||
// update in-memory header
|
||||
header_guard.default_page_cache_size = cache_size_unformatted
|
||||
.try_into()
|
||||
.unwrap_or_else(|_| panic!("invalid value, too big for a i32 {}", value));
|
||||
|
||||
// update in disk
|
||||
pager.write_database_header(&header_guard)?;
|
||||
connection
|
||||
.upgrade()
|
||||
.unwrap()
|
||||
.set_cache_size(cache_size_unformatted as i32);
|
||||
|
||||
// update cache size
|
||||
pager
|
||||
|
||||
@@ -3,6 +3,16 @@
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
do_execsql_test_on_specific_db ":memory:" pragma-cache-size-default {
|
||||
PRAGMA cache_size
|
||||
} {-2000}
|
||||
|
||||
do_execsql_test pragma-set-cache-size {
|
||||
PRAGMA cache_size = 100;
|
||||
PRAGMA cache_size
|
||||
} {100}
|
||||
|
||||
# Even though the cache size was set to 100 in previous test, a new connection defaults back to -2000.
|
||||
do_execsql_test pragma-cache-size {
|
||||
PRAGMA cache_size
|
||||
} {-2000}
|
||||
|
||||
Reference in New Issue
Block a user