Skip to content

Commit d4cb889

Browse files
rdemellowdaverigby
authored andcommitted
MB-35413 Fix data race in Timings::get_or_create_timing_histogram
Fix data race in Timings::get_or_create_timing_histogram() to prevent the data race were in one thread we might not observe correctly the pointer to a given Hdr1sfMicroSecHistogram stored by the timings array. Which could lead to the Hdr1sfMicroSecHistogram being allocated multiple times. WARNING: ThreadSanitizer: data race (pid=1085) Read of size 8 at 0x0000009bad18 by thread T7 (mutexes: write M2377): #0 std::__uniq_ptr_impl<Hdr1sfMicroSecHistogram, std::default_delete<Hdr1sfMicroSecHistogram> >::_M_ptr() const /usr/local/include/c++/7.3.0/bits/unique_ptr.h:147 (memcached+0x0000004bf317) couchbase#1 std::unique_ptr<Hdr1sfMicroSecHistogram, std::default_delete<Hdr1sfMicroSecHistogram> >::get() const /usr/local/include/c++/7.3.0/bits/unique_ptr.h:337 (memcached+0x0000004bf317) couchbase#2 std::unique_ptr<Hdr1sfMicroSecHistogram, std::default_delete<Hdr1sfMicroSecHistogram> >::operator bool() const /usr/local/include/c++/7.3.0/bits/unique_ptr.h:351 (memcached+0x0000004bf317) couchbase#3 bool std::operator==<Hdr1sfMicroSecHistogram, std::default_delete<Hdr1sfMicroSecHistogram> >(std::unique_ptr<Hdr1sfMicroSecHistogram, std::default_delete<Hdr1sfMicroSecHistogram> > const&, decltype(nullptr)) /usr/local/include/c++/7.3.0/bits/unique_ptr.h:690 (memcached+0x0000004bf317) couchbase#4 Timings::get_or_create_timing_histogram(unsigned char) /home/couchbase/couchbase/kv_engine/daemon/timings.cc:146 (memcached+0x0000004bf317) couchbase#5 Timings::collect(cb::mcbp::ClientOpcode, std::chrono::duration<long, std::ratio<1l, 1000000000l> >) /home/couchbase/couchbase/kv_engine/daemon/timings.cc:42 (memcached+0x0000004bf4aa) ... Previous write of size 8 at 0x0000009bad18 by thread T8 (mutexes: write M2371, write M2392): #0 std::enable_if<std::__and_<std::__not_<std::__is_tuple_like<Hdr1sfMicroSecHistogram*> >, std::is_move_constructible<Hdr1sfMicroSecHistogram*>, std::is_move_assignable<Hdr1sfMicroSecHistogram*> >::value, void>::type std::swap<Hdr1sfMicroSecHistogram*>(Hdr1sfMicroSecHistogram*&, Hdr1sfMicroSecHistogram*&) /usr/local/include/c++/7.3.0/bits/move.h:199 (memcached+0x0000004bf3cf) couchbase#1 std::unique_ptr<Hdr1sfMicroSecHistogram, std::default_delete<Hdr1sfMicroSecHistogram> >::reset(Hdr1sfMicroSecHistogram*) /usr/local/include/c++/7.3.0/bits/unique_ptr.h:374 (memcached+0x0000004bf3cf) couchbase#2 std::unique_ptr<Hdr1sfMicroSecHistogram, std::default_delete<Hdr1sfMicroSecHistogram> >::operator=(std::unique_ptr<Hdr1sfMicroSecHistogram, std::default_delete<Hdr1sfMicroSecHistogram> >&&) /usr/local/include/c++/7.3.0/bits/unique_ptr.h:283 (memcached+0x0000004bf3cf) couchbase#3 Timings::get_or_create_timing_histogram(unsigned char) /home/couchbase/couchbase/kv_engine/daemon/timings.cc:149 (memcached+0x0000004bf3cf) couchbase#4 Timings::collect(cb::mcbp::ClientOpcode, std::chrono::duration<long, std::ratio<1l, 1000000000l> >) /home/couchbase/couchbase/kv_engine/daemon/timings.cc:42 (memcached+0x0000004bf4aa) ... Change-Id: I34db63854a1909cbf43a9feb273a13dfa40f313d Reviewed-on: http://review.couchbase.org/113024 Reviewed-by: James Harrison <james.harrison@couchbase.com> Tested-by: Build Bot <build@couchbase.com> Reviewed-by: Dave Rigby <daver@couchbase.com>
1 parent 5c6b3ba commit d4cb889

