/** * __eblob_l2hash_resolve_collision() - extracts rb_entry from found node */ static struct eblob_l2hash_collision * __eblob_l2hash_resolve_collision(struct rb_root *root, struct eblob_key *key) { struct rb_node *n; struct eblob_l2hash_collision *collision = NULL; assert(root != NULL); assert(key != NULL); if ((n = __eblob_l2hash_collision_walk(root, key, NULL, NULL)) != NULL) collision = rb_entry(n, struct eblob_l2hash_collision, node); return collision; }
/** * __eblob_l2hash_collision_insert() - inserts entry into collision tree */ static int __eblob_l2hash_collision_insert(struct rb_root *root, struct eblob_key *key, struct eblob_ram_control *rctl) { struct eblob_l2hash_collision *collision; struct rb_node *n, *parent, **node; n = __eblob_l2hash_collision_walk(root, key, &parent, &node); if (n != NULL) return -EEXIST; collision = calloc(1, sizeof(struct eblob_l2hash_collision)); if (collision == NULL) return -ENOMEM; collision->key = *key; collision->rctl = *rctl; rb_link_node(&collision->node, parent, node); rb_insert_color(&collision->node, root); 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; }