@@ -12,8 +12,8 @@ use super::{Database, Error, Result, Rows, RowsFuture, Statement, Transaction};
1212use crate :: TransactionBehavior ;
1313
1414use libsql_sys:: ffi;
15- use std:: { ffi:: c_int, fmt, path:: Path , sync:: Arc } ;
1615use 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
641669unsafe 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