@@ -316,6 +316,9 @@ private static class EstimateTimeBasedBacklogQuotaCheckResult {
316
316
Long estimatedOldestUnacknowledgedMessageTimestamp ;
317
317
}
318
318
319
+ // The last position that can be dispatched to consumers
320
+ private volatile Position lastDispatchablePosition ;
321
+
319
322
/***
320
323
* We use 3 futures to prevent a new closing if there is an in-progress deletion or closing. We make Pulsar return
321
324
* the in-progress one when it is called the second time.
@@ -3889,18 +3892,57 @@ public Position getLastPosition() {
3889
3892
3890
3893
@ Override
3891
3894
public CompletableFuture <Position > getLastDispatchablePosition () {
3892
- return ManagedLedgerImplUtils .asyncGetLastValidPosition ((ManagedLedgerImpl ) ledger , entry -> {
3893
- MessageMetadata md = Commands .parseMessageMetadata (entry .getDataBuffer ());
3894
- // If a messages has marker will filter by AbstractBaseDispatcher.filterEntriesForConsumer
3895
- if (Markers .isServerOnlyMarker (md )) {
3896
- return false ;
3897
- } else if (md .hasTxnidMostBits () && md .hasTxnidLeastBits ()) {
3898
- // Filter-out transaction aborted messages.
3899
- TxnID txnID = new TxnID (md .getTxnidMostBits (), md .getTxnidLeastBits ());
3900
- return !isTxnAborted (txnID , (PositionImpl ) entry .getPosition ());
3901
- }
3902
- return true ;
3903
- }, getMaxReadPosition ());
3895
+ if (lastDispatchablePosition != null ) {
3896
+ return CompletableFuture .completedFuture (lastDispatchablePosition );
3897
+ }
3898
+ return ManagedLedgerImplUtils
3899
+ .asyncGetLastValidPosition ((ManagedLedgerImpl ) ledger , entry -> {
3900
+ MessageMetadata md = Commands .parseMessageMetadata (entry .getDataBuffer ());
3901
+ // If a messages has marker will filter by AbstractBaseDispatcher.filterEntriesForConsumer
3902
+ if (Markers .isServerOnlyMarker (md )) {
3903
+ return false ;
3904
+ } else if (md .hasTxnidMostBits () && md .hasTxnidLeastBits ()) {
3905
+ // Filter-out transaction aborted messages.
3906
+ TxnID txnID = new TxnID (md .getTxnidMostBits (), md .getTxnidLeastBits ());
3907
+ return !isTxnAborted (txnID , (PositionImpl ) entry .getPosition ());
3908
+ }
3909
+ return true ;
3910
+ }, getMaxReadPosition ())
3911
+ .thenApply (position -> {
3912
+ // Update lastDispatchablePosition to the given position
3913
+ updateLastDispatchablePosition (position );
3914
+ return position ;
3915
+ });
3916
+ }
3917
+
3918
+ /**
3919
+ * Update lastDispatchablePosition if the given position is greater than the lastDispatchablePosition.
3920
+ *
3921
+ * @param position
3922
+ */
3923
+ public synchronized void updateLastDispatchablePosition (Position position ) {
3924
+ // Update lastDispatchablePosition to null if the position is null, fallback to
3925
+ // ManagedLedgerImplUtils#asyncGetLastValidPosition
3926
+ if (position == null ) {
3927
+ lastDispatchablePosition = null ;
3928
+ return ;
3929
+ }
3930
+
3931
+ PositionImpl position0 = (PositionImpl ) position ;
3932
+ // If the position is greater than the maxReadPosition, ignore
3933
+ if (position0 .compareTo (getMaxReadPosition ()) > 0 ) {
3934
+ return ;
3935
+ }
3936
+ // If the lastDispatchablePosition is null, set it to the position
3937
+ if (lastDispatchablePosition == null ) {
3938
+ lastDispatchablePosition = position ;
3939
+ return ;
3940
+ }
3941
+ // If the position is greater than the lastDispatchablePosition, update it
3942
+ PositionImpl lastDispatchablePosition0 = (PositionImpl ) lastDispatchablePosition ;
3943
+ if (position0 .compareTo (lastDispatchablePosition0 ) > 0 ) {
3944
+ lastDispatchablePosition = position ;
3945
+ }
3904
3946
}
3905
3947
3906
3948
@ Override
0 commit comments