Skip to content

Commit 4533635

Browse files
committed
Cache cl for pks in map
Signed-off-by: Somtochi Onyekwere <[email protected]>
1 parent b0930e2 commit 4533635

File tree

20 files changed

+485
-102
lines changed

20 files changed

+485
-102
lines changed

core/rs/bundle/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ crate-type = ["rlib"]
1616
crsql_fractindex_core = {path="../fractindex-core"}
1717
crsql_core = { path="../core" }
1818
sqlite_nostd = { path="../sqlite-rs-embedded/sqlite_nostd" }
19+
libc-print = "*"
1920

2021
[profile.dev]
2122
panic = "abort"

core/rs/bundle/src/lib.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ use crsql_core::sqlite3_crsqlcore_init;
1111
#[cfg(feature = "test")]
1212
pub use crsql_core::test_exports;
1313
use crsql_fractindex_core::sqlite3_crsqlfractionalindex_init;
14+
#[cfg(feature = "test")]
15+
use libc_print::std_name::println;
1416
use sqlite_nostd as sqlite;
1517
use sqlite_nostd::SQLite3Allocator;
1618

@@ -21,11 +23,20 @@ static ALLOCATOR: SQLite3Allocator = SQLite3Allocator {};
2123

2224
// This must be our panic handler for WASM builds. For simplicity, we make it our panic handler for
2325
// all builds. Abort is also more portable than unwind, enabling us to go to more embedded use cases.
26+
#[cfg(not(feature = "test"))]
2427
#[panic_handler]
2528
fn panic(_info: &PanicInfo) -> ! {
2629
core::intrinsics::abort()
2730
}
2831

32+
// Print panic info for tests
33+
#[cfg(feature = "test")]
34+
#[panic_handler]
35+
fn panic(info: &PanicInfo) -> ! {
36+
println!("PANIC!: {}", info);
37+
core::intrinsics::abort();
38+
}
39+
2940
#[cfg(not(target_family = "wasm"))]
3041
#[lang = "eh_personality"]
3142
extern "C" fn eh_personality() {}

core/rs/bundle_static/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.

core/rs/core/src/c.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ pub struct crsql_ExtData {
7474
pub mergeEqualValues: ::core::ffi::c_int,
7575
pub timestamp: ::core::ffi::c_ulonglong,
7676
pub ordinalMap: *mut ::core::ffi::c_void,
77+
pub clCache: *mut ::core::ffi::c_void,
7778
}
7879

7980
#[repr(C)]
@@ -271,7 +272,7 @@ fn bindgen_test_layout_crsql_ExtData() {
271272
let ptr = UNINIT.as_ptr();
272273
assert_eq!(
273274
::core::mem::size_of::<crsql_ExtData>(),
274-
168usize,
275+
176usize,
275276
concat!("Size of: ", stringify!(crsql_ExtData))
276277
);
277278
assert_eq!(
@@ -511,4 +512,14 @@ fn bindgen_test_layout_crsql_ExtData() {
511512
stringify!(ordinalMap)
512513
)
513514
);
515+
assert_eq!(
516+
unsafe { ::core::ptr::addr_of!((*ptr).clCache) as usize - ptr as usize },
517+
168usize,
518+
concat!(
519+
"Offset of field: ",
520+
stringify!(crsql_ExtData),
521+
"::",
522+
stringify!(clCache)
523+
)
524+
);
514525
}

core/rs/core/src/changes_vtab.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,19 @@ pub extern "C" fn crsql_changes_rollback_to(vtab: *mut sqlite::vtab, _: c_int) -
586586
(*(*tab).pExtData).ordinalMap as *mut BTreeMap<Vec<u8>, i64>,
587587
))
588588
};
589+
590+
let mut cl_cache = unsafe {
591+
mem::ManuallyDrop::new(Box::from_raw(
592+
(*(*tab).pExtData).clCache as *mut BTreeMap<String, BTreeMap<i64, i64>>,
593+
))
594+
};
595+
596+
for (_, map) in cl_cache.iter_mut() {
597+
if !map.is_empty() {
598+
map.clear();
599+
}
600+
}
601+
589602
ordinals.clear();
590603
ResultCode::OK as c_int
591604
}

