xref: /6.6.0/couchstore/src/couch_latency.cc (revision cf120ada)
1/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 *     Copyright 2017 Couchbase, Inc
4 *
5 *   Licensed under the Apache License, Version 2.0 (the "License");
6 *   you may not use this file except in compliance with the License.
7 *   You may obtain a copy of the License at
8 *
9 *       http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *   Unless required by applicable law or agreed to in writing, software
12 *   distributed under the License is distributed on an "AS IS" BASIS,
13 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *   See the License for the specific language governing permissions and
15 *   limitations under the License.
16 */
17
18#include "couch_latency_internal.h"
19
20SingletonWrapper<cb::RelaxedAtomic<CouchLatency*> > CouchLatency::instance(
21        cb::RelaxedAtomic<CouchLatency*>(nullptr));
22
23CouchLatency* CouchLatency::init() {
24    CouchLatency* tmp = instance.object.load();
25    if (tmp == nullptr) {
26        // Ensure two threads don't both create an instance.
27        std::lock_guard<std::mutex> lock(instance.mutex);
28        tmp = instance.object.load();
29        if (tmp == nullptr) {
30            tmp = new CouchLatency();
31            instance.object.store(tmp);
32        }
33    }
34    return tmp;
35}
36
37CouchLatency* CouchLatency::getInstance() {
38    // Instance should be initialized explicitly.
39    return instance.object.load();
40}
41
42void CouchLatency::destroyInstance() {
43    std::lock_guard<std::mutex> lock(instance.mutex);
44    CouchLatency* tmp = instance.object.load();
45    if (tmp != nullptr) {
46        delete tmp;
47        instance.object = nullptr;
48    }
49}
50
51CouchLatency::~CouchLatency() {
52    // Deregister all items, and reset their Histograms.
53    // As CouchLatencyItem itself is a static unique_ptr
54    // that is owned by each API functions,
55    // it doesn't need to be destroyed here.
56    for (auto& itr : itemsMap.object) {
57        itr.second->changeRegisterStatus(false);
58        itr.second->resetHistogram();
59    }
60}
61
62CouchLatencyItem* CouchLatency::addItem(CouchLatencyItem* item) {
63    // This lock will be grabbed during the registration phase only.
64    // Once an item is registered, they will run in a lock-free manner.
65    std::lock_guard<std::mutex> l(itemsMap.mutex);
66    auto itr = itemsMap.object.find(item->statName);
67    if (itr != itemsMap.object.end()) {
68        // Already registered by other thread.
69        // Return it.
70        return itr->second;
71    }
72    itemsMap.object.insert( std::make_pair(item->statName, item) );
73    item->changeRegisterStatus(true);
74    return item;
75}
76
77void CouchLatency::getLatencyInfo(couchstore_latency_callback_fn cb_func,
78                                  couchstore_latency_dump_options options,
79                                  void *ctx) {
80    (void)options;
81    for (auto& itr : itemsMap.object) {
82        CouchLatencyItem *item = itr.second;
83        if (!item->latencySum) {
84            continue;
85        }
86        int ret = cb_func(item->statName.c_str(),
87                          &item->latencies,
88                          item->latencySum,
89                          ctx);
90        if (ret) {
91            // Abort by user.
92            break;
93        }
94    }
95}
96
97void couchstore_latency_collector_start() {
98    CouchLatency::init();
99}
100
101void couchstore_get_latency_info(couchstore_latency_callback_fn callback,
102                                 couchstore_latency_dump_options options,
103                                 void *ctx) {
104    CouchLatency* tmp = CouchLatency::getInstance();
105    if (!tmp) {
106        // Latency collector is disabled.
107        return;
108    }
109    tmp->getLatencyInfo(callback, options, ctx);
110}
111
112void couchstore_latency_collector_stop() {
113    CouchLatency::destroyInstance();
114}
115
116
117