Skip to content

Commit 9469159

Browse files
abhinavdangetichiyoung
authored andcommitted
MB-19228: Address possible data races in ActiveStream context
Address possible data races in ActiveStream context when gathering stats. WARNING: ThreadSanitizer: data race (pid=27028) Read of size 8 at 0x7d480000b1f8 by main thread (mutexes: write M32941632, write M1367, write M32940809): #0 void STATWRITER_NAMESPACE::add_casted_stat<unsigned long>(char const*, unsigned long const&, void (*)(char const*, unsigned short, char const*, unsigned int, void const*), void const*) /home/abhinav/couchbase/ep-engine/src/statwriter.h:45 (ep.so+0x000000037825) #1 ActiveStream::addStats(void (*)(char const*, unsigned short, char const*, unsigned int, void const*), void const*) /home/abhinav/couchbase/ep-engine/src/dcp/stream.cc:477 (ep.so+0x000000071d16) #2 DcpProducer::addStats(void (*)(char const*, unsigned short, char const*, unsigned int, void const*), void const*) /home/abhinav/couchbase/ep-engine/src/dcp/producer.cc:602 (ep.so+0x000000068057) #3 ConnStatBuilder::operator()(SingleThreadedRCPtr<ConnHandler>&) /home/abhinav/couchbase/ep-engine/src/ep_engine.cc:3887 (ep.so+0x0000000e13e1) #4 EventuallyPersistentEngine::doDcpStats(void const*, void (*)(char const*, unsigned short, char const*, unsigned int, void const*)) /home/abhinav/couchbase/ep-engine/src/ep_engine.cc:4144 (ep.so+0x0000000c151a) #5 EventuallyPersistentEngine::getStats(void const*, char const*, int, void (*)(char const*, unsigned short, char const*, unsigned int, void const*)) /home/abhinav/couchbase/ep-engine/src/ep_engine.cc:4564 (ep.so+0x0000000c5405) #6 EvpGetStats(engine_interface*, void const*, char const*, int, void (*)(char const*, unsigned short, char const*, unsigned int, void const*)) /home/abhinav/couchbase/ep-engine/src/ep_engine.cc:213 (ep.so+0x0000000b422e) #7 mock_get_stats(engine_interface*, void const*, char const*, int, void (*)(char const*, unsigned short, char const*, unsigned int, void const*)) /home/abhinav/couchbase/memcached/programs/engine_testapp/engine_testapp.cc:239 (engine_testapp+0x0000000ba9ad) #8 get_int_stat(engine_interface*, engine_interface_v1*, char const*, char const*) /home/abhinav/couchbase/ep-engine/tests/ep_test_apis.cc:990 (ep_testsuite.so+0x0000000aeb81) #9 dcp_stream(engine_interface*, engine_interface_v1*, char const*, void const*, unsigned short, unsigned int, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, int, int, int, int, bool, bool, unsigned char, bool, unsigned long*, bool) /home/abhinav/couchbase/ep-engine/tests/ep_testsuite.cc:4090 (ep_testsuite.so+0x00000009790c) #10 test_dcp_producer_stream_req_dgm(engine_interface*, engine_interface_v1*) /home/abhinav/couchbase/ep-engine/tests/ep_testsuite.cc:4564 (ep_testsuite.so+0x000000077604) #11 execute_test(test, char const*, char const*) /home/abhinav/couchbase/memcached/programs/engine_testapp/engine_testapp.cc:1090 (engine_testapp+0x0000000b946c) #12 __libc_start_main /build/buildd/eglibc-2.19/csu/libc-start.c:287 (libc.so.6+0x000000021ec4) Previous write of size 8 at 0x7d480000b1f8 by thread T9 (mutexes: write M32940880, write M32940855): #0 ActiveStream::backfillReceived(Item*, backfill_source_t) /home/abhinav/couchbase/ep-engine/src/dcp/stream.cc:287 (ep.so+0x00000007054e) #1 DiskCallback::callback(GetValue&) /home/abhinav/couchbase/ep-engine/src/dcp/backfill.cc:94 (ep.so+0x000000056067) #2 CouchKVStore::recordDbDump(_db*, _docinfo*, void*) /home/abhinav/couchbase/ep-engine/src/couch-kvstore/couch-kvstore.cc:1757 (ep.so+0x00000018103f) #3 recordDbDumpC(_db*, _docinfo*, void*) /home/abhinav/couchbase/ep-engine/src/couch-kvstore/couch-kvstore.cc:66 (ep.so+0x00000017fcc5) #4 lookup_callback(couchfile_lookup_request*, _sized_buf const*, _sized_buf const*) /home/abhinav/couchbase/couchstore/src/couch_db.cc:767 (libcouchstore.so+0x00000000d7f5) #5 btree_lookup_inner(couchfile_lookup_request*, unsigned long, int, int) /home/abhinav/couchbase/couchstore/src/btree_read.cc:99 (libcouchstore.so+0x00000000b5b2) #6 btree_lookup_inner(couchfile_lookup_request*, unsigned long, int, int) /home/abhinav/couchbase/couchstore/src/btree_read.cc:69 (libcouchstore.so+0x00000000b370) #7 btree_lookup_inner(couchfile_lookup_request*, unsigned long, int, int) /home/abhinav/couchbase/couchstore/src/btree_read.cc:69 (libcouchstore.so+0x00000000b370) #8 btree_lookup /home/abhinav/couchbase/couchstore/src/btree_read.cc:131 (libcouchstore.so+0x00000000b00c) #9 couchstore_changes_since /home/abhinav/couchbase/couchstore/src/couch_db.cc:812 (libcouchstore.so+0x00000000d601) #10 CouchKVStore::scan(ScanContext*) /home/abhinav/couchbase/ep-engine/src/couch-kvstore/couch-kvstore.cc:1264 (ep.so+0x00000017f77e) #11 DCPBackfill::scan() /home/abhinav/couchbase/ep-engine/src/dcp/backfill.cc:193 (ep.so+0x000000057672) #12 DCPBackfill::run() /home/abhinav/couchbase/ep-engine/src/dcp/backfill.cc:118 (ep.so+0x000000056647) #13 BackfillManager::backfill() /home/abhinav/couchbase/ep-engine/src/dcp/backfill-manager.cc:240 (ep.so+0x0000000508d5) #14 BackfillManagerTask::run() /home/abhinav/couchbase/ep-engine/src/dcp/backfill-manager.cc:43 (ep.so+0x00000005052f) #15 ExecutorThread::run() /home/abhinav/couchbase/ep-engine/src/executorthread.cc:112 (ep.so+0x0000000f8796) #16 launch_executor_thread(void*) /home/abhinav/couchbase/ep-engine/src/executorthread.cc:33 (ep.so+0x0000000f8335) #17 platform_thread_wrap /home/abhinav/couchbase/platform/src/cb_pthreads.c:23 (libplatform.so.0.1.0+0x000000003d31) Change-Id: I166917524b5fcad285b3623ff160e875c316d983 Reviewed-on: http://review.couchbase.org/62918 Well-Formed: buildbot <[email protected]> Reviewed-by: Will Gardner <[email protected]> Tested-by: buildbot <[email protected]>
1 parent 379d1e6 commit 9469159

