@@ -568,14 +568,31 @@ pub unsafe extern "C" fn snapshot(
568
568
) -> ExternResult < Handle < SharedSnapshot > > {
569
569
let url = unsafe { unwrap_and_parse_path_as_url ( path) } ;
570
570
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)
572
588
}
573
589
574
590
fn snapshot_impl (
575
591
url : DeltaResult < Url > ,
576
592
extern_engine : & dyn ExternEngine ,
593
+ version : Option < u64 > ,
577
594
) -> 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 ( ) ) ?;
579
596
Ok ( Arc :: new ( snapshot) . into ( ) )
580
597
}
581
598
@@ -776,6 +793,12 @@ mod tests {
776
793
Some ( ptr)
777
794
}
778
795
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
+
779
802
// helper to recover a string from the above
780
803
fn recover_string ( ptr : NonNull < c_void > ) -> String {
781
804
let ptr = ptr. as_ptr ( ) . cast ( ) ;
@@ -834,18 +857,40 @@ mod tests {
834
857
let engine = engine_to_handle ( Arc :: new ( engine) , allocate_err) ;
835
858
let path = "memory:///" ;
836
859
837
- let snapshot =
860
+ // Test getting latest snapshot
861
+ let snapshot1 =
838
862
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
+ }
839
886
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) } ;
844
888
assert ! ( table_root. is_some( ) ) ;
845
889
let s = recover_string ( table_root. unwrap ( ) ) ;
846
890
assert_eq ! ( & s, path) ;
847
891
848
- unsafe { free_snapshot ( snapshot) }
892
+ unsafe { free_snapshot ( snapshot1) }
893
+ unsafe { free_snapshot ( snapshot2) }
849
894
unsafe { free_engine ( engine) }
850
895
Ok ( ( ) )
851
896
}
0 commit comments