Пример #1
0
/**
 * Tests basic functionality for cuckoo_insert and cuckoo_get with small key/val. Checks that the
 * commands succeed and that the item returned is well-formed.
 */
void
test_insert_basic(uint32_t policy, bool cas)
{
#define KEY "key"
#define VAL "value"
    struct bstring key, testval;
    struct val val;
    rstatus_i status;
    struct item *it;

    test_reset(policy, cas);

    key.data = KEY;
    key.len = sizeof(KEY) - 1;

    val.type = VAL_TYPE_STR;
    val.vstr.data = VAL;
    val.vstr.len = sizeof(VAL) - 1;

    time_update();
    status = cuckoo_insert(&key, &val, UINT32_MAX - 1);
    ck_assert_msg(status == CC_OK, "cuckoo_insert not OK - return status %d",
            status);

    it = cuckoo_get(&key);
    ck_assert_msg(it != NULL, "cuckoo_get returned NULL");
    ck_assert_int_eq(it->vlen, sizeof(VAL) - 1);
    ck_assert_int_eq(it->klen, sizeof(KEY) - 1);
    item_value_str(&testval, it);
    ck_assert_int_eq(it->vlen, testval.len);
    ck_assert_int_eq(cc_memcmp(testval.data, VAL, testval.len), 0);
#undef KEY
#undef VAL
}
Пример #2
0
/*
 * test_load_factor -- calculates the average load factor of the hash table
 *	when inserting <0, 1M> elements in random order.
 *
 * The factor itself isn't really that important because the implementation
 *	is optimized for lookup speed, but it should be reasonable.
 */
static void
test_load_factor()
{
	struct cuckoo *c = cuckoo_new();
	UT_ASSERT(c != NULL);

	/*
	 * The seed is intentionally constant so that the test result is
	 * consistent (at least on the same platform).
	 */
	srand(INITIAL_SEED);

	float avg_load = 0.f;
	rand64();
	int inserted = 0;
	for (int i = 0; ; ++i) {
		if (cuckoo_insert(c, rand64() % NVALUES, TEST_VALUE) == 0) {
			inserted++;
			avg_load += (float)inserted / cuckoo_get_size(c);
			if (inserted == NVALUES)
				break;
		}
	}
	avg_load /= inserted;

	UT_ASSERT(avg_load >= 0.4f);

	cuckoo_delete(c);
}
Пример #3
0
/**
 * Tests basic functionality for cuckoo_insert and cuckoo_get with small key/val.
 * Checks that the commands succeed and that the item returned is well-formed.
 */
void
test_insert_basic(uint32_t policy, bool cas)
{
#define KEY "key"
#define VAL "value"

    struct bstring key;
    struct val val;
    struct item *it;

    test_reset(policy, cas, CUCKOO_MAX_TTL, 0);

    bstring_set_literal(&key, KEY);

    val.type = VAL_TYPE_STR;
    bstring_set_literal(&val.vstr, VAL);

    time_update();
    it = cuckoo_insert(&key, &val, INT32_MAX);
    ck_assert_msg(it != NULL, "cuckoo_insert not OK");

    test_assert_entry_exists(&key, &val);

    test_reset(policy, cas, CUCKOO_MAX_TTL, 0);

    test_assert_entry_exists(&key, &val);

#undef KEY
#undef VAL
}
Пример #4
0
END_TEST

