Skip to content

Commit e02cef3

Browse files
committed
Pin<Box<Storage>> to ensure that Storage never moves, removed changes to sqlite-vfs, new just test command
1 parent d88c36b commit e02cef3

File tree

12 files changed

+84
-11
lines changed

12 files changed

+84
-11
lines changed

CONTRIBUTING.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ These tests are useful for learning more about how SQLSync works.
5252
just unit-test
5353
just test-end-to-end-local
5454
just test-end-to-end-local-net
55+
just test-sqlsync-reducer
56+
```
57+
58+
You can run all the tests in one command like so:
59+
60+
```bash
61+
just test
5562
```
5663

5764
### Submitting a pull request

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ worker = "0.0.18"
5151
event-listener = "3.0"
5252
sha2 = "0.10.8"
5353
serde-wasm-bindgen = "0.6"
54+
pin-project = "1.1"
5455

5556
# specific revision of tsify needed for serde updates
5657
tsify = { git = "https://github.com/siefkenj/tsify", rev = "145ed4c8ef6417003e182fad41d1c0f26ed645e5", default-features = false }

justfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ unit-test:
1414
build: build-wasm
1515
cargo build -p sqlsync
1616

17+
test:
18+
just unit-test
19+
just run-with-prefix 'test-'
20+
1721
build-wasm:
1822
just run-with-prefix 'wasm-'
1923

lib/sqlite-vfs/README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# sqlite-vfs
22

3-
Copied from https://github.com/rklaehn/sqlite-vfs and modified to include more hooks. Plan to upstream.
3+
Copy of https://github.com/rklaehn/sqlite-vfs.
4+
Only changed rusqlite dependency.
45

5-
LICENSE: Apache 2.0
6+
LICENSE: Apache 2.0

lib/sqlsync-reducer/examples/host.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ fn main() -> anyhow::Result<()> {
6565
}
6666
Request::Exec { sql, params } => {
6767
log::info!("received exec request: {} {:?}", sql, params);
68+
log::info!("the following error is EXPECTED");
6869
if sql == "FAIL" {
6970
let ptr = ffi.encode(
7071
&mut store,

lib/sqlsync/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ bs58.workspace = true
2525
hex.workspace = true
2626
libsqlite3-sys.workspace = true
2727
rusqlite.workspace = true
28+
pin-project.workspace = true
2829

2930
[dependencies.sqlsync-reducer]
3031
path = "../sqlsync-reducer"

lib/sqlsync/src/coordinator.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::collections::{HashMap, VecDeque};
33
use std::convert::From;
44
use std::fmt::Debug;
55
use std::io;
6+
use std::pin::Pin;
67

78
use rusqlite::Transaction;
89

@@ -25,7 +26,7 @@ struct ReceiveQueueEntry {
2526

2627
pub struct CoordinatorDocument<J: Journal, R> {
2728
reducer: R,
28-
storage: Box<Storage<J>>,
29+
storage: Pin<Box<Storage<J>>>,
2930
sqlite: ConnectionPair,
3031
timeline_factory: J::Factory,
3132
timelines: HashMap<JournalId, J>,

lib/sqlsync/src/db.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
1-
use std::convert::From;
1+
use std::{convert::From, pin::Pin};
22

33
use rusqlite::{
44
hooks::{AuthAction, AuthContext, Authorization},
55
Connection, OpenFlags, Transaction,
66
};
7-
use sqlite_vfs::FilePtr;
87

9-
use crate::{journal::Journal, page::PAGESIZE, storage::Storage, vfs::StorageVfs};
8+
use crate::{
9+
journal::Journal,
10+
page::PAGESIZE,
11+
storage::Storage,
12+
vfs::{FilePtr, StorageVfs},
13+
};
1014

1115
pub struct ConnectionPair {
1216
pub readwrite: Connection,
@@ -15,8 +19,8 @@ pub struct ConnectionPair {
1519

1620
pub fn open_with_vfs<J: Journal>(
1721
journal: J,
18-
) -> rusqlite::Result<(ConnectionPair, Box<Storage<J>>)> {
19-
let mut storage = Box::new(Storage::new(journal));
22+
) -> rusqlite::Result<(ConnectionPair, Pin<Box<Storage<J>>>)> {
23+
let mut storage = Box::pin(Storage::new(journal));
2024
let storage_ptr = FilePtr::new(&mut storage);
2125

2226
// generate random vfs name

lib/sqlsync/src/local.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{fmt::Debug, io};
1+
use std::{fmt::Debug, io, pin::Pin};
22

33
use rusqlite::Connection;
44

@@ -26,7 +26,7 @@ impl Signal for NoopSignal {
2626
pub struct LocalDocument<J, S> {
2727
reducer: WasmReducer,
2828
timeline: J,
29-
storage: Box<Storage<J>>,
29+
storage: Pin<Box<Storage<J>>>,
3030
sqlite: ConnectionPair,
3131

3232
// signals

lib/sqlsync/src/storage.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::{collections::HashSet, fmt::Debug, io};
22

3+
use pin_project::pin_project;
34
use serde::{Deserialize, Serialize};
45
use sqlite_vfs::SQLITE_IOERR;
56

@@ -34,6 +35,7 @@ pub enum StorageChange {
3435
Tables { root_pages_sorted: Vec<PageIdx> },
3536
}
3637

38+
#[pin_project]
3739
pub struct Storage<J> {
3840
journal: J,
3941
visible_lsn_range: LsnRange,

lib/sqlsync/src/vfs.rs

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
use std::pin::Pin;
2+
13
use libsqlite3_sys::SQLITE_IOERR;
24
use log::{debug, trace};
3-
use sqlite_vfs::{File, FilePtr, OpenKind, Vfs, VfsResult};
5+
use sqlite_vfs::{File, OpenKind, Vfs, VfsResult};
46

57
use crate::{journal::Journal, storage::Storage, unixtime::unix_timestamp_milliseconds};
68

@@ -59,3 +61,51 @@ impl<J: Journal> Vfs for StorageVfs<J> {
5961
((2440587.5 + now / 864.0e5) * 864.0e5) as i64
6062
}
6163
}
64+
65+
/// Allow File to be an unsafe pointer
66+
pub struct FilePtr<T: File>(*mut T);
67+
68+
impl<T: File> FilePtr<T> {
69+
pub fn new(f: &mut Pin<Box<T>>) -> Self {
70+
// SAFETY: we are creating a raw pointer from a reference to a Box
71+
// and we are not moving the Box, so the Box will not be dropped
72+
// while the raw pointer is still in use.
73+
Self(unsafe { f.as_mut().get_unchecked_mut() })
74+
}
75+
}
76+
77+
impl<T: File> Clone for FilePtr<T> {
78+
fn clone(&self) -> Self {
79+
Self(self.0)
80+
}
81+
}
82+
83+
impl<T: File> File for FilePtr<T> {
84+
fn sector_size(&self) -> usize {
85+
unsafe { (*self.0).sector_size() }
86+
}
87+
88+
fn device_characteristics(&self) -> i32 {
89+
unsafe { (*self.0).device_characteristics() }
90+
}
91+
92+
fn file_size(&self) -> VfsResult<u64> {
93+
unsafe { (*self.0).file_size() }
94+
}
95+
96+
fn truncate(&mut self, size: u64) -> VfsResult<()> {
97+
unsafe { (*self.0).truncate(size) }
98+
}
99+
100+
fn write(&mut self, pos: u64, buf: &[u8]) -> VfsResult<usize> {
101+
unsafe { (*self.0).write(pos, buf) }
102+
}
103+
104+
fn read(&mut self, pos: u64, buf: &mut [u8]) -> VfsResult<usize> {
105+
unsafe { (*self.0).read(pos, buf) }
106+
}
107+
108+
fn sync(&mut self) -> VfsResult<()> {
109+
unsafe { (*self.0).sync() }
110+
}
111+
}

0 commit comments

Comments
 (0)