Skip to content

Commit 1cfc940

Browse files
authored
Add APIs to get/set reserved bytes (#2170)
2 parents 268d169 + 8f1a7be commit 1cfc940

File tree

2 files changed

+98
-1
lines changed

2 files changed

+98
-1
lines changed

libsql-sys/src/connection.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,31 @@ impl<W: Wal> Connection<W> {
385385
};
386386
Ok(counter)
387387
}
388+
389+
fn reserved_bytes(&self, reserve: Option<i32>) -> Result<i32, std::ffi::c_int> {
390+
let mut reserve_value = reserve.unwrap_or(0) as std::ffi::c_int;
391+
let rc = unsafe {
392+
libsql_ffi::sqlite3_file_control(
393+
self.handle(),
394+
"main\0".as_ptr() as *const _,
395+
libsql_ffi::SQLITE_FCNTL_RESERVE_BYTES,
396+
&mut reserve_value as *mut _ as *mut _,
397+
)
398+
};
399+
if rc != libsql_ffi::SQLITE_OK {
400+
return Err(rc);
401+
}
402+
Ok(reserve_value as i32)
403+
}
404+
405+
pub fn set_reserved_bytes(&self, reserved_bytes: i32) -> Result<(), std::ffi::c_int> {
406+
self.reserved_bytes(Some(reserved_bytes))?;
407+
Ok(())
408+
}
409+
410+
pub fn get_reserved_bytes(&self) -> Result<i32, std::ffi::c_int> {
411+
self.reserved_bytes(None)
412+
}
388413
}
389414
// pub struct Connection<'a> {
390415
// pub conn: *mut crate::ffi::sqlite3,

libsql/src/local/connection.rs

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ use super::{Database, Error, Result, Rows, RowsFuture, Statement, Transaction};
1212
use crate::TransactionBehavior;
1313

1414
use libsql_sys::ffi;
15-
use std::{ffi::c_int, fmt, path::Path, sync::Arc};
1615
use parking_lot::RwLock;
16+
use std::{ffi::c_int, fmt, path::Path, sync::Arc};
1717

1818
/// A connection to a libSQL database.
1919
#[derive(Clone)]
@@ -636,6 +636,34 @@ impl Connection {
636636
in_session: RwLock::new(false),
637637
}
638638
}
639+
640+
fn reserved_bytes(&self, reserve: Option<i32>) -> Result<i32> {
641+
let mut reserve_value = reserve.unwrap_or(0) as std::ffi::c_int;
642+
let rc = unsafe {
643+
ffi::sqlite3_file_control(
644+
self.raw,
645+
"main\0".as_ptr() as *const _,
646+
ffi::SQLITE_FCNTL_RESERVE_BYTES,
647+
&mut reserve_value as *mut _ as *mut std::ffi::c_void,
648+
)
649+
};
650+
if rc != ffi::SQLITE_OK {
651+
return Err(Error::SqliteFailure(
652+
rc,
653+
errors::error_from_handle(self.raw),
654+
));
655+
}
656+
Ok(reserve_value as i32)
657+
}
658+
659+
pub fn set_reserved_bytes(&self, reserved_bytes: i32) -> Result<()> {
660+
self.reserved_bytes(Some(reserved_bytes))?;
661+
Ok(())
662+
}
663+
664+
pub fn get_reserved_bytes(&self) -> Result<i32> {
665+
self.reserved_bytes(None)
666+
}
639667
}
640668

641669
unsafe extern "C" fn authorizer_callback(
@@ -784,4 +812,48 @@ mod tests {
784812
let cnt = *column.as_integer().unwrap();
785813
assert_eq!(cnt, 32 as i64);
786814
}
815+
816+
#[tokio::test]
817+
pub async fn test_reserved_bytes() {
818+
let temp_dir = tempfile::tempdir().unwrap();
819+
let db_path = temp_dir.path().join("local1.db");
820+
let reserved_bytes = 28;
821+
822+
{
823+
let db = Database::new(db_path.to_str().unwrap().to_string(), OpenFlags::default());
824+
let conn = Connection::connect(&db).unwrap();
825+
conn.query("PRAGMA journal_mode = WAL", Params::None)
826+
.unwrap();
827+
conn.set_reserved_bytes(reserved_bytes).unwrap();
828+
conn.query("VACUUM", Params::None).unwrap();
829+
let reserved = conn.get_reserved_bytes().unwrap();
830+
assert_eq!(reserved, reserved_bytes);
831+
}
832+
833+
// let's verify we can see this from another connection
834+
{
835+
let db = Database::new(db_path.to_str().unwrap().to_string(), OpenFlags::default());
836+
let conn = Connection::connect(&db).unwrap();
837+
let reserved = conn.get_reserved_bytes().unwrap();
838+
assert_eq!(reserved, reserved_bytes);
839+
}
840+
841+
// lets make some inserts, checkpoint and verify again
842+
{
843+
let db = Database::new(db_path.to_str().unwrap().to_string(), OpenFlags::default());
844+
let conn = Connection::connect(&db).unwrap();
845+
conn.execute("CREATE TABLE t(x)", Params::None).unwrap();
846+
const CNT: usize = 8;
847+
for _ in 0..CNT {
848+
conn.execute(
849+
"INSERT INTO t VALUES (randomblob(1024 * 1024))",
850+
Params::None,
851+
)
852+
.unwrap();
853+
}
854+
conn.wal_checkpoint(true).unwrap();
855+
let reserved = conn.get_reserved_bytes().unwrap();
856+
assert_eq!(reserved, reserved_bytes);
857+
}
858+
}
787859
}

0 commit comments

Comments
 (0)