1 /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  *     Copyright 2015 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 #pragma once
19 
20 #include "config.h"
21 
22 #include "hdrhistogram.h"
23 #include "objectregistry.h"
24 
25 #include <memcached/engine_common.h>
26 #include <platform/histogram.h>
27 #include <platform/sized_buffer.h>
28 
29 #include <atomic>
30 #include <cstring>
31 
32 class EventuallyPersistentEngine;
33 
add_casted_stat(const char *k, const char *v, ADD_STAT add_stat, const void *cookie)34 inline void add_casted_stat(const char *k, const char *v,
35                             ADD_STAT add_stat, const void *cookie) {
36     EventuallyPersistentEngine *e = ObjectRegistry::onSwitchThread(NULL, true);
37     add_stat(k, static_cast<uint16_t>(strlen(k)),
38              v, static_cast<uint32_t>(strlen(v)), cookie);
39     ObjectRegistry::onSwitchThread(e);
40 }
41 
42 template <typename T>
add_casted_stat(const char *k, const T &v, ADD_STAT add_stat, const void *cookie)43 void add_casted_stat(const char *k, const T &v,
44                             ADD_STAT add_stat, const void *cookie) {
45     std::stringstream vals;
46     vals << v;
47     add_casted_stat(k, vals.str().c_str(), add_stat, cookie);
48 }
49 
add_casted_stat(const char *k, const bool v, ADD_STAT add_stat, const void *cookie)50 inline void add_casted_stat(const char *k, const bool v,
51                             ADD_STAT add_stat, const void *cookie) {
52     add_casted_stat(k, v ? "true" : "false", add_stat, cookie);
53 }
54 
55 template <typename T>
add_casted_stat(const char *k, const std::atomic<T> &v, ADD_STAT add_stat, const void *cookie)56 void add_casted_stat(const char *k, const std::atomic<T> &v,
57                             ADD_STAT add_stat, const void *cookie) {
58     add_casted_stat(k, v.load(), add_stat, cookie);
59 }
60 
61 template <>
add_casted_stat(const char* k, const cb::const_char_buffer& v, ADD_STAT add_stat, const void* cookie)62 inline void add_casted_stat(const char* k,
63                      const cb::const_char_buffer& v,
64                      ADD_STAT add_stat,
65                      const void* cookie) {
66     EventuallyPersistentEngine* e = ObjectRegistry::onSwitchThread(NULL, true);
67     add_stat(k, static_cast<uint16_t>(strlen(k)), v.data(), v.size(), cookie);
68     ObjectRegistry::onSwitchThread(e);
69 }
70 
71 template <>
add_casted_stat(const char* k, const HdrHistogram& v, ADD_STAT add_stat, const void* cookie)72 inline void add_casted_stat(const char* k,
73                             const HdrHistogram& v,
74                             ADD_STAT add_stat,
75                             const void* cookie) {
76     HdrHistogram::Iterator iter{v.makeLinearIterator(1)};
77     while (auto result = v.getNextValueAndCount(iter)) {
78         if (result->second > 0) {
79             std::stringstream ss;
80             ss << k << "_" << result->first << "," << result->first;
81             add_casted_stat(ss.str().c_str(), result->second, add_stat, cookie);
82         }
83     }
84 }
85 
86 /// @cond DETAILS
87 /**
88  * Convert a histogram into a bunch of calls to add stats.
89  */
90 template <typename T, template <class> class Limits>
91 struct histo_stat_adder {
histo_stat_adderhisto_stat_adder92     histo_stat_adder(const char *k, ADD_STAT a, const void *c)
93         : prefix(k), add_stat(a), cookie(c) {}
94 
operator ()histo_stat_adder95     void operator()(const std::unique_ptr<HistogramBin<T, Limits>>& b) {
96         std::stringstream ss;
97         ss << prefix << "_" << b->start() << "," << b->end();
98         add_casted_stat(ss.str().c_str(), b->count(), add_stat, cookie);
99     }
100     const char *prefix;
101     ADD_STAT add_stat;
102     const void *cookie;
103 };
104 
105 // Specialization for UnsignedMicroseconds - needs count() calling to get
106 // a raw integer which can be printed.
107 template <>
108 inline void histo_stat_adder<UnsignedMicroseconds, cb::duration_limits>::
operator ()(const MicrosecondHistogram::value_type& b)109 operator()(const MicrosecondHistogram::value_type& b) {
110     std::stringstream ss;
111     ss << prefix << "_" << b->start().count() << "," << b->end().count();
112 
113     add_casted_stat(ss.str().c_str(), b->count(), add_stat, cookie);
114 }
115 /// @endcond
116 
117 template <typename T, template <class> class Limits>
add_casted_stat(const char* k, const Histogram<T, Limits>& v, ADD_STAT add_stat, const void* cookie)118 void add_casted_stat(const char* k,
119                      const Histogram<T, Limits>& v,
120                      ADD_STAT add_stat,
121                      const void* cookie) {
122     histo_stat_adder<T, Limits> a(k, add_stat, cookie);
123     std::for_each(v.begin(), v.end(), a);
124 }
125 
126 template <typename P, typename T>
add_prefixed_stat(P prefix, const char *nm, T val, ADD_STAT add_stat, const void *cookie)127 void add_prefixed_stat(P prefix, const char *nm, T val,
128                   ADD_STAT add_stat, const void *cookie) {
129     std::stringstream name;
130     name << prefix << ":" << nm;
131 
132     add_casted_stat(name.str().c_str(), val, add_stat, cookie);
133 }
134 
135 template <typename P, typename T, template <class> class Limits>
add_prefixed_stat(P prefix, const char* nm, Histogram<T, Limits>& val, ADD_STAT add_stat, const void* cookie)136 void add_prefixed_stat(P prefix,
137                        const char* nm,
138                        Histogram<T, Limits>& val,
139                        ADD_STAT add_stat,
140                        const void* cookie) {
141     std::stringstream name;
142     name << prefix << ":" << nm;
143 
144     add_casted_stat(name.str().c_str(), val, add_stat, cookie);
145 }
146