File tree

2 files changed

+23
-13
lines changed

2 files changed

+23
-13
lines changed

daemon/timings.cc

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,20 @@ Timings::Timings() {
2121
reset();
2222
}
2323

24-
void Timings::reset() {
24+
Timings::~Timings() {
25+
std::lock_guard<std::mutex> lg(histogram_mutex);
2526
for (auto& t : timings) {
26-
if (t) {
27-
t->reset();
27+
delete t;
28+
}
29+
}
30+
31+
void Timings::reset() {
32+
{
33+
std::lock_guard<std::mutex> lg(histogram_mutex);
34+
for (auto& t : timings) {
35+
if (t) {
36+
t.load()->reset();
37+
}
2838
}
2939
}
3040

@@ -50,7 +60,7 @@ void Timings::collect(cb::mcbp::ClientOpcode opcode,
5060
std::string Timings::generate(cb::mcbp::ClientOpcode opcode) {
5161
auto* histoPtr =
5262
timings[std::underlying_type<cb::mcbp::ClientOpcode>::type(opcode)]
53-
.get();
63+
.load();
5464
if (histoPtr) {
5565
return histoPtr->to_string();
5666
}
@@ -109,7 +119,7 @@ uint64_t Timings::get_aggregated_mutation_stats() {
109119
for (auto cmd : timings_mutations) {
110120
auto* histoPtr =
111121
timings[std::underlying_type<cb::mcbp::ClientOpcode>::type(cmd)]
112-
.get();
122+
.load();
113123
if (histoPtr) {
114124
ret += histoPtr->getValueCount();
115125
}
@@ -123,7 +133,7 @@ uint64_t Timings::get_aggregated_retrival_stats() {
123133
for (auto cmd : timings_retrievals) {
124134
auto* histoPtr =
125135
timings[std::underlying_type<cb::mcbp::ClientOpcode>::type(cmd)]
126-
.get();
136+
.load();
127137
if (histoPtr) {
128138
ret += histoPtr->getValueCount();
129139
}
@@ -143,17 +153,17 @@ cb::sampling::Interval Timings::get_interval_lookup_latency() {
143153

144154
Hdr1sfMicroSecHistogram& Timings::get_or_create_timing_histogram(
145155
uint8_t opcode) {
146-
if (timings[opcode] == nullptr) {
156+
if (!timings[opcode]) {
147157
std::lock_guard<std::mutex> allocLock(histogram_mutex);
148-
if (timings[opcode] == nullptr) {
149-
timings[opcode] = std::make_unique<Hdr1sfMicroSecHistogram>();
158+
if (!timings[opcode]) {
159+
timings[opcode] = new Hdr1sfMicroSecHistogram();
150160
}
151161
}
152-
return *timings[opcode];
162+
return *(timings[opcode].load());
153163
}
154164

155165
Hdr1sfMicroSecHistogram* Timings::get_timing_histogram(uint8_t opcode) const {
156-
return timings[opcode].get();
166+
return timings[opcode].load();
157167
}
158168

159169
void Timings::sample(std::chrono::seconds sample_interval) {

daemon/timings.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class Timings {
3434
public:
3535
Timings();
3636
Timings(const Timings&) = delete;
37+
~Timings();
3738

3839
void reset();
3940
void collect(cb::mcbp::ClientOpcode opcode, std::chrono::nanoseconds nsec);
@@ -69,8 +70,7 @@ class Timings {
6970
// create an array of unique_ptrs as we want to create HdrHistograms
7071
// in a lazy manner as their foot print is larger than our old
7172
// histogram class
72-
std::array<std::unique_ptr<Hdr1sfMicroSecHistogram>, MAX_NUM_OPCODES>
73-
timings;
73+
std::array<std::atomic<Hdr1sfMicroSecHistogram*>, MAX_NUM_OPCODES> timings;
7474
std::mutex histogram_mutex;
7575
std::array<cb::sampling::Interval, MAX_NUM_OPCODES> interval_counters;
7676
};

0 commit comments

Comments
 (0)