START_TEST(test_insert_insert_expire_swap)
{
#define NOW 12345678
    struct bstring key;
    struct val val;
    rstatus_i status;
    char keystring[30];
    uint64_t i;
    int hits = 0;

    metrics = (cuckoo_metrics_st) { CUCKOO_METRIC(METRIC_INIT) };
    test_reset(CUCKOO_POLICY_EXPIRE, false);

    now = NOW;
    for (i = 0; metrics.item_curr.counter < CUCKOO_NITEM; i++) {
        key.len = sprintf(keystring, "%"PRIu64, i);
        key.data = keystring;

        val.type = VAL_TYPE_INT;
        val.vint = i;

        status = cuckoo_insert(&key, &val, now + i);
        ck_assert_msg(status == CC_OK, "cuckoo_insert not OK - return status %d",
                status);
    }

    key.len = sprintf(keystring, "%"PRIu64, i);
    key.data = keystring;

    val.type = VAL_TYPE_INT;
    val.vint = i;

    status = cuckoo_insert(&key, &val, now + i);
    ck_assert_msg(status == CC_OK, "cuckoo_insert not OK - return status %d",
            status);

    for (;i > 0 && hits < CUCKOO_NITEM;i--) {
        if (cuckoo_get(&key) != NULL) {
            hits++;
        }
    }
    ck_assert_msg(hits == CUCKOO_NITEM, "expected %d hits, got %d",
            CUCKOO_NITEM, hits);
#undef NOW
}
Пример #5
0
/*
 * pmemobj_runtime_init -- (internal) initialize runtime part of the pool header
 */
static int
pmemobj_runtime_init(PMEMobjpool *pop, int rdonly, int boot)
{
	LOG(3, "pop %p rdonly %d boot %d", pop, rdonly, boot);

	if (pop->replica != NULL) {
		/* switch to functions that replicate data */
		pop->persist = obj_rep_persist;
		pop->flush = obj_rep_flush;
		pop->drain = obj_rep_drain;
		pop->memcpy_persist = obj_rep_memcpy_persist;
		pop->memset_persist = obj_rep_memset_persist;
	}

	/* run_id is made unique by incrementing the previous value */
	pop->run_id += 2;
	if (pop->run_id == 0)
		pop->run_id += 2;
	pop->persist(pop, &pop->run_id, sizeof (pop->run_id));

	/*
	 * Use some of the memory pool area for run-time info.  This
	 * run-time state is never loaded from the file, it is always
	 * created here, so no need to worry about byte-order.
	 */
	pop->rdonly = rdonly;
	pop->lanes = NULL;

	pop->uuid_lo = pmemobj_get_uuid_lo(pop);
	pop->store = (struct object_store *)
			((uintptr_t)pop + pop->obj_store_offset);

	if (boot) {
		if ((errno = pmemobj_boot(pop)) != 0)
			return -1;

		if ((errno = cuckoo_insert(pools_ht, pop->uuid_lo, pop)) != 0) {
			ERR("!cuckoo_insert");
			return -1;
		}

		if ((errno = ctree_insert(pools_tree, (uint64_t)pop, pop->size))
				!= 0) {
			ERR("!ctree_insert");
			return -1;
		}
	}

	/*
	 * If possible, turn off all permissions on the pool header page.
	 *
	 * The prototype PMFS doesn't allow this when large pages are in
	 * use. It is not considered an error if this fails.
	 */
	util_range_none(pop->addr, sizeof (struct pool_hdr));

	return 0;
}
Пример #6
0
END_TEST

