2 Unix SMB/CIFS implementation.
4 trivial database library
6 Copyright (C) Andrew Tridgell 1999-2005
7 Copyright (C) Paul `Rusty' Russell 2000
8 Copyright (C) Jeremy Allison 2000-2003
10 ** NOTE! The following LGPL license applies to the tdb
11 ** library. This does NOT imply that all of Samba is released
14 This library is free software; you can redistribute it and/or
15 modify it under the terms of the GNU Lesser General Public
16 License as published by the Free Software Foundation; either
17 version 3 of the License, or (at your option) any later version.
19 This library is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 Lesser General Public License for more details.
24 You should have received a copy of the GNU Lesser General Public
25 License along with this library; if not, see <http://www.gnu.org/licenses/>.
28 #include "tdb1_private.h"
34 non-blocking increment of the tdb sequence number if the tdb has been opened using
37 void tdb1_increment_seqnum_nonblock(struct tdb_context *tdb)
41 if (!(tdb->flags & TDB_SEQNUM)) {
45 /* we ignore errors from this, as we have no sane way of
48 tdb1_ofs_read(tdb, TDB1_SEQNUM_OFS, &seqnum);
50 tdb1_ofs_write(tdb, TDB1_SEQNUM_OFS, &seqnum);
54 increment the tdb sequence number if the tdb has been opened using
57 static void tdb1_increment_seqnum(struct tdb_context *tdb)
59 if (!(tdb->flags & TDB_SEQNUM)) {
63 if (tdb1_nest_lock(tdb, TDB1_SEQNUM_OFS, F_WRLCK,
64 TDB_LOCK_WAIT|TDB_LOCK_PROBE) != 0) {
68 tdb1_increment_seqnum_nonblock(tdb);
70 tdb1_nest_unlock(tdb, TDB1_SEQNUM_OFS, F_WRLCK);
73 static int tdb1_key_compare(TDB_DATA key, TDB_DATA data, void *private_data)
75 return memcmp(data.dptr, key.dptr, data.dsize);
78 /* Returns 0 on fail. On success, return offset of record, and fills
80 static tdb1_off_t tdb1_find(struct tdb_context *tdb, TDB_DATA key, uint32_t hash,
81 struct tdb1_record *r)
85 /* read in the hash top */
86 if (tdb1_ofs_read(tdb, TDB1_HASH_TOP(hash), &rec_ptr) == -1)
89 /* keep looking until we find the right record */
91 if (tdb1_rec_read(tdb, rec_ptr, r) == -1)
94 if (!TDB1_DEAD(r) && hash==r->full_hash
95 && key.dsize==r->key_len
96 && tdb1_parse_data(tdb, key, rec_ptr + sizeof(*r),
97 r->key_len, tdb1_key_compare,
101 /* detect tight infinite loop */
102 if (rec_ptr == r->next) {
103 tdb->last_error = tdb_logerr(tdb, TDB_ERR_CORRUPT,
105 "tdb1_find: loop detected.");
110 tdb->last_error = TDB_ERR_NOEXIST;
114 /* As tdb1_find, but if you succeed, keep the lock */
115 tdb1_off_t tdb1_find_lock_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, int locktype,
116 struct tdb1_record *rec)
120 if (tdb1_lock(tdb, TDB1_BUCKET(hash), locktype) == -1)
122 if (!(rec_ptr = tdb1_find(tdb, key, hash, rec)))
123 tdb1_unlock(tdb, TDB1_BUCKET(hash), locktype);
127 static TDB_DATA _tdb1_fetch(struct tdb_context *tdb, TDB_DATA key);
129 /* update an entry in place - this only works if the new data size
130 is <= the old data size and the key exists.
131 on failure return -1.
133 static int tdb1_update_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, TDB_DATA dbuf)
135 struct tdb1_record rec;
139 if (!(rec_ptr = tdb1_find(tdb, key, hash, &rec)))
142 /* it could be an exact duplicate of what is there - this is
143 * surprisingly common (eg. with a ldb re-index). */
144 if (rec.key_len == key.dsize &&
145 rec.data_len == dbuf.dsize &&
146 rec.full_hash == hash) {
147 TDB_DATA data = _tdb1_fetch(tdb, key);
148 if (data.dsize == dbuf.dsize &&
149 memcmp(data.dptr, dbuf.dptr, data.dsize) == 0) {
160 /* must be long enough key, data and tailer */
161 if (rec.rec_len < key.dsize + dbuf.dsize + sizeof(tdb1_off_t)) {
162 tdb->last_error = TDB_SUCCESS; /* Not really an error */
166 if (tdb->tdb1.io->tdb1_write(tdb, rec_ptr + sizeof(rec) + rec.key_len,
167 dbuf.dptr, dbuf.dsize) == -1)
170 if (dbuf.dsize != rec.data_len) {
172 rec.data_len = dbuf.dsize;
173 return tdb1_rec_write(tdb, rec_ptr, &rec);
179 /* find an entry in the database given a key */
180 /* If an entry doesn't exist tdb1_err will be set to
181 * TDB_ERR_NOEXIST. If a key has no data attached
182 * then the TDB_DATA will have zero length but
185 static TDB_DATA _tdb1_fetch(struct tdb_context *tdb, TDB_DATA key)
188 struct tdb1_record rec;
192 /* find which hash bucket it is in */
193 hash = tdb_hash(tdb, key.dptr, key.dsize);
194 if (!(rec_ptr = tdb1_find_lock_hash(tdb,key,hash,F_RDLCK,&rec)))
197 ret.dptr = tdb1_alloc_read(tdb, rec_ptr + sizeof(rec) + rec.key_len,
199 ret.dsize = rec.data_len;
200 tdb1_unlock(tdb, TDB1_BUCKET(rec.full_hash), F_RDLCK);
204 enum TDB_ERROR tdb1_fetch(struct tdb_context *tdb, TDB_DATA key, TDB_DATA *data)
206 *data = _tdb1_fetch(tdb, key);
207 if (data->dptr == NULL)
208 return tdb->last_error;
212 enum TDB_ERROR tdb1_parse_record(struct tdb_context *tdb, TDB_DATA key,
213 enum TDB_ERROR (*parser)(TDB_DATA key,
219 struct tdb1_record rec;
223 /* find which hash bucket it is in */
224 hash = tdb_hash(tdb, key.dptr, key.dsize);
226 if (!(rec_ptr = tdb1_find_lock_hash(tdb,key,hash,F_RDLCK,&rec))) {
227 /* record not found */
228 return TDB_ERR_NOEXIST;
231 ret = tdb1_parse_data(tdb, key, rec_ptr + sizeof(rec) + rec.key_len,
232 rec.data_len, parser, private_data);
234 tdb1_unlock(tdb, TDB1_BUCKET(rec.full_hash), F_RDLCK);
239 /* check if an entry in the database exists
241 note that 1 is returned if the key is found and 0 is returned if not found
242 this doesn't match the conventions in the rest of this module, but is
245 static int tdb1_exists_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash)
247 struct tdb1_record rec;
249 if (tdb1_find_lock_hash(tdb, key, hash, F_RDLCK, &rec) == 0)
251 tdb1_unlock(tdb, TDB1_BUCKET(rec.full_hash), F_RDLCK);
255 int tdb1_exists(struct tdb_context *tdb, TDB_DATA key)
257 uint32_t hash = tdb_hash(tdb, key.dptr, key.dsize);
260 assert(tdb->flags & TDB_VERSION1);
261 ret = tdb1_exists_hash(tdb, key, hash);
265 /* actually delete an entry in the database given the offset */
266 int tdb1_do_delete(struct tdb_context *tdb, tdb1_off_t rec_ptr, struct tdb1_record *rec)
268 tdb1_off_t last_ptr, i;
269 struct tdb1_record lastrec;
271 if ((tdb->flags & TDB_RDONLY) || tdb->tdb1.traverse_read) return -1;
273 if (((tdb->tdb1.traverse_write != 0) && (!TDB1_DEAD(rec))) ||
274 tdb1_write_lock_record(tdb, rec_ptr) == -1) {
275 /* Someone traversing here: mark it as dead */
276 rec->magic = TDB1_DEAD_MAGIC;
277 return tdb1_rec_write(tdb, rec_ptr, rec);
279 if (tdb1_write_unlock_record(tdb, rec_ptr) != 0)
282 /* find previous record in hash chain */
283 if (tdb1_ofs_read(tdb, TDB1_HASH_TOP(rec->full_hash), &i) == -1)
285 for (last_ptr = 0; i != rec_ptr; last_ptr = i, i = lastrec.next)
286 if (tdb1_rec_read(tdb, i, &lastrec) == -1)
289 /* unlink it: next ptr is at start of record. */
291 last_ptr = TDB1_HASH_TOP(rec->full_hash);
292 if (tdb1_ofs_write(tdb, last_ptr, &rec->next) == -1)
295 /* recover the space */
296 if (tdb1_free(tdb, rec_ptr, rec) == -1)
301 static int tdb1_count_dead(struct tdb_context *tdb, uint32_t hash)
305 struct tdb1_record rec;
307 /* read in the hash top */
308 if (tdb1_ofs_read(tdb, TDB1_HASH_TOP(hash), &rec_ptr) == -1)
312 if (tdb1_rec_read(tdb, rec_ptr, &rec) == -1)
315 if (rec.magic == TDB1_DEAD_MAGIC) {
324 * Purge all DEAD records from a hash chain
326 static int tdb1_purge_dead(struct tdb_context *tdb, uint32_t hash)
329 struct tdb1_record rec;
332 if (tdb1_lock(tdb, -1, F_WRLCK) == -1) {
336 /* read in the hash top */
337 if (tdb1_ofs_read(tdb, TDB1_HASH_TOP(hash), &rec_ptr) == -1)
343 if (tdb1_rec_read(tdb, rec_ptr, &rec) == -1) {
349 if (rec.magic == TDB1_DEAD_MAGIC
350 && tdb1_do_delete(tdb, rec_ptr, &rec) == -1) {
357 tdb1_unlock(tdb, -1, F_WRLCK);
361 /* delete an entry in the database given a key */
362 static int tdb1_delete_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash)
365 struct tdb1_record rec;
368 if (tdb->tdb1.max_dead_records != 0) {
371 * Allow for some dead records per hash chain, mainly for
372 * tdb's with a very high create/delete rate like locking.tdb.
375 if (tdb1_lock(tdb, TDB1_BUCKET(hash), F_WRLCK) == -1)
378 if (tdb1_count_dead(tdb, hash) >= tdb->tdb1.max_dead_records) {
380 * Don't let the per-chain freelist grow too large,
381 * delete all existing dead records
383 tdb1_purge_dead(tdb, hash);
386 if (!(rec_ptr = tdb1_find(tdb, key, hash, &rec))) {
387 tdb1_unlock(tdb, TDB1_BUCKET(hash), F_WRLCK);
392 * Just mark the record as dead.
394 rec.magic = TDB1_DEAD_MAGIC;
395 ret = tdb1_rec_write(tdb, rec_ptr, &rec);
398 if (!(rec_ptr = tdb1_find_lock_hash(tdb, key, hash, F_WRLCK,
402 ret = tdb1_do_delete(tdb, rec_ptr, &rec);
406 tdb1_increment_seqnum(tdb);
409 if (tdb1_unlock(tdb, TDB1_BUCKET(rec.full_hash), F_WRLCK) != 0)
410 tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
411 "tdb1_delete: WARNING tdb1_unlock failed!");
415 int tdb1_delete(struct tdb_context *tdb, TDB_DATA key)
417 uint32_t hash = tdb_hash(tdb, key.dptr, key.dsize);
420 assert(tdb->flags & TDB_VERSION1);
421 ret = tdb1_delete_hash(tdb, key, hash);
426 * See if we have a dead record around with enough space
428 static tdb1_off_t tdb1_find_dead(struct tdb_context *tdb, uint32_t hash,
429 struct tdb1_record *r, tdb1_len_t length)
433 /* read in the hash top */
434 if (tdb1_ofs_read(tdb, TDB1_HASH_TOP(hash), &rec_ptr) == -1)
437 /* keep looking until we find the right record */
439 if (tdb1_rec_read(tdb, rec_ptr, r) == -1)
442 if (TDB1_DEAD(r) && r->rec_len >= length) {
444 * First fit for simple coding, TODO: change to best
454 static int _tdb1_store(struct tdb_context *tdb, TDB_DATA key,
455 TDB_DATA dbuf, int flag, uint32_t hash)
457 struct tdb1_record rec;
462 /* check for it existing, on insert. */
463 if (flag == TDB_INSERT) {
464 if (tdb1_exists_hash(tdb, key, hash)) {
465 tdb->last_error = TDB_ERR_EXISTS;
469 /* first try in-place update, on modify or replace. */
470 if (tdb1_update_hash(tdb, key, hash, dbuf) == 0) {
473 if (tdb->last_error == TDB_ERR_NOEXIST &&
474 flag == TDB_MODIFY) {
475 /* if the record doesn't exist and we are in TDB1_MODIFY mode then
476 we should fail the store */
480 /* reset the error code potentially set by the tdb1_update() */
481 tdb->last_error = TDB_SUCCESS;
483 /* delete any existing record - if it doesn't exist we don't
484 care. Doing this first reduces fragmentation, and avoids
485 coalescing with `allocated' block before it's updated. */
486 if (flag != TDB_INSERT)
487 tdb1_delete_hash(tdb, key, hash);
489 /* Copy key+value *before* allocating free space in case malloc
490 fails and we are left with a dead spot in the tdb. */
492 if (!(p = (char *)malloc(key.dsize + dbuf.dsize))) {
493 tdb->last_error = TDB_ERR_OOM;
497 memcpy(p, key.dptr, key.dsize);
499 memcpy(p+key.dsize, dbuf.dptr, dbuf.dsize);
501 if (tdb->tdb1.max_dead_records != 0) {
503 * Allow for some dead records per hash chain, look if we can
504 * find one that can hold the new record. We need enough space
505 * for key, data and tailer. If we find one, we don't have to
506 * consult the central freelist.
508 rec_ptr = tdb1_find_dead(
510 key.dsize + dbuf.dsize + sizeof(tdb1_off_t));
513 rec.key_len = key.dsize;
514 rec.data_len = dbuf.dsize;
515 rec.full_hash = hash;
516 rec.magic = TDB1_MAGIC;
517 if (tdb1_rec_write(tdb, rec_ptr, &rec) == -1
518 || tdb->tdb1.io->tdb1_write(
519 tdb, rec_ptr + sizeof(rec),
520 p, key.dsize + dbuf.dsize) == -1) {
528 * We have to allocate some space from the freelist, so this means we
529 * have to lock it. Use the chance to purge all the DEAD records from
530 * the hash chain under the freelist lock.
533 if (tdb1_lock(tdb, -1, F_WRLCK) == -1) {
537 if ((tdb->tdb1.max_dead_records != 0)
538 && (tdb1_purge_dead(tdb, hash) == -1)) {
539 tdb1_unlock(tdb, -1, F_WRLCK);
543 /* we have to allocate some space */
544 rec_ptr = tdb1_allocate(tdb, key.dsize + dbuf.dsize, &rec);
546 tdb1_unlock(tdb, -1, F_WRLCK);
552 /* Read hash top into next ptr */
553 if (tdb1_ofs_read(tdb, TDB1_HASH_TOP(hash), &rec.next) == -1)
556 rec.key_len = key.dsize;
557 rec.data_len = dbuf.dsize;
558 rec.full_hash = hash;
559 rec.magic = TDB1_MAGIC;
561 /* write out and point the top of the hash chain at it */
562 if (tdb1_rec_write(tdb, rec_ptr, &rec) == -1
563 || tdb->tdb1.io->tdb1_write(tdb, rec_ptr+sizeof(rec), p, key.dsize+dbuf.dsize)==-1
564 || tdb1_ofs_write(tdb, TDB1_HASH_TOP(hash), &rec_ptr) == -1) {
565 /* Need to tdb1_unallocate() here */
573 tdb1_increment_seqnum(tdb);
580 /* store an element in the database, replacing any existing element
583 return 0 on success, -1 on failure
585 int tdb1_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag)
590 assert(tdb->flags & TDB_VERSION1);
592 if ((tdb->flags & TDB_RDONLY) || tdb->tdb1.traverse_read) {
593 tdb->last_error = TDB_ERR_RDONLY;
597 /* find which hash bucket it is in */
598 hash = tdb_hash(tdb, key.dptr, key.dsize);
599 if (tdb1_lock(tdb, TDB1_BUCKET(hash), F_WRLCK) == -1)
602 ret = _tdb1_store(tdb, key, dbuf, flag, hash);
603 tdb1_unlock(tdb, TDB1_BUCKET(hash), F_WRLCK);
607 /* Append to an entry. Create if not exist. */
608 int tdb1_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf)
614 assert(tdb->flags & TDB_VERSION1);
616 /* find which hash bucket it is in */
617 hash = tdb_hash(tdb, key.dptr, key.dsize);
618 if (tdb1_lock(tdb, TDB1_BUCKET(hash), F_WRLCK) == -1)
621 dbuf = _tdb1_fetch(tdb, key);
623 if (dbuf.dptr == NULL) {
624 dbuf.dptr = (unsigned char *)malloc(new_dbuf.dsize);
626 unsigned int new_len = dbuf.dsize + new_dbuf.dsize;
627 unsigned char *new_dptr;
629 /* realloc '0' is special: don't do that. */
632 new_dptr = (unsigned char *)realloc(dbuf.dptr, new_len);
633 if (new_dptr == NULL) {
636 dbuf.dptr = new_dptr;
639 if (dbuf.dptr == NULL) {
640 tdb->last_error = TDB_ERR_OOM;
644 memcpy(dbuf.dptr + dbuf.dsize, new_dbuf.dptr, new_dbuf.dsize);
645 dbuf.dsize += new_dbuf.dsize;
647 ret = _tdb1_store(tdb, key, dbuf, 0, hash);
650 tdb1_unlock(tdb, TDB1_BUCKET(hash), F_WRLCK);
651 SAFE_FREE(dbuf.dptr);
657 get the tdb sequence number. Only makes sense if the writers opened
658 with TDB1_SEQNUM set. Note that this sequence number will wrap quite
659 quickly, so it should only be used for a 'has something changed'
660 test, not for code that relies on the count of the number of changes
661 made. If you want a counter then use a tdb record.
663 The aim of this sequence number is to allow for a very lightweight
664 test of a possible tdb change.
666 int tdb1_get_seqnum(struct tdb_context *tdb)
670 tdb1_ofs_read(tdb, TDB1_SEQNUM_OFS, &seqnum);
676 add a region of the file to the freelist. Length is the size of the region in bytes,
677 which includes the free list header that needs to be added
679 static int tdb1_free_region(struct tdb_context *tdb, tdb1_off_t offset, ssize_t length)
681 struct tdb1_record rec;
682 if (length <= sizeof(rec)) {
683 /* the region is not worth adding */
686 if (length + offset > tdb->file->map_size) {
687 tdb->last_error = tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_LOG_ERROR,
688 "tdb1_free_region: adding region beyond"
692 memset(&rec,'\0',sizeof(rec));
693 rec.rec_len = length - sizeof(rec);
694 if (tdb1_free(tdb, offset, &rec) == -1) {
695 tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
696 "tdb1_free_region: failed to add free record");
703 wipe the entire database, deleting all records. This can be done
704 very fast by using a allrecord lock. The entire data portion of the
705 file becomes a single entry in the freelist.
707 This code carefully steps around the recovery area, leaving it alone
709 int tdb1_wipe_all(struct tdb_context *tdb)
712 tdb1_off_t offset = 0;
714 tdb1_off_t recovery_head;
715 tdb1_len_t recovery_size = 0;
717 if (tdb_lockall(tdb) != TDB_SUCCESS) {
722 /* see if the tdb has a recovery area, and remember its size
723 if so. We don't want to lose this as otherwise each
724 tdb1_wipe_all() in a transaction will increase the size of
725 the tdb by the size of the recovery area */
726 if (tdb1_ofs_read(tdb, TDB1_RECOVERY_HEAD, &recovery_head) == -1) {
727 tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
728 "tdb1_wipe_all: failed to read recovery head");
732 if (recovery_head != 0) {
733 struct tdb1_record rec;
734 if (tdb->tdb1.io->tdb1_read(tdb, recovery_head, &rec, sizeof(rec), TDB1_DOCONV()) == -1) {
735 tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
736 "tdb1_wipe_all: failed to read recovery record");
739 recovery_size = rec.rec_len + sizeof(rec);
742 /* wipe the hashes */
743 for (i=0;i<tdb->tdb1.header.hash_size;i++) {
744 if (tdb1_ofs_write(tdb, TDB1_HASH_TOP(i), &offset) == -1) {
745 tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
746 "tdb1_wipe_all: failed to write hash %d", i);
751 /* wipe the freelist */
752 if (tdb1_ofs_write(tdb, TDB1_FREELIST_TOP, &offset) == -1) {
753 tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
754 "tdb1_wipe_all: failed to write freelist");
758 /* add all the rest of the file to the freelist, possibly leaving a gap
759 for the recovery area */
760 if (recovery_size == 0) {
761 /* the simple case - the whole file can be used as a freelist */
762 data_len = (tdb->file->map_size - TDB1_DATA_START(tdb->tdb1.header.hash_size));
763 if (tdb1_free_region(tdb, TDB1_DATA_START(tdb->tdb1.header.hash_size), data_len) != 0) {
767 /* we need to add two freelist entries - one on either
768 side of the recovery area
770 Note that we cannot shift the recovery area during
771 this operation. Only the transaction.c code may
772 move the recovery area or we risk subtle data
775 data_len = (recovery_head - TDB1_DATA_START(tdb->tdb1.header.hash_size));
776 if (tdb1_free_region(tdb, TDB1_DATA_START(tdb->tdb1.header.hash_size), data_len) != 0) {
779 /* and the 2nd free list entry after the recovery area - if any */
780 data_len = tdb->file->map_size - (recovery_head+recovery_size);
781 if (tdb1_free_region(tdb, recovery_head+recovery_size, data_len) != 0) {
794 struct traverse_state {
795 enum TDB_ERROR error;
796 struct tdb_context *dest_db;
800 traverse function for repacking
802 static int repack_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *private_data)
804 struct traverse_state *state = (struct traverse_state *)private_data;
805 if (tdb1_store(state->dest_db, key, data, TDB_INSERT) != 0) {
806 state->error = state->dest_db->last_error;
815 int tdb1_repack(struct tdb_context *tdb)
817 struct tdb_context *tmp_db;
818 struct traverse_state state;
819 union tdb_attribute hsize;
821 hsize.base.attr = TDB_ATTRIBUTE_TDB1_HASHSIZE;
822 hsize.base.next = NULL;
823 hsize.tdb1_hashsize.hsize = tdb->tdb1.header.hash_size;
825 if (tdb1_transaction_start(tdb) != 0) {
826 tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
827 __location__ " Failed to start transaction");
831 tmp_db = tdb_open("tmpdb", TDB_INTERNAL, O_RDWR|O_CREAT, 0, &hsize);
832 if (tmp_db == NULL) {
833 tdb->last_error = tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
834 __location__ " Failed to create tmp_db");
835 tdb1_transaction_cancel(tdb);
839 state.error = TDB_SUCCESS;
840 state.dest_db = tmp_db;
842 if (tdb1_traverse(tdb, repack_traverse, &state) == -1) {
843 tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
844 __location__ " Failed to traverse copying out");
845 tdb1_transaction_cancel(tdb);
850 if (state.error != TDB_SUCCESS) {
851 tdb->last_error = tdb_logerr(tdb, state.error, TDB_LOG_ERROR,
852 __location__ " Error during traversal");
853 tdb1_transaction_cancel(tdb);
858 if (tdb1_wipe_all(tdb) != 0) {
859 tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
860 __location__ " Failed to wipe database\n");
861 tdb1_transaction_cancel(tdb);
866 state.error = TDB_SUCCESS;
869 if (tdb1_traverse(tmp_db, repack_traverse, &state) == -1) {
870 tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
871 __location__ " Failed to traverse copying back");
872 tdb1_transaction_cancel(tdb);
878 tdb->last_error = tdb_logerr(tdb, state.error, TDB_LOG_ERROR,
879 __location__ " Error during second traversal");
880 tdb1_transaction_cancel(tdb);
887 if (tdb1_transaction_commit(tdb) != 0) {
888 tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
889 __location__ " Failed to commit");
896 /* Even on files, we can get partial writes due to signals. */
897 bool tdb1_write_all(int fd, const void *buf, size_t count)
901 ret = write(fd, buf, count);
904 buf = (const char *)buf + ret;