/* update an entry in place - this only works if the new data size is <= the old data size and the key exists. on failure return -1. */ static int tdb_update_hash(struct tdb_context *tdb, TDB_DATA key, u32 hash, TDB_DATA dbuf) { struct list_struct rec; tdb_off_t rec_ptr; /* find entry */ if (!(rec_ptr = tdb_find(tdb, key, hash, &rec))) return -1; /* must be long enough key, data and tailer */ if (rec.rec_len < key.dsize + dbuf.dsize + sizeof(tdb_off_t)) { tdb->ecode = TDB_SUCCESS; /* Not really an error */ return -1; } if (tdb->methods->tdb_write(tdb, rec_ptr + sizeof(rec) + rec.key_len, dbuf.dptr, dbuf.dsize) == -1) return -1; if (dbuf.dsize != rec.data_len) { /* update size */ rec.data_len = dbuf.dsize; return tdb_rec_write(tdb, rec_ptr, &rec); } return 0; }
/* As tdb_find, but if you succeed, keep the lock */ tdb_off_t tdb_find_lock_hash(struct tdb_context *tdb, TDB_DATA key, u32 hash, int locktype, struct list_struct *rec) { u32 rec_ptr; if (tdb_lock(tdb, BUCKET(hash), locktype) == -1) return 0; if (!(rec_ptr = tdb_find(tdb, key, hash, rec))) tdb_unlock(tdb, BUCKET(hash), locktype); return rec_ptr; }
/* delete an entry in the database given a key */ static int tdb_delete_hash(struct tdb_context *tdb, TDB_DATA key, u32 hash) { tdb_off_t rec_ptr; struct list_struct rec; int ret; if (tdb->max_dead_records != 0) { /* * Allow for some dead records per hash chain, mainly for * tdb's with a very high create/delete rate like locking.tdb. */ if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1) return -1; if (tdb_count_dead(tdb, hash) >= tdb->max_dead_records) { /* * Don't let the per-chain freelist grow too large, * delete all existing dead records */ tdb_purge_dead(tdb, hash); } if (!(rec_ptr = tdb_find(tdb, key, hash, &rec))) { tdb_unlock(tdb, BUCKET(hash), F_WRLCK); return -1; } /* * Just mark the record as dead. */ rec.magic = TDB_DEAD_MAGIC; ret = tdb_rec_write(tdb, rec_ptr, &rec); } else { if (!(rec_ptr = tdb_find_lock_hash(tdb, key, hash, F_WRLCK, &rec))) return -1; ret = tdb_do_delete(tdb, rec_ptr, &rec); } if (ret == 0) { tdb_increment_seqnum(tdb); } if (tdb_unlock(tdb, BUCKET(rec.full_hash), F_WRLCK) != 0) TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_delete: WARNING tdb_unlock failed!\n")); return ret; }
/* update an entry in place - this only works if the new data size is <= the old data size and the key exists. on failure return -1. */ static int tdb_update_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, TDB_DATA dbuf) { struct tdb_record rec; tdb_off_t rec_ptr; /* find entry */ if (!(rec_ptr = tdb_find(tdb, key, hash, &rec))) return -1; /* it could be an exact duplicate of what is there - this is * surprisingly common (eg. with a ldb re-index). */ if (rec.key_len == key.dsize && rec.data_len == dbuf.dsize && rec.full_hash == hash && tdb_parse_record(tdb, key, tdb_update_hash_cmp, &dbuf) == 0) { return 0; } /* must be long enough key, data and tailer */ if (rec.rec_len < key.dsize + dbuf.dsize + sizeof(tdb_off_t)) { tdb->ecode = TDB_SUCCESS; /* Not really an error */ return -1; } if (tdb->methods->tdb_write(tdb, rec_ptr + sizeof(rec) + rec.key_len, dbuf.dptr, dbuf.dsize) == -1) return -1; if (dbuf.dsize != rec.data_len) { /* update size */ rec.data_len = dbuf.dsize; return tdb_rec_write(tdb, rec_ptr, &rec); } return 0; }