Skip to content

Comments

Add shared memory support#73

Closed
bkoropoff wants to merge 1 commit intoorbitinghail:mainfrom
bkoropoff:shm
Closed

Add shared memory support#73
bkoropoff wants to merge 1 commit intoorbitinghail:mainfrom
bkoropoff:shm

Conversation

@bkoropoff
Copy link
Contributor

This requires a new associated type for mapped pages/regions which would break backward compatibility without default associated types, which is currently unstable in Rust. Instead, a new ShmVfs trait is introduced with alternate registration methods. Most of the code is shared between the two except for the open/close glue functions for ShmVfs, which must initialize and tear down a derived file handle structure.

The lifetime semantics of returned mapped regions is a little odd: the region is only accessed once by sqlite immediately upon return, but we don't know for sure when it's done until it explicitly requests a new region, unmaps all regions, or closes the handle. Therefore the API glue obtains a region from the trait as an owned AsMut<[u8]> and holds on to it until its known to no longer be referenced, at which point its Drop impl can release resources.

The previous code which cast the sqlite3_file directly to &mut looked like it could lead to undefined behavior (it's UB to create an &mut to uninitialized memory, and even if sqlite zeroes the memory first, if there were any embedded NonZero you're still in UB territory). I instead ptr::write and ptr::read the whole thing.

This requires a new associated type for mapped regions which
would break backward compatibility without default associated types,
which is currently unstable in Rust.  Instead, a new `ShmVfs` trait
is introduced with alternate registration methods.  Most of the code
is shared between the two except for the open/close glue functions for
`ShmVfs`, which must initialize and tear down a derived file handle
structure.

The lifetime semantics of returned mapped regions is a little odd: the
region is only accessed once by sqlite immediately upon return, but we
don't know for sure when it's done until it explicitly requests a new
region, unmaps all regions, or closes the handle.  Therefore the API
glue obtains a region from the trait as an owned `AsMut<[u8]>` and holds
on to it until its known to no longer be referenced, at which point its
`Drop` impl can release resources.

The previous code which cast the `sqlite3_file` directly to `&mut`
looked like it could lead to undefined behavior (it's UB to create an
`&mut` to uninitialized memory, and even if sqlite zeroes the memory
first, if there were any embedded `NonZero` you're still in UB
territory).  I instead `ptr::write` and `ptr::read` the whole thing.
@carlsverre
Copy link
Contributor

Woof, this is a much larger change. I'd like to find time to connect and chat about this one before merging. Are you open to that?

@bkoropoff
Copy link
Contributor Author

On Discord? Yeah, hold on.

@bkoropoff
Copy link
Contributor Author

This can't work as designed since sqlite does hold multiple mapped regions at once, making a safe Rust interface very challenging. Needs a rework.

@bkoropoff bkoropoff closed this Feb 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants