@@ -1075,10 +1075,20 @@ void ActiveStreamCheckpointProcessorTask::addStats(const std::string& name,
10751075}
10761076
10771077void ActiveStream::nextCheckpointItemTask () {
1078+ // MB-29369: Obtain stream mutex here
1079+ LockHolder lh (streamMutex);
1080+ nextCheckpointItemTask (lh);
1081+ }
1082+
1083+ void ActiveStream::nextCheckpointItemTask (const LockHolder& streamMutex) {
10781084 VBucketPtr vbucket = engine->getVBucket (vb_);
10791085 if (vbucket) {
1080- auto items = getOutstandingItems (*vbucket);
1081- processItems (items);
1086+ // MB-29369: only run the task's work if the stream is in an in-memory
1087+ // phase (of which takeover is a variant).
1088+ if (isInMemory () || isTakeoverSend ()) {
1089+ auto items = getOutstandingItems (*vbucket);
1090+ processItems (items, streamMutex);
1091+ }
10821092 } else {
10831093 /* The entity deleting the vbucket must set stream to dead,
10841094 calling setDead(END_STREAM_STATE) will cause deadlock because
@@ -1207,7 +1217,8 @@ std::unique_ptr<DcpResponse> ActiveStream::makeResponseFromItem(
12071217 }
12081218}
12091219
1210- void ActiveStream::processItems (std::vector<queued_item>& items) {
1220+ void ActiveStream::processItems (std::vector<queued_item>& items,
1221+ const LockHolder& streamMutex) {
12111222 if (!items.empty ()) {
12121223 bool mark = false ;
12131224 if (items.front ()->getOperation () == queue_op::checkpoint_start) {
@@ -1243,7 +1254,7 @@ void ActiveStream::processItems(std::vector<queued_item>& items) {
12431254 if (mutations.empty ()) {
12441255 // If we only got checkpoint start or ends check to see if there are
12451256 // any more snapshots before pausing the stream.
1246- nextCheckpointItemTask ();
1257+ nextCheckpointItemTask (streamMutex );
12471258 } else {
12481259 snapshot (mutations, mark);
12491260 }
@@ -1267,19 +1278,6 @@ void ActiveStream::snapshot(std::deque<std::unique_ptr<DcpResponse>>& items,
12671278 return ;
12681279 }
12691280
1270- LockHolder lh (streamMutex);
1271-
1272- if (!isActive () || isBackfilling ()) {
1273- // If stream was closed forcefully by the time the checkpoint items
1274- // retriever task completed, or if we decided to switch the stream to
1275- // backfill state from in-memory state, none of the acquired mutations
1276- // should be added on the stream's readyQ. We must drop items in case
1277- // we switch state from in-memory to backfill because we schedule
1278- // backfill from lastReadSeqno + 1
1279- items.clear ();
1280- return ;
1281- }
1282-
12831281 /* This assumes that all items in the "items deque" is put onto readyQ */
12841282 lastReadSeqno.store (lastReadSeqnoUnSnapshotted);
12851283
0 commit comments