Blame stats_prefix.c

Packit 4e8bc4
/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
Packit 4e8bc4
/* Author: Steven Grimm <sgrimm@facebook.com> */
Packit 4e8bc4
#include "memcached.h"
Packit 4e8bc4
#include <stdio.h>
Packit 4e8bc4
#include <stdlib.h>
Packit 4e8bc4
#include <string.h>
Packit 4e8bc4
#include <assert.h>
Packit 4e8bc4
Packit 4e8bc4
/* Hash table that uses the global hash function */
Packit 4e8bc4
static PREFIX_STATS *prefix_stats[PREFIX_HASH_SIZE];
Packit 4e8bc4
Packit 4e8bc4
static char prefix_delimiter;
Packit 4e8bc4
static int num_prefixes = 0;
Packit 4e8bc4
static int total_prefix_size = 0;
Packit 4e8bc4
Packit 4e8bc4
void stats_prefix_init(char delimiter) {
Packit 4e8bc4
    prefix_delimiter = delimiter;
Packit 4e8bc4
    memset(prefix_stats, 0, sizeof(prefix_stats));
Packit 4e8bc4
}
Packit 4e8bc4
Packit 4e8bc4
void stats_prefix_clear(void) {
Packit 4e8bc4
    int i;
Packit 4e8bc4
Packit 4e8bc4
    for (i = 0; i < PREFIX_HASH_SIZE; i++) {
Packit 4e8bc4
        PREFIX_STATS *cur, *next;
Packit 4e8bc4
        for (cur = prefix_stats[i]; cur != NULL; cur = next) {
Packit 4e8bc4
            next = cur->next;
Packit 4e8bc4
            free(cur->prefix);
Packit 4e8bc4
            free(cur);
Packit 4e8bc4
        }
Packit 4e8bc4
        prefix_stats[i] = NULL;
Packit 4e8bc4
    }
Packit 4e8bc4
    num_prefixes = 0;
Packit 4e8bc4
    total_prefix_size = 0;
Packit 4e8bc4
}
Packit 4e8bc4
Packit 4e8bc4
PREFIX_STATS *stats_prefix_find(const char *key, const size_t nkey) {
Packit 4e8bc4
    PREFIX_STATS *pfs;
Packit 4e8bc4
    uint32_t hashval;
Packit 4e8bc4
    size_t length;
Packit 4e8bc4
    bool bailout = true;
Packit 4e8bc4
Packit 4e8bc4
    assert(key != NULL);
Packit 4e8bc4
Packit 4e8bc4
    for (length = 0; length < nkey && key[length] != '\0'; length++) {
Packit 4e8bc4
        if (key[length] == prefix_delimiter) {
Packit 4e8bc4
            bailout = false;
Packit 4e8bc4
            break;
Packit 4e8bc4
        }
Packit 4e8bc4
    }
Packit 4e8bc4
Packit 4e8bc4
    if (bailout) {
Packit 4e8bc4
        return NULL;
Packit 4e8bc4
    }
Packit 4e8bc4
Packit 4e8bc4
    hashval = hash(key, length) % PREFIX_HASH_SIZE;
Packit 4e8bc4
Packit 4e8bc4
    for (pfs = prefix_stats[hashval]; NULL != pfs; pfs = pfs->next) {
Packit 4e8bc4
        if (strncmp(pfs->prefix, key, length) == 0)
Packit 4e8bc4
            return pfs;
Packit 4e8bc4
    }
Packit 4e8bc4
Packit 4e8bc4
    pfs = calloc(sizeof(PREFIX_STATS), 1);
Packit 4e8bc4
    if (NULL == pfs) {
Packit 4e8bc4
        perror("Can't allocate space for stats structure: calloc");
Packit 4e8bc4
        return NULL;
Packit 4e8bc4
    }
Packit 4e8bc4
Packit 4e8bc4
    pfs->prefix = malloc(length + 1);
Packit 4e8bc4
    if (NULL == pfs->prefix) {
Packit 4e8bc4
        perror("Can't allocate space for copy of prefix: malloc");
Packit 4e8bc4
        free(pfs);
Packit 4e8bc4
        return NULL;
Packit 4e8bc4
    }
Packit 4e8bc4
Packit 4e8bc4
    strncpy(pfs->prefix, key, length);
Packit 4e8bc4
    pfs->prefix[length] = '\0';      /* because strncpy() sucks */
Packit 4e8bc4
    pfs->prefix_len = length;
Packit 4e8bc4
Packit 4e8bc4
    pfs->next = prefix_stats[hashval];
Packit 4e8bc4
    prefix_stats[hashval] = pfs;
Packit 4e8bc4
Packit 4e8bc4
    num_prefixes++;
Packit 4e8bc4
    total_prefix_size += length;
Packit 4e8bc4
Packit 4e8bc4
    return pfs;
Packit 4e8bc4
}
Packit 4e8bc4
Packit 4e8bc4
void stats_prefix_record_get(const char *key, const size_t nkey, const bool is_hit) {
Packit 4e8bc4
    PREFIX_STATS *pfs;
Packit 4e8bc4
Packit 4e8bc4
    STATS_LOCK();
Packit 4e8bc4
    pfs = stats_prefix_find(key, nkey);
Packit 4e8bc4
    if (NULL != pfs) {
Packit 4e8bc4
        pfs->num_gets++;
Packit 4e8bc4
        if (is_hit) {
Packit 4e8bc4
            pfs->num_hits++;
Packit 4e8bc4
        }
Packit 4e8bc4
    }
Packit 4e8bc4
    STATS_UNLOCK();
Packit 4e8bc4
}
Packit 4e8bc4
Packit 4e8bc4
void stats_prefix_record_delete(const char *key, const size_t nkey) {
Packit 4e8bc4
    PREFIX_STATS *pfs;
Packit 4e8bc4
Packit 4e8bc4
    STATS_LOCK();
Packit 4e8bc4
    pfs = stats_prefix_find(key, nkey);
Packit 4e8bc4
    if (NULL != pfs) {
Packit 4e8bc4
        pfs->num_deletes++;
Packit 4e8bc4
    }
Packit 4e8bc4
    STATS_UNLOCK();
Packit 4e8bc4
}
Packit 4e8bc4
Packit 4e8bc4
void stats_prefix_record_set(const char *key, const size_t nkey) {
Packit 4e8bc4
    PREFIX_STATS *pfs;
Packit 4e8bc4
Packit 4e8bc4
    STATS_LOCK();
Packit 4e8bc4
    pfs = stats_prefix_find(key, nkey);
Packit 4e8bc4
    if (NULL != pfs) {
Packit 4e8bc4
        pfs->num_sets++;
Packit 4e8bc4
    }
Packit 4e8bc4
    STATS_UNLOCK();
Packit 4e8bc4
}
Packit 4e8bc4
Packit 4e8bc4
char *stats_prefix_dump(int *length) {
Packit 4e8bc4
    const char *format = "PREFIX %s get %llu hit %llu set %llu del %llu\r\n";
Packit 4e8bc4
    PREFIX_STATS *pfs;
Packit 4e8bc4
    char *buf;
Packit 4e8bc4
    int i, pos;
Packit 4e8bc4
    size_t size = 0, written = 0, total_written = 0;
Packit 4e8bc4
Packit 4e8bc4
    /*
Packit 4e8bc4
     * Figure out how big the buffer needs to be. This is the sum of the
Packit 4e8bc4
     * lengths of the prefixes themselves, plus the size of one copy of
Packit 4e8bc4
     * the per-prefix output with 20-digit values for all the counts,
Packit 4e8bc4
     * plus space for the "END" at the end.
Packit 4e8bc4
     */
Packit 4e8bc4
    STATS_LOCK();
Packit 4e8bc4
    size = strlen(format) + total_prefix_size +
Packit 4e8bc4
           num_prefixes * (strlen(format) - 2 /* %s */
Packit 4e8bc4
                           + 4 * (20 - 4)) /* %llu replaced by 20-digit num */
Packit 4e8bc4
                           + sizeof("END\r\n");
Packit 4e8bc4
    buf = malloc(size);
Packit 4e8bc4
    if (NULL == buf) {
Packit 4e8bc4
        perror("Can't allocate stats response: malloc");
Packit 4e8bc4
        STATS_UNLOCK();
Packit 4e8bc4
        return NULL;
Packit 4e8bc4
    }
Packit 4e8bc4
Packit 4e8bc4
    pos = 0;
Packit 4e8bc4
    for (i = 0; i < PREFIX_HASH_SIZE; i++) {
Packit 4e8bc4
        for (pfs = prefix_stats[i]; NULL != pfs; pfs = pfs->next) {
Packit 4e8bc4
            written = snprintf(buf + pos, size-pos, format,
Packit 4e8bc4
                           pfs->prefix, pfs->num_gets, pfs->num_hits,
Packit 4e8bc4
                           pfs->num_sets, pfs->num_deletes);
Packit 4e8bc4
            pos += written;
Packit 4e8bc4
            total_written += written;
Packit 4e8bc4
            assert(total_written < size);
Packit 4e8bc4
        }
Packit 4e8bc4
    }
Packit 4e8bc4
Packit 4e8bc4
    STATS_UNLOCK();
Packit 4e8bc4
    memcpy(buf + pos, "END\r\n", 6);
Packit 4e8bc4
Packit 4e8bc4
    *length = pos + 5;
Packit 4e8bc4
    return buf;
Packit 4e8bc4
}