- tdb_off_t new_off, off, start, end, room;
- uint64_t h;
- bool growing = false;
-
- h = tdb_hash(tdb, key.dptr, key.dsize);
- off = find_bucket_and_lock(tdb, &key, h, &start, &end, &room, F_WRLCK);
- if (off == TDB_OFF_ERR)
- return -1;
-
- /* Now we have lock on this hash bucket. */
- if (flag == TDB_INSERT) {
- if (off) {
- tdb->ecode = TDB_ERR_EXISTS;
- goto fail;
- }
- } else {
- if (off) {
- if (room >= key.dsize + dbuf.dsize) {
- new_off = off;
- if (update_rec_hdr(tdb, off,
- key.dsize, dbuf.dsize,
- room, h))
- goto fail;
- goto write;
- }
- /* FIXME: See if right record is free? */
- /* Hint to allocator that we've realloced. */
- growing = true;
- } else {
- if (flag == TDB_MODIFY) {
- /* if the record doesn't exist and we
- are in TDB_MODIFY mode then we should fail
- the store */
- tdb->ecode = TDB_ERR_NOEXIST;
- goto fail;
- }
- }
- }
-
- /* Allocate a new record. */
- new_off = alloc(tdb, key.dsize, dbuf.dsize, h, growing);
- if (new_off == 0) {
- unlock_lists(tdb, start, end, F_WRLCK);
- /* Expand, then try again... */
- if (tdb_expand(tdb, key.dsize, dbuf.dsize, growing) == -1)
- return -1;
- return tdb_store(tdb, key, dbuf, flag);
- }
-
- /* We didn't like the existing one: remove it. */
- if (off) {
- add_free_record(tdb, off, sizeof(struct tdb_used_record)
- + key.dsize + room);
- }
-
-write:
- off = tdb->header.v.hash_off + end * sizeof(tdb_off_t);
- /* FIXME: Encode extra hash bits! */
- if (tdb_write_off(tdb, off, new_off) == -1)
- goto fail;
-
- off = new_off + sizeof(struct tdb_used_record);
- if (tdb->methods->write(tdb, off, key.dptr, key.dsize) == -1)
- goto fail;
- off += key.dsize;
- if (tdb->methods->write(tdb, off, dbuf.dptr, dbuf.dsize) == -1)
- goto fail;
-
- /* FIXME: tdb_increment_seqnum(tdb); */
- unlock_lists(tdb, start, end, F_WRLCK);
-
- /* By simple trial and error, this roughly approximates a 60%
- * full measure. */
- if (unlikely(end - start > 4 * tdb->header.v.hash_bits - 32))
- enlarge_hash(tdb);
-
- return 0;
-
-fail:
- unlock_lists(tdb, start, end, F_WRLCK);
- return -1;