Example #1
0
/**
 * eblob_l2hash_lookup() - finds matching l2hash in tree and performs
 * collision resolution of @key for each entry in collision list.
 * If match is found it's placed into structure pointed by @rctl.
 *
 * Returns:
 *	0:		Key resolved
 *	-ENOENT:	Key not found
 *	<0:		Error during lookup
 */
int eblob_l2hash_lookup(struct eblob_l2hash *l2h,
		const struct eblob_key *key,
		struct eblob_ram_control *rctl)
{
	struct eblob_l2hash_entry *e;

	if (l2h == NULL || key == NULL || rctl == NULL)
		return -EINVAL;

	if ((e = __eblob_l2hash_lookup(l2h, key)) != NULL)
		return eblob_l2hash_resolve_collision(&l2h->collisions, e, key, rctl);

	return -ENOENT;
}
Example #2
0
/**
 * eblob_l2hash_lookup_nolock() - finds matching l2hash in tree and performs
 * collision resolution of @key for each entry in collision list.
 * If match is found it's placed into structure pointed by @rctl.
 *
 * Returns:
 *	0:		Key resolved
 *	-ENOENT:	Key not found
 *	<0:		Error during lookup
 */
static int eblob_l2hash_lookup_nolock(struct eblob_l2hash *l2h,
		struct eblob_key *key, struct eblob_ram_control *rctl)
{
	struct eblob_l2hash_entry *e;

	assert(l2h != NULL);
	assert(key != NULL);
	assert(rctl != NULL);
	assert(pthread_mutex_trylock(&l2h->root_lock) == EBUSY);

	if ((e = __eblob_l2hash_lookup(l2h, key)) != NULL)
		return eblob_l2hash_resolve_collision(&l2h->collisions, e, key, rctl);

	return -ENOENT;
}
Example #3
0
/**
 * eblob_l2hash_remove_nolock() - remove l2hash entry specified by @key
 *
 * Returns:
 *	0:		@key removed
 *	-ENOENT:	@key not found
 *	Other:		Error
 */
static int eblob_l2hash_remove_nolock(struct eblob_l2hash *l2h,
		struct eblob_key *key)
{
	struct eblob_l2hash_collision *collision;
	struct eblob_l2hash_entry *e;
	int err;

	assert(l2h != NULL);
	assert(key != NULL);
	assert(pthread_mutex_trylock(&l2h->root_lock) == EBUSY);

	/* Find entry in tree */
	if ((e = __eblob_l2hash_lookup(l2h, key)) == NULL)
		return -ENOENT;

	/*
	 * If there are no collisions check that key belongs to rctl and
	 * remove entry from tree
	 */
	if (e->collision == 0) {
		switch(err = eblob_l2hash_compare_index(key, &e->rctl)) {
		case 0:
			rb_erase(&e->node, &l2h->root);
			free(e);
			return 0;
		case 1:
			return -ENOENT;
		default:
			return err;
		}
	}

	/* If collision is set and entry is not present in collision tree */
	collision = __eblob_l2hash_resolve_collision(&l2h->collisions, key);
	if (collision == NULL)
		return -ENOENT;

	/* Otherwise - remove entry from collision tree */
	rb_erase(&collision->node, &l2h->collisions);
	free(collision);
	return 0;
}
Example #4
0
/**
 * __eblob_l2hash_insert() - inserts @rctl entry into l2hash.
 * @type:	changes behaviour depending on existence of @key in cache.
 *
 * This is very complicated routine - should be modified with care.
 *
 * Returns:
 *	0:	Success
 *	Other:	Error
 */
static int __eblob_l2hash_insert(struct eblob_l2hash *l2h, struct eblob_key *key,
		struct eblob_ram_control *rctl, unsigned int type)
{
	struct eblob_l2hash_collision *collision;
	struct eblob_l2hash_entry *e;
	struct rb_node *n, *parent, **node;
	int err = 0;

	assert(l2h != NULL);
	assert(key != NULL);
	assert(rctl != NULL);
	assert(pthread_mutex_trylock(&l2h->root_lock) == EBUSY);

	if (type <= EBLOB_L2HASH_TYPE_FIRST)
		return -EINVAL;
	if (type >= EBLOB_L2HASH_TYPE_LAST)
		return -EINVAL;

