cdjingit commented on code in PR #1608:
URL: https://github.com/apache/incubator-brpc/pull/1608#discussion_r937613829


##########
src/bvar/mvariable.cpp:
##########
@@ -0,0 +1,253 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// Date: 2021/11/17 14:37:53
+
+#include <gflags/gflags.h>
+#include <gflags/gflags_declare.h>
+#include "butil/logging.h"                       // LOG
+#include "butil/errno.h"                         // berror
+#include "butil/containers/flat_map.h"           // butil::FlatMap
+#include "butil/scoped_lock.h"                   // BAIDU_SCOPE_LOCK
+#include "butil/file_util.h"                     // butil::FilePath
+#include "bvar/variable.h"
+#include "bvar/mvariable.h"
+
+namespace bvar {
+
+constexpr uint64_t MAX_LABELS_COUNT = 10;
+
+DECLARE_bool(bvar_abort_on_same_name);
+
+extern bool s_bvar_may_abort;
+
+DEFINE_int32(bvar_max_multi_dimension_metric_number, 1024, "Max number of 
multi dimension");
+
+static bool validator_bvar_max_multi_dimension_metric_number(const char*, 
int32_t v) {
+    if (v < 1) {
+        LOG(ERROR) << "Invalid bvar_max_multi_dimension_metric_number=" << v;
+        return false;
+    }
+    return true;
+}
+
+const bool ALLOW_UNUSED dummp_bvar_max_multi_dimension_metric_number = 
::google::RegisterFlagValidator(
+    &FLAGS_bvar_max_multi_dimension_metric_number, 
validator_bvar_max_multi_dimension_metric_number);
+
+class MVarEntry {
+public:
+    MVarEntry() : var(NULL) {}
+
+    MVariable* var;
+};
+
+typedef butil::FlatMap<std::string, MVarEntry> MVarMap;
+
+struct MVarMapWithLock : public MVarMap {
+    pthread_mutex_t mutex;
+
+    MVarMapWithLock() {
+        CHECK_EQ(0, init(256, 80));
+        pthread_mutex_init(&mutex, NULL);
+    }
+};
+
+// We have to initialize global map on need because bvar is possibly used
+// before main().
+static pthread_once_t s_mvar_map_once = PTHREAD_ONCE_INIT;
+static MVarMapWithLock* s_mvar_map = NULL;
+
+static void init_mvar_map() {
+    // It's probably slow to initialize all sub maps, but rpc often expose 
+    // variables before user. So this should not be an issue to users.
+    s_mvar_map = new MVarMapWithLock();
+}
+
+inline MVarMapWithLock& get_mvar_map() {
+    pthread_once(&s_mvar_map_once, init_mvar_map);
+    return *s_mvar_map;
+}
+
+MVariable::MVariable(const std::list<std::string>& labels) {
+    _labels.assign(labels.begin(), labels.end());
+    size_t n = labels.size();
+    if (n > MAX_LABELS_COUNT) {
+        LOG(ERROR) << "Too many labels: " << n << " seen, overflow detected, 
max labels count: " << MAX_LABELS_COUNT;
+        _labels.resize(MAX_LABELS_COUNT);
+    }
+}
+
+MVariable::~MVariable() {
+    CHECK(!hide()) << "Subclass of MVariable MUST call hide() manually in 
their"
+    " dtors to avoid displaying a variable that is just destructing";
+}
+
+std::string MVariable::get_description() {
+    std::ostringstream os;
+    describe(os);
+    return os.str();
+}
+
+int MVariable::describe_exposed(const std::string& name,
+                                std::ostream& os) {
+    MVarMapWithLock& m = get_mvar_map();
+    BAIDU_SCOPED_LOCK(m.mutex);
+    MVarEntry* entry = m.seek(name);
+    if (entry == NULL) {
+        return -1;
+    }
+    entry->var->describe(os);
+    return 0;
+}
+
+std::string MVariable::describe_exposed(const std::string& name) {
+    std::ostringstream oss;
+    if (describe_exposed(name, oss) == 0) {
+        return oss.str();
+    }
+    return std::string();
+}
+
+int MVariable::expose_impl(const butil::StringPiece& prefix,
+                           const butil::StringPiece& name) {
+    if (name.empty()) {
+        LOG(ERROR) << "Parameter[name] is empty";
+        return -1;
+    }
+    // NOTE: It's impossible to atomically erase from a submap and insert into
+    // another submap without a global lock. When the to-be-exposed name
+    // already exists, there's a chance that we can't insert back previous
+    // name. But it should be fine generally because users are unlikely to
+    // expose a variable more than once and calls to expose() are unlikely
+    // to contend heavily.
+
+    // remove previous pointer from the map if needed.
+    hide();
+    
+    // Build the name.
+    _name.clear();
+    _name.reserve((prefix.size() + name.size()) * 5 / 4);
+    if (!prefix.empty()) {
+        to_underscored_name(&_name, prefix);
+        if (!_name.empty() && butil::back_char(_name) != '_') {
+            _name.push_back('_');
+        }     
+    }
+    to_underscored_name(&_name, name);
+   
+    if (count_exposed() > 
(size_t)FLAGS_bvar_max_multi_dimension_metric_number) {
+        LOG(ERROR) << "Too many metric seen, overflow detected, max metric 
count:" << FLAGS_bvar_max_multi_dimension_metric_number;
+        return -1;
+    }
+
+    MVarMapWithLock& m = get_mvar_map();
+    {
+        BAIDU_SCOPED_LOCK(m.mutex);
+        MVarEntry* entry = m.seek(_name);
+        if (entry == NULL) {
+            entry = &m[_name];
+            entry->var = this;
+            return 0;
+        }
+    }
+
+    if (FLAGS_bvar_abort_on_same_name) {
+        LOG(FATAL) << "Abort due to name conflict";
+        abort();
+    } else if (!s_bvar_may_abort) {
+        // Mark name conflict occurs, If this conflict happens before
+        // initialization of bvar_abort_on_same_name, the validator will
+        // abort the program if needed.
+        s_bvar_may_abort = true;
+    }
+
+    LOG(FATAL) << "Already exposed `" << _name << "' whose describe is`"

Review Comment:
   LOG(ERROR)



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to