START_TEST(test_insert_replace_expired)
{
#define NOW 12345678

    struct bstring key;
    struct val val;
    rstatus_i status;
    char keystring[30];
    uint64_t i;

    metrics = (cuckoo_metrics_st) { CUCKOO_METRIC(METRIC_INIT) };
    test_reset(CUCKOO_POLICY_EXPIRE, true);

    now = NOW;
    for (i = 0; metrics.item_curr.counter < CUCKOO_NITEM; i++) {
        key.len = sprintf(keystring, "%"PRIu64, i);
        key.data = keystring;

        val.type = VAL_TYPE_INT;
        val.vint = i;

        status = cuckoo_insert(&key, &val, now + 1);
        ck_assert_msg(status == CC_OK, "cuckoo_insert not OK - return status %d",
                status);
    }

    // dict is full, all items will expire in now + 1
    now += 2;
    key.len = sprintf(keystring, "%"PRIu64, i);
    key.data = keystring;

    val.type = VAL_TYPE_INT;
    val.vint = i;

    status = cuckoo_insert(&key, &val, now + 1);
    ck_assert_msg(status == CC_OK, "cuckoo_insert not OK - return status %d",
            status);
    ck_assert_int_eq(metrics.item_expire.counter, 1);
#undef NOW
}
Пример #7
0
void
test_cas(uint32_t policy)
{
#define KEY "key"
#define VAL "value"
#define VAL2 "value2"
    struct bstring key;
    struct val val;
    rstatus_i status;
    struct item *it;
    uint64_t cas1, cas2;

    test_reset(policy, true);

    key.data = KEY;
    key.len = sizeof(KEY) - 1;

    val.type = VAL_TYPE_STR;
    val.vstr.data = VAL;
    val.vstr.len = sizeof(VAL) - 1;

    time_update();
    status = cuckoo_insert(&key, &val, UINT32_MAX - 1);
    ck_assert_msg(status == CC_OK, "cuckoo_insert not OK - return status %d",
            status);

    it = cuckoo_get(&key);
    cas1 = item_cas(it);
    ck_assert_uint_ne(cas1, 0);

    val.vstr.data = VAL2;
    val.vstr.len = sizeof(VAL2) - 1;

    status = cuckoo_update(it, &val, UINT32_MAX - 1);
    ck_assert_msg(status == CC_OK, "cuckoo_update not OK - return status %d",
            status);

    it = cuckoo_get(&key);
    cas2 = item_cas(it);
    ck_assert_uint_ne(cas2, 0);
    ck_assert_uint_ne(cas1, cas2);
#undef KEY
#undef VAL
#undef VAL2
}
Пример #8
0
void
test_insert_collision(uint32_t policy, bool cas)
{
    struct bstring key;
    struct val val;
    rstatus_i status;
    struct item *it;
    int hits = 0;
    char keystring[CC_UINTMAX_MAXLEN];
    uint64_t i, testval;

    test_reset(policy, cas);

    time_update();
    for (i = 0; i < CUCKOO_NITEM + 1; i++) {
        key.len = sprintf(keystring, "%"PRIu64, i);
        key.data = keystring;

        val.type = VAL_TYPE_INT;
        val.vint = i;

        status = cuckoo_insert(&key, &val, UINT32_MAX - 1);
        ck_assert_msg(status == CC_OK, "cuckoo_insert not OK - return status %d",
                status);
    }

    for (i = 0; i < CUCKOO_NITEM + 1; i++) {
        key.len = sprintf(keystring, "%"PRIu64, i);
        key.data = keystring;

        it = cuckoo_get(&key);
        if (it == NULL) {
            continue;
        }
        hits++;
        ck_assert_int_eq(it->klen, key.len);
        testval = item_value_int(it);
        ck_assert_int_eq(testval, i);
    }

    ck_assert_msg(hits > (double)CUCKOO_NITEM * 9 / 10, "hit rate is lower than expected when hash collision occurs");
    ck_assert_msg(hits <= CUCKOO_NITEM, "hit rate is too high, expected more evicted values");
}
Пример #9
0
void
test_delete_basic(uint32_t policy, bool cas)
{
#define KEY "key"
#define VAL "value"
    struct bstring key;
    struct val val;
    rstatus_i status;
    struct item *it;
    bool deleted;

    test_reset(policy, cas);

    key.data = KEY;
    key.len = sizeof(KEY) - 1;

    val.type = VAL_TYPE_STR;
    val.vstr.data = VAL;
    val.vstr.len = sizeof(VAL) - 1;

    time_update();
    status = cuckoo_insert(&key, &val, UINT32_MAX - 1);
    ck_assert_msg(status == CC_OK, "cuckoo_insert not OK - return status %d",
            status);

    it = cuckoo_get(&key);
    ck_assert_msg(it != NULL, "cuckoo_get returned NULL");

    deleted = cuckoo_delete(&key);
    ck_assert_msg(deleted, "cuckoo_delete return false");

    it = cuckoo_get(&key);
    ck_assert_msg(it == NULL, "cuckoo_get returned not NULL");

    deleted = cuckoo_delete(&key);
    ck_assert_msg(!deleted, "cuckoo_delete return true");
#undef KEY
#undef VAL
}
Пример #10
0
/*
 * get_lane_info_record -- (internal) get lane record attached to memory pool
 *	or first free
 */