core/rs/core/src/changes_vtab_write.rs

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use alloc::boxed::Box;
2+
use alloc::collections::BTreeMap;
23
use alloc::ffi::CString;
34
use alloc::format;
5+
use alloc::string::String;
46
use alloc::vec::Vec;
57
use core::ffi::{c_char, c_int};
68
use core::mem;
@@ -466,6 +468,11 @@ unsafe fn merge_insert(
466468
let tbl_infos = mem::ManuallyDrop::new(Box::from_raw(
467469
(*(*tab).pExtData).tableInfos as *mut Vec<TableInfo>,
468470
));
471+
472+
let mut cl_cache = mem::ManuallyDrop::new(Box::from_raw(
473+
(*(*tab).pExtData).clCache as *mut BTreeMap<String, BTreeMap<i64, i64>>,
474+
));
475+
469476
// TODO: will this work given `insert_tbl` is null termed?
470477
let tbl_info_index = tbl_infos.iter().position(|x| x.tbl_name == insert_tbl);
471478

@@ -487,7 +494,7 @@ unsafe fn merge_insert(
487494
// We'll need the key for all later operations.
488495
let key = tbl_info.get_or_create_key(db, &unpacked_pks)?;
489496

490-
let local_cl = get_local_cl(db, &tbl_info, key)?;
497+
let local_cl = get_pk_cl(db, &mut cl_cache, &tbl_info, key)?;
491498

492499
// We can ignore all updates from older causal lengths.
493500
// They won't win at anything.
@@ -593,8 +600,6 @@ unsafe fn merge_insert(
593600
*rowid = slab_rowid(tbl_info_index as i32, inner_rowid);
594601
}
595602
return Ok(ResultCode::OK);
596-
597-
598603
}
599604

600605
// we got a causal length which would resurrect the row.
@@ -712,7 +717,40 @@ unsafe fn merge_insert(
712717
*errmsg = err.into_raw();
713718
return Err(rc);
714719
}
720+
721+
// a bigger cl always wins
722+
if insert_cl > local_cl {
723+
match cl_cache.get_mut(&tbl_info.tbl_name) {
724+
Some(x) => {
725+
x.insert(key, insert_cl);
726+
}
727+
None => {
728+
let mut new_map = BTreeMap::new();
729+
new_map.insert(key, insert_cl);
730+
cl_cache.insert(tbl_info.tbl_name.clone(), new_map);
731+
}
732+
}
733+
}
715734
}
716735

717736
res
718737
}
738+
739+
unsafe fn get_pk_cl(
740+
db: *mut sqlite3,
741+
cl_cache: &mut BTreeMap<String, BTreeMap<i64, i64>>,
742+
tbl_info: &TableInfo,
743+
key: sqlite::int64,
744+
) -> Result<sqlite::int64, ResultCode> {
745+
match cl_cache.get(&tbl_info.tbl_name).and_then(|x| x.get(&key)) {
746+
Some(cl) => Ok(*cl),
747+
None => {
748+
let cl = get_local_cl(db, tbl_info, key)?;
749+
cl_cache
750+
.entry(tbl_info.tbl_name.clone())
751+
.or_default()
752+
.insert(key, cl);
753+
Ok(cl)
754+
}
755+
}
756+
}

