Skip to content

Commit f982fe5

Browse files
committed
refactor the fix
1 parent b030d2c commit f982fe5

2 files changed

Lines changed: 56 additions & 33 deletions

File tree

lib/ConsumerImpl.cc

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <pulsar/MessageIdBuilder.h>
2424

2525
#include <algorithm>
26+
#include <utility>
2627

2728
#include "AckGroupingTracker.h"
2829
#include "AckGroupingTrackerDisabled.h"
@@ -235,19 +236,28 @@ Future<Result, bool> ConsumerImpl::connectionOpened(const ClientConnectionPtr& c
235236

236237
// Register consumer so that we can handle other incomming commands (e.g. ACTIVE_CONSUMER_CHANGE) after
237238
// sending the subscribe request.
238-
cnx->registerConsumer(consumerId_, get_shared_this_ptr());
239-
LOG_DEBUG(cnx->cnxString() << "Registered consumer " << consumerId_);
239+
optional<MessageId> subscribeMessageId;
240+
bool duringSeek = false;
241+
{
242+
std::lock_guard<std::mutex> lock(mutex_);
243+
setCnx(cnx);
244+
cnx->registerConsumer(consumerId_, get_shared_this_ptr());
245+
LOG_DEBUG(cnx->cnxString() << "Registered consumer " << consumerId_);
240246

241-
if (hasPendingSeek_.load(std::memory_order_acquire)) {
247+
{
248+
std::lock_guard<std::mutex> lock(mutexForMessageId_);
249+
clearReceiveQueue();
250+
subscribeMessageId = (subscriptionMode_ == Commands::SubscriptionModeNonDurable)
251+
? startMessageId_.get()
252+
: std::nullopt;
253+
}
254+
255+
duringSeek = seekCallback_.has_value();
256+
}
257+
if (duringSeek) {
242258
ackGroupingTrackerPtr_->flushAndClean();
243259
}
244260

245-
Lock lockForMessageId(mutexForMessageId_);
246-
clearReceiveQueue();
247-
const auto subscribeMessageId =
248-
(subscriptionMode_ == Commands::SubscriptionModeNonDurable) ? startMessageId_.get() : std::nullopt;
249-
lockForMessageId.unlock();
250-
251261
unAckedMessageTrackerPtr_->clear();
252262

253263
ClientImplPtr client = client_.lock();
@@ -269,7 +279,6 @@ Future<Result, bool> ConsumerImpl::connectionOpened(const ClientConnectionPtr& c
269279
} else {
270280
promise.setFailed(handleResult);
271281
}
272-
completeSeekCallback(ResultOk);
273282
});
274283

