コード例 #1
0
ファイル: stats.c プロジェクト: ngleader/arcus-memcached
static void test_prefix_dump() {
    int hashval = mc_hash("abc", 3, 0) % PREFIX_HASH_SIZE;
    char tmp[500];
    char *expected;
    int keynum;
    int length;

    test_equals_str("empty stats", "END\r\n", stats_prefix_dump(&length));
    test_equals_int("empty stats length", 5, length);
    stats_prefix_record_set("abc:123");
    expected = "PREFIX abc get 0 hit 0 set 1 del 0\r\nEND\r\n";
    test_equals_str("stats after set", expected, stats_prefix_dump(&length));
    test_equals_int("stats length after set", strlen(expected), length);
    stats_prefix_record_get("abc:123", 0);
    expected = "PREFIX abc get 1 hit 0 set 1 del 0\r\nEND\r\n";
    test_equals_str("stats after get #1", expected, stats_prefix_dump(&length));
    test_equals_int("stats length after get #1", strlen(expected), length);
    stats_prefix_record_get("abc:123", 1);
    expected = "PREFIX abc get 2 hit 1 set 1 del 0\r\nEND\r\n";
    test_equals_str("stats after get #2", expected, stats_prefix_dump(&length));
    test_equals_int("stats length after get #2", strlen(expected), length);
    stats_prefix_record_delete("abc:123");
    expected = "PREFIX abc get 2 hit 1 set 1 del 1\r\nEND\r\n";
    test_equals_str("stats after del #1", expected, stats_prefix_dump(&length));
    test_equals_int("stats length after del #1", strlen(expected), length);

    /* The order of results might change if we switch hash functions. */
    stats_prefix_record_delete("def:123");
    expected = "PREFIX abc get 2 hit 1 set 1 del 1\r\n"
               "PREFIX def get 0 hit 0 set 0 del 1\r\n"
               "END\r\n";
    test_equals_str("stats after del #2", expected, stats_prefix_dump(&length));
    test_equals_int("stats length after del #2", strlen(expected), length);

    /* Find a key that hashes to the same bucket as "abc" */
    for (keynum = 0; keynum < PREFIX_HASH_SIZE * 100; keynum++) {
        snprintf(tmp, sizeof(tmp), "%d", keynum);
        if (hashval == mc_hash(tmp, strlen(tmp), 0) % PREFIX_HASH_SIZE) {
            break;
        }
    }
    stats_prefix_record_set(tmp);
    snprintf(tmp, sizeof(tmp),
             "PREFIX %d get 0 hit 0 set 1 del 0\r\n"
             "PREFIX abc get 2 hit 1 set 1 del 1\r\n"
             "PREFIX def get 0 hit 0 set 0 del 1\r\n"
             "END\r\n", keynum);
    test_equals_str("stats with two stats in one bucket",
                    tmp, stats_prefix_dump(&length));
    test_equals_int("stats length with two stats in one bucket",
                    strlen(tmp), length);
}
コード例 #2
0
ファイル: assoc.c プロジェクト: hgschmie/memcached
item *assoc_find(const char *key, const size_t nkey) {
    uint32_t hv = mc_hash(key, nkey, 0);
    item *it;
    unsigned int oldbucket;

    if (expanding &&
        (oldbucket = (hv & hashmask(hashpower - 1))) >= expand_bucket)
    {
        it = old_hashtable[oldbucket];
    } else {
        it = primary_hashtable[hv & hashmask(hashpower)];
    }

    item *ret = NULL;
    int depth = 0;
    while (it) {
        if ((nkey == it->nkey) && (memcmp(key, ITEM_key(it), nkey) == 0)) {
            ret = it;
            break;
        }
        it = it->h_next;
        ++depth;
    }
    MEMCACHED_ASSOC_FIND(key, nkey, depth);
    return ret;
}
コード例 #3
0
ファイル: assoc.c プロジェクト: hgschmie/memcached
/* Note: this isn't an assoc_update.  The key must not already exist to call this */
int assoc_insert(item *it) {
    uint32_t hv;
    unsigned int oldbucket;

    assert(assoc_find(ITEM_key(it), it->nkey) == 0);  /* shouldn't have duplicately named things defined */

    hv = mc_hash(ITEM_key(it), it->nkey, 0);
    if (expanding &&
        (oldbucket = (hv & hashmask(hashpower - 1))) >= expand_bucket)
    {
        it->h_next = old_hashtable[oldbucket];
        old_hashtable[oldbucket] = it;
    } else {
        it->h_next = primary_hashtable[hv & hashmask(hashpower)];
        primary_hashtable[hv & hashmask(hashpower)] = it;
    }

    hash_items++;
    if (! expanding && hash_items > (hashsize(hashpower) * 3) / 2) {
        assoc_expand();
    }

    MEMCACHED_ASSOC_INSERT(ITEM_key(it), it->nkey, hash_items);
    return 1;
}
コード例 #4
0
ファイル: stats.c プロジェクト: ngleader/arcus-memcached
int stats_prefix_delete(const char *prefix, const size_t nprefix) {
    PREFIX_STATS *curr, *next, *prev;
    int hidx;
    int ret = -1;

    STATS_LOCK();
    if (nprefix == 0) {
        hidx = mc_hash(prefix, nprefix, 0) % PREFIX_HASH_SIZE;
        prev = NULL;
        for (curr = prefix_stats[hidx]; curr != NULL; prev = curr, curr = curr->next) {
            if (curr->prefix_len == 0) break;
        }
        if (curr != NULL) { /* found */
            if (prev == NULL) prefix_stats[hidx] = curr->next;
            else              prev->next = curr->next;
            num_prefixes--;
            total_prefix_size -= strlen(null_prefix_str);

            free(curr->prefix);
            free(curr);
            ret = 0;
        }
    } else { /* nprefix > 0 */
        // Full scan for sub-prefixies (we would fix it in future)
        for (hidx = 0; hidx < PREFIX_HASH_SIZE; hidx++) {
            prev = NULL;
            for (curr = prefix_stats[hidx]; curr != NULL; curr = next) {
                next = curr->next;
                if ((curr->prefix_len >= nprefix && strncmp(curr->prefix, prefix, nprefix) == 0) &&
                    (curr->prefix_len == nprefix || *(curr->prefix+nprefix)==settings.prefix_delimiter)) {
                    if (prev == NULL) prefix_stats[hidx] = curr->next;
                    else              prev->next = curr->next;
                    num_prefixes--;
                    total_prefix_size -= curr->prefix_len;

                    free(curr->prefix);
                    free(curr);
                    ret = 0;
                } else {
                    prev = curr;
                }
            }
        }
    }
    STATS_UNLOCK();
    return ret;
}
コード例 #5
0
ファイル: assoc.c プロジェクト: hgschmie/memcached
static void *assoc_maintenance_thread(void *arg) {

    while (do_run_maintenance_thread) {
        int ii = 0;

        /* Lock the cache, and bulk move multiple buckets to the new
         * hash table. */
        pthread_mutex_lock(&cache_lock);

        for (ii = 0; ii < hash_bulk_move && expanding; ++ii) {
            item *it, *next;
            int bucket;

            for (it = old_hashtable[expand_bucket]; NULL != it; it = next) {
                next = it->h_next;

                bucket = mc_hash(ITEM_key(it), it->nkey, 0) & hashmask(hashpower);
                it->h_next = primary_hashtable[bucket];
                primary_hashtable[bucket] = it;
            }

            old_hashtable[expand_bucket] = NULL;

            expand_bucket++;
            if (expand_bucket == hashsize(hashpower - 1)) {
                expanding = false;
                free(old_hashtable);
                if (settings.verbose > 1)
                    fprintf(stderr, "Hash table expansion done\n");
            }
        }

        if (!expanding) {
            /* We are done expanding.. just wait for next invocation */
            pthread_cond_wait(&maintenance_cond, &cache_lock);
        }

        pthread_mutex_unlock(&cache_lock);
    }
    return NULL;
}
コード例 #6
0
ファイル: stats.c プロジェクト: ngleader/arcus-memcached
/*@null@*/
static PREFIX_STATS *stats_prefix_find(const char *key, const size_t nkey) {
    PREFIX_STATS *pfs;
    uint32_t hashval;
    size_t length;
    char *token = NULL;
    int i = 0;
    int prefix_depth = 0;

    assert(key != NULL);

    while ((token = memchr(key + i + 1, settings.prefix_delimiter, nkey - i - 1)) != NULL) {
        i = token - key;
        prefix_depth++;

        if (prefix_depth >= PREFIX_MAX_DEPTH) {
            break;
        }
    }

    if (prefix_depth <= 0) {
        length = 0;
    } else {
        length = i;
    }

    hashval = mc_hash(key, length, 0) % PREFIX_HASH_SIZE;

    for (pfs = prefix_stats[hashval]; NULL != pfs; pfs = pfs->next) {
        if ((pfs->prefix_len==length) && (length==0 || strncmp(pfs->prefix, key, length)==0))
            return pfs;
    }

    if (length > 0) {
        if (!mc_isvalidname(key, length)) {
            /* Invalid prefix name */
            return NULL;
        }
    }

    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;
    }

    if (length > 0)
        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++;

    if (length > 0)
        total_prefix_size += length;
    else /* length == 0 */
        total_prefix_size += strlen(null_prefix_str);

    return pfs;
}