Skip to content

Commit ef82950

Browse files
authored
Support shared mbvar (#3129)
* Support shared mbvar * Update document
1 parent fe63d79 commit ef82950

File tree

6 files changed

+303
-197
lines changed

6 files changed

+303
-197
lines changed

docs/cn/mbvar_c++.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,7 @@ public:
412412
```
413413

414414
### get_stats
415+
415416
根据指定label获取对应的单维度统计项bvar。
416417

417418
get_stats除了支持(默认)std::list<std::string>参数类型,也支持自定义参数类型,满足以下条件:
@@ -421,6 +422,12 @@ get_stats除了支持(默认)std::list<std::string>参数类型,也支持
421422

422423
推荐使用不需要分配内存的容器(例如,std::array、absl::InlinedVector)和不需要拷贝字符串的数据结构(例如,const char*、std::string_view、butil::StringPieces),可以提高性能。
423424

425+
bvar::MultiDimension的模板参数Shared,默认为false:
426+
1. 如果Shared等于false,get_stats返回模板参数T的指针,例如bvar::Adder<int>*
427+
2. 如果Shared等于true,get_stats返回模板参数T的shared_ptr,例如std::shared_ptr\<bvar::Adder<int>\>
428+
429+
**注意**:因为shared_ptr的开销,Shared等于true的性能会比Shared等于false的性能差一些。
430+
424431
```c++
425432
#include <bvar/bvar.h>
426433
#include <bvar/multi_dimension.h>
@@ -523,6 +530,20 @@ int request_count = get_request_count(request_label_list);
523530
* store(bvar)
524531
* return bvar
525532

533+
### delete_stats
534+
535+
根据指定label删除对应的单维度统计项bvar。
536+
537+
bvar::MultiDimension的模板参数Shared,默认为false:
538+
1. 如果Shared等于false,get_stats返回的是模板参数T的指针,delete_stats无法保证没有使用者,所以无法安全删除bvar。
539+
2. 如果Shared等于true,get_stats返回的是模板参数T的shared_ptr,delete_stats可以安全删除bvar。
540+
541+
### clear_stats
542+
543+
清理所有单维度统计项bvar。
544+
545+
安全性同样受bvar::MultiDimension的模板参数Shared的影响,见delete_stats一节说明。
546+
526547
**bvar的生命周期**
527548

528549
label对应的单维度统计项bvar存储在多维度统计项(mbvar)中,当mbvar析构的时候会释放自身所有bvar,所以用户必须保证在mbvar的生命周期之内操作bvar,在mbvar生命周期外访问bvar的行为未定义,极有可能出core。

src/bvar/detail/combiner.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -205,12 +205,10 @@ friend class GlobalValue<self_type>;
205205
//
206206
// NOTE: Only available to non-atomic types.
207207
template <typename Op>
208-
void merge_global(const Op &op, self_shared_type c = NULL) {
209-
if (NULL == c) {
210-
c = combiner.lock();
211-
}
212-
if (NULL != c) {
213-
GlobalValue<self_type> g(this, c.get());
208+
void merge_global(const Op &op, self_shared_type& c) {
209+
const self_shared_type& c_ref = NULL != c ? c : combiner.lock();
210+
if (NULL != c_ref) {
211+
GlobalValue<self_type> g(this, c_ref.get());
214212
element.merge_global(op, g);
215213
}
216214
}

src/bvar/multi_dimension.h

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
#ifndef BVAR_MULTI_DIMENSION_H
2121
#define BVAR_MULTI_DIMENSION_H
2222

23+
#include <memory>
24+
#include <type_traits>
2325
#include "butil/logging.h" // LOG
2426
#include "butil/macros.h" // BAIDU_CASSERT
2527
#include "butil/scoped_lock.h" // BAIDU_SCOPE_LOCK
@@ -35,8 +37,15 @@ namespace bvar {
3537
// 2. KeyType::value_type must be std::string.
3638
// 3. KeyType::size() returns the number of labels.
3739
// 4. KeyType::push_back() adds a label to the end of the container.
38-
template <typename T, typename KeyType = std::list<std::string>>
40+
//
41+
// If `Shared' is false, `get_stats' returns a raw pointer,
42+
// `delete_stats' and `clear_stats' are not thread safe.
43+
// If `Shared' is true, `get_stats` returns a shared_ptr,
44+
// `delete_stats' and `clear_stats' are thread safe.
45+
// Note: The shared mode may be less performant than the non-shared mode.
46+
template <typename T, typename KeyType = std::list<std::string>, bool Shared = false>
3947
class MultiDimension : public MVariable<KeyType> {
48+
typedef std::shared_ptr<T> shared_value_type;
4049
public:
4150
enum STATS_OP {
4251
READ_ONLY,
@@ -45,7 +54,7 @@ class MultiDimension : public MVariable<KeyType> {
4554

4655
typedef KeyType key_type;
4756
typedef T value_type;
48-
typedef T* value_ptr_type;
57+
typedef typename std::conditional<Shared, shared_value_type, T*>::type value_ptr_type;
4958
typedef MVariable<key_type> Base;
5059

5160
struct KeyHash {
@@ -102,11 +111,15 @@ class MultiDimension : public MVariable<KeyType> {
102111
// 2. K::value_type must be able to convert to std::string and butil::StringPiece
103112
// through operator std::string() function and operator butil::StringPiece() function.
104113
// 3. K::value_type must be able to compare with std::string.
114+
//
115+
// Returns a shared_ptr if `Shared' is true, otherwise returns a raw pointer.
105116
template <typename K = key_type>
106-
T* get_stats(const K& labels_value) {
117+
value_ptr_type get_stats(const K& labels_value) {
107118
return get_stats_impl(labels_value, READ_OR_INSERT);
108119
}
109120

121+
// `delete_stats' and `clear_stats' are thread safe
122+
// if `Shared' is true, otherwise not.
110123
// Remove stat so those not count and dump
111124
template <typename K = key_type>
112125
void delete_stats(const K& labels_value);
@@ -133,25 +146,26 @@ class MultiDimension : public MVariable<KeyType> {
133146
// Return real bvar pointer if labels_name exist, NULL otherwise.
134147
// CAUTION!!! Just For Debug!!!
135148
template <typename K = key_type>
136-
T* get_stats_read_only(const K& labels_value) {
149+
value_ptr_type get_stats_read_only(const K& labels_value) {
137150
return get_stats_impl(labels_value);
138151
}
139152

140153
// Get real bvar pointer object
141154
// Return real bvar pointer if labels_name exist, otherwise(not exist) create bvar pointer.
142155
// CAUTION!!! Just For Debug!!!
143156
template <typename K = key_type>
144-
T* get_stats_read_or_insert(const K& labels_value, bool* do_write = NULL) {
157+
value_ptr_type get_stats_read_or_insert(const K& labels_value, bool* do_write = NULL) {
145158
return get_stats_impl(labels_value, READ_OR_INSERT, do_write);
146159
}
147160
#endif
148161

149162
private:
150163
template <typename K>
151-
T* get_stats_impl(const K& labels_value);
164+
value_ptr_type get_stats_impl(const K& labels_value);
152165

153166
template <typename K>
154-
T* get_stats_impl(const K& labels_value, STATS_OP stats_op, bool* do_write = NULL);
167+
value_ptr_type get_stats_impl(
168+
const K& labels_value, STATS_OP stats_op, bool* do_write = NULL);
155169

156170
template <typename K>
157171
static typename std::enable_if<butil::is_same<K, key_type>::value>::type
@@ -162,11 +176,8 @@ class MultiDimension : public MVariable<KeyType> {
162176
template <typename K>
163177
static typename std::enable_if<!butil::is_same<K, key_type>::value>::type
164178
insert_metrics_map(MetricMap& bg, const K& labels_value, op_value_type metric) {
165-
key_type labels_value_str;
166-
for (auto& label : labels_value) {
167-
// key_type::value_type must be able to convert to std::string.
168-
labels_value_str.push_back(std::string(label));
169-
}
179+
// key_type::value_type must be able to convert to std::string.
180+
key_type labels_value_str(labels_value.cbegin(), labels_value.cend());
170181
bg.insert(labels_value_str, metric);
171182
}
172183

@@ -192,7 +203,27 @@ class MultiDimension : public MVariable<KeyType> {
192203
void delete_stats();
193204

194205
static size_t init_flatmap(MetricMap& bg);
195-
206+
207+
// If Shared is true, return std::shared_ptr, otherwise return raw pointer.
208+
template <bool S = Shared>
209+
typename std::enable_if<S, value_ptr_type>::type new_value() {
210+
return std::make_shared<value_type>();
211+
}
212+
template <bool S = Shared>
213+
typename std::enable_if<!S, value_ptr_type>::type new_value() {
214+
return new value_type();
215+
}
216+
217+
// If Shared is true, reset std::shared_ptr, otherwise delete raw pointer.
218+
template <bool S = Shared>
219+
typename std::enable_if<S>::type delete_value(value_ptr_type& v) {
220+
v.reset();
221+
}
222+
template <bool S = Shared>
223+
typename std::enable_if<!S>::type delete_value(value_ptr_type& v) {
224+
delete v;
225+
}
226+
196227
size_t _max_stats_count;
197228
MetricMapDBD _metric_map;
198229
};

0 commit comments

Comments
 (0)