/** * 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; }
/** * 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; }
/** * 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; }
/** * __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; }
/** * _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; }