tdb2: unify tdb1_append into tdb_append
[ccan] / ccan / tdb2 / tdb1_tdb.c
1  /*
2    Unix SMB/CIFS implementation.
3
4    trivial database library
5
6    Copyright (C) Andrew Tridgell              1999-2005
7    Copyright (C) Paul `Rusty' Russell              2000
8    Copyright (C) Jeremy Allison                    2000-2003
9
10      ** NOTE! The following LGPL license applies to the tdb
11      ** library. This does NOT imply that all of Samba is released
12      ** under the LGPL
13
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.
18
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.
23
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/>.
26 */
27
28 #include "tdb1_private.h"
29 #include <assert.h>
30
31 TDB_DATA tdb1_null;
32
33 /*
34   non-blocking increment of the tdb sequence number if the tdb has been opened using
35   the TDB_SEQNUM flag
36 */
37 void tdb1_increment_seqnum_nonblock(struct tdb_context *tdb)
38 {
39         tdb1_off_t seqnum=0;
40
41         if (!(tdb->flags & TDB_SEQNUM)) {
42                 return;
43         }
44
45         /* we ignore errors from this, as we have no sane way of
46            dealing with them.
47         */
48         tdb1_ofs_read(tdb, TDB1_SEQNUM_OFS, &seqnum);
49         seqnum++;
50         tdb1_ofs_write(tdb, TDB1_SEQNUM_OFS, &seqnum);
51 }
52
53 /*
54   increment the tdb sequence number if the tdb has been opened using
55   the TDB_SEQNUM flag
56 */
57 static void tdb1_increment_seqnum(struct tdb_context *tdb)
58 {
59         if (!(tdb->flags & TDB_SEQNUM)) {
60                 return;
61         }
62
63         if (tdb1_nest_lock(tdb, TDB1_SEQNUM_OFS, F_WRLCK,
64                            TDB_LOCK_WAIT|TDB_LOCK_PROBE) != 0) {
65                 return;
66         }
67
68         tdb1_increment_seqnum_nonblock(tdb);
69
70         tdb1_nest_unlock(tdb, TDB1_SEQNUM_OFS, F_WRLCK);
71 }
72
73 static int tdb1_key_compare(TDB_DATA key, TDB_DATA data, void *private_data)
74 {
75         return memcmp(data.dptr, key.dptr, data.dsize);
76 }
77
78 /* Returns 0 on fail.  On success, return offset of record, and fills
79    in rec */
80 static tdb1_off_t tdb1_find(struct tdb_context *tdb, TDB_DATA key, uint32_t hash,
81                         struct tdb1_record *r)
82 {
83         tdb1_off_t rec_ptr;
84
85         /* read in the hash top */
86         if (tdb1_ofs_read(tdb, TDB1_HASH_TOP(hash), &rec_ptr) == -1)
87                 return 0;
88
89         /* keep looking until we find the right record */
90         while (rec_ptr) {
91                 if (tdb1_rec_read(tdb, rec_ptr, r) == -1)
92                         return 0;
93
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,
98                                       NULL) == 0) {
99                         return rec_ptr;
100                 }
101                 /* detect tight infinite loop */
102                 if (rec_ptr == r->next) {
103                         tdb->last_error = tdb_logerr(tdb, TDB_ERR_CORRUPT,
104                                                 TDB_LOG_ERROR,
105                                                 "tdb1_find: loop detected.");
106                         return 0;
107                 }
108                 rec_ptr = r->next;
109         }
110         tdb->last_error = TDB_ERR_NOEXIST;
111         return 0;
112 }
113
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)
117 {
118         uint32_t rec_ptr;
119
120         if (tdb1_lock(tdb, TDB1_BUCKET(hash), locktype) == -1)
121                 return 0;
122         if (!(rec_ptr = tdb1_find(tdb, key, hash, rec)))
123                 tdb1_unlock(tdb, TDB1_BUCKET(hash), locktype);
124         return rec_ptr;
125 }
126
127 static TDB_DATA _tdb1_fetch(struct tdb_context *tdb, TDB_DATA key);
128
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.
132 */
133 static int tdb1_update_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, TDB_DATA dbuf)
134 {
135         struct tdb1_record rec;
136         tdb1_off_t rec_ptr;
137
138         /* find entry */
139         if (!(rec_ptr = tdb1_find(tdb, key, hash, &rec)))
140                 return -1;
141
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) {
150                         if (data.dptr) {
151                                 free(data.dptr);
152                         }
153                         return 0;
154                 }
155                 if (data.dptr) {
156                         free(data.dptr);
157                 }
158         }
159
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 */
163                 return -1;
164         }
165
166         if (tdb->tdb1.io->tdb1_write(tdb, rec_ptr + sizeof(rec) + rec.key_len,
167                       dbuf.dptr, dbuf.dsize) == -1)
168                 return -1;
169
170         if (dbuf.dsize != rec.data_len) {
171                 /* update size */
172                 rec.data_len = dbuf.dsize;
173                 return tdb1_rec_write(tdb, rec_ptr, &rec);
174         }
175
176         return 0;
177 }
178
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
183  * a non-zero pointer
184  */
185 static TDB_DATA _tdb1_fetch(struct tdb_context *tdb, TDB_DATA key)
186 {
187         tdb1_off_t rec_ptr;
188         struct tdb1_record rec;
189         TDB_DATA ret;
190         uint32_t hash;
191
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)))
195                 return tdb1_null;
196
197         ret.dptr = tdb1_alloc_read(tdb, rec_ptr + sizeof(rec) + rec.key_len,
198                                   rec.data_len);
199         ret.dsize = rec.data_len;
200         tdb1_unlock(tdb, TDB1_BUCKET(rec.full_hash), F_RDLCK);
201         return ret;
202 }
203
204 enum TDB_ERROR tdb1_fetch(struct tdb_context *tdb, TDB_DATA key, TDB_DATA *data)
205 {
206         *data = _tdb1_fetch(tdb, key);
207         if (data->dptr == NULL)
208                 return tdb->last_error;
209         return TDB_SUCCESS;
210 }
211
212 /*
213  * Find an entry in the database and hand the record's data to a parsing
214  * function. The parsing function is executed under the chain read lock, so it
215  * should be fast and should not block on other syscalls.
216  *
217  * DON'T CALL OTHER TDB CALLS FROM THE PARSER, THIS MIGHT LEAD TO SEGFAULTS.
218  *
219  * For mmapped tdb's that do not have a transaction open it points the parsing
220  * function directly at the mmap area, it avoids the malloc/memcpy in this
221  * case. If a transaction is open or no mmap is available, it has to do
222  * malloc/read/parse/free.
223  *
224  * This is interesting for all readers of potentially large data structures in
225  * the tdb records, ldb indexes being one example.
226  *
227  * Return -1 if the record was not found.
228  */
229
230 int tdb1_parse_record(struct tdb_context *tdb, TDB_DATA key,
231                      int (*parser)(TDB_DATA key, TDB_DATA data,
232                                    void *private_data),
233                      void *private_data)
234 {
235         tdb1_off_t rec_ptr;
236         struct tdb1_record rec;
237         int ret;
238         uint32_t hash;
239
240         /* find which hash bucket it is in */
241         hash = tdb_hash(tdb, key.dptr, key.dsize);
242
243         if (!(rec_ptr = tdb1_find_lock_hash(tdb,key,hash,F_RDLCK,&rec))) {
244                 /* record not found */
245                 tdb->last_error = TDB_ERR_NOEXIST;
246                 return -1;
247         }
248
249         ret = tdb1_parse_data(tdb, key, rec_ptr + sizeof(rec) + rec.key_len,
250                              rec.data_len, parser, private_data);
251
252         tdb1_unlock(tdb, TDB1_BUCKET(rec.full_hash), F_RDLCK);
253
254         return ret;
255 }
256
257 /* check if an entry in the database exists
258
259    note that 1 is returned if the key is found and 0 is returned if not found
260    this doesn't match the conventions in the rest of this module, but is
261    compatible with gdbm
262 */
263 static int tdb1_exists_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash)
264 {
265         struct tdb1_record rec;
266
267         if (tdb1_find_lock_hash(tdb, key, hash, F_RDLCK, &rec) == 0)
268                 return 0;
269         tdb1_unlock(tdb, TDB1_BUCKET(rec.full_hash), F_RDLCK);
270         return 1;
271 }
272
273 int tdb1_exists(struct tdb_context *tdb, TDB_DATA key)
274 {
275         uint32_t hash = tdb_hash(tdb, key.dptr, key.dsize);
276         int ret;
277
278         ret = tdb1_exists_hash(tdb, key, hash);
279         return ret;
280 }
281
282 /* actually delete an entry in the database given the offset */
283 int tdb1_do_delete(struct tdb_context *tdb, tdb1_off_t rec_ptr, struct tdb1_record *rec)
284 {
285         tdb1_off_t last_ptr, i;
286         struct tdb1_record lastrec;
287
288         if ((tdb->flags & TDB_RDONLY) || tdb->tdb1.traverse_read) return -1;
289
290         if (((tdb->tdb1.traverse_write != 0) && (!TDB1_DEAD(rec))) ||
291             tdb1_write_lock_record(tdb, rec_ptr) == -1) {
292                 /* Someone traversing here: mark it as dead */
293                 rec->magic = TDB1_DEAD_MAGIC;
294                 return tdb1_rec_write(tdb, rec_ptr, rec);
295         }
296         if (tdb1_write_unlock_record(tdb, rec_ptr) != 0)
297                 return -1;
298
299         /* find previous record in hash chain */
300         if (tdb1_ofs_read(tdb, TDB1_HASH_TOP(rec->full_hash), &i) == -1)
301                 return -1;
302         for (last_ptr = 0; i != rec_ptr; last_ptr = i, i = lastrec.next)
303                 if (tdb1_rec_read(tdb, i, &lastrec) == -1)
304                         return -1;
305
306         /* unlink it: next ptr is at start of record. */
307         if (last_ptr == 0)
308                 last_ptr = TDB1_HASH_TOP(rec->full_hash);
309         if (tdb1_ofs_write(tdb, last_ptr, &rec->next) == -1)
310                 return -1;
311
312         /* recover the space */
313         if (tdb1_free(tdb, rec_ptr, rec) == -1)
314                 return -1;
315         return 0;
316 }
317
318 static int tdb1_count_dead(struct tdb_context *tdb, uint32_t hash)
319 {
320         int res = 0;
321         tdb1_off_t rec_ptr;
322         struct tdb1_record rec;
323
324         /* read in the hash top */
325         if (tdb1_ofs_read(tdb, TDB1_HASH_TOP(hash), &rec_ptr) == -1)
326                 return 0;
327
328         while (rec_ptr) {
329                 if (tdb1_rec_read(tdb, rec_ptr, &rec) == -1)
330                         return 0;
331
332                 if (rec.magic == TDB1_DEAD_MAGIC) {
333                         res += 1;
334                 }
335                 rec_ptr = rec.next;
336         }
337         return res;
338 }
339
340 /*
341  * Purge all DEAD records from a hash chain
342  */
343 static int tdb1_purge_dead(struct tdb_context *tdb, uint32_t hash)
344 {
345         int res = -1;
346         struct tdb1_record rec;
347         tdb1_off_t rec_ptr;
348
349         if (tdb1_lock(tdb, -1, F_WRLCK) == -1) {
350                 return -1;
351         }
352
353         /* read in the hash top */
354         if (tdb1_ofs_read(tdb, TDB1_HASH_TOP(hash), &rec_ptr) == -1)
355                 goto fail;
356
357         while (rec_ptr) {
358                 tdb1_off_t next;
359
360                 if (tdb1_rec_read(tdb, rec_ptr, &rec) == -1) {
361                         goto fail;
362                 }
363
364                 next = rec.next;
365
366                 if (rec.magic == TDB1_DEAD_MAGIC
367                     && tdb1_do_delete(tdb, rec_ptr, &rec) == -1) {
368                         goto fail;
369                 }
370                 rec_ptr = next;
371         }
372         res = 0;
373  fail:
374         tdb1_unlock(tdb, -1, F_WRLCK);
375         return res;
376 }
377
378 /* delete an entry in the database given a key */
379 static int tdb1_delete_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash)
380 {
381         tdb1_off_t rec_ptr;
382         struct tdb1_record rec;
383         int ret;
384
385         if (tdb->tdb1.max_dead_records != 0) {
386
387                 /*
388                  * Allow for some dead records per hash chain, mainly for
389                  * tdb's with a very high create/delete rate like locking.tdb.
390                  */
391
392                 if (tdb1_lock(tdb, TDB1_BUCKET(hash), F_WRLCK) == -1)
393                         return -1;
394
395                 if (tdb1_count_dead(tdb, hash) >= tdb->tdb1.max_dead_records) {
396                         /*
397                          * Don't let the per-chain freelist grow too large,
398                          * delete all existing dead records
399                          */
400                         tdb1_purge_dead(tdb, hash);
401                 }
402
403                 if (!(rec_ptr = tdb1_find(tdb, key, hash, &rec))) {
404                         tdb1_unlock(tdb, TDB1_BUCKET(hash), F_WRLCK);
405                         return -1;
406                 }
407
408                 /*
409                  * Just mark the record as dead.
410                  */
411                 rec.magic = TDB1_DEAD_MAGIC;
412                 ret = tdb1_rec_write(tdb, rec_ptr, &rec);
413         }
414         else {
415                 if (!(rec_ptr = tdb1_find_lock_hash(tdb, key, hash, F_WRLCK,
416                                                    &rec)))
417                         return -1;
418
419                 ret = tdb1_do_delete(tdb, rec_ptr, &rec);
420         }
421
422         if (ret == 0) {
423                 tdb1_increment_seqnum(tdb);
424         }
425
426         if (tdb1_unlock(tdb, TDB1_BUCKET(rec.full_hash), F_WRLCK) != 0)
427                 tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
428                            "tdb1_delete: WARNING tdb1_unlock failed!");
429         return ret;
430 }
431
432 int tdb1_delete(struct tdb_context *tdb, TDB_DATA key)
433 {
434         uint32_t hash = tdb_hash(tdb, key.dptr, key.dsize);
435         int ret;
436
437         ret = tdb1_delete_hash(tdb, key, hash);
438         return ret;
439 }
440
441 /*
442  * See if we have a dead record around with enough space
443  */
444 static tdb1_off_t tdb1_find_dead(struct tdb_context *tdb, uint32_t hash,
445                                struct tdb1_record *r, tdb1_len_t length)
446 {
447         tdb1_off_t rec_ptr;
448
449         /* read in the hash top */
450         if (tdb1_ofs_read(tdb, TDB1_HASH_TOP(hash), &rec_ptr) == -1)
451                 return 0;
452
453         /* keep looking until we find the right record */
454         while (rec_ptr) {
455                 if (tdb1_rec_read(tdb, rec_ptr, r) == -1)
456                         return 0;
457
458                 if (TDB1_DEAD(r) && r->rec_len >= length) {
459                         /*
460                          * First fit for simple coding, TODO: change to best
461                          * fit
462                          */
463                         return rec_ptr;
464                 }
465                 rec_ptr = r->next;
466         }
467         return 0;
468 }
469
470 static int _tdb1_store(struct tdb_context *tdb, TDB_DATA key,
471                        TDB_DATA dbuf, int flag, uint32_t hash)
472 {
473         struct tdb1_record rec;
474         tdb1_off_t rec_ptr;
475         char *p = NULL;
476         int ret = -1;
477
478         /* check for it existing, on insert. */
479         if (flag == TDB_INSERT) {
480                 if (tdb1_exists_hash(tdb, key, hash)) {
481                         tdb->last_error = TDB_ERR_EXISTS;
482                         goto fail;
483                 }
484         } else {
485                 /* first try in-place update, on modify or replace. */
486                 if (tdb1_update_hash(tdb, key, hash, dbuf) == 0) {
487                         goto done;
488                 }
489                 if (tdb->last_error == TDB_ERR_NOEXIST &&
490                     flag == TDB_MODIFY) {
491                         /* if the record doesn't exist and we are in TDB1_MODIFY mode then
492                          we should fail the store */
493                         goto fail;
494                 }
495         }
496         /* reset the error code potentially set by the tdb1_update() */
497         tdb->last_error = TDB_SUCCESS;
498
499         /* delete any existing record - if it doesn't exist we don't
500            care.  Doing this first reduces fragmentation, and avoids
501            coalescing with `allocated' block before it's updated. */
502         if (flag != TDB_INSERT)
503                 tdb1_delete_hash(tdb, key, hash);
504
505         /* Copy key+value *before* allocating free space in case malloc
506            fails and we are left with a dead spot in the tdb. */
507
508         if (!(p = (char *)malloc(key.dsize + dbuf.dsize))) {
509                 tdb->last_error = TDB_ERR_OOM;
510                 goto fail;
511         }
512
513         memcpy(p, key.dptr, key.dsize);
514         if (dbuf.dsize)
515                 memcpy(p+key.dsize, dbuf.dptr, dbuf.dsize);
516
517         if (tdb->tdb1.max_dead_records != 0) {
518                 /*
519                  * Allow for some dead records per hash chain, look if we can
520                  * find one that can hold the new record. We need enough space
521                  * for key, data and tailer. If we find one, we don't have to
522                  * consult the central freelist.
523                  */
524                 rec_ptr = tdb1_find_dead(
525                         tdb, hash, &rec,
526                         key.dsize + dbuf.dsize + sizeof(tdb1_off_t));
527
528                 if (rec_ptr != 0) {
529                         rec.key_len = key.dsize;
530                         rec.data_len = dbuf.dsize;
531                         rec.full_hash = hash;
532                         rec.magic = TDB1_MAGIC;
533                         if (tdb1_rec_write(tdb, rec_ptr, &rec) == -1
534                             || tdb->tdb1.io->tdb1_write(
535                                     tdb, rec_ptr + sizeof(rec),
536                                     p, key.dsize + dbuf.dsize) == -1) {
537                                 goto fail;
538                         }
539                         goto done;
540                 }
541         }
542
543         /*
544          * We have to allocate some space from the freelist, so this means we
545          * have to lock it. Use the chance to purge all the DEAD records from
546          * the hash chain under the freelist lock.
547          */
548
549         if (tdb1_lock(tdb, -1, F_WRLCK) == -1) {
550                 goto fail;
551         }
552
553         if ((tdb->tdb1.max_dead_records != 0)
554             && (tdb1_purge_dead(tdb, hash) == -1)) {
555                 tdb1_unlock(tdb, -1, F_WRLCK);
556                 goto fail;
557         }
558
559         /* we have to allocate some space */
560         rec_ptr = tdb1_allocate(tdb, key.dsize + dbuf.dsize, &rec);
561
562         tdb1_unlock(tdb, -1, F_WRLCK);
563
564         if (rec_ptr == 0) {
565                 goto fail;
566         }
567
568         /* Read hash top into next ptr */
569         if (tdb1_ofs_read(tdb, TDB1_HASH_TOP(hash), &rec.next) == -1)
570                 goto fail;
571
572         rec.key_len = key.dsize;
573         rec.data_len = dbuf.dsize;
574         rec.full_hash = hash;
575         rec.magic = TDB1_MAGIC;
576
577         /* write out and point the top of the hash chain at it */
578         if (tdb1_rec_write(tdb, rec_ptr, &rec) == -1
579             || tdb->tdb1.io->tdb1_write(tdb, rec_ptr+sizeof(rec), p, key.dsize+dbuf.dsize)==-1
580             || tdb1_ofs_write(tdb, TDB1_HASH_TOP(hash), &rec_ptr) == -1) {
581                 /* Need to tdb1_unallocate() here */
582                 goto fail;
583         }
584
585  done:
586         ret = 0;
587  fail:
588         if (ret == 0) {
589                 tdb1_increment_seqnum(tdb);
590         }
591
592         SAFE_FREE(p);
593         return ret;
594 }
595
596 /* store an element in the database, replacing any existing element
597    with the same key
598
599    return 0 on success, -1 on failure
600 */
601 int tdb1_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag)
602 {
603         uint32_t hash;
604         int ret;
605
606         assert(tdb->flags & TDB_VERSION1);
607
608         if ((tdb->flags & TDB_RDONLY) || tdb->tdb1.traverse_read) {
609                 tdb->last_error = TDB_ERR_RDONLY;
610                 return -1;
611         }
612
613         /* find which hash bucket it is in */
614         hash = tdb_hash(tdb, key.dptr, key.dsize);
615         if (tdb1_lock(tdb, TDB1_BUCKET(hash), F_WRLCK) == -1)
616                 return -1;
617
618         ret = _tdb1_store(tdb, key, dbuf, flag, hash);
619         tdb1_unlock(tdb, TDB1_BUCKET(hash), F_WRLCK);
620         return ret;
621 }
622
623 /* Append to an entry. Create if not exist. */
624 int tdb1_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf)
625 {
626         uint32_t hash;
627         TDB_DATA dbuf;
628         int ret = -1;
629
630         assert(tdb->flags & TDB_VERSION1);
631
632         /* find which hash bucket it is in */
633         hash = tdb_hash(tdb, key.dptr, key.dsize);
634         if (tdb1_lock(tdb, TDB1_BUCKET(hash), F_WRLCK) == -1)
635                 return -1;
636
637         dbuf = _tdb1_fetch(tdb, key);
638
639         if (dbuf.dptr == NULL) {
640                 dbuf.dptr = (unsigned char *)malloc(new_dbuf.dsize);
641         } else {
642                 unsigned int new_len = dbuf.dsize + new_dbuf.dsize;
643                 unsigned char *new_dptr;
644
645                 /* realloc '0' is special: don't do that. */
646                 if (new_len == 0)
647                         new_len = 1;
648                 new_dptr = (unsigned char *)realloc(dbuf.dptr, new_len);
649                 if (new_dptr == NULL) {
650                         free(dbuf.dptr);
651                 }
652                 dbuf.dptr = new_dptr;
653         }
654
655         if (dbuf.dptr == NULL) {
656                 tdb->last_error = TDB_ERR_OOM;
657                 goto failed;
658         }
659
660         memcpy(dbuf.dptr + dbuf.dsize, new_dbuf.dptr, new_dbuf.dsize);
661         dbuf.dsize += new_dbuf.dsize;
662
663         ret = _tdb1_store(tdb, key, dbuf, 0, hash);
664
665 failed:
666         tdb1_unlock(tdb, TDB1_BUCKET(hash), F_WRLCK);
667         SAFE_FREE(dbuf.dptr);
668         return ret;
669 }
670
671
672 /*
673   get the tdb sequence number. Only makes sense if the writers opened
674   with TDB1_SEQNUM set. Note that this sequence number will wrap quite
675   quickly, so it should only be used for a 'has something changed'
676   test, not for code that relies on the count of the number of changes
677   made. If you want a counter then use a tdb record.
678
679   The aim of this sequence number is to allow for a very lightweight
680   test of a possible tdb change.
681 */
682 int tdb1_get_seqnum(struct tdb_context *tdb)
683 {
684         tdb1_off_t seqnum=0;
685
686         tdb1_ofs_read(tdb, TDB1_SEQNUM_OFS, &seqnum);
687         return seqnum;
688 }
689
690
691 /*
692   add a region of the file to the freelist. Length is the size of the region in bytes,
693   which includes the free list header that needs to be added
694  */
695 static int tdb1_free_region(struct tdb_context *tdb, tdb1_off_t offset, ssize_t length)
696 {
697         struct tdb1_record rec;
698         if (length <= sizeof(rec)) {
699                 /* the region is not worth adding */
700                 return 0;
701         }
702         if (length + offset > tdb->file->map_size) {
703                 tdb->last_error = tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_LOG_ERROR,
704                                         "tdb1_free_region: adding region beyond"
705                                         " end of file");
706                 return -1;
707         }
708         memset(&rec,'\0',sizeof(rec));
709         rec.rec_len = length - sizeof(rec);
710         if (tdb1_free(tdb, offset, &rec) == -1) {
711                 tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
712                            "tdb1_free_region: failed to add free record");
713                 return -1;
714         }
715         return 0;
716 }
717
718 /*
719   wipe the entire database, deleting all records. This can be done
720   very fast by using a allrecord lock. The entire data portion of the
721   file becomes a single entry in the freelist.
722
723   This code carefully steps around the recovery area, leaving it alone
724  */
725 int tdb1_wipe_all(struct tdb_context *tdb)
726 {
727         int i;
728         tdb1_off_t offset = 0;
729         ssize_t data_len;
730         tdb1_off_t recovery_head;
731         tdb1_len_t recovery_size = 0;
732
733         if (tdb1_lockall(tdb) != 0) {
734                 return -1;
735         }
736
737
738         /* see if the tdb has a recovery area, and remember its size
739            if so. We don't want to lose this as otherwise each
740            tdb1_wipe_all() in a transaction will increase the size of
741            the tdb by the size of the recovery area */
742         if (tdb1_ofs_read(tdb, TDB1_RECOVERY_HEAD, &recovery_head) == -1) {
743                 tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
744                            "tdb1_wipe_all: failed to read recovery head");
745                 goto failed;
746         }
747
748         if (recovery_head != 0) {
749                 struct tdb1_record rec;
750                 if (tdb->tdb1.io->tdb1_read(tdb, recovery_head, &rec, sizeof(rec), TDB1_DOCONV()) == -1) {
751                         tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
752                                    "tdb1_wipe_all: failed to read recovery record");
753                         return -1;
754                 }
755                 recovery_size = rec.rec_len + sizeof(rec);
756         }
757
758         /* wipe the hashes */
759         for (i=0;i<tdb->tdb1.header.hash_size;i++) {
760                 if (tdb1_ofs_write(tdb, TDB1_HASH_TOP(i), &offset) == -1) {
761                         tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
762                                    "tdb1_wipe_all: failed to write hash %d", i);
763                         goto failed;
764                 }
765         }
766
767         /* wipe the freelist */
768         if (tdb1_ofs_write(tdb, TDB1_FREELIST_TOP, &offset) == -1) {
769                 tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
770                            "tdb1_wipe_all: failed to write freelist");
771                 goto failed;
772         }
773
774         /* add all the rest of the file to the freelist, possibly leaving a gap
775            for the recovery area */
776         if (recovery_size == 0) {
777                 /* the simple case - the whole file can be used as a freelist */
778                 data_len = (tdb->file->map_size - TDB1_DATA_START(tdb->tdb1.header.hash_size));
779                 if (tdb1_free_region(tdb, TDB1_DATA_START(tdb->tdb1.header.hash_size), data_len) != 0) {
780                         goto failed;
781                 }
782         } else {
783                 /* we need to add two freelist entries - one on either
784                    side of the recovery area
785
786                    Note that we cannot shift the recovery area during
787                    this operation. Only the transaction.c code may
788                    move the recovery area or we risk subtle data
789                    corruption
790                 */
791                 data_len = (recovery_head - TDB1_DATA_START(tdb->tdb1.header.hash_size));
792                 if (tdb1_free_region(tdb, TDB1_DATA_START(tdb->tdb1.header.hash_size), data_len) != 0) {
793                         goto failed;
794                 }
795                 /* and the 2nd free list entry after the recovery area - if any */
796                 data_len = tdb->file->map_size - (recovery_head+recovery_size);
797                 if (tdb1_free_region(tdb, recovery_head+recovery_size, data_len) != 0) {
798                         goto failed;
799                 }
800         }
801
802         if (tdb1_unlockall(tdb) != 0) {
803                 tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
804                            "tdb1_wipe_all: failed to unlock");
805                 goto failed;
806         }
807
808         return 0;
809
810 failed:
811         tdb1_unlockall(tdb);
812         return -1;
813 }
814
815 struct traverse_state {
816         enum TDB_ERROR error;
817         struct tdb_context *dest_db;
818 };
819
820 /*
821   traverse function for repacking
822  */
823 static int repack_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *private_data)
824 {
825         struct traverse_state *state = (struct traverse_state *)private_data;
826         if (tdb1_store(state->dest_db, key, data, TDB_INSERT) != 0) {
827                 state->error = state->dest_db->last_error;
828                 return -1;
829         }
830         return 0;
831 }
832
833 /*
834   repack a tdb
835  */
836 int tdb1_repack(struct tdb_context *tdb)
837 {
838         struct tdb_context *tmp_db;
839         struct traverse_state state;
840         union tdb_attribute hsize;
841
842         hsize.base.attr = TDB_ATTRIBUTE_TDB1_HASHSIZE;
843         hsize.base.next = NULL;
844         hsize.tdb1_hashsize.hsize = tdb->tdb1.header.hash_size;
845
846         if (tdb1_transaction_start(tdb) != 0) {
847                 tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
848                            __location__ " Failed to start transaction");
849                 return -1;
850         }
851
852         tmp_db = tdb_open("tmpdb", TDB_INTERNAL, O_RDWR|O_CREAT, 0, &hsize);
853         if (tmp_db == NULL) {
854                 tdb->last_error = tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
855                                         __location__ " Failed to create tmp_db");
856                 tdb1_transaction_cancel(tdb);
857                 return -1;
858         }
859
860         state.error = TDB_SUCCESS;
861         state.dest_db = tmp_db;
862
863         if (tdb1_traverse_read(tdb, repack_traverse, &state) == -1) {
864                 tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
865                            __location__ " Failed to traverse copying out");
866                 tdb1_transaction_cancel(tdb);
867                 tdb_close(tmp_db);
868                 return -1;
869         }
870
871         if (state.error != TDB_SUCCESS) {
872                 tdb->last_error = tdb_logerr(tdb, state.error, TDB_LOG_ERROR,
873                                         __location__ " Error during traversal");
874                 tdb1_transaction_cancel(tdb);
875                 tdb_close(tmp_db);
876                 return -1;
877         }
878
879         if (tdb1_wipe_all(tdb) != 0) {
880                 tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
881                            __location__ " Failed to wipe database\n");
882                 tdb1_transaction_cancel(tdb);
883                 tdb_close(tmp_db);
884                 return -1;
885         }
886
887         state.error = TDB_SUCCESS;
888         state.dest_db = tdb;
889
890         if (tdb1_traverse_read(tmp_db, repack_traverse, &state) == -1) {
891                 tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
892                            __location__ " Failed to traverse copying back");
893                 tdb1_transaction_cancel(tdb);
894                 tdb_close(tmp_db);
895                 return -1;
896         }
897
898         if (state.error) {
899                 tdb->last_error = tdb_logerr(tdb, state.error, TDB_LOG_ERROR,
900                                         __location__ " Error during second traversal");
901                 tdb1_transaction_cancel(tdb);
902                 tdb_close(tmp_db);
903                 return -1;
904         }
905
906         tdb_close(tmp_db);
907
908         if (tdb1_transaction_commit(tdb) != 0) {
909                 tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
910                            __location__ " Failed to commit");
911                 return -1;
912         }
913
914         return 0;
915 }
916
917 /* Even on files, we can get partial writes due to signals. */
918 bool tdb1_write_all(int fd, const void *buf, size_t count)
919 {
920         while (count) {
921                 ssize_t ret;
922                 ret = write(fd, buf, count);
923                 if (ret < 0)
924                         return false;
925                 buf = (const char *)buf + ret;
926                 count -= ret;
927         }
928         return true;
929 }