@@ -236,16 +236,14 @@ Future<Result, bool> ConsumerImpl::connectionOpened(const ClientConnectionPtr& c
236236 // sending the subscribe request.
237237 cnx->registerConsumer (consumerId_, get_shared_this_ptr ());
238238
239- if (duringSeek_ ) {
239+ if (duringSeek () ) {
240240 ackGroupingTrackerPtr_->flushAndClean ();
241241 }
242242
243243 Lock lockForMessageId (mutexForMessageId_);
244- // Update startMessageId so that we can discard messages after delivery restarts
245- const auto startMessageId = clearReceiveQueue ();
244+ clearReceiveQueue ();
246245 const auto subscribeMessageId =
247- (subscriptionMode_ == Commands::SubscriptionModeNonDurable) ? startMessageId : boost::none;
248- startMessageId_ = startMessageId;
246+ (subscriptionMode_ == Commands::SubscriptionModeNonDurable) ? startMessageId_.get () : boost::none;
249247 lockForMessageId.unlock ();
250248
251249 unAckedMessageTrackerPtr_->clear ();
@@ -1048,14 +1046,21 @@ void ConsumerImpl::messageProcessed(Message& msg, bool track) {
10481046 * Clear the internal receiver queue and returns the message id of what was the 1st message in the queue that
10491047 * was
10501048 * not seen by the application
1049+ * `startMessageId_` is updated so that we can discard messages after delivery restarts.
10511050 */
1052- boost::optional<MessageId> ConsumerImpl::clearReceiveQueue () {
1053- bool expectedDuringSeek = true ;
1054- if (duringSeek_.compare_exchange_strong (expectedDuringSeek, false )) {
1055- return seekMessageId_.get ();
1051+ void ConsumerImpl::clearReceiveQueue () {
1052+ if (duringSeek ()) {
1053+ startMessageId_ = seekMessageId_.get ();
1054+ SeekStatus expected = SeekStatus::COMPLETED;
1055+ if (seekStatus_.compare_exchange_strong (expected, SeekStatus::NOT_STARTED)) {
1056+ auto seekCallback = seekCallback_.release ();
1057+ executor_->postWork ([seekCallback] { seekCallback (ResultOk); });
1058+ }
1059+ return ;
10561060 } else if (subscriptionMode_ == Commands::SubscriptionModeDurable) {
1057- return startMessageId_. get () ;
1061+ return ;
10581062 }
1063+
10591064 Message nextMessageInQueue;
10601065 if (incomingMessages_.peekAndClear (nextMessageInQueue)) {
10611066 // There was at least one message pending in the queue
@@ -1071,16 +1076,12 @@ boost::optional<MessageId> ConsumerImpl::clearReceiveQueue() {
10711076 .ledgerId (nextMessageId.ledgerId ())
10721077 .entryId (nextMessageId.entryId () - 1 )
10731078 .build ();
1074- return previousMessageId;
1079+ startMessageId_ = previousMessageId;
10751080 } else if (lastDequedMessageId_ != MessageId::earliest ()) {
10761081 // If the queue was empty we need to restart from the message just after the last one that has been
10771082 // dequeued
10781083 // in the past
1079- return lastDequedMessageId_;
1080- } else {
1081- // No message was received or dequeued by this consumer. Next message would still be the
1082- // startMessageId
1083- return startMessageId_.get ();
1084+ startMessageId_ = lastDequedMessageId_;
10841085 }
10851086}
10861087
@@ -1500,18 +1501,15 @@ void ConsumerImpl::seekAsync(uint64_t timestamp, ResultCallback callback) {
15001501
15011502bool ConsumerImpl::isReadCompacted () { return readCompacted_; }
15021503
1503- inline bool hasMoreMessages (const MessageId& lastMessageIdInBroker, const MessageId& messageId) {
1504- return lastMessageIdInBroker > messageId && lastMessageIdInBroker.entryId () != -1 ;
1505- }
1506-
15071504void ConsumerImpl::hasMessageAvailableAsync (HasMessageAvailableCallback callback) {
1508- const auto startMessageId = startMessageId_.get ();
1509- Lock lock (mutexForMessageId_);
1510- const auto messageId =
1511- (lastDequedMessageId_ == MessageId::earliest ()) ? startMessageId.value () : lastDequedMessageId_;
1512-
1513- if (messageId == MessageId::latest ()) {
1514- lock.unlock ();
1505+ bool compareMarkDeletePosition;
1506+ {
1507+ std::lock_guard<std::mutex> lock{mutexForMessageId_};
1508+ compareMarkDeletePosition =
1509+ (lastDequedMessageId_ == MessageId::earliest ()) &&
1510+ (startMessageId_.get ().value_or (MessageId::earliest ()) == MessageId::latest ());
1511+ }
1512+ if (compareMarkDeletePosition) {
15151513 auto self = get_shared_this_ptr ();
15161514 getLastMessageIdAsync ([self, callback](Result result, const GetLastMessageIdResponse& response) {
15171515 if (result != ResultOk) {
@@ -1543,16 +1541,15 @@ void ConsumerImpl::hasMessageAvailableAsync(HasMessageAvailableCallback callback
15431541 }
15441542 });
15451543 } else {
1546- if (hasMoreMessages (lastMessageIdInBroker_, messageId)) {
1547- lock.unlock ();
1544+ if (hasMoreMessages ()) {
15481545 callback (ResultOk, true );
15491546 return ;
15501547 }
1551- lock. unlock ();
1552-
1553- getLastMessageIdAsync ([callback, messageId ](Result result, const GetLastMessageIdResponse& response) {
1554- callback (result, (result == ResultOk) && hasMoreMessages (response. getLastMessageId (), messageId ));
1555- });
1548+ auto self = get_shared_this_ptr ();
1549+ getLastMessageIdAsync (
1550+ [ this , self, callback ](Result result, const GetLastMessageIdResponse& response) {
1551+ callback (result, (result == ResultOk) && hasMoreMessages ());
1552+ });
15561553 }
15571554}
15581555
@@ -1656,9 +1653,18 @@ void ConsumerImpl::seekAsyncInternal(long requestId, SharedBuffer seek, const Me
16561653 return ;
16571654 }
16581655
1656+ auto expected = SeekStatus::NOT_STARTED;
1657+ if (!seekStatus_.compare_exchange_strong (expected, SeekStatus::IN_PROGRESS)) {
1658+ LOG_ERROR (getName () << " attempted to seek (" << seekId << " , " << timestamp << " when the status is "
1659+ << static_cast <int >(expected));
1660+ callback (ResultNotAllowedError);
1661+ return ;
1662+ }
1663+
16591664 const auto originalSeekMessageId = seekMessageId_.get ();
16601665 seekMessageId_ = seekId;
1661- duringSeek_ = true ;
1666+ seekStatus_ = SeekStatus::IN_PROGRESS;
1667+ seekCallback_ = std::move (callback);
16621668 if (timestamp > 0 ) {
16631669 LOG_INFO (getName () << " Seeking subscription to " << timestamp);
16641670 } else {
@@ -1682,12 +1688,19 @@ void ConsumerImpl::seekAsyncInternal(long requestId, SharedBuffer seek, const Me
16821688 Lock lock (mutexForMessageId_);
16831689 lastDequedMessageId_ = MessageId::earliest ();
16841690 lock.unlock ();
1691+ if (getCnx ().expired ()) {
1692+ // It's during reconnection, complete the seek future after connection is established
1693+ seekStatus_ = SeekStatus::COMPLETED;
1694+ } else {
1695+ startMessageId_ = seekMessageId_.get ();
1696+ seekCallback_.release ()(result);
1697+ }
16851698 } else {
16861699 LOG_ERROR (getName () << " Failed to seek: " << result);
16871700 seekMessageId_ = originalSeekMessageId;
1688- duringSeek_ = false ;
1701+ seekStatus_ = SeekStatus::NOT_STARTED;
1702+ seekCallback_.release ()(result);
16891703 }
1690- callback (result);
16911704 });
16921705}
16931706
0 commit comments