1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
|
/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/* Author: Steven Grimm <sgrimm@facebook.com> */
#include "memcached.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
/* Hash table that uses the global hash function */
static PREFIX_STATS *prefix_stats[PREFIX_HASH_SIZE];
static char prefix_delimiter;
static int num_prefixes = 0;
static int total_prefix_size = 0;
void stats_prefix_init(char delimiter) {
prefix_delimiter = delimiter;
memset(prefix_stats, 0, sizeof(prefix_stats));
}
void stats_prefix_clear(void) {
int i;
for (i = 0; i < PREFIX_HASH_SIZE; i++) {
PREFIX_STATS *cur, *next;
for (cur = prefix_stats[i]; cur != NULL; cur = next) {
next = cur->next;
free(cur->prefix);
free(cur);
}
prefix_stats[i] = NULL;
}
num_prefixes = 0;
total_prefix_size = 0;
}
PREFIX_STATS *stats_prefix_find(const char *key, const size_t nkey) {
PREFIX_STATS *pfs;
uint32_t hashval;
size_t length;
bool bailout = true;
assert(key != NULL);
for (length = 0; length < nkey && key[length] != '\0'; length++) {
if (key[length] == prefix_delimiter) {
bailout = false;
break;
}
}
if (bailout) {
return NULL;
}
hashval = hash(key, length) % PREFIX_HASH_SIZE;
for (pfs = prefix_stats[hashval]; NULL != pfs; pfs = pfs->next) {
if (strncmp(pfs->prefix, key, length) == 0)
return pfs;
}
pfs = calloc(sizeof(PREFIX_STATS), 1);
if (NULL == pfs) {
perror("Can't allocate space for stats structure: calloc");
return NULL;
}
pfs->prefix = malloc(length + 1);
if (NULL == pfs->prefix) {
perror("Can't allocate space for copy of prefix: malloc");
free(pfs);
return NULL;
}
strncpy(pfs->prefix, key, length);
pfs->prefix[length] = '\0'; /* because strncpy() sucks */
pfs->prefix_len = length;
pfs->next = prefix_stats[hashval];
prefix_stats[hashval] = pfs;
num_prefixes++;
total_prefix_size += length;
return pfs;
}
void stats_prefix_record_get(const char *key, const size_t nkey, const bool is_hit) {
PREFIX_STATS *pfs;
STATS_LOCK();
pfs = stats_prefix_find(key, nkey);
if (NULL != pfs) {
pfs->num_gets++;
if (is_hit) {
pfs->num_hits++;
}
}
STATS_UNLOCK();
}
void stats_prefix_record_delete(const char *key, const size_t nkey) {
PREFIX_STATS *pfs;
STATS_LOCK();
pfs = stats_prefix_find(key, nkey);
if (NULL != pfs) {
pfs->num_deletes++;
}
STATS_UNLOCK();
}
void stats_prefix_record_set(const char *key, const size_t nkey) {
PREFIX_STATS *pfs;
STATS_LOCK();
pfs = stats_prefix_find(key, nkey);
if (NULL != pfs) {
pfs->num_sets++;
}
STATS_UNLOCK();
}
char *stats_prefix_dump(int *length) {
const char *format = "PREFIX %s get %llu hit %llu set %llu del %llu\r\n";
PREFIX_STATS *pfs;
char *buf;
int i, pos;
size_t size = 0, written = 0;
#ifndef NDEBUG
size_t total_written = 0;
#endif
/*
* Figure out how big the buffer needs to be. This is the sum of the
* lengths of the prefixes themselves, plus the size of one copy of
* the per-prefix output with 20-digit values for all the counts,
* plus space for the "END" at the end.
*/
STATS_LOCK();
size = strlen(format) + total_prefix_size +
num_prefixes * (strlen(format) - 2 /* %s */
+ 4 * (20 - 4)) /* %llu replaced by 20-digit num */
+ sizeof("END\r\n");
buf = malloc(size);
if (NULL == buf) {
perror("Can't allocate stats response: malloc");
STATS_UNLOCK();
return NULL;
}
pos = 0;
for (i = 0; i < PREFIX_HASH_SIZE; i++) {
for (pfs = prefix_stats[i]; NULL != pfs; pfs = pfs->next) {
written = snprintf(buf + pos, size-pos, format,
pfs->prefix, pfs->num_gets, pfs->num_hits,
pfs->num_sets, pfs->num_deletes);
pos += written;
#ifndef NDEBUG
total_written += written;
assert(total_written < size);
#endif
}
}
STATS_UNLOCK();
memcpy(buf + pos, "END\r\n", 6);
*length = pos + 5;
return buf;
}
|