Ejemplo n.º 1
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;
}
Ejemplo n.º 2
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;
}