275284
return promise.getFuture();
@@ -1130,7 +1139,11 @@ void ConsumerImpl::messageProcessed(Message& msg, bool track) {
11301139
* `startMessageId_` is updated so that we can discard messages after delivery restarts.
11311140
*/
11321141
void ConsumerImpl::clearReceiveQueue() {
1133-
if (hasPendingSeek_.load(std::memory_order_acquire)) {
1142+
// NOTE: This method must be called with `mutex_` held for thread safety where
1143+
if (seekCallback_.has_value()) {
1144+
executor_->postWork(
1145+
[callback{std::exchange(seekCallback_, std::nullopt).value()}] { callback(ResultOk); });
1146+
11341147
if (hasSoughtByTimestamp()) {
11351148
// Invalidate startMessageId_ so that isPriorBatchIndex and isPriorEntryIndex checks will be
11361149
// skipped, and hasMessageAvailableAsync won't use startMessageId_ in compare.
@@ -1733,9 +1746,16 @@ void ConsumerImpl::seekAsyncInternal(long requestId, const SharedBuffer& seek, c
17331746
callback(ResultNotConnected);
17341747
return;
17351748
}
1736-
1737-
auto expected = false;
1738-
if (!hasPendingSeek_.compare_exchange_strong(expected, true)) {
1749+
bool hasPendingSeek = false;
1750+
{
1751+
std::lock_guard<std::mutex> lock(mutex_);
1752+
if (seekCallback_.has_value()) {
1753+
hasPendingSeek = true;
1754+
} else {
1755+
seekCallback_ = std::move(callback);
1756+
}
1757+
}
1758+
if (hasPendingSeek) {
17391759
LOG_ERROR(getName() << " attempted to seek " << seekArg << " when there is a pending seek");
17401760
callback(ResultNotAllowedError);
17411761
return;
@@ -1748,37 +1768,46 @@ void ConsumerImpl::seekAsyncInternal(long requestId, const SharedBuffer& seek, c
17481768
seekMessageId_ = *boost::get<MessageId>(&seekArg);
17491769
hasSoughtByTimestamp_.store(false, std::memory_order_release);
17501770
}
1751-
seekCallback_ = std::move(callback);
17521771
LOG_INFO(getName() << " Seeking subscription to " << seekArg);
17531772

17541773
auto weakSelf = weak_from_this();
17551774

17561775
cnx->sendRequestWithId(seek, requestId, "SEEK")
1757-
.addListener([this, weakSelf, callback, originalSeekMessageId](Result result,
1758-
const ResponseData& responseData) {
1776+
.addListener([this, weakSelf, originalSeekMessageId](Result result,
1777+
const ResponseData& responseData) {
17591778
auto self = weakSelf.lock();
17601779
if (!self) {
1761-
callback(result);
17621780
return;
17631781
}
17641782
if (result == ResultOk) {
17651783
LOG_INFO(getName() << "Seek successfully");
17661784
ackGroupingTrackerPtr_->flushAndClean();
17671785
incomingMessages_.clear();
1768-
Lock lock(mutexForMessageId_);
1769-
lastDequedMessageId_ = MessageId::earliest();
1770-
lock.unlock();
1786+
{
1787+
std::lock_guard<std::mutex> lock(mutexForMessageId_);
1788+
lastDequedMessageId_ = MessageId::earliest();
1789+
}
17711790

1791+
std::lock_guard<std::mutex> lock(mutex_);
17721792
if (!getCnx().expired()) {
17731793
if (!hasSoughtByTimestamp()) {
17741794
startMessageId_ = seekMessageId_.get();
17751795
}
1776-
completeSeekCallback(result);
1796+
if (!seekCallback_.has_value()) {
1797+
LOG_ERROR(getName() << "Seek callback is not set");
1798+
return;
1799+
}
1800+
executor_->postWork(
1801+
[self, callback{std::exchange(seekCallback_, std::nullopt).value()}]() {
1802+
callback(ResultOk);
1803+
});
17771804
} // else: complete the seek future after connection is established
17781805
} else {
17791806
LOG_ERROR(getName() << "Failed to seek: " << result);
17801807
seekMessageId_ = originalSeekMessageId;
1781-
completeSeekCallback(result);
1808+
executor_->postWork([self, callback{std::exchange(seekCallback_, std::nullopt).value()}]() {
1809+
callback(ResultOk);
1810+
});
17821811
}
17831812
});
17841813
}

lib/ConsumerImpl.h

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <functional>
2828
#include <list>
2929
#include <memory>
30+
#include <optional>
3031
#include <set>
3132
#include <utility>
3233

@@ -225,14 +226,6 @@ class ConsumerImpl : public ConsumerImplBase {
225226

226227
void seekAsyncInternal(long requestId, const SharedBuffer& seek, const SeekArg& seekArg,
227228
ResultCallback&& callback);
228-
void completeSeekCallback(Result result) {
229-
bool expected = true;
230-
if (hasPendingSeek_.compare_exchange_strong(expected, false)) {
231-
if (auto callback = seekCallback_.release()) {
232-
callback(result);
233-
}
234-
}
235-
}
236229
void processPossibleToDLQ(const MessageId& messageId, const ProcessDLQCallBack& cb);
237230

238231
std::mutex mutexForReceiveWithZeroQueueSize;
@@ -276,9 +269,10 @@ class ConsumerImpl : public ConsumerImplBase {
276269
MessageId lastDequedMessageId_{MessageId::earliest()};
277270
MessageId lastMessageIdInBroker_{MessageId::earliest()};
278271

279-
Synchronized<ResultCallback> seekCallback_{[](Result) {}};
272+
// NOTE: The modification must be protected by `mutex_`
273+
std::optional<ResultCallback> seekCallback_;
274+
280275
Synchronized<optional<MessageId>> startMessageId_;
281-
std::atomic_bool hasPendingSeek_{false};
282276
Synchronized<MessageId> seekMessageId_{MessageId::earliest()};
283277
std::atomic<bool> hasSoughtByTimestamp_{false};
284278

0 commit comments

Comments
 (0)