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 #pragma once 18 19 #include <cstdint> 20 #include <relaxed_atomic.h> 21 #include <mutex> 22 23 #include "timing_histogram.h" 24 25 /** 26 * Stats stored per-thread. 27 */ 28 struct thread_stats { thread_statsthread_stats29 thread_stats() { 30 reset(); 31 } 32 resetthread_stats33 void reset() { 34 cmd_get = 0; 35 get_hits = 0; 36 get_misses = 0; 37 cmd_set = 0; 38 delete_hits = 0; 39 cas_hits = 0; 40 cas_badval = 0; 41 delete_misses = 0; 42 incr_misses = 0; 43 decr_misses = 0; 44 incr_hits = 0; 45 decr_hits = 0; 46 cas_misses = 0; 47 bytes_written = 0; 48 bytes_read = 0; 49 cmd_flush = 0; 50 conn_yields = 0; 51 auth_cmds = 0; 52 auth_errors = 0; 53 cmd_subdoc_lookup = 0; 54 cmd_subdoc_mutation = 0; 55 cmd_lock = 0; 56 lock_errors = 0; 57 58 bytes_subdoc_lookup_total = 0; 59 bytes_subdoc_lookup_extracted = 0; 60 bytes_subdoc_mutation_total = 0; 61 bytes_subdoc_mutation_inserted = 0; 62 63 rbufs_allocated = 0; 64 rbufs_loaned = 0; 65 rbufs_existing = 0; 66 wbufs_allocated = 0; 67 wbufs_loaned = 0; 68 wbufs_existing = 0; 69 70 iovused_high_watermark = 0; 71 msgused_high_watermark = 0; 72 } 73 operator +=thread_stats74 thread_stats & operator += (const thread_stats &other) { 75 cmd_get += other.cmd_get; 76 get_misses += other.get_misses; 77 cmd_set += other.cmd_set; 78 get_hits += other.get_hits; 79 delete_hits += other.delete_hits; 80 cas_hits += other.cas_hits; 81 cas_badval += other.cas_badval; 82 delete_misses += other.delete_misses; 83 decr_misses += other.decr_misses; 84 incr_misses += other.incr_misses; 85 decr_hits += other.decr_hits; 86 incr_hits += other.incr_hits; 87 cas_misses += other.cas_misses; 88 bytes_read += other.bytes_read; 89 bytes_written += other.bytes_written; 90 cmd_flush += other.cmd_flush; 91 conn_yields += other.conn_yields; 92 auth_cmds += other.auth_cmds; 93 auth_errors += other.auth_errors; 94 cmd_subdoc_lookup += other.cmd_subdoc_lookup; 95 cmd_subdoc_mutation += other.cmd_subdoc_mutation; 96 97 cmd_lock += other.cmd_lock; 98 lock_errors += other.lock_errors; 99 100 bytes_subdoc_lookup_total += other.bytes_subdoc_lookup_total; 101 bytes_subdoc_lookup_extracted += other.bytes_subdoc_lookup_extracted; 102 bytes_subdoc_mutation_total += other.bytes_subdoc_mutation_total; 103 bytes_subdoc_mutation_inserted += other.bytes_subdoc_mutation_inserted; 104 105 rbufs_allocated += other.rbufs_allocated; 106 rbufs_loaned += other.rbufs_loaned; 107 rbufs_existing += other.rbufs_existing; 108 wbufs_allocated += other.wbufs_allocated; 109 wbufs_loaned += other.wbufs_loaned; 110 wbufs_existing += other.wbufs_existing; 111 112 iovused_high_watermark.setIfGreater(other.iovused_high_watermark); 113 msgused_high_watermark.setIfGreater(other.msgused_high_watermark); 114 115 return *this; 116 } 117 aggregatethread_stats118 void aggregate(const std::vector<thread_stats>& thread_stats) { 119 for (auto& ii : thread_stats) { 120 *this += ii; 121 } 122 } 123 124 Couchbase::RelaxedAtomic<uint64_t> cmd_get; 125 Couchbase::RelaxedAtomic<uint64_t> get_hits; 126 Couchbase::RelaxedAtomic<uint64_t> get_misses; 127 Couchbase::RelaxedAtomic<uint64_t> cmd_set; 128 Couchbase::RelaxedAtomic<uint64_t> delete_hits; 129 Couchbase::RelaxedAtomic<uint64_t> cas_hits; 130 Couchbase::RelaxedAtomic<uint64_t> cas_badval; 131 Couchbase::RelaxedAtomic<uint64_t> delete_misses; 132 Couchbase::RelaxedAtomic<uint64_t> incr_misses; 133 Couchbase::RelaxedAtomic<uint64_t> decr_misses; 134 Couchbase::RelaxedAtomic<uint64_t> incr_hits; 135 Couchbase::RelaxedAtomic<uint64_t> decr_hits; 136 Couchbase::RelaxedAtomic<uint64_t> cas_misses; 137 Couchbase::RelaxedAtomic<uint64_t> bytes_read; 138 Couchbase::RelaxedAtomic<uint64_t> bytes_written; 139 Couchbase::RelaxedAtomic<uint64_t> cmd_flush; 140 Couchbase::RelaxedAtomic<uint64_t> conn_yields; /* # of yields for connections (-R option)*/ 141 Couchbase::RelaxedAtomic<uint64_t> auth_cmds; 142 Couchbase::RelaxedAtomic<uint64_t> auth_errors; 143 /* # of subdoc lookup commands (GET/EXISTS/MULTI_LOOKUP) */ 144 Couchbase::RelaxedAtomic<uint64_t> cmd_subdoc_lookup; 145 /* # of subdoc mutation commands */ 146 Couchbase::RelaxedAtomic<uint64_t> cmd_subdoc_mutation; 147 148 /** # of lock commands */ 149 Couchbase::RelaxedAtomic<uint64_t> cmd_lock; 150 151 /** # of times an operation failed due to accessing a locked item */ 152 Couchbase::RelaxedAtomic<uint64_t> lock_errors; 153 154 /* # of bytes in the complete document which subdoc lookups searched 155 within. Compare with 'bytes_subdoc_lookup_extracted' */ 156 Couchbase::RelaxedAtomic<uint64_t> bytes_subdoc_lookup_total; 157 /* # of bytes extracted during a subdoc lookup operation and sent back to 158 the client. */ 159 Couchbase::RelaxedAtomic<uint64_t> bytes_subdoc_lookup_extracted; 160 161 /* # of bytes in the complete document which subdoc mutations updated. 162 Compare with 'bytes_subdoc_mutation_inserted' */ 163 Couchbase::RelaxedAtomic<uint64_t> bytes_subdoc_mutation_total; 164 /* # of bytes inserted during a subdoc mutation operation (which were 165 received from the client). */ 166 Couchbase::RelaxedAtomic<uint64_t> bytes_subdoc_mutation_inserted; 167 168 /* # of read buffers allocated. */ 169 Couchbase::RelaxedAtomic<uint64_t> rbufs_allocated; 170 /* # of read buffers which could be loaned (and hence didn't need to be allocated). */ 171 Couchbase::RelaxedAtomic<uint64_t> rbufs_loaned; 172 /* # of read buffers which already existed (with partial data) on the connection 173 (and hence didn't need to be allocated). */ 174 Couchbase::RelaxedAtomic<uint64_t> rbufs_existing; 175 /* # of write buffers allocated. */ 176 Couchbase::RelaxedAtomic<uint64_t> wbufs_allocated; 177 /* # of write buffers which could be loaned (and hence didn't need to be allocated). */ 178 Couchbase::RelaxedAtomic<uint64_t> wbufs_loaned; 179 /* # of write buffers which already existed (with partial data) on the 180 connection (and hence didn't need to be allocated). */ 181 Couchbase::RelaxedAtomic<uint64_t> wbufs_existing; 182 183 /* Highest value iovsize has got to */ 184 Couchbase::RelaxedAtomic<int> iovused_high_watermark; 185 /* High value Connection->msgused has got to */ 186 Couchbase::RelaxedAtomic<int> msgused_high_watermark; 187 }; 188 189 /** 190 * A class representing the properties used by Listening port. 191 * 192 * This class differs from the "interface" class that it represents 193 * an actual port memcached have open. It contains some dynamic and 194 * some fixed properties 195 */ 196 class ListeningPort { 197 public: ListeningPort(const in_port_t port_, const std::string& host_, bool tcp_nodelay_, int backlog_, bool management_)198 ListeningPort(const in_port_t port_, 199 const std::string& host_, 200 bool tcp_nodelay_, 201 int backlog_, 202 bool management_) 203 : port(port_), 204 curr_conns(1), 205 maxconns(0), 206 host(host_), 207 backlog(backlog_), 208 ipv6(false), 209 ipv4(false), 210 tcp_nodelay(tcp_nodelay_), 211 management(management_) { 212 } 213 214 /** 215 * The actual port number being used by this connection. Please note 216 * that you cannot configure the system to use the same port, but different 217 * hostnames. 218 */ 219 const in_port_t port; 220 221 /** The current number of connections connected to this port */ 222 int curr_conns; 223 224 /** The maximum number of connections allowed for this port */ 225 int maxconns; 226 227 /** The hostname this port is bound to ("*" means all interfaces) */ 228 const std::string host; 229 230 /** SSL related properties for the port */ 231 struct ifc_ssl_info { ifc_ssl_infoListeningPort::ifc_ssl_info232 ifc_ssl_info() 233 : enabled(false) { 234 } 235 ifc_ssl_infoListeningPort::ifc_ssl_info236 ifc_ssl_info(const ifc_ssl_info& o) 237 : enabled(o.enabled), 238 key(o.key), 239 cert(o.cert) {} 240 241 /** Is ssl enabled or not */ 242 bool enabled; 243 /** The name of the file containing the SSL key */ 244 std::string key; 245 /** The name of the file containing the certificate */ 246 std::string cert; 247 } ssl; 248 249 /** The backlog size before the kernel will deny connect requests */ 250 int backlog; 251 /** Is IPv6 enabled for this port */ 252 bool ipv6; 253 /** Is IPv4 enabled for this port */ 254 bool ipv4; 255 /** Should TCP_NODELAY be enabled or not */ 256 bool tcp_nodelay; 257 // You can't change the purpose of a port dynamically (It is only 258 // used during startup 259 const bool management; 260 }; 261 262 /** 263 * Global stats. 264 */ 265 struct stats { 266 /** Number of connections used by the server itself (listen ports etc). */ 267 Couchbase::RelaxedAtomic<unsigned int> daemon_conns; 268 269 /** The current number of connections to the server */ 270 std::atomic<unsigned int> curr_conns; 271 272 /** The total number of connections to the server since start (or reset) */ 273 Couchbase::RelaxedAtomic<unsigned int> total_conns; 274 275 /** The current number of allocated connection objects */ 276 Couchbase::RelaxedAtomic<unsigned int> conn_structs; 277 278 /** The number of times I reject a client */ 279 Couchbase::RelaxedAtomic<uint64_t> rejected_conns; 280 281 std::vector<ListeningPort> listening_ports; 282 }; 283 284 class Connection; 285 struct thread_stats* get_thread_stats(Connection* c); 286 287 /* 288 * Macros for managing statistics inside memcached 289 */ 290 291 /* The item must always be called "it" */ 292 #define SLAB_GUTS(conn, thread_stats, slab_op, thread_op) \ 293 thread_stats->slab_op++; 294 295 #define THREAD_GUTS(conn, thread_stats, slab_op, thread_op) \ 296 thread_stats->thread_op++; 297 298 #define THREAD_GUTS2(conn, thread_stats, slab_op, thread_op) \ 299 thread_stats->slab_op++; \ 300 thread_stats->thread_op++; 301 302 #define SLAB_THREAD_GUTS(conn, thread_stats, slab_op, thread_op) \ 303 SLAB_GUTS(conn, thread_stats, slab_op, thread_op) \ 304 THREAD_GUTS(conn, thread_stats, slab_op, thread_op) 305 306 #define STATS_INCR1(GUTS, conn, slab_op, thread_op) { \ 307 struct thread_stats *thread_stats = get_thread_stats(conn); \ 308 GUTS(conn, thread_stats, slab_op, thread_op); \ 309 } 310 311 #define STATS_INCR(conn, op) \ 312 STATS_INCR1(THREAD_GUTS, conn, op, op) 313 314 #define SLAB_INCR(conn, op) \ 315 STATS_INCR1(SLAB_GUTS, conn, op, op) 316 317 #define STATS_TWO(conn, slab_op, thread_op) \ 318 STATS_INCR1(THREAD_GUTS2, conn, slab_op, thread_op) 319 320 #define SLAB_TWO(conn, slab_op, thread_op) \ 321 STATS_INCR1(SLAB_THREAD_GUTS, conn, slab_op, thread_op) 322 323 #define STATS_HIT(conn, op) \ 324 SLAB_TWO(conn, op##_hits, cmd_##op) 325 326 #define STATS_MISS(conn, op) \ 327 STATS_TWO(conn, op##_misses, cmd_##op) 328 329 /* 330 * Set the statistic to the maximum of the current value, and the specified 331 * value. 332 */ 333 #define STATS_MAX(conn, op, value) get_thread_stats(conn)->op.setIfGreater(value); 334 335 extern std::mutex stats_mutex; 336 extern char reset_stats_time[80]; 337 338 class Cookie; 339 void stats_reset(Cookie& cookie); 340