static inline struct lane_info *
get_lane_info_record(PMEMobjpool *pop)
{
	if (likely(Lane_info_cache != NULL &&
			Lane_info_cache->pop_uuid_lo == pop->uuid_lo)) {
		return Lane_info_cache;
	}

	if (unlikely(Lane_info_ht == NULL)) {
		lane_info_ht_boot();
	}

	struct lane_info *info = cuckoo_get(Lane_info_ht, pop->uuid_lo);

	if (unlikely(info == NULL)) {
		info = Malloc(sizeof(struct lane_info));
		if (unlikely(info == NULL)) {
			FATAL("Malloc");
		}
		info->pop_uuid_lo = pop->uuid_lo;
		info->lane_idx = UINT64_MAX;
		info->nest_count = 0;
		info->next = Lane_info_records;
		info->prev = NULL;
		if (Lane_info_records) {
			Lane_info_records->prev = info;
		}
		Lane_info_records = info;

		if (unlikely(cuckoo_insert(
				Lane_info_ht, pop->uuid_lo, info) != 0)) {
			FATAL("cuckoo_insert");
		}
	}

	Lane_info_cache = info;
	return info;
}
Пример #11
0
static void
test_insert_get_remove()
{
	struct cuckoo *c = cuckoo_new();
	ASSERT(c != NULL);

	for (int i = 0; i < TEST_INSERTS; ++i)
		ASSERT(cuckoo_insert(c, i, TEST_VAL(i)) == 0);

	for (int i = 0; i < TEST_INSERTS; ++i)
		ASSERT(cuckoo_get(c, i) == TEST_VAL(i));

	for (int i = 0; i < TEST_INSERTS; ++i)
		ASSERT(cuckoo_remove(c, i) == TEST_VAL(i));

	for (int i = 0; i < TEST_INSERTS; ++i)
		ASSERT(cuckoo_remove(c, i) == NULL);

	for (int i = 0; i < TEST_INSERTS; ++i)
		ASSERT(cuckoo_get(c, i) == NULL);

	cuckoo_delete(c);
}
Пример #12
0
static void *insert_thread(void *arg) {
    cuckoo_status st;
    KeyType key;
    ValType val;

    thread_arg_t* th = (thread_arg_t*) arg;
    th->ops         = 0;
    th->failures    = 0;
    th->num_read    = 0;
    th->num_written = 0;
    
    while (keep_writing) {
        size_t i, task;
        task = task_assign();
        if (task >= task_num)
            break;
        for (i = task * task_size + 1; i <= (task + 1) * task_size; i ++) {
            th->ops ++;
            key = (KeyType) i;
            val = (ValType) VALUE(i);
            st = cuckoo_insert(table, (const char*) &key, (const char*) &val);

            if (st == ok) {
                th->num_written ++;

            }
            else {
                printf("[writer%d] unknown error for key %zu (%d)\n", th->id, i, st);
                th->failures ++;
            }
        }
        task_complete(task);        
    }

    pthread_exit(NULL);
}
Пример #13
0
/*
 * alloc_class_register -- registers an allocation classes in the collection
 */
struct alloc_class *
alloc_class_register(struct alloc_class_collection *ac,
	struct alloc_class *c)
{
	struct alloc_class *nc = Malloc(sizeof(*nc));
	if (nc == NULL)
		goto error_class_alloc;

	*nc = *c;

