11// cargo build --example memvfs --features dynamic
22
3- use std:: { ffi:: c_void, os:: raw:: c_char, sync:: Arc } ;
3+ use std:: { ffi:: c_void, os:: raw:: c_char, ptr :: NonNull , sync:: Arc } ;
44
55use parking_lot:: Mutex ;
66use sqlite_plugin:: {
7- flags:: { AccessFlags , LockLevel , OpenOpts } ,
7+ flags:: { AccessFlags , LockLevel , OpenOpts , ShmLockMode } ,
88 logger:: { SqliteLogLevel , SqliteLogger } ,
99 sqlite3_api_routines, vars,
1010 vfs:: { Pragma , PragmaErr , RegisterOpts , Vfs , VfsHandle , VfsResult , register_dynamic} ,
@@ -14,6 +14,8 @@ use sqlite_plugin::{
1414struct File {
1515 name : Option < String > ,
1616 data : Arc < Mutex < Vec < u8 > > > ,
17+ /// Single shared-memory page used for WAL index.
18+ shm : Arc < Mutex < Option < Vec < u8 > > > > ,
1719 delete_on_close : bool ,
1820 opts : OpenOpts ,
1921}
@@ -65,6 +67,7 @@ impl Vfs for MemVfs {
6567 let file = File {
6668 name : Some ( path. to_owned ( ) ) ,
6769 data : Default :: default ( ) ,
70+ shm : Default :: default ( ) ,
6871 delete_on_close : opts. delete_on_close ( ) ,
6972 opts,
7073 } ;
@@ -74,6 +77,7 @@ impl Vfs for MemVfs {
7477 let file = File {
7578 name : None ,
7679 data : Default :: default ( ) ,
80+ shm : Default :: default ( ) ,
7781 delete_on_close : opts. delete_on_close ( ) ,
7882 opts,
7983 } ;
@@ -188,6 +192,65 @@ impl Vfs for MemVfs {
188192 log:: debug!( "pragma: file={:?}, pragma={:?}" , handle. name, pragma) ;
189193 Err ( PragmaErr :: NotFound )
190194 }
195+
196+ fn shm_map (
197+ & self ,
198+ handle : & mut Self :: Handle ,
199+ region_idx : usize ,
200+ region_size : usize ,
201+ extend : bool ,
202+ ) -> VfsResult < Option < NonNull < u8 > > > {
203+ log:: debug!(
204+ "shm_map: file={:?}, region_idx={}, region_size={}, extend={}" ,
205+ handle. name,
206+ region_idx,
207+ region_size,
208+ extend
209+ ) ;
210+
211+ assert_eq ! ( region_idx, 0 , "memvfs only supports a single shm region" ) ;
212+
213+ let mut shm = handle. shm . lock ( ) ;
214+ if shm. is_none ( ) {
215+ if !extend {
216+ return Ok ( None ) ;
217+ }
218+ * shm = Some ( vec ! [ 0u8 ; region_size] ) ;
219+ }
220+ let buf = shm. as_mut ( ) . unwrap ( ) ;
221+ Ok ( NonNull :: new ( buf. as_mut_ptr ( ) ) )
222+ }
223+
224+ fn shm_lock (
225+ & self ,
226+ handle : & mut Self :: Handle ,
227+ offset : u32 ,
228+ count : u32 ,
229+ mode : ShmLockMode ,
230+ ) -> VfsResult < ( ) > {
231+ log:: debug!(
232+ "shm_lock: file={:?}, offset={}, count={}, mode={:?}" ,
233+ handle. name,
234+ offset,
235+ count,
236+ mode
237+ ) ;
238+ // No-op: single-process in-memory VFS needs no locking.
239+ Ok ( ( ) )
240+ }
241+
242+ fn shm_barrier ( & self , handle : & mut Self :: Handle ) {
243+ log:: debug!( "shm_barrier: file={:?}" , handle. name) ;
244+ // No-op: single-process, no cross-process memory ordering needed.
245+ }
246+
247+ fn shm_unmap ( & self , handle : & mut Self :: Handle , delete : bool ) -> VfsResult < ( ) > {
248+ log:: debug!( "shm_unmap: file={:?}, delete={}" , handle. name, delete) ;
249+ if delete {
250+ * handle. shm . lock ( ) = None ;
251+ }
252+ Ok ( ( ) )
253+ }
191254}
192255
193256fn setup_logger ( logger : SqliteLogger ) {
0 commit comments