Skip to content

Commit 907cbc3

Browse files
committed
feat: add timetravel by version number
1 parent 4a13e74 commit 907cbc3

File tree

1 file changed

+53
-8
lines changed

1 file changed

+53
-8
lines changed

ffi/src/lib.rs

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -568,14 +568,31 @@ pub unsafe extern "C" fn snapshot(
568568
) -> ExternResult<Handle<SharedSnapshot>> {
569569
let url = unsafe { unwrap_and_parse_path_as_url(path) };
570570
let engine = unsafe { engine.as_ref() };
571-
snapshot_impl(url, engine).into_extern_result(&engine)
571+
snapshot_impl(url, engine, None).into_extern_result(&engine)
572+
}
573+
574+
/// Get the snapshot from the specified table at a specific version
575+
///
576+
/// # Safety
577+
///
578+
/// Caller is responsible for passing valid handles and path pointer.
579+
#[no_mangle]
580+
pub unsafe extern "C" fn snapshot_at_version(
581+
path: KernelStringSlice,
582+
engine: Handle<SharedExternEngine>,
583+
version: u64,
584+
) -> ExternResult<Handle<SharedSnapshot>> {
585+
let url = unsafe { unwrap_and_parse_path_as_url(path) };
586+
let engine = unsafe { engine.as_ref() };
587+
snapshot_impl(url, engine, version.into()).into_extern_result(&engine)
572588
}
573589

574590
fn snapshot_impl(
575591
url: DeltaResult<Url>,
576592
extern_engine: &dyn ExternEngine,
593+
version: Option<u64>,
577594
) -> DeltaResult<Handle<SharedSnapshot>> {
578-
let snapshot = Snapshot::try_new(url?, extern_engine.engine().as_ref(), None)?;
595+
let snapshot = Snapshot::try_new(url?, extern_engine.engine().as_ref(), version.into())?;
579596
Ok(Arc::new(snapshot).into())
580597
}
581598

@@ -776,6 +793,12 @@ mod tests {
776793
Some(ptr)
777794
}
778795

796+
// helper to recover an error from the above
797+
fn recover_error(ptr: *mut EngineError) -> EngineError {
798+
let ptr = ptr.cast();
799+
*unsafe { Box::from_raw(ptr) }
800+
}
801+
779802
// helper to recover a string from the above
780803
fn recover_string(ptr: NonNull<c_void>) -> String {
781804
let ptr = ptr.as_ptr().cast();
@@ -834,18 +857,40 @@ mod tests {
834857
let engine = engine_to_handle(Arc::new(engine), allocate_err);
835858
let path = "memory:///";
836859

837-
let snapshot =
860+
// Test getting latest snapshot
861+
let snapshot1 =
838862
unsafe { ok_or_panic(snapshot(kernel_string_slice!(path), engine.shallow_copy())) };
863+
let version1 = unsafe { version(snapshot1.shallow_copy()) };
864+
assert_eq!(version1, 0);
865+
866+
// Test getting snapshot at version
867+
let snapshot2 = unsafe {
868+
ok_or_panic(snapshot_at_version(
869+
kernel_string_slice!(path),
870+
engine.shallow_copy(),
871+
0,
872+
))
873+
};
874+
let version2 = unsafe { version(snapshot2.shallow_copy()) };
875+
assert_eq!(version2, 0);
876+
877+
// Test getting non-existent snapshot
878+
let snapshot_at_non_existent_version =
879+
unsafe { snapshot_at_version(kernel_string_slice!(path), engine.shallow_copy(), 1) };
880+
assert!(snapshot_at_non_existent_version.is_err());
881+
882+
// Avoid leaking the error by recovering it
883+
if let ExternResult::Err(e) = snapshot_at_non_existent_version {
884+
recover_error(e);
885+
}
839886

840-
let version = unsafe { version(snapshot.shallow_copy()) };
841-
assert_eq!(version, 0);
842-
843-
let table_root = unsafe { snapshot_table_root(snapshot.shallow_copy(), allocate_str) };
887+
let table_root = unsafe { snapshot_table_root(snapshot1.shallow_copy(), allocate_str) };
844888
assert!(table_root.is_some());
845889
let s = recover_string(table_root.unwrap());
846890
assert_eq!(&s, path);
847891

848-
unsafe { free_snapshot(snapshot) }
892+
unsafe { free_snapshot(snapshot1) }
893+
unsafe { free_snapshot(snapshot2) }
849894
unsafe { free_engine(engine) }
850895
Ok(())
851896
}

0 commit comments

Comments
 (0)