	if (c->type == CLASS_RUN) {
		size_t map_idx = SIZE_TO_CLASS_MAP_INDEX(nc->unit_size,
			ac->granularity);
		ASSERT(map_idx <= UINT32_MAX);
		uint32_t map_idx_s = (uint32_t)map_idx;
		ASSERT(nc->run.size_idx <= UINT16_MAX);
		uint16_t size_idx_s = (uint16_t)nc->run.size_idx;
		uint16_t header_type_s = (uint16_t)nc->header_type;
		uint64_t k = RUN_CLASS_KEY_PACK(map_idx_s,
			header_type_s, size_idx_s);
		if (cuckoo_insert(ac->class_map_by_unit_size, k, nc) != 0) {
			ERR("unable to register allocation class");
			goto error_map_insert;
		}
	}

	ac->aclasses[nc->id] = nc;

	return nc;

error_map_insert:
	Free(nc);
error_class_alloc:
	alloc_class_reservation_clear(ac, c->id);
	return NULL;
}
Пример #14
0
void
test_expire_basic(uint32_t policy, bool cas)
{
#define KEY "key"
#define VAL "value"
#define NOW 12345678
    struct bstring key;
    struct val val;
    rstatus_i status;
    struct item *it;

    test_reset(policy, cas);

    key.data = KEY;
    key.len = sizeof(KEY) - 1;

    val.type = VAL_TYPE_STR;
    val.vstr.data = VAL;
    val.vstr.len = sizeof(VAL) - 1;

    now = NOW;
    status = cuckoo_insert(&key, &val, NOW + 1);
    ck_assert_msg(status == CC_OK, "cuckoo_insert not OK - return status %d",
            status);

    it = cuckoo_get(&key);
    ck_assert_msg(it != NULL, "cuckoo_get returned NULL");

    now += 2;

    it = cuckoo_get(&key);
    ck_assert_msg(it == NULL, "cuckoo_get returned not NULL after expiration");
#undef NOW
#undef KEY
#undef VAL
}
Пример #15
0
/*
 * alloc_class_new -- creates a new allocation class
 */
