@@ -163,6 +163,13 @@ impl<'a> CommitBuilder<'a> {
163163 self
164164 }
165165
166+ /// When enabled, fail the commit if any transactions have been committed since
167+ /// the transaction's read version. This enforces strict serial ordering.
168+ pub fn with_serial_commit ( mut self , serial_commit : bool ) -> Self {
169+ self . commit_config . serial_commit = serial_commit;
170+ self
171+ }
172+
166173 /// Provide the set of row addresses that were deleted or updated. This is
167174 /// used to perform fast conflict resolution.
168175 pub fn with_affected_rows ( mut self , affected_rows : RowAddrTreeMap ) -> Self {
@@ -725,6 +732,54 @@ mod tests {
725732 assert_io_eq ! ( io_stats, write_iops, 2 ) ; // txn + manifest
726733 }
727734
735+ #[ tokio:: test]
736+ async fn test_serial_commit ( ) {
737+ // Create a dataset with a single committed version.
738+ let session = Arc :: new ( Session :: default ( ) ) ;
739+ let write_params = WriteParams {
740+ session : Some ( session. clone ( ) ) ,
741+ ..Default :: default ( )
742+ } ;
743+ let data = RecordBatch :: try_new (
744+ Arc :: new ( ArrowSchema :: new ( vec ! [ ArrowField :: new(
745+ "a" ,
746+ DataType :: Int32 ,
747+ false ,
748+ ) ] ) ) ,
749+ vec ! [ Arc :: new( Int32Array :: from( vec![ 0 ; 5 ] ) ) ] ,
750+ )
751+ . unwrap ( ) ;
752+ let dataset = InsertBuilder :: new ( "memory://force_fail_any_update" )
753+ . with_params ( & write_params)
754+ . execute ( vec ! [ data] )
755+ . await
756+ . unwrap ( ) ;
757+ let dataset = Arc :: new ( dataset) ;
758+ let base_read_version = dataset. manifest ( ) . version ;
759+ assert_eq ! ( base_read_version, 1 ) ;
760+
761+ // Advance the dataset to version 2 using the same read_version.
762+ let _ = CommitBuilder :: new ( dataset. clone ( ) )
763+ . execute ( sample_transaction ( base_read_version) )
764+ . await
765+ . unwrap ( ) ;
766+
767+ // Attempt to commit again using the stale read_version and serial_commit.
768+ let result = CommitBuilder :: new ( dataset. clone ( ) )
769+ . with_serial_commit ( true )
770+ . execute ( sample_transaction ( base_read_version) )
771+ . await ;
772+
773+ assert ! ( matches!( result, Err ( Error :: CommitConflict { .. } ) ) ) ;
774+
775+ // Successfully commit using the same read_version and non serial_isolation.
776+ CommitBuilder :: new ( dataset. clone ( ) )
777+ . with_serial_commit ( false )
778+ . execute ( sample_transaction ( base_read_version) )
779+ . await
780+ . unwrap ( ) ;
781+ }
782+
728783 #[ tokio:: test]
729784 async fn test_commit_batch ( ) {
730785 // Create a dataset
0 commit comments