core/rs/core/src/commit.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use alloc::{boxed::Box, collections::BTreeMap, vec::Vec};
1+
use alloc::{boxed::Box, collections::BTreeMap, string::String, vec::Vec};
22
use core::{
33
ffi::{c_int, c_void},
44
mem,
@@ -37,5 +37,17 @@ pub unsafe fn commit_or_rollback_reset(ext_data: *mut crsql_ExtData) {
3737
let mut ordinals: mem::ManuallyDrop<Box<BTreeMap<Vec<u8>, i64>>> = mem::ManuallyDrop::new(
3838
Box::from_raw((*ext_data).ordinalMap as *mut BTreeMap<Vec<u8>, i64>),
3939
);
40+
41+
let mut cl_cache = unsafe {
42+
mem::ManuallyDrop::new(Box::from_raw(
43+
(*ext_data).clCache as *mut BTreeMap<String, BTreeMap<i64, i64>>,
44+
))
45+
};
46+
47+
for (_, map) in cl_cache.iter_mut() {
48+
if !map.is_empty() {
49+
map.clear();
50+
}
51+
}
4052
ordinals.clear();
4153
}

core/rs/core/src/db_version.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,21 @@ pub extern "C" fn crsql_drop_ordinal_map(ext_data: *mut crsql_ExtData) {
211211
}
212212
}
213213