struct alloc_class *
alloc_class_new(int id, struct alloc_class_collection *ac,
	enum alloc_class_type type, enum header_type htype,
	size_t unit_size, size_t alignment,
	uint32_t size_idx)
{
	LOG(10, NULL);

	struct alloc_class *c = Malloc(sizeof(*c));
	if (c == NULL)
		goto error_class_alloc;

	c->unit_size = unit_size;
	c->header_type = htype;
	c->type = type;
	c->flags = (uint16_t)
		(header_type_to_flag[c->header_type] |
		(alignment ? CHUNK_FLAG_ALIGNED : 0));

	switch (type) {
		case CLASS_HUGE:
			id = DEFAULT_ALLOC_CLASS_ID;
			break;
		case CLASS_RUN:
			alloc_class_generate_run_proto(&c->run, unit_size,
				size_idx, alignment);

			uint8_t slot = (uint8_t)id;
			if (id < 0 && alloc_class_find_first_free_slot(ac,
			    &slot) != 0)
				goto error_class_alloc;
			id = slot;

			size_t map_idx = SIZE_TO_CLASS_MAP_INDEX(c->unit_size,
				ac->granularity);
			ASSERT(map_idx <= UINT32_MAX);
			uint32_t map_idx_s = (uint32_t)map_idx;
			ASSERT(c->run.size_idx <= UINT16_MAX);
			uint16_t size_idx_s = (uint16_t)c->run.size_idx;
			uint16_t flags_s = (uint16_t)c->flags;
			uint64_t k = RUN_CLASS_KEY_PACK(map_idx_s,
				flags_s, size_idx_s);
			if (cuckoo_insert(ac->class_map_by_unit_size,
			    k, c) != 0) {
				ERR("unable to register allocation class");
				goto error_map_insert;
			}

			break;
		default:
			ASSERT(0);
	}

	c->id = (uint8_t)id;
	ac->aclasses[c->id] = c;
	return c;

error_map_insert:
	Free(c);
error_class_alloc:
	if (id >= 0)
		alloc_class_reservation_clear(ac, id);
	return NULL;
}
Пример #16
0
static int dtread_readline(const char *line, struct cuckoo_ctx *cu, unsigned int *maxid)
{
    struct dtread_data *dr, *drp;
    struct dt_dentry *d;
    unsigned int pid, id, fid, items;
    unsigned long long size;
    const char *s;
    char *name;

    switch (line[0]) {
        case '0':
            if ((dr = dtread_data_alloc()) == NULL)
                return 0;
            if ((dr->de->id = atoi(&line[2])) == 0 ) {
                LOG_ERR("parsing failed for line %s\n", line);
                dtread_data_free(dr);
                return 0;
            }
            if (!cuckoo_insert(cu, dr->de->id, (void *) dr)) {
                LOG_ERR("cuckoo_insert() failed at line %s\n", line);
                dtread_data_free(dr);
                return 0;
            }
            if (dr->de->id > *maxid)
                *maxid = dr->de->id;
            break;
        case '1':
            
            s = strchr(line, ' ');
            if ((s == NULL) || (sscanf(++s, "%u", &pid) < 1 )) {
                LOG_ERR("parsing pid failed for line %s\n", line);
                return 0;
            }
            
            if (pid != 0) {
                drp = (struct dtread_data *) cuckoo_lookup(cu, pid);
                if (drp == NULL) {
                    LOG_ERR("cuckoo_lookup() returned null for id %u line %s\n",
                        pid, line);
                    return 0;
                }
            }

            s = strchr(s, ' ');
            if ((s == NULL) || (sscanf(++s, "%u", &fid) < 1)) {
                LOG_ERR("Parsing fid failed for line %s\n", line);
                return 0;
            }
            s = strchr(s, ' ');
            if ((s == NULL) || (sscanf(++s, "%llu", &size) < 1)) {
                LOG_ERR("Parsing size failed for line %s\n", line);
                return 0;
            }
            s = strchr(s, ' ');
            if ((s == NULL) || (sscanf(++s, "%u", &id) < 1)) {
                LOG_ERR("Parsing id failed for line %s\n", line);
                return 0;
            }
            s = strchr(s, ' ');
            if ((s == NULL) || (sscanf(++s, "%u", &items) < 1)) {
                LOG_ERR("Parsing items failed for line %s\n", line);
                return 0;
            }
            s = strchr(s, ' ');
            if ((s == NULL) || ((name = strdup(++s))== NULL)) {
                LOG_ERR("Parsing name failed for line %s\n", line);
                return 0;
            }

            if (id == 0) {
                /* file */
                LOG_ASSERT(pid != 0, "File with parent id=0 "
                    "(only root dir has parent id=0). Line %s\n", line);

                if ((d = dt_alloc()) == NULL) {
                    free(name);
                    return 0;
                }
                d->type = DT_FILE;
                d->fid = fid;
                d->size = size;
                d->name = name;
                d->parent = drp->de;
                if (drp->file_child)
                    drp->file_child->sibling = d;
                else
                    drp->de->file_child = d;
                drp->file_child = d;
            } else {
                /* directory */
                dr = (struct dtread_data *) cuckoo_lookup(cu, id);
                if (dr == NULL) {
                    LOG_ERR("cuckoo_lookup() returned null for id %u\n", id);
                    return 0;
                }
                d = dr->de; 
                d->type = DT_DIR;
                d->fid = fid;
                d->size = size;
                d->name = name;
                d->items = items;

                if (pid != 0){
                    if (drp->child)
                        drp->child->sibling = d;
                    else
                        drp->de->child = d;
                    drp->child = d;
                    d->parent = drp->de;
                    cuckoo_delete(cu, id);
                    free(dr);
                }
            }

            break;
        case '+':
        case '-':
        case '*':
            return 1;
        default:
            LOG_ERR("Unknown line format: %s\n", line);
            return 0;
    }
    return 1;
}