33
33
34
34
#include " mock/mock_dcp.h"
35
35
36
+ template <typename T> class HistogramStats ;
37
+
36
38
// 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.
44
41
std::mutex vals_mutex;
45
42
statistic_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;
48
61
49
62
bool dump_stats = false ;
50
63
std::atomic<protocol_binary_response_status> last_status (
@@ -118,10 +131,6 @@ class HistogramStats {
118
131
uint64_t total_count;
119
132
};
120
133
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
-
125
134
static void get_histo_stat (ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
126
135
const char *statname, const char *statkey);
127
136
@@ -233,6 +242,7 @@ void add_stats(const char *key, const uint16_t klen, const char *val,
233
242
std::cout << " stat[" << k << " ] = " << v << std::endl;
234
243
}
235
244
245
+ std::lock_guard<std::mutex> lh (vals_mutex);
236
246
vals[k] = v;
237
247
}
238
248
@@ -243,10 +253,11 @@ void add_stats(const char *key, const uint16_t klen, const char *val,
243
253
void add_individual_stat (const char *key, const uint16_t klen, const char *val,
244
254
const uint32_t vlen, const void *cookie) {
245
255
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);
250
261
}
251
262
}
252
263
@@ -255,13 +266,13 @@ void add_individual_histo_stat(const char *key, const uint16_t klen,
255
266
const void *cookie) {
256
267
/* Convert key to string */
257
268
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 );
259
270
if (pos1 != std::string::npos)
260
271
{
261
- actual_stat_value.append (val, vlen);
272
+ get_stat_context. actual_stat_value .append (val, vlen);
262
273
/* Parse start and end from the key.
263
274
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 ();
265
276
/* Find ',' to move to end of bin_start */
266
277
size_t pos2 = key_str.find (' ,' , pos1);
267
278
if ((std::string::npos == pos2) || (pos1 >= pos2)) {
@@ -277,7 +288,8 @@ void add_individual_histo_stat(const char *key, const uint16_t klen,
277
288
throw std::invalid_argument (" Malformed histogram stat: " + key_str);
278
289
}
279
290
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));
281
293
}
282
294
}
283
295
@@ -1049,17 +1061,23 @@ bool verify_vbucket_missing(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
1049
1061
1050
1062
// Try up to three times to verify the bucket is missing. Bucket
1051
1063
// 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
+
1054
1069
check (h1->get_stats (h, NULL , NULL , 0 , add_stats) == ENGINE_SUCCESS,
1055
1070
" Failed to get stats." );
1056
1071
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
+ }
1062
1077
1078
+ std::cerr << " Expected bucket missing, got " <<
1079
+ vals[vbstr] << std::endl;
1080
+ }
1063
1081
return false ;
1064
1082
}
1065
1083
@@ -1143,10 +1161,10 @@ bool get_stat(ENGINE_HANDLE* h, ENGINE_HANDLE_V1* h1,
1143
1161
template <>
1144
1162
std::string get_stat (ENGINE_HANDLE* h, ENGINE_HANDLE_V1* h1,
1145
1163
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 );
1147
1165
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 ();
1150
1168
1151
1169
ENGINE_ERROR_CODE err = h1->get_stats (h, NULL , statkey,
1152
1170
statkey == NULL ? 0 : strlen (statkey),
@@ -1156,15 +1174,16 @@ std::string get_stat(ENGINE_HANDLE* h, ENGINE_HANDLE_V1* h1,
1156
1174
throw engine_error (err);
1157
1175
}
1158
1176
1159
- if (actual_stat_value.empty ()) {
1177
+ if (get_stat_context. actual_stat_value .empty ()) {
1160
1178
throw std::out_of_range (std::string (" Failed to find requested statname '" ) +
1161
1179
statname + " '" );
1162
1180
}
1163
1181
1164
1182
// Here we are explictly forcing a copy of the object to work
1165
1183
// around std::string copy-on-write data-race issues seen on some
1166
1184
// 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 ());
1168
1187
}
1169
1188
1170
1189
// / 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,
1224
1243
const char *statname, const char *statkey,
1225
1244
const Histo_stat_info histo_info)
1226
1245
{
1227
- std::lock_guard<std::mutex> lh (vals_mutex );
1246
+ std::lock_guard<std::mutex> lh (get_stat_context. mutex );
1228
1247
1229
- histogram_stat_int_value = new HistogramStats<int >();
1248
+ get_stat_context. histogram_stat_int_value = new HistogramStats<int >();
1230
1249
get_histo_stat (h, h1, statname, statkey);
1231
1250
1232
1251
/* Get the necessary info from the histogram */
1233
1252
uint64_t ret_val = 0 ;
1234
1253
switch (histo_info) {
1235
1254
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 ();
1237
1256
break ;
1238
1257
case Histo_stat_info::NUM_BINS:
1239
1258
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 ());
1241
1261
break ;
1242
1262
}
1243
1263
1244
- delete histogram_stat_int_value;
1264
+ delete get_stat_context. histogram_stat_int_value ;
1245
1265
return ret_val;
1246
1266
}
1247
1267
1248
1268
static void get_histo_stat (ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
1249
1269
const char *statname, const char *statkey)
1250
1270
{
1251
- requested_stat_name = statname;
1271
+ get_stat_context. requested_stat_name = statname;
1252
1272
/* Histo stats for tasks are append as task_name_START,END.
1253
1273
Hence append _ */
1254
- requested_stat_name.append (" _" );
1274
+ get_stat_context. requested_stat_name .append (" _" );
1255
1275
1256
1276
ENGINE_ERROR_CODE err = h1->get_stats (h, NULL , statkey,
1257
1277
statkey == NULL ? 0 : strlen (statkey),
@@ -1266,9 +1286,10 @@ static void get_histo_stat(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
1266
1286
1267
1287
statistic_map get_all_stats (ENGINE_HANDLE *h,ENGINE_HANDLE_V1 *h1,
1268
1288
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
+ }
1272
1293
ENGINE_ERROR_CODE err = h1->get_stats (h, NULL , statset,
1273
1294
statset == NULL ? 0 : strlen (statset),
1274
1295
add_stats);
@@ -1277,6 +1298,7 @@ statistic_map get_all_stats(ENGINE_HANDLE *h,ENGINE_HANDLE_V1 *h1,
1277
1298
throw engine_error (err);
1278
1299
}
1279
1300
1301
+ std::lock_guard<std::mutex> lh (vals_mutex);
1280
1302
return vals;
1281
1303
}
1282
1304
0 commit comments