3333
3434#include " mock/mock_dcp.h"
3535
36+ template <typename T> class HistogramStats ;
37+
3638// Due to the limitations of the add_stats callback (essentially we cannot pass
37- // a context into it) we instead have a single, global `vals` map. This mutex
38- // is used to serialise modifications to it to allow multiple threads to request
39- // stats.
40- // There is also an optimized add_stats callback (add_individual_stat) which
41- // checks for one stat (and hence doesn't have to keep a map of all of them).
42- // the vals_mutex is also used for serializing acccess to it's data
43- // (requested_stat_name and actual_stat_value).
39+ // a context into it) we instead have a single, global `vals` map. The
40+ // vals_mutex is to ensure serialised modifications to this data structure.
4441std::mutex vals_mutex;
4542statistic_map vals;
46- std::string requested_stat_name;
47- std::string actual_stat_value;
43+
44+ // get_stat and get_histo_stat can only be called one at a time as they use
45+ // the three global variables (requested_stat_name, actual_stat_value and
46+ // histogram_stat_int_value). Therefore the two functions need to acquire a
47+ // lock and keep it for the whole function duration.
48+
49+ // The requested_stat_name and actual_stat_value are used in an optimized
50+ // add_stats callback (add_individual_stat) which checks for one stat
51+ // (and hence doesn't have to keep a map of all of them).
52+ struct {
53+ std::mutex mutex;
54+ std::string requested_stat_name;
55+ std::string actual_stat_value;
56+ /* HistogramStats<T>* is supported C++14 onwards.
57+ * Until then use a separate ptr for each type.
58+ */
59+ HistogramStats<int >* histogram_stat_int_value;
60+ } get_stat_context;
4861
4962bool dump_stats = false ;
5063std::atomic<protocol_binary_response_status> last_status (
@@ -118,10 +131,6 @@ class HistogramStats {
118131 uint64_t total_count;
119132};
120133
121- /* HistogramStats<T>* is supported C++14 onwards. Until then use a separate
122- ptr for each type */
123- static HistogramStats<int >* histogram_stat_int_value;
124-
125134static void get_histo_stat (ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
126135 const char *statname, const char *statkey);
127136
@@ -233,6 +242,7 @@ void add_stats(const char *key, const uint16_t klen, const char *val,
233242 std::cout << " stat[" << k << " ] = " << v << std::endl;
234243 }
235244
245+ std::lock_guard<std::mutex> lh (vals_mutex);
236246 vals[k] = v;
237247}
238248
@@ -243,10 +253,11 @@ void add_stats(const char *key, const uint16_t klen, const char *val,
243253void add_individual_stat (const char *key, const uint16_t klen, const char *val,
244254 const uint32_t vlen, const void *cookie) {
245255
246- if (actual_stat_value.empty () &&
247- requested_stat_name.compare (0 , requested_stat_name.size (),
248- key, klen) == 0 ) {
249- actual_stat_value = std::string (val, vlen);
256+ if (get_stat_context.actual_stat_value .empty () &&
257+ get_stat_context.requested_stat_name .compare (
258+ 0 , get_stat_context.requested_stat_name .size (),
259+ key, klen) == 0 ) {
260+ get_stat_context.actual_stat_value = std::string (val, vlen);
250261 }
251262}
252263
@@ -255,13 +266,13 @@ void add_individual_histo_stat(const char *key, const uint16_t klen,
255266 const void *cookie) {
256267 /* Convert key to string */
257268 std::string key_str (key, klen);
258- size_t pos1 = key_str.find (requested_stat_name);
269+ size_t pos1 = key_str.find (get_stat_context. requested_stat_name );
259270 if (pos1 != std::string::npos)
260271 {
261- actual_stat_value.append (val, vlen);
272+ get_stat_context. actual_stat_value .append (val, vlen);
262273 /* Parse start and end from the key.
263274 Key is in the format task_name_START,END (backfill_tasks_20,100) */
264- pos1 += requested_stat_name.length ();
275+ pos1 += get_stat_context. requested_stat_name .length ();
265276 /* Find ',' to move to end of bin_start */
266277 size_t pos2 = key_str.find (' ,' , pos1);
267278 if ((std::string::npos == pos2) || (pos1 >= pos2)) {
@@ -277,7 +288,8 @@ void add_individual_histo_stat(const char *key, const uint16_t klen,
277288 throw std::invalid_argument (" Malformed histogram stat: " + key_str);
278289 }
279290 int end = std::stoi (std::string (key_str, pos1, pos2));
280- histogram_stat_int_value->add_bin (start, end, std::stoull (val));
291+ get_stat_context.histogram_stat_int_value ->add_bin (start, end,
292+ std::stoull (val));
281293 }
282294}
283295
@@ -1049,17 +1061,23 @@ bool verify_vbucket_missing(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
10491061
10501062 // Try up to three times to verify the bucket is missing. Bucket
10511063 // state changes are async.
1052- std::lock_guard<std::mutex> lh (vals_mutex);
1053- vals.clear ();
1064+ {
1065+ std::lock_guard<std::mutex> lh (vals_mutex);
1066+ vals.clear ();
1067+ }
1068+
10541069 check (h1->get_stats (h, NULL , NULL , 0 , add_stats) == ENGINE_SUCCESS,
10551070 " Failed to get stats." );
10561071
1057- if (vals. find (vbstr) == vals. end ()) {
1058- return true ;
1059- }
1060-
1061- std::cerr << " Expected bucket missing, got " << vals[vbstr] << std::endl;
1072+ {
1073+ std::lock_guard<std::mutex> lh (vals_mutex) ;
1074+ if (vals. find (vbstr) == vals. end ()) {
1075+ return true ;
1076+ }
10621077
1078+ std::cerr << " Expected bucket missing, got " <<
1079+ vals[vbstr] << std::endl;
1080+ }
10631081 return false ;
10641082}
10651083
@@ -1143,10 +1161,10 @@ bool get_stat(ENGINE_HANDLE* h, ENGINE_HANDLE_V1* h1,
11431161template <>
11441162std::string get_stat (ENGINE_HANDLE* h, ENGINE_HANDLE_V1* h1,
11451163 const char * statname, const char * statkey) {
1146- std::lock_guard<std::mutex> lh (vals_mutex );
1164+ std::lock_guard<std::mutex> lh (get_stat_context. mutex );
11471165
1148- requested_stat_name = statname;
1149- actual_stat_value.clear ();
1166+ get_stat_context. requested_stat_name = statname;
1167+ get_stat_context. actual_stat_value .clear ();
11501168
11511169 ENGINE_ERROR_CODE err = h1->get_stats (h, NULL , statkey,
11521170 statkey == NULL ? 0 : strlen (statkey),
@@ -1156,15 +1174,16 @@ std::string get_stat(ENGINE_HANDLE* h, ENGINE_HANDLE_V1* h1,
11561174 throw engine_error (err);
11571175 }
11581176
1159- if (actual_stat_value.empty ()) {
1177+ if (get_stat_context. actual_stat_value .empty ()) {
11601178 throw std::out_of_range (std::string (" Failed to find requested statname '" ) +
11611179 statname + " '" );
11621180 }
11631181
11641182 // Here we are explictly forcing a copy of the object to work
11651183 // around std::string copy-on-write data-race issues seen on some
11661184 // versions of libstdc++ - see MB-18510 / MB-19688.
1167- return std::string (actual_stat_value.begin (), actual_stat_value.end ());
1185+ return std::string (get_stat_context.actual_stat_value .begin (),
1186+ get_stat_context.actual_stat_value .end ());
11681187}
11691188
11701189// / Backward-compatible functions (encode type name in function name).
@@ -1224,34 +1243,35 @@ uint64_t get_histo_stat(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
12241243 const char *statname, const char *statkey,
12251244 const Histo_stat_info histo_info)
12261245{
1227- std::lock_guard<std::mutex> lh (vals_mutex );
1246+ std::lock_guard<std::mutex> lh (get_stat_context. mutex );
12281247
1229- histogram_stat_int_value = new HistogramStats<int >();
1248+ get_stat_context. histogram_stat_int_value = new HistogramStats<int >();
12301249 get_histo_stat (h, h1, statname, statkey);
12311250
12321251 /* Get the necessary info from the histogram */
12331252 uint64_t ret_val = 0 ;
12341253 switch (histo_info) {
12351254 case Histo_stat_info::TOTAL_COUNT:
1236- ret_val = histogram_stat_int_value->total ();
1255+ ret_val = get_stat_context. histogram_stat_int_value ->total ();
12371256 break ;
12381257 case Histo_stat_info::NUM_BINS:
12391258 ret_val =
1240- static_cast <uint64_t >(histogram_stat_int_value->num_bins ());
1259+ static_cast <uint64_t >(get_stat_context.
1260+ histogram_stat_int_value->num_bins ());
12411261 break ;
12421262 }
12431263
1244- delete histogram_stat_int_value;
1264+ delete get_stat_context. histogram_stat_int_value ;
12451265 return ret_val;
12461266}
12471267
12481268static void get_histo_stat (ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
12491269 const char *statname, const char *statkey)
12501270{
1251- requested_stat_name = statname;
1271+ get_stat_context. requested_stat_name = statname;
12521272 /* Histo stats for tasks are append as task_name_START,END.
12531273 Hence append _ */
1254- requested_stat_name.append (" _" );
1274+ get_stat_context. requested_stat_name .append (" _" );
12551275
12561276 ENGINE_ERROR_CODE err = h1->get_stats (h, NULL , statkey,
12571277 statkey == NULL ? 0 : strlen (statkey),
@@ -1266,9 +1286,10 @@ static void get_histo_stat(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
12661286
12671287statistic_map get_all_stats (ENGINE_HANDLE *h,ENGINE_HANDLE_V1 *h1,
12681288 const char *statset) {
1269- std::lock_guard<std::mutex> lh (vals_mutex);
1270-
1271- vals.clear ();
1289+ {
1290+ std::lock_guard<std::mutex> lh (vals_mutex);
1291+ vals.clear ();
1292+ }
12721293 ENGINE_ERROR_CODE err = h1->get_stats (h, NULL , statset,
12731294 statset == NULL ? 0 : strlen (statset),
12741295 add_stats);
@@ -1277,6 +1298,7 @@ statistic_map get_all_stats(ENGINE_HANDLE *h,ENGINE_HANDLE_V1 *h1,
12771298 throw engine_error (err);
12781299 }
12791300
1301+ std::lock_guard<std::mutex> lh (vals_mutex);
12801302 return vals;
12811303}
12821304
0 commit comments