@@ -287,6 +287,11 @@ pub enum OplogEntry {
287287 Error {
288288 timestamp : Timestamp ,
289289 error : WorkerError ,
290+ /// Points to the oplog index where the retry should start from. Normally this can be just the
291+ /// current oplog index (after the last persisted side-effect). When failing in an atomic region
292+ /// or batched remote writes, this should point to the start of the region.
293+ /// When counting the number of retries for a specific error, the error entries are grouped by this index.
294+ retry_from : OplogIndex ,
290295 } ,
291296 /// Marker entry added when get-oplog-index is called from the worker, to make the jumping behavior
292297 /// more predictable.
@@ -455,22 +460,31 @@ pub enum OplogEntry {
455460 timestamp : Timestamp ,
456461 level : PersistenceLevel ,
457462 } ,
463+ /// Marks the beginning of a remote transaction
458464 BeginRemoteTransaction {
459465 timestamp : Timestamp ,
460466 transaction_id : TransactionId ,
467+ /// BeginRemoteTransaction entries need to be repeated on retries, because they may need a new
468+ /// transaction_id. The `begin_index` field always points to the original, first entry. This makes
469+ /// error grouping work. When None, this is the original begin entry.
470+ original_begin_index : Option < OplogIndex > ,
461471 } ,
472+ /// Marks the point before a remote transaction is committed
462473 PreCommitRemoteTransaction {
463474 timestamp : Timestamp ,
464475 begin_index : OplogIndex ,
465476 } ,
477+ /// Marks the point before a remote transaction is rolled back
466478 PreRollbackRemoteTransaction {
467479 timestamp : Timestamp ,
468480 begin_index : OplogIndex ,
469481 } ,
482+ /// Marks the point after a remote transaction is committed
470483 CommittedRemoteTransaction {
471484 timestamp : Timestamp ,
472485 begin_index : OplogIndex ,
473486 } ,
487+ /// Marks the point after a remote transaction is rolled back
474488 RolledBackRemoteTransaction {
475489 timestamp : Timestamp ,
476490 begin_index : OplogIndex ,
@@ -526,10 +540,11 @@ impl OplogEntry {
526540 }
527541 }
528542
529- pub fn error ( error : WorkerError ) -> OplogEntry {
543+ pub fn error ( error : WorkerError , retry_from : OplogIndex ) -> OplogEntry {
530544 OplogEntry :: Error {
531545 timestamp : Timestamp :: now_utc ( ) ,
532546 error,
547+ retry_from,
533548 }
534549 }
535550
@@ -718,10 +733,14 @@ impl OplogEntry {
718733 }
719734 }
720735
721- pub fn begin_remote_transaction ( transaction_id : TransactionId ) -> OplogEntry {
736+ pub fn begin_remote_transaction (
737+ transaction_id : TransactionId ,
738+ original_begin_index : Option < OplogIndex > ,
739+ ) -> OplogEntry {
722740 OplogEntry :: BeginRemoteTransaction {
723741 timestamp : Timestamp :: now_utc ( ) ,
724742 transaction_id,
743+ original_begin_index,
725744 }
726745 }
727746
@@ -761,6 +780,10 @@ impl OplogEntry {
761780 matches ! ( self , OplogEntry :: EndRemoteWrite { begin_index, .. } if * begin_index == idx)
762781 }
763782
783+ pub fn is_end_remote_write_s < S > ( & self , idx : OplogIndex , _: & S ) -> bool {
784+ matches ! ( self , OplogEntry :: EndRemoteWrite { begin_index, .. } if * begin_index == idx)
785+ }
786+
764787 pub fn is_pre_commit_remote_transaction ( & self , idx : OplogIndex ) -> bool {
765788 matches ! ( self , OplogEntry :: PreCommitRemoteTransaction { begin_index, .. } if * begin_index == idx)
766789 }
@@ -773,43 +796,79 @@ impl OplogEntry {
773796 self . is_pre_commit_remote_transaction ( idx) || self . is_pre_rollback_remote_transaction ( idx)
774797 }
775798
799+ pub fn is_pre_remote_transaction_s < S > ( & self , idx : OplogIndex , _: & S ) -> bool {
800+ self . is_pre_commit_remote_transaction ( idx) || self . is_pre_rollback_remote_transaction ( idx)
801+ }
802+
776803 pub fn is_committed_remote_transaction ( & self , idx : OplogIndex ) -> bool {
777804 matches ! ( self , OplogEntry :: CommittedRemoteTransaction { begin_index, .. } if * begin_index == idx)
778805 }
779806
807+ pub fn is_committed_remote_transaction_s < S > ( & self , idx : OplogIndex , _: & S ) -> bool {
808+ matches ! ( self , OplogEntry :: CommittedRemoteTransaction { begin_index, .. } if * begin_index == idx)
809+ }
810+
780811 pub fn is_rolled_back_remote_transaction ( & self , idx : OplogIndex ) -> bool {
781812 matches ! ( self , OplogEntry :: RolledBackRemoteTransaction { begin_index, .. } if * begin_index == idx)
782813 }
783814
815+ pub fn is_rolled_back_remote_transaction_s < S > ( & self , idx : OplogIndex , _: & S ) -> bool {
816+ matches ! ( self , OplogEntry :: RolledBackRemoteTransaction { begin_index, .. } if * begin_index == idx)
817+ }
818+
784819 pub fn is_end_remote_transaction ( & self , idx : OplogIndex ) -> bool {
785820 self . is_committed_remote_transaction ( idx) || self . is_rolled_back_remote_transaction ( idx)
786821 }
787822
823+ pub fn is_end_remote_transaction_s < S > ( & self , idx : OplogIndex , s : & S ) -> bool {
824+ self . is_committed_remote_transaction_s ( idx, s)
825+ || self . is_rolled_back_remote_transaction_s ( idx, s)
826+ }
827+
788828 /// Checks that an "intermediate oplog entry" between a `BeginRemoteWrite` and an `EndRemoteWrite`
789829 /// is not a RemoteWrite entry which does not belong to the batched remote write started at `idx`.
790- pub fn no_concurrent_side_effect ( & self , idx : OplogIndex ) -> bool {
791- match self {
792- OplogEntry :: ImportedFunctionInvoked {
793- durable_function_type,
794- ..
795- } => match durable_function_type {
796- DurableFunctionType :: WriteRemoteBatched ( Some ( begin_index) )
797- if * begin_index == idx =>
798- {
799- true
800- }
801- DurableFunctionType :: WriteRemoteTransaction ( Some ( begin_index) )
802- if * begin_index == idx =>
803- {
804- true
805- }
806- DurableFunctionType :: ReadLocal => true ,
807- DurableFunctionType :: WriteLocal => true ,
808- DurableFunctionType :: ReadRemote => true ,
809- _ => false ,
810- } ,
811- OplogEntry :: ExportedFunctionCompleted { .. } => false ,
812- _ => true ,
830+ /// Side effects in a PersistenceLevel::PersistNothing region are ignored.
831+ pub fn no_concurrent_side_effect (
832+ & self ,
833+ idx : OplogIndex ,
834+ persistence_level : & PersistenceLevel ,
835+ ) -> bool {
836+ if persistence_level == & PersistenceLevel :: PersistNothing {
837+ true
838+ } else {
839+ match self {
840+ OplogEntry :: ImportedFunctionInvoked {
841+ durable_function_type,
842+ ..
843+ } => match durable_function_type {
844+ DurableFunctionType :: WriteRemoteBatched ( Some ( begin_index) )
845+ if * begin_index == idx =>
846+ {
847+ true
848+ }
849+ DurableFunctionType :: WriteRemoteTransaction ( Some ( begin_index) )
850+ if * begin_index == idx =>
851+ {
852+ true
853+ }
854+ DurableFunctionType :: ReadLocal => true ,
855+ DurableFunctionType :: WriteLocal => true ,
856+ DurableFunctionType :: ReadRemote => true ,
857+ _ => false ,
858+ } ,
859+ OplogEntry :: ExportedFunctionCompleted { .. } => false ,
860+ _ => true ,
861+ }
862+ }
863+ }
864+
865+ pub fn track_persistence_level (
866+ & self ,
867+ _idx : OplogIndex ,
868+ persistence_level : & mut PersistenceLevel ,
869+ ) {
870+ if let OplogEntry :: ChangePersistenceLevel { level, .. } = self {
871+ * persistence_level = * level
813872 }
814873 }
815874
0 commit comments