214+
#[no_mangle]
215+
pub extern "C" fn crsql_init_cl_cache(ext_data: *mut crsql_ExtData) {
216+
let map: BTreeMap<String, BTreeMap<i64, i64>> = BTreeMap::new();
217+
unsafe { (*ext_data).clCache = Box::into_raw(Box::new(map)) as *mut c_void }
218+
}
219+
220+
#[no_mangle]
221+
pub extern "C" fn crsql_drop_cl_cache(ext_data: *mut crsql_ExtData) {
222+
unsafe {
223+
drop(Box::from_raw(
224+
(*ext_data).clCache as *mut BTreeMap<String, BTreeMap<i64, i64>>,
225+
));
226+
}
227+
}
228+
214229
pub fn insert_db_version(
215230
ext_data: *mut crsql_ExtData,
216231
insert_site_id: &[u8],

core/rs/core/src/lib.rs

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ mod unpack_columns_vtab;
4949
mod util;
5050

5151
use alloc::format;
52+
use alloc::string::String;
5253
use alloc::string::ToString;
5354
use alloc::{borrow::Cow, boxed::Box, collections::BTreeMap, vec::Vec};
5455
use core::ffi::c_char;
@@ -453,19 +454,30 @@ pub extern "C" fn sqlite3_crsqlcore_init(
453454
}
454455

455456
#[cfg(feature = "test")]
456-
let rc = db
457-
.create_function_v2(
458-
"crsql_cache_site_ordinal",
459-
1,
460-
sqlite::UTF8 | sqlite::DETERMINISTIC,
461-
Some(ext_data as *mut c_void),
462-
Some(x_crsql_cache_site_ordinal),
463-
None,
464-
None,
465-
None,
466-
)
467-
.unwrap_or(ResultCode::ERROR);
468-
if rc != ResultCode::OK {
457+
if let Err(_) = db.create_function_v2(
458+
"crsql_cache_site_ordinal",
459+
1,
460+
sqlite::UTF8 | sqlite::DETERMINISTIC,
461+
Some(ext_data as *mut c_void),
462+
Some(x_crsql_cache_site_ordinal),
463+
None,
464+
None,
465+
None,
466+
) {
467+
unsafe { crsql_freeExtData(ext_data) };
468+
return null_mut();
469+
}
470+
471+
if let Err(_) = db.create_function_v2(
472+
"crsql_cache_pk_cl",
473+
2,
474+
sqlite::UTF8 | sqlite::DETERMINISTIC,
475+
Some(ext_data as *mut c_void),
476+
Some(x_crsql_cache_pk_cl),
477+
None,
478+
None,
479+
None,
480+
) {
469481
unsafe { crsql_freeExtData(ext_data) };
470482
return null_mut();
471483
}
@@ -975,6 +987,39 @@ unsafe extern "C" fn x_crsql_cache_site_ordinal(
975987
sqlite::result_int64(ctx, res);
976988
}
977989

990+
/**
991+
* Get the pk cl cached in the ext data for the current transaction.
992+
* only used for test to inspect the cl cache.
993+
*/
994+
unsafe extern "C" fn x_crsql_cache_pk_cl(
995+
ctx: *mut sqlite::context,
996+
argc: i32,
997+
argv: *mut *mut sqlite::value,
998+
) {
999+
if argc < 2 {
1000+
ctx.result_error(
1001+
"Wrong number of args provided to crsql_cache_pk_cl. Provide the table name and pk key.",
1002+
);
1003+
return;
1004+
}
1005+
1006+
let ext_data = ctx.user_data() as *mut c::crsql_ExtData;
1007+
let args = sqlite::args!(argc, argv);
1008+
let table_name = args[0].text();
1009+
let pk_key = args[1].int64();
1010+
1011+
let cl_cache = mem::ManuallyDrop::new(Box::from_raw(
1012+
(*ext_data).clCache as *mut BTreeMap<String, BTreeMap<i64, i64>>,
1013+
));
1014+
1015+
let table_map = cl_cache.get(table_name);
1016+
let cl = table_map
1017+
.and_then(|x| x.get(&pk_key))
1018+
.cloned()
1019+
.unwrap_or(-1);
1020+
sqlite::result_int64(ctx, cl);
1021+
}
1022+
9781023
/**
9791024
* Return the timestamp for the current transaction.
9801025
*/

core/rs/core/src/local_writes/after_delete.rs

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use alloc::string::String;
22
use alloc::string::ToString;
3+
use alloc::{boxed::Box, collections::BTreeMap};
34
use core::ffi::c_int;
5+
use core::mem;
46
use sqlite::sqlite3;
57
use sqlite::value;
68
use sqlite::Context;
@@ -10,6 +12,7 @@ use sqlite_nostd as sqlite;
1012
use crate::{c::crsql_ExtData, tableinfo::TableInfo};
1113

1214
use super::bump_seq;
15+
use super::mark_locally_deleted;
1316
use super::trigger_fn_preamble;
1417

1518
/**
@@ -47,19 +50,7 @@ fn after_delete(
4750
.get_or_create_key_via_raw_values(db, pks_old)
4851
.map_err(|_| "failed getting or creating lookaside key")?;
4952

50-
let mark_locally_deleted_stmt_ref = tbl_info
51-
.get_mark_locally_deleted_stmt(db)
52-
.map_err(|_e| "failed to get mark_locally_deleted_stmt")?;
53-
let mark_locally_deleted_stmt = mark_locally_deleted_stmt_ref
54-
.as_ref()
55-
.ok_or("Failed to deref sentinel stmt")?;
56-
mark_locally_deleted_stmt
57-
.bind_int64(1, key)
58-
.and_then(|_| mark_locally_deleted_stmt.bind_int64(2, db_version))
59-
.and_then(|_| mark_locally_deleted_stmt.bind_int(3, seq))
60-
.and_then(|_| mark_locally_deleted_stmt.bind_text(4, &ts, sqlite::Destructor::STATIC))
61-
.map_err(|_| "failed binding to mark locally deleted stmt")?;
62-
super::step_trigger_stmt(mark_locally_deleted_stmt)?;
53+
let cl = mark_locally_deleted(db, tbl_info, key, db_version, seq, &ts)?;
6354

6455
// now actually delete the row metadata
6556
let drop_clocks_stmt_ref = tbl_info
@@ -72,5 +63,17 @@ fn after_delete(
7263
drop_clocks_stmt
7364
.bind_int64(1, key)
7465
.map_err(|_e| "failed to bind pks to drop_clocks_stmt")?;
75-
super::step_trigger_stmt(drop_clocks_stmt)
66+
super::step_trigger_stmt(drop_clocks_stmt)?;
67+
68+
let mut cl_cache = unsafe {
69+
mem::ManuallyDrop::new(Box::from_raw(
70+
(*ext_data).clCache as *mut BTreeMap<String, BTreeMap<i64, i64>>,
71+
))
72+
};
73+
cl_cache
74+
.entry(tbl_info.tbl_name.clone())
75+
.or_default()
76+
.insert(key, cl);
77+
78+
Ok(ResultCode::OK)
7679
}

0 commit comments

Comments
 (0)