示例#1
0
bool assoc_prefix_isvalid(struct default_engine *engine, hash_item *it)
{
    rel_time_t current_time = engine->server.core->get_current_time();
    prefix_t *pt;

    if (it->nprefix == it->nkey) {
        /* the prefix of key: null */
        assert(root_pt != NULL);
        pt = root_pt;
        if (pt->oldest_live != 0 && pt->oldest_live <= current_time && it->time <= pt->oldest_live) {
            return false;
        }
    } else {
        /* the prifix of key: given */
        pt = assoc_prefix_find(engine, engine->server.core->hash(item_get_key(it), it->nprefix, 0),
                               item_get_key(it), it->nprefix);
        while (pt != NULL && pt != root_pt) {
            // validation check between prefix and hash_item
            if (pt->oldest_live != 0 && pt->oldest_live <= current_time && it->time <= pt->oldest_live) {
                return false;
            }
            // traversal parent prefixes to validate
            pt = pt->parent_prefix;
        }
    }
    return true;
}
示例#2
0
void assoc_prefix_unlink(struct default_engine *engine, hash_item *it,
                         const size_t item_size, bool drop_if_empty)
{
    prefix_t *pt;
    assert(it->nprefix != 0);

    if (it->nprefix == it->nkey) {
        pt = root_pt;
    } else {
        pt = assoc_prefix_find(engine, engine->server.core->hash(item_get_key(it), it->nprefix, 0),
                               item_get_key(it), it->nprefix);
    }
    assert(pt != NULL);

    // update prefix information
    if ((it->iflag & ITEM_IFLAG_LIST) != 0) {
        pt->list_hash_items--;
        pt->list_hash_items_bytes -= item_size;
    } else if ((it->iflag & ITEM_IFLAG_SET) != 0) {
        pt->set_hash_items--;
        pt->set_hash_items_bytes -= item_size;
    } else if ((it->iflag & ITEM_IFLAG_BTREE) != 0) {
        pt->btree_hash_items--;
        pt->btree_hash_items_bytes -= item_size;
    } else {
        pt->hash_items--;
        pt->hash_items_bytes -= item_size;
    }
#if 0 // might be used later
    if (1) {
        prefix_t *curr_pt = pt->parent_prefix;
        while (curr_pt != NULL) {
            curr_pt->tot_hash_items--;
            curr_pt->tot_hash_items_bytes -= item_size;
            curr_pt = curr_pt->parent_prefix;
        }
    }
#endif
    if (drop_if_empty) {
        while (pt != NULL) {
            prefix_t *parent_pt = pt->parent_prefix;

            if (pt != root_pt && pt->prefix_items == 0 && pt->hash_items == 0 &&
                pt->list_hash_items == 0 && pt->set_hash_items == 0 && pt->btree_hash_items == 0) {
                assert(pt->hash_items_bytes == 0 && pt->list_hash_items_bytes == 0 &&
                       pt->set_hash_items_bytes == 0 && pt->btree_hash_items_bytes == 0);
                _prefix_delete(engine, engine->server.core->hash(_get_prefix(pt), pt->nprefix, 0),
                               _get_prefix(pt), pt->nprefix);
            } else {
                break;
            }
            pt = parent_pt;
        }
    }
}
示例#3
0
static int _prefix_insert(struct default_engine *engine, uint32_t hash, prefix_t *pt)
{
    assert(assoc_prefix_find(engine, hash, _get_prefix(pt), pt->nprefix) == NULL);

    pt->h_next = engine->assoc.prefix_hashtable[hash & hashmask(DEFAULT_PREFIX_HASHPOWER)];
    engine->assoc.prefix_hashtable[hash & hashmask(DEFAULT_PREFIX_HASHPOWER)] = pt;

    assert(pt->parent_prefix != NULL);
    pt->parent_prefix->prefix_items++;
    engine->assoc.tot_prefix_items++;
    return 1;
}
示例#4
0
static ENGINE_ERROR_CODE do_assoc_get_prefix_stats(struct default_engine *engine,
                                                   const char *prefix, const int  nprefix, void *prefix_data)
{
    prefix_t *pt;

    if (nprefix < 0) { // all prefix information
        char *buf;
        struct tm *t;
        const char *format = "PREFIX %s itm %llu kitm %llu litm %llu sitm %llu bitm %llu "
                             "tsz %llu ktsz %llu ltsz %llu stsz %llu btsz %llu time %04d%02d%02d%02d%02d%02d\r\n";
        uint32_t i, hsize = hashsize(DEFAULT_PREFIX_HASHPOWER);
        uint32_t num_prefixes = engine->assoc.tot_prefix_items;
        uint32_t tot_prefix_name_len = 0;
        uint32_t msize, pos, written;

        pt = root_pt;
        if (pt != NULL && (pt->hash_items > 0 || pt->list_hash_items > 0 || pt->set_hash_items > 0 || pt->btree_hash_items > 0)) {
            /* including null prefix */
            num_prefixes += 1;
            tot_prefix_name_len = strlen("<null>");
        }
        for (i = 0; i < hsize; i++) {
            pt = engine->assoc.prefix_hashtable[i];
            while (pt) {
                tot_prefix_name_len += pt->nprefix;
                pt = pt->h_next;
            }
        }

        msize = sizeof(uint32_t) + strlen(format) + tot_prefix_name_len
                + num_prefixes * (strlen(format) - 2 /* %s */
                                  + (10 * (20 - 4))) /* %llu replaced by 20-digit num */
                - (5 * (4 - 2)) /* %02d replaced by 2-digit num */
                + sizeof("END\r\n");

        buf = malloc(msize);
        if (buf == NULL) {
            return ENGINE_ENOMEM;
        }
        pos = sizeof(uint32_t);

        pt = root_pt;
        if (pt != NULL && (pt->hash_items > 0 || pt->list_hash_items > 0 || pt->set_hash_items > 0 || pt->btree_hash_items > 0)) {
            /* including null prefix */
            t = localtime(&pt->create_time);
            written = snprintf(buf+pos, msize-pos, format, "<null>",
                               pt->hash_items+pt->list_hash_items+pt->set_hash_items+pt->btree_hash_items,
                               pt->hash_items,pt->list_hash_items,pt->set_hash_items,pt->btree_hash_items,
                               pt->hash_items_bytes+pt->list_hash_items_bytes+pt->set_hash_items_bytes+pt->btree_hash_items_bytes,
                               pt->hash_items_bytes,pt->list_hash_items_bytes,pt->set_hash_items_bytes,pt->btree_hash_items_bytes,
                               t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
            pos += written;
        }

        for (i = 0; i < hsize; i++) {
            pt = engine->assoc.prefix_hashtable[i];
            while (pt) {
                t = localtime(&pt->create_time);
                written = snprintf(buf+pos, msize-pos, format, _get_prefix(pt),
                               pt->hash_items+pt->list_hash_items+pt->set_hash_items+pt->btree_hash_items,
                               pt->hash_items,pt->list_hash_items,pt->set_hash_items,pt->btree_hash_items,
                               pt->hash_items_bytes+pt->list_hash_items_bytes+pt->set_hash_items_bytes+pt->btree_hash_items_bytes,
                               pt->hash_items_bytes,pt->list_hash_items_bytes,pt->set_hash_items_bytes,pt->btree_hash_items_bytes,
                               t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
                pos += written;
                assert(pos < msize);
                pt = pt->h_next;
            }
        }
        memcpy(buf+pos, "END\r\n", 6);
        *(uint32_t*)buf = pos + 5 - sizeof(uint32_t);

        *(char**)prefix_data = buf;
    } else {
        prefix_engine_stats *prefix_stats = (prefix_engine_stats*)prefix_data;

        if (prefix != NULL) {
            pt = assoc_prefix_find(engine, engine->server.core->hash(prefix,nprefix,0), prefix, nprefix);
        } else {
            pt = root_pt;
        }
        if (pt == NULL) {
            return ENGINE_PREFIX_ENOENT;
        }

        prefix_stats->hash_items = pt->hash_items;
        prefix_stats->hash_items_bytes = pt->hash_items_bytes;
        prefix_stats->prefix_items = pt->prefix_items;
        if (prefix != NULL)
            prefix_stats->tot_prefix_items = pt->prefix_items;
        else
            prefix_stats->tot_prefix_items = engine->assoc.tot_prefix_items;
    }
    return ENGINE_SUCCESS;
}
示例#5
0
ENGINE_ERROR_CODE assoc_prefix_link(struct default_engine *engine,
                                    hash_item *it, const size_t item_size, prefix_t **pfx_item)
{
    assert(it->nprefix == 0);
    const char *key = item_get_key(it);
    size_t     nkey = it->nkey;
    int prefix_depth = 0;
    int i = 0;
    char *token;
    prefix_t *pt = NULL;
    prefix_t_list_elem prefix_list[DEFAULT_PREFIX_MAX_DEPTH];

    // prefix discovering: we don't even know prefix existence at this time
    while ((token = memchr(key + i + 1, engine->config.prefix_delimiter, nkey - i - 1)) != NULL) {
        i = token - key;
        prefix_list[prefix_depth].nprefix = i;

        prefix_depth++;
        if (prefix_depth >= DEFAULT_PREFIX_MAX_DEPTH) {
            break;
        }
    }

    if (prefix_depth == 0) {
        pt = root_pt;
        time(&pt->create_time);
        it->nprefix = nkey;
    } else {
        for (i = prefix_depth - 1; i >= 0; i--) {
            prefix_list[i].hash = engine->server.core->hash(key, prefix_list[i].nprefix, 0);
            pt = assoc_prefix_find(engine, prefix_list[i].hash, key, prefix_list[i].nprefix);
            if (pt != NULL) break;
        }

        if (i < (prefix_depth - 1)) {
            if (prefix_depth == 1) {
                if (!mc_isvalidname(key, prefix_list[0].nprefix)) {
                    return ENGINE_PREFIX_ENAME; /* Invalid prefix name */
                }
            }

            // need building prefixes
            if (pt != NULL && i >= 0) {
                prefix_list[i].pt = pt; // i >= 0
            }

            for (int j = i + 1; j < prefix_depth; j++) {
                pt = (prefix_t*)malloc(sizeof(prefix_t) + prefix_list[j].nprefix + 1);
                if (pt == NULL) {
                    for (j = j - 1; j >= i + 1; j--) {
                        assert(prefix_list[j].pt != NULL);
                        _prefix_delete(engine, prefix_list[j].hash, key, prefix_list[j].nprefix);
                    }
                    return ENGINE_ENOMEM;
                }

                // building a prefix_t
                memset(pt, 0, sizeof(prefix_t));
                memcpy(pt + 1, key, prefix_list[j].nprefix);
                memcpy((char*)pt+sizeof(prefix_t)+prefix_list[j].nprefix, "\0", 1);
                pt->nprefix = prefix_list[j].nprefix;
                pt->parent_prefix = (j == 0 ? root_pt : prefix_list[j-1].pt);
                time(&pt->create_time);

                // registering allocated prefixes to prefix hastable
                _prefix_insert(engine, prefix_list[j].hash, pt);
                prefix_list[j].pt = pt;
            }
        }
        // update item information about prefix length
        it->nprefix = pt->nprefix;
    }

    assert(pt != NULL);

    // update prefix information
    if ((it->iflag & ITEM_IFLAG_LIST) != 0) {
        pt->list_hash_items++;
        pt->list_hash_items_bytes += item_size;
    } else if ((it->iflag & ITEM_IFLAG_SET) != 0) {
        pt->set_hash_items++;
        pt->set_hash_items_bytes += item_size;
    } else if ((it->iflag & ITEM_IFLAG_BTREE) != 0) {
        pt->btree_hash_items++;
        pt->btree_hash_items_bytes += item_size;
    } else {
        pt->hash_items++;
        pt->hash_items_bytes += item_size;
    }
#if 0 // might be used later
    if (1) {
        curr_pt = pt->parent_prefix;
        while (curr_pt != NULL) {
            curr_pt->tot_hash_items++;
            curr_pt->tot_hash_items_bytes += item_size;
            curr_pt = curr_pt->parent_prefix;
        }
    }
#endif

    *pfx_item = pt;
    return ENGINE_SUCCESS;
}
示例#6
0
static ENGINE_ERROR_CODE
do_assoc_get_prefix_stats(struct default_engine *engine,
                          const char *prefix, const int nprefix,
                          void *prefix_data)
{
    struct assoc *assoc = &engine->assoc;
    prefix_t *pt;

    if (nprefix < 0) /* all prefix stats */
    {
        const char *format = "PREFIX %s "
                             "itm %llu kitm %llu litm %llu sitm %llu mitm %llu bitm %llu " /* total item count */
                             "tsz %llu ktsz %llu ltsz %llu stsz %llu mtsz %llu btsz %llu " /* total item bytes */
                             "time %04d%02d%02d%02d%02d%02d\r\n"; /* create time */
        char *buffer;
        struct tm *t;
        uint32_t prefix_hsize = hashsize(DEFAULT_PREFIX_HASHPOWER);
        uint32_t num_prefixes = assoc->tot_prefix_items;
        uint32_t sum_nameleng = 0; /* sum of prefix name length */
        uint32_t i, buflen, pos;

        /* get # of prefixes and num of prefix names */
        assert(root_pt != NULL);
        if (root_pt->total_count_exclusive > 0) {
            /* Include the valid null prefix (that is root prefix) */
            num_prefixes += 1;
            sum_nameleng += strlen("<null>");
        }
        for (i = 0; i < prefix_hsize; i++) {
            pt = assoc->prefix_hashtable[i];
            while (pt) {
                sum_nameleng += pt->nprefix;
                pt = pt->h_next;
            }
        }

        /* Allocate stats buffer: <length, prefix stats list, tail>.
         * Check the count of "%llu" and "%02d" in the above format string.
         *   - 10 : the count of "%llu" strings.
         *   -  5 : the count of "%02d" strings.
         */
        buflen = sizeof(uint32_t) /* length */
               + sum_nameleng
               + num_prefixes * (strlen(format) - 2 /* %s replaced by prefix name */
                                 + (12 * (20 - 4))  /* %llu replaced by 20-digit num */
                                 - ( 5 * ( 4 - 2))) /* %02d replaced by 2-digit num */
               + sizeof("END\r\n"); /* tail string */

        if ((buffer = malloc(buflen)) == NULL) {
            return ENGINE_ENOMEM;
        }

        /* write prefix stats in the buffer */
        pos = sizeof(uint32_t);
        if (num_prefixes > assoc->tot_prefix_items) { /* include root prefix */
            pt = root_pt;
            t = localtime(&pt->create_time);
            pos += snprintf(buffer+pos, buflen-pos, format, "<null>",
                            pt->total_count_exclusive,
                            pt->items_count[ITEM_TYPE_KV],
                            pt->items_count[ITEM_TYPE_LIST],
                            pt->items_count[ITEM_TYPE_SET],
                            pt->items_count[ITEM_TYPE_MAP],
                            pt->items_count[ITEM_TYPE_BTREE],
                            pt->total_bytes_exclusive,
                            pt->items_bytes[ITEM_TYPE_KV],
                            pt->items_bytes[ITEM_TYPE_LIST],
                            pt->items_bytes[ITEM_TYPE_SET],
                            pt->items_bytes[ITEM_TYPE_MAP],
                            pt->items_bytes[ITEM_TYPE_BTREE],
                            t->tm_year+1900, t->tm_mon+1, t->tm_mday,
                            t->tm_hour, t->tm_min, t->tm_sec);
            assert(pos < buflen);
        }
        for (i = 0; i < prefix_hsize; i++) {
            pt = assoc->prefix_hashtable[i];
            while (pt) {
                t = localtime(&pt->create_time);
                pos += snprintf(buffer+pos, buflen-pos, format, _get_prefix(pt),
                                pt->total_count_exclusive,
                                pt->items_count[ITEM_TYPE_KV],
                                pt->items_count[ITEM_TYPE_LIST],
                                pt->items_count[ITEM_TYPE_SET],
                                pt->items_count[ITEM_TYPE_MAP],
                                pt->items_count[ITEM_TYPE_BTREE],
                                pt->total_bytes_exclusive,
                                pt->items_bytes[ITEM_TYPE_KV],
                                pt->items_bytes[ITEM_TYPE_LIST],
                                pt->items_bytes[ITEM_TYPE_SET],
                                pt->items_bytes[ITEM_TYPE_MAP],
                                pt->items_bytes[ITEM_TYPE_BTREE],
                                t->tm_year+1900, t->tm_mon+1, t->tm_mday,
                                t->tm_hour, t->tm_min, t->tm_sec);
                assert(pos < buflen);
                pt = pt->h_next;
            }
        }
        memcpy(buffer+pos, "END\r\n", 6);
        *(uint32_t*)buffer = pos + 5 - sizeof(uint32_t);

        *(char**)prefix_data = buffer;
    }
    else /* prefix stats on the given prefix */
    {
        prefix_engine_stats *prefix_stats = (prefix_engine_stats*)prefix_data;

        if (prefix != NULL) {
            pt = assoc_prefix_find(engine, engine->server.core->hash(prefix,nprefix,0),
                                   prefix, nprefix);
        } else {
            pt = root_pt;
        }
        if (pt == NULL) {
            return ENGINE_PREFIX_ENOENT;
        }

        prefix_stats->hash_items = pt->items_count[ITEM_TYPE_KV];
        prefix_stats->hash_items_bytes = pt->items_bytes[ITEM_TYPE_KV];
        prefix_stats->prefix_items = pt->prefix_items;
        if (prefix != NULL)
            prefix_stats->tot_prefix_items = pt->prefix_items;
        else
            prefix_stats->tot_prefix_items = assoc->tot_prefix_items;
    }
    return ENGINE_SUCCESS;
}
示例#7
0
ENGINE_ERROR_CODE assoc_prefix_link(struct default_engine *engine, hash_item *it,
                                    const size_t item_size)
{
    const char *key = item_get_key(it);
    size_t     nkey = it->nkey;
    int prefix_depth = 0;
    int i = 0;
    char *token;
    prefix_t *pt = NULL;
    prefix_t_list_elem prefix_list[DEFAULT_PREFIX_MAX_DEPTH];

    // prefix discovering: we don't even know prefix existence at this time
    while ((token = memchr(key+i+1, engine->config.prefix_delimiter, nkey-i-1)) != NULL) {
        i = token - key;
        prefix_list[prefix_depth].nprefix = i;

        prefix_depth++;
        if (prefix_depth >= DEFAULT_PREFIX_MAX_DEPTH) {
            break;
        }
    }

    if (prefix_depth == 0) {
        pt = root_pt;
        time(&pt->create_time);
        /* save prefix pointer in hash_item */
        it->pfxptr = pt;
    } else {
        for (i = prefix_depth - 1; i >= 0; i--) {
            prefix_list[i].hash = engine->server.core->hash(key, prefix_list[i].nprefix, 0);
            pt = assoc_prefix_find(engine, prefix_list[i].hash, key, prefix_list[i].nprefix);
            if (pt != NULL) break;
        }

        if (i < (prefix_depth - 1)) {
            if (prefix_depth == 1) {
                if (!mc_isvalidname(key, prefix_list[0].nprefix)) {
                    return ENGINE_PREFIX_ENAME; /* Invalid prefix name */
                }
            }

            // need building prefixes
            if (pt != NULL && i >= 0) {
                prefix_list[i].pt = pt; // i >= 0
            }

            for (int j = i + 1; j < prefix_depth; j++) {
                pt = (prefix_t*)malloc(sizeof(prefix_t) + prefix_list[j].nprefix + 1);
                if (pt == NULL) {
                    for (j = j - 1; j >= i + 1; j--) {
                        assert(prefix_list[j].pt != NULL);
                        _prefix_delete(engine, prefix_list[j].hash, key, prefix_list[j].nprefix);
                    }
                    return ENGINE_ENOMEM;
                }

                // building a prefix_t
                memset(pt, 0, sizeof(prefix_t));
                memcpy(pt + 1, key, prefix_list[j].nprefix);
                memcpy((char*)pt+sizeof(prefix_t)+prefix_list[j].nprefix, "\0", 1);
                pt->nprefix = prefix_list[j].nprefix;
                if (PREFIX_IS_RSVD(key, pt->nprefix)) {
                    pt->internal = 1; /* internal prefix */
                }
                pt->parent_prefix = (j == 0 ? root_pt : prefix_list[j-1].pt);
                time(&pt->create_time);

                // registering allocated prefixes to prefix hastable
                _prefix_insert(engine, prefix_list[j].hash, pt);
                prefix_list[j].pt = pt;
            }
        }
        /* save prefix pointer in hash_item */
        it->pfxptr = pt;
    }
    assert(pt != NULL);

    /* update prefix information */
    int item_type = GET_ITEM_TYPE(it);
    pt->items_count[item_type] += 1;
    pt->items_bytes[item_type] += item_size;
    pt->total_count_exclusive += 1;
    pt->total_bytes_exclusive += item_size;
#if 0 // might be used later
    if (1) {
        prefix_t *curr_pt = pt->parent_prefix;
        while (curr_pt != NULL) {
            curr_pt->total_count_inclusive += 1;
            curr_pt->total_bytes_inclusive += item_size;
            curr_pt = curr_pt->parent_prefix;
        }
    }
#endif

    return ENGINE_SUCCESS;
}