	/* Search tree for matching entry */
	e = __eblob_l2hash_lookup(l2h, key);
	if (e == NULL) {
		/* No entry with matching l2hash - inserting */
		if (type == EBLOB_L2HASH_TYPE_UPDATE)
			return -ENOENT;
		return __eblob_l2hash_noncollision_insert(&l2h->root, key, rctl);
	}
	/* There is already entry with matching l2hash */
	if (e->collision == 0) {
		struct eblob_disk_control dc;

		/* No collisions - only one entry to check */
		if ((err = __eblob_l2hash_index_hdr(&e->rctl, &dc)) != 0)
			return err;
		if (eblob_id_cmp(key->id, dc.key.id) == 0) {
			/* Not a collision - updating in-place */
			if (type == EBLOB_L2HASH_TYPE_INSERT)
				return -EEXIST;
			e->rctl = *rctl;
			return 0;
		}

		/* This is a collision */
		if (type == EBLOB_L2HASH_TYPE_UPDATE)
			return -ENOENT;

		/* Move old entry to collision tree */
		err = __eblob_l2hash_collision_insert(&l2h->collisions, &dc.key, &e->rctl);
		if (err != 0)
			return err;

		e->collision = 1;
		memset(&e->rctl, 0, sizeof(struct eblob_ram_control));
		return __eblob_l2hash_collision_insert(&l2h->collisions, key, rctl);
	}

	/* Search tree of collisions for matching entry */
	n = __eblob_l2hash_collision_walk(&l2h->collisions, key, &parent, &node);
	if (n == NULL) {
		/* No entry found - inserting one */
		if (type == EBLOB_L2HASH_TYPE_UPDATE)
			return -ENOENT;
		return __eblob_l2hash_collision_insert(&l2h->collisions, key, rctl);
	}

	/* Entry found - modifying in-place  */
	if (type == EBLOB_L2HASH_TYPE_INSERT)
		return -EEXIST;
	collision = rb_entry(n, struct eblob_l2hash_collision, node);
	collision->rctl = *rctl;
	return 0;
}
Example #5
0
/**
 * _eblob_l2hash_insert() - inserts @rctl entry into l2hash.
 * @flavor:	changes behaviour depending on existence of @key in cache.
 * @replaced:	set to 1 if entry was replaced, to 0 otherwise.
 *
 * This is very complicated routine - should be modified with care.
 *
 * Returns:
 *	0:	Success
 *	Other:	Error
 */
static int _eblob_l2hash_insert(struct eblob_l2hash *l2h,
		const struct eblob_key *key,
		const struct eblob_ram_control *rctl,
		const unsigned int flavor,
		int *replaced)
{
	struct eblob_l2hash_collision *collision;
	struct eblob_l2hash_entry *e;
	struct rb_node *n, *parent, **node;
	int err = 0;

	if (l2h == NULL || key == NULL || rctl == NULL)
		return -EINVAL;

	if (flavor <= EBLOB_L2HASH_FLAVOR_FIRST)
		return -EINVAL;
	if (flavor >= EBLOB_L2HASH_FLAVOR_LAST)
		return -EINVAL;

	if (replaced != NULL)
		*replaced = 0;

	/* Search tree for matching entry */
	e = __eblob_l2hash_lookup(l2h, key);
	if (e == NULL) {
		/* No entry with matching l2hash - inserting */
		if (flavor == EBLOB_L2HASH_FLAVOR_UPDATE)
			return -ENOENT;
		return __eblob_l2hash_noncollision_insert(&l2h->root, key, rctl);
	}
	/* There is already entry with matching l2hash */
	if (e->collision == 0) {
		struct eblob_disk_control dc;

		/* No collisions - only one entry to check */
		if ((err = __eblob_l2hash_index_hdr(&e->rctl, &dc)) != 0)
			return err;
		if (eblob_id_cmp(key->id, dc.key.id) == 0) {
			/* Not a collision - updating in-place */
			if (flavor == EBLOB_L2HASH_FLAVOR_INSERT)
				return -EEXIST;

			/* If entry was replaced - notify caller */
			if (replaced != NULL)
				*replaced = 1;

			e->rctl = *rctl;
			return 0;
		}

		/* This is a collision */
		if (flavor == EBLOB_L2HASH_FLAVOR_UPDATE)
			return -ENOENT;

		/* Move old entry to collision tree */
		err = __eblob_l2hash_collision_insert(&l2h->collisions, &dc.key, &e->rctl);
		if (err != 0)
			return err;

		e->collision = 1;
		memset(&e->rctl, 0, sizeof(struct eblob_ram_control));
		return __eblob_l2hash_collision_insert(&l2h->collisions, key, rctl);
	}

	/* Search tree of collisions for matching entry */
	n = __eblob_l2hash_collision_walk(&l2h->collisions, key, &parent, &node);
	if (n == NULL) {
		/* No entry found - inserting one */
		if (flavor == EBLOB_L2HASH_FLAVOR_UPDATE)
			return -ENOENT;
		return __eblob_l2hash_collision_insert(&l2h->collisions, key, rctl);
	}

	/* Entry found - modifying in-place  */
	if (flavor == EBLOB_L2HASH_FLAVOR_INSERT)
		return -EEXIST;
	collision = rb_entry(n, struct eblob_l2hash_collision, node);
	collision->rctl = *rctl;

	/* If entry was replaced - notify caller */
	if (replaced != NULL)
		*replaced = 1;

	return 0;
}