File tree

2 files changed

+23
-18
lines changed

2 files changed

+23
-18
lines changed

src/dcp-stream.cc

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ void ActiveStream::completeBackfill() {
421421
LockHolder lh(streamMutex);
422422
LOG(EXTENSION_LOG_WARNING, "%s (vb %d) Backfill complete, %d items read"
423423
" from disk, last seqno read: %ld", producer->logHeader(), vb_,
424-
itemsFromBackfill, lastReadSeqno);
424+
itemsFromBackfill, lastReadSeqno.load());
425425
}
426426

427427
isBackfillTaskRunning.store(false);
@@ -455,7 +455,7 @@ void ActiveStream::setVBucketStateAckRecieved() {
455455
RCPtr<VBucket> vbucket = engine->getVBucket(vb_);
456456
LOG(EXTENSION_LOG_WARNING, "%s (vb %" PRIu16 ") Vbucket marked as "
457457
"dead, last sent seqno: %" PRIu64 ", high seqno: %" PRIu64 "",
458-
producer->logHeader(), vb_, lastSentSeqno,
458+
producer->logHeader(), vb_, lastSentSeqno.load(),
459459
vbucket->getHighSeqno());
460460
} else {
461461
LOG(EXTENSION_LOG_INFO, "%s (vb %" PRIu16 ") Receive ack for set "
@@ -487,8 +487,8 @@ DcpResponse* ActiveStream::backfillPhase() {
487487
}
488488

489489
if (!isBackfillTaskRunning && readyQ.empty()) {
490-
backfillRemaining = 0;
491-
if (lastReadSeqno >= end_seqno_) {
490+
backfillRemaining.store(0, memory_order_relaxed);
491+
if (lastReadSeqno.load() >= end_seqno_) {
492492
endStream(END_STREAM_OK);
493493
} else if (flags_ & DCP_ADD_STREAM_FLAG_TAKEOVER) {
494494
transitionState(STREAM_TAKEOVER_SEND);
@@ -507,7 +507,7 @@ DcpResponse* ActiveStream::backfillPhase() {
507507
}
508508

509509
DcpResponse* ActiveStream::inMemoryPhase() {
510-
if (lastSentSeqno >= end_seqno_) {
510+
if (lastSentSeqno.load() >= end_seqno_) {
511511
endStream(END_STREAM_OK);
512512
} else if (readyQ.empty()) {
513513
if (nextCheckpointItem()) {
@@ -556,9 +556,9 @@ void ActiveStream::addStats(ADD_STAT add_stat, const void *c) {
556556
snprintf(buffer, bsize, "%s:stream_%d_memory", name_.c_str(), vb_);
557557
add_casted_stat(buffer, itemsFromMemory, add_stat, c);
558558
snprintf(buffer, bsize, "%s:stream_%d_last_sent_seqno", name_.c_str(), vb_);
559-
add_casted_stat(buffer, lastSentSeqno, add_stat, c);
559+
add_casted_stat(buffer, lastSentSeqno.load(), add_stat, c);
560560
snprintf(buffer, bsize, "%s:stream_%d_last_read_seqno", name_.c_str(), vb_);
561-
add_casted_stat(buffer, lastReadSeqno, add_stat, c);
561+
add_casted_stat(buffer, lastReadSeqno.load(), add_stat, c);
562562
snprintf(buffer, bsize, "%s:stream_%d_ready_queue_memory", name_.c_str(), vb_);
563563
add_casted_stat(buffer, getReadyQueueMemory(), add_stat, c);
564564
snprintf(buffer, bsize, "%s:stream_%d_items_ready", name_.c_str(), vb_);
@@ -830,7 +830,8 @@ void ActiveStream::endStream(end_stream_status_t reason) {
830830
LOG(EXTENSION_LOG_WARNING, "%s (vb %d) Stream closing, %llu items sent"
831831
" from disk, %llu items sent from memory, %llu was last seqno sent"
832832
" %s is the reason", producer->logHeader(), vb_, itemsFromBackfill,
833-
itemsFromMemory, lastSentSeqno, getEndStreamStatusStr(reason));
833+
itemsFromMemory.load(), lastSentSeqno.load(),
834+
getEndStreamStatusStr(reason));
834835
}
835836
}
836837

@@ -988,12 +989,12 @@ size_t ActiveStream::getItemsRemaining() {
988989
uint64_t high_seqno = vbucket->getHighSeqno();
989990

990991
if (end_seqno_ < high_seqno) {
991-
if (end_seqno_ > lastSentSeqno) {
992-
return (end_seqno_ - lastSentSeqno);
992+
if (end_seqno_ > lastSentSeqno.load()) {
993+
return (end_seqno_ - lastSentSeqno.load());
993994
}
994995
} else {
995-
if (high_seqno > lastSentSeqno) {
996-
return (high_seqno - lastSentSeqno);
996+
if (high_seqno > lastSentSeqno.load()) {
997+
return (high_seqno - lastSentSeqno.load());
997998
}
998999
}
9991000

src/dcp-stream.h

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ class ActiveStream : public Stream {
194194
void setVBucketStateAckRecieved();
195195

196196
void incrBackfillRemaining(size_t by) {
197-
backfillRemaining += by;
197+
backfillRemaining.fetch_add(by);
198198
}
199199

200200
void markDiskSnapshot(uint64_t startSeqno, uint64_t endSeqno);
@@ -251,20 +251,24 @@ class ActiveStream : public Stream {
251251
bool isCurrentSnapshotCompleted() const;
252252

253253
//! The last sequence number queued from disk or memory
254-
uint64_t lastReadSeqno;
254+
AtomicValue<uint64_t> lastReadSeqno;
255255
//! The last sequence number sent to the network layer
256-
uint64_t lastSentSeqno;
256+
AtomicValue<uint64_t> lastSentSeqno;
257257
//! The last known seqno pointed to by the checkpoint cursor
258258
uint64_t curChkSeqno;
259259
//! The current vbucket state to send in the takeover stream
260260
vbucket_state_t takeoverState;
261-
//! The amount of items remaining to be read from disk
262-
size_t backfillRemaining;
261+
/* backfillRemaining is a stat recording the amount of
262+
* items remaining to be read from disk. It is an atomic
263+
* because otherwise the function incrBackfillRemaining
264+
* must acquire the streamMutex lock.
265+
*/
266+
AtomicValue <size_t> backfillRemaining;
263267

264268
//! The amount of items that have been read from disk
265269
size_t itemsFromBackfill;
266270
//! The amount of items that have been read from memory
267-
size_t itemsFromMemory;
271+
AtomicValue<size_t> itemsFromMemory;
268272
//! Whether ot not this is the first snapshot marker sent
269273
bool firstMarkerSent;
270274

0 commit comments

Comments
 (0)