]> git.ozlabs.org Git - ccan/commitdiff
tdb: delete from CCAN.
authorRusty Russell <rusty@rustcorp.com.au>
Tue, 14 Feb 2012 09:39:18 +0000 (20:09 +1030)
committerRusty Russell <rusty@rustcorp.com.au>
Tue, 14 Feb 2012 09:39:18 +0000 (20:09 +1030)
This was an early experiment in putting code into CCAN, but TDB is a public
library distributed as part of the Samba sources; there is no reason to
publish it here (especially now the unit tests are also in Samba).

74 files changed:
ccan/tdb/LICENSE [deleted symlink]
ccan/tdb/_info [deleted file]
ccan/tdb/check.c [deleted file]
ccan/tdb/dump.c [deleted file]
ccan/tdb/error.c [deleted file]
ccan/tdb/freelist.c [deleted file]
ccan/tdb/freelistcheck.c [deleted file]
ccan/tdb/hash.c [deleted file]
ccan/tdb/io.c [deleted file]
ccan/tdb/lock.c [deleted file]
ccan/tdb/open.c [deleted file]
ccan/tdb/summary.c [deleted file]
ccan/tdb/tdb.c [deleted file]
ccan/tdb/tdb.h [deleted file]
ccan/tdb/tdb_private.h [deleted file]
ccan/tdb/test/external-agent.c [deleted file]
ccan/tdb/test/external-agent.h [deleted file]
ccan/tdb/test/jenkins-be-hash.tdb [deleted file]
ccan/tdb/test/jenkins-le-hash.tdb [deleted file]
ccan/tdb/test/lock-tracking.c [deleted file]
ccan/tdb/test/lock-tracking.h [deleted file]
ccan/tdb/test/logging.c [deleted file]
ccan/tdb/test/logging.h [deleted file]
ccan/tdb/test/old-nohash-be.tdb [deleted file]
ccan/tdb/test/old-nohash-le.tdb [deleted file]
ccan/tdb/test/run-3G-file.c [deleted file]
ccan/tdb/test/run-bad-tdb-header.c [deleted file]
ccan/tdb/test/run-check.c [deleted file]
ccan/tdb/test/run-corrupt.c [deleted file]
ccan/tdb/test/run-die-during-transaction.c [deleted file]
ccan/tdb/test/run-endian.c [deleted file]
ccan/tdb/test/run-incompatible.c [deleted file]
ccan/tdb/test/run-nested-transactions.c [deleted file]
ccan/tdb/test/run-nested-traverse.c [deleted file]
ccan/tdb/test/run-no-lock-during-traverse.c [deleted file]
ccan/tdb/test/run-oldhash.c [deleted file]
ccan/tdb/test/run-open-during-transaction.c [deleted file]
ccan/tdb/test/run-readonly-check.c [deleted file]
ccan/tdb/test/run-rwlock-check.c [deleted file]
ccan/tdb/test/run-summary.c [deleted file]
ccan/tdb/test/run-transaction-expand.c [deleted file]
ccan/tdb/test/run-traverse-in-transaction.c [deleted file]
ccan/tdb/test/run-wronghash-fail.c [deleted file]
ccan/tdb/test/run-zero-append.c [deleted file]
ccan/tdb/test/run.c [deleted file]
ccan/tdb/test/rwlock-be.tdb [deleted file]
ccan/tdb/test/rwlock-le.tdb [deleted file]
ccan/tdb/test/tdb.corrupt [deleted file]
ccan/tdb/tools/Makefile [deleted file]
ccan/tdb/tools/benchmarks/configuration.ldb.trace.19774.rz [deleted file]
ccan/tdb/tools/benchmarks/sam.ldb.trace.19774.rz [deleted file]
ccan/tdb/tools/benchmarks/schema.ldb.trace.19774.rz [deleted file]
ccan/tdb/tools/benchmarks/templates.ldb.trace.19774.rz [deleted file]
ccan/tdb/tools/benchmarks/users.ldb.trace.19774.rz [deleted file]
ccan/tdb/tools/keywords.c [deleted file]
ccan/tdb/tools/keywords.gperf [deleted file]
ccan/tdb/tools/mktdb.c [deleted file]
ccan/tdb/tools/replay_trace.c [deleted file]
ccan/tdb/tools/speed.c [deleted file]
ccan/tdb/tools/starvation.c [deleted file]
ccan/tdb/tools/tdbdump.c [deleted file]
ccan/tdb/tools/tdbtool.c [deleted file]
ccan/tdb/tools/tdbtorture.c [deleted file]
ccan/tdb/tools/tests/1-torture.trace.tar.bz2 [deleted file]
ccan/tdb/tools/tests/2-torture.trace.tar.bz2 [deleted file]
ccan/tdb/tools/tests/3-torture.trace.tar.bz2 [deleted file]
ccan/tdb/tools/tests/4-torture.trace.tar.bz2 [deleted file]
ccan/tdb/tools/tests/5-torture.trace.tar.bz2 [deleted file]
ccan/tdb/tools/tests/6-torture.trace.tar.bz2 [deleted file]
ccan/tdb/tools/tests/7-torture.trace.tar.bz2 [deleted file]
ccan/tdb/tools/tests/8-torture.trace.tar.bz2 [deleted file]
ccan/tdb/tools/tests/9-torture.trace.tar.bz2 [deleted file]
ccan/tdb/transaction.c [deleted file]
ccan/tdb/traverse.c [deleted file]

diff --git a/ccan/tdb/LICENSE b/ccan/tdb/LICENSE
deleted file mode 120000 (symlink)
index 7455044..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../../licenses/LGPL-3
\ No newline at end of file
diff --git a/ccan/tdb/_info b/ccan/tdb/_info
deleted file mode 100644 (file)
index ca49e3f..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-#include <string.h>
-#include <stdio.h>
-
-/**
- * tdb - The trivial (transactional) database
- *
- * The tdb module provides an efficient keyword data mapping (usually
- * within a file).  It supports transactions, so the contents of the
- * database is reliable even across crashes.
- *
- * Example:
- *     #include <ccan/tdb/tdb.h>
- *     #include <ccan/str/str.h>
- *     #include <err.h>
- *     #include <stdio.h>
- *     
- *     static void usage(const char *argv0)
- *     {
- *             errx(1, "Usage: %s fetch <dbfile> <key>\n"
- *                  "OR %s store <dbfile> <key> <data>", argv0, argv0);
- *     }
- *     
- *     int main(int argc, char *argv[])
- *     {
- *             struct tdb_context *tdb;
- *             TDB_DATA key, value;
- *     
- *             if (argc < 4)
- *                     usage(argv[0]);
- *     
- *             tdb = tdb_open(argv[2], 1024, TDB_DEFAULT, O_CREAT|O_RDWR,
- *                             0600);
- *             if (!tdb)
- *                     err(1, "Opening %s", argv[2]);
- *     
- *             key.dptr = (void *)argv[3];
- *             key.dsize = strlen(argv[3]);
- *     
- *             if (streq(argv[1], "fetch")) {
- *                     if (argc != 4)
- *                             usage(argv[0]);
- *                     value = tdb_fetch(tdb, key);
- *                     if (!value.dptr)
- *                             errx(1, "fetch %s: %s",
- *                                  argv[3], tdb_errorstr(tdb));
- *                     printf("%.*s\n", value.dsize, (char *)value.dptr);
- *                     free(value.dptr);
- *             } else if (streq(argv[1], "store")) {
- *                     if (argc != 5)
- *                             usage(argv[0]);
- *                     value.dptr = (void *)argv[4];
- *                     value.dsize = strlen(argv[4]);
- *                     if (tdb_store(tdb, key, value, 0) != 0)
- *                             errx(1, "store %s: %s",
- *                                  argv[3], tdb_errorstr(tdb));
- *             } else
- *                     usage(argv[0]);
- *     
- *             return 0;
- *     }
- *
- * Maintainer: Rusty Russell <rusty@rustcorp.com.au>
- *
- * Author: Andrew Tridgell, Jeremy Allison, Rusty Russell
- *
- * License: LGPL (v3 or any later version)
- *
- * Ccanlint:
- *     // valgrind breaks fcntl locks.
- *     tests_pass_valgrind test/run-open-during-transaction.c:FAIL
- *     tests_pass_valgrind_noleaks test/run-die-during-transaction.c:FAIL
- */
-int main(int argc, char *argv[])
-{
-       if (argc != 2)
-               return 1;
-
-       if (strcmp(argv[1], "depends") == 0) {
-               printf("ccan/compiler\n");
-               return 0;
-       }
-
-       return 1;
-}
diff --git a/ccan/tdb/check.c b/ccan/tdb/check.c
deleted file mode 100644 (file)
index 4fbbb92..0000000
+++ /dev/null
@@ -1,473 +0,0 @@
- /*
-   Unix SMB/CIFS implementation.
-
-   trivial database library
-
-   Copyright (C) Rusty Russell            2009
-
-     ** NOTE! The following LGPL license applies to the tdb
-     ** library. This does NOT imply that all of Samba is released
-     ** under the LGPL
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-#include "tdb_private.h"
-#include <limits.h>
-
-/* Since we opened it, these shouldn't fail unless it's recent corruption. */
-static bool tdb_check_header(struct tdb_context *tdb, tdb_off_t *recovery)
-{
-       struct tdb_header hdr;
-       uint32_t h1, h2;
-
-       if (tdb->methods->tdb_read(tdb, 0, &hdr, sizeof(hdr), 0) == -1)
-               return false;
-       if (strcmp(hdr.magic_food, TDB_MAGIC_FOOD) != 0)
-               goto corrupt;
-
-       CONVERT(hdr);
-       if (hdr.version != TDB_VERSION)
-               goto corrupt;
-
-       if (hdr.rwlocks != 0 && hdr.rwlocks != TDB_HASH_RWLOCK_MAGIC)
-               goto corrupt;
-
-       tdb_header_hash(tdb, &h1, &h2);
-       if (hdr.magic1_hash && hdr.magic2_hash &&
-           (hdr.magic1_hash != h1 || hdr.magic2_hash != h2))
-               goto corrupt;
-
-       if (hdr.hash_size == 0)
-               goto corrupt;
-
-       if (hdr.hash_size != tdb->header.hash_size)
-               goto corrupt;
-
-       if (hdr.recovery_start != 0 &&
-           hdr.recovery_start < TDB_DATA_START(tdb->header.hash_size))
-               goto corrupt;
-
-       *recovery = hdr.recovery_start;
-       return true;
-
-corrupt:
-       tdb->ecode = TDB_ERR_CORRUPT;
-       TDB_LOG((tdb, TDB_DEBUG_ERROR, "Header is corrupt\n"));
-       return false;
-}
-
-/* Generic record header check. */
-static bool tdb_check_record(struct tdb_context *tdb,
-                            tdb_off_t off,
-                            const struct tdb_record *rec)
-{
-       tdb_off_t tailer;
-
-       /* Check rec->next: 0 or points to record offset, aligned. */
-       if (rec->next > 0 && rec->next < TDB_DATA_START(tdb->header.hash_size)){
-               TDB_LOG((tdb, TDB_DEBUG_ERROR,
-                        "Record offset %d too small next %d\n",
-                        off, rec->next));
-               goto corrupt;
-       }
-       if (rec->next + sizeof(*rec) < rec->next) {
-               TDB_LOG((tdb, TDB_DEBUG_ERROR,
-                        "Record offset %d too large next %d\n",
-                        off, rec->next));
-               goto corrupt;
-       }
-       if ((rec->next % TDB_ALIGNMENT) != 0) {
-               TDB_LOG((tdb, TDB_DEBUG_ERROR,
-                        "Record offset %d misaligned next %d\n",
-                        off, rec->next));
-               goto corrupt;
-       }
-       if (tdb->methods->tdb_oob(tdb, rec->next+sizeof(*rec), 0))
-               goto corrupt;
-
-       /* Check rec_len: similar to rec->next, implies next record. */
-       if ((rec->rec_len % TDB_ALIGNMENT) != 0) {
-               TDB_LOG((tdb, TDB_DEBUG_ERROR,
-                        "Record offset %d misaligned length %d\n",
-                        off, rec->rec_len));
-               goto corrupt;
-       }
-       /* Must fit tailer. */
-       if (rec->rec_len < sizeof(tailer)) {
-               TDB_LOG((tdb, TDB_DEBUG_ERROR,
-                        "Record offset %d too short length %d\n",
-                        off, rec->rec_len));
-               goto corrupt;
-       }
-       /* OOB allows "right at the end" access, so this works for last rec. */
-       if (tdb->methods->tdb_oob(tdb, off+sizeof(*rec)+rec->rec_len, 0))
-               goto corrupt;
-
-       /* Check tailer. */
-       if (tdb_ofs_read(tdb, off+sizeof(*rec)+rec->rec_len-sizeof(tailer),
-                        &tailer) == -1)
-               goto corrupt;
-       if (tailer != sizeof(*rec) + rec->rec_len) {
-               TDB_LOG((tdb, TDB_DEBUG_ERROR,
-                        "Record offset %d invalid tailer\n", off));
-               goto corrupt;
-       }
-
-       return true;
-
-corrupt:
-       tdb->ecode = TDB_ERR_CORRUPT;
-       return false;
-}
-
-/* Grab some bytes: may copy if can't use mmap.
-   Caller has already done bounds check. */
-static TDB_DATA get_bytes(struct tdb_context *tdb,
-                         tdb_off_t off, tdb_len_t len)
-{
-       TDB_DATA d;
-
-       d.dsize = len;
-
-       if (tdb->transaction == NULL && tdb->map_ptr != NULL)
-               d.dptr = (unsigned char *)tdb->map_ptr + off;
-       else
-               d.dptr = tdb_alloc_read(tdb, off, d.dsize);
-       return d;
-}
-
-/* Frees data if we're not able to simply use mmap. */
-static void put_bytes(struct tdb_context *tdb, TDB_DATA d)
-{
-       if (tdb->transaction == NULL && tdb->map_ptr != NULL)
-               return;
-       free(d.dptr);
-}
-
-/* We use the excellent Jenkins lookup3 hash; this is based on hash_word2.
- * See: http://burtleburtle.net/bob/c/lookup3.c
- */
-#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
-static void hash(uint32_t key, uint32_t *pc, uint32_t *pb)
-{
-       uint32_t a,b,c;
-
-       /* Set up the internal state */
-       a = b = c = 0xdeadbeef + *pc;
-       c += *pb;
-       a += key;
-       c ^= b; c -= rot(b,14);
-       a ^= c; a -= rot(c,11);
-       b ^= a; b -= rot(a,25);
-       c ^= b; c -= rot(b,16);
-       a ^= c; a -= rot(c,4);
-       b ^= a; b -= rot(a,14);
-       c ^= b; c -= rot(b,24);
-       *pc=c; *pb=b;
-}
-
-/*
-  We want to check that all free records are in the free list
-  (only once), and all free list entries are free records.  Similarly
-  for each hash chain of used records.
-
-  Doing that naively (without walking hash chains, since we want to be
-  linear) means keeping a list of records which have been seen in each
-  hash chain, and another of records pointed to (ie. next pointers
-  from records and the initial hash chain heads).  These two lists
-  should be equal.  This will take 8 bytes per record, and require
-  sorting at the end.
-
-  So instead, we record each offset in a bitmap such a way that
-  recording it twice will cancel out.  Since each offset should appear
-  exactly twice, the bitmap should be zero at the end.
-
-  The approach was inspired by Bloom Filters (see Wikipedia).  For
-  each value, we flip K bits in a bitmap of size N.  The number of
-  distinct arrangements is:
-
-       N! / (K! * (N-K)!)
-
-  Of course, not all arrangements are actually distinct, but testing
-  shows this formula to be close enough.
-
-  So, if K == 8 and N == 256, the probability of two things flipping the same
-  bits is 1 in 409,663,695,276,000.
-
-  Given that ldb uses a hash size of 10000, using 32 bytes per hash chain
-  (320k) seems reasonable.
-*/
-#define NUM_HASHES 8
-#define BITMAP_BITS 256
-
-static void bit_flip(unsigned char bits[], unsigned int idx)
-{
-       bits[idx / CHAR_BIT] ^= (1 << (idx % CHAR_BIT));
-}
-
-/* We record offsets in a bitmap for the particular chain it should be in.  */
-static void record_offset(unsigned char bits[], tdb_off_t off)
-{
-       uint32_t h1 = off, h2 = 0;
-       unsigned int i;
-
-       /* We get two good hash values out of jhash2, so we use both.  Then
-        * we keep going to produce further hash values. */
-       for (i = 0; i < NUM_HASHES / 2; i++) {
-               hash(off, &h1, &h2);
-               bit_flip(bits, h1 % BITMAP_BITS);
-               bit_flip(bits, h2 % BITMAP_BITS);
-               h2++;
-       }
-}
-
-/* Check that an in-use record is valid. */
-static bool tdb_check_used_record(struct tdb_context *tdb,
-                                 tdb_off_t off,
-                                 const struct tdb_record *rec,
-                                 unsigned char **hashes,
-                                 int (*check)(TDB_DATA, TDB_DATA, void *),
-                                 void *private_data)
-{
-       TDB_DATA key, data;
-
-       if (!tdb_check_record(tdb, off, rec))
-               return false;
-
-       /* key + data + tailer must fit in record */
-       if (rec->key_len + rec->data_len + sizeof(tdb_off_t) > rec->rec_len) {
-               TDB_LOG((tdb, TDB_DEBUG_ERROR,
-                        "Record offset %d too short for contents\n", off));
-               return false;
-       }
-
-       key = get_bytes(tdb, off + sizeof(*rec), rec->key_len);
-       if (!key.dptr)
-               return false;
-
-       if (tdb->hash_fn(&key) != rec->full_hash) {
-               TDB_LOG((tdb, TDB_DEBUG_ERROR,
-                        "Record offset %d has incorrect hash\n", off));
-               goto fail_put_key;
-       }
-
-       /* Mark this offset as a known value for this hash bucket. */
-       record_offset(hashes[BUCKET(rec->full_hash)+1], off);
-       /* And similarly if the next pointer is valid. */
-       if (rec->next)
-               record_offset(hashes[BUCKET(rec->full_hash)+1], rec->next);
-
-       /* If they supply a check function and this record isn't dead,
-          get data and feed it. */
-       if (check && rec->magic != TDB_DEAD_MAGIC) {
-               data = get_bytes(tdb, off + sizeof(*rec) + rec->key_len,
-                                rec->data_len);
-               if (!data.dptr)
-                       goto fail_put_key;
-
-               if (check(key, data, private_data) == -1)
-                       goto fail_put_data;
-               put_bytes(tdb, data);
-       }
-
-       put_bytes(tdb, key);
-       return true;
-
-fail_put_data:
-       put_bytes(tdb, data);
-fail_put_key:
-       put_bytes(tdb, key);
-       return false;
-}
-
-/* Check that an unused record is valid. */
-static bool tdb_check_free_record(struct tdb_context *tdb,
-                                 tdb_off_t off,
-                                 const struct tdb_record *rec,
-                                 unsigned char **hashes)
-{
-       if (!tdb_check_record(tdb, off, rec))
-               return false;
-
-       /* Mark this offset as a known value for the free list. */
-       record_offset(hashes[0], off);
-       /* And similarly if the next pointer is valid. */
-       if (rec->next)
-               record_offset(hashes[0], rec->next);
-       return true;
-}
-
-/* Slow, but should be very rare. */
-size_t tdb_dead_space(struct tdb_context *tdb, tdb_off_t off)
-{
-       size_t len;
-
-       for (len = 0; off + len < tdb->map_size; len++) {
-               char c;
-               if (tdb->methods->tdb_read(tdb, off, &c, 1, 0))
-                       return 0;
-               if (c != 0 && c != 0x42)
-                       break;
-       }
-       return len;
-}
-
-int tdb_check(struct tdb_context *tdb,
-             int (*check)(TDB_DATA key, TDB_DATA data, void *private_data),
-             void *private_data)
-{
-       unsigned int h;
-       unsigned char **hashes;
-       tdb_off_t off, recovery_start;
-       struct tdb_record rec;
-       bool found_recovery = false;
-       tdb_len_t dead;
-       bool locked;
-
-       /* Read-only databases use no locking at all: it's best-effort.
-        * We may have a write lock already, so skip that case too. */
-       if (tdb->read_only || tdb->allrecord_lock.count != 0) {
-               locked = false;
-       } else {
-               if (tdb_lockall_read(tdb) == -1)
-                       return -1;
-               locked = true;
-       }
-
-       /* Make sure we know true size of the underlying file. */
-       tdb->methods->tdb_oob(tdb, tdb->map_size + 1, 1);
-
-       /* Header must be OK: also gets us the recovery ptr, if any. */
-       if (!tdb_check_header(tdb, &recovery_start))
-               goto unlock;
-
-       /* We should have the whole header, too. */
-       if (tdb->map_size < TDB_DATA_START(tdb->header.hash_size)) {
-               tdb->ecode = TDB_ERR_CORRUPT;
-               TDB_LOG((tdb, TDB_DEBUG_ERROR, "File too short for hashes\n"));
-               goto unlock;
-       }
-
-       /* One big malloc: pointers then bit arrays. */
-       hashes = (unsigned char **)calloc(
-                       1, sizeof(hashes[0]) * (1+tdb->header.hash_size)
-                       + BITMAP_BITS / CHAR_BIT * (1+tdb->header.hash_size));
-       if (!hashes) {
-               tdb->ecode = TDB_ERR_OOM;
-               goto unlock;
-       }
-
-       /* Initialize pointers */
-       hashes[0] = (unsigned char *)(&hashes[1+tdb->header.hash_size]);
-       for (h = 1; h < 1+tdb->header.hash_size; h++)
-               hashes[h] = hashes[h-1] + BITMAP_BITS / CHAR_BIT;
-
-       /* Freelist and hash headers are all in a row: read them. */
-       for (h = 0; h < 1+tdb->header.hash_size; h++) {
-               if (tdb_ofs_read(tdb, FREELIST_TOP + h*sizeof(tdb_off_t),
-                                &off) == -1)
-                       goto free;
-               if (off)
-                       record_offset(hashes[h], off);
-       }
-
-       /* For each record, read it in and check it's ok. */
-       for (off = TDB_DATA_START(tdb->header.hash_size);
-            off < tdb->map_size;
-            off += sizeof(rec) + rec.rec_len) {
-               if (tdb->methods->tdb_read(tdb, off, &rec, sizeof(rec),
-                                          DOCONV()) == -1)
-                       goto free;
-               switch (rec.magic) {
-               case TDB_MAGIC:
-               case TDB_DEAD_MAGIC:
-                       if (!tdb_check_used_record(tdb, off, &rec, hashes,
-                                                  check, private_data))
-                               goto free;
-                       break;
-               case TDB_FREE_MAGIC:
-                       if (!tdb_check_free_record(tdb, off, &rec, hashes))
-                               goto free;
-                       break;
-               /* If we crash after ftruncate, we can get zeroes or fill. */
-               case TDB_RECOVERY_INVALID_MAGIC:
-               case 0x42424242:
-                       if (recovery_start == off) {
-                               found_recovery = true;
-                               break;
-                       }
-                       dead = tdb_dead_space(tdb, off);
-                       if (dead < sizeof(rec))
-                               goto corrupt;
-
-                       TDB_LOG((tdb, TDB_DEBUG_ERROR,
-                                "Dead space at %d-%d (of %u)\n",
-                                off, off + dead, tdb->map_size));
-                       rec.rec_len = dead - sizeof(rec);
-                       break;
-               case TDB_RECOVERY_MAGIC:
-                       if (recovery_start != off) {
-                               TDB_LOG((tdb, TDB_DEBUG_ERROR,
-                                        "Unexpected recovery record at offset %d\n",
-                                        off));
-                               goto free;
-                       }
-                       found_recovery = true;
-                       break;
-               default: ;
-               corrupt:
-                       tdb->ecode = TDB_ERR_CORRUPT;
-                       TDB_LOG((tdb, TDB_DEBUG_ERROR,
-                                "Bad magic 0x%x at offset %d\n",
-                                rec.magic, off));
-                       goto free;
-               }
-       }
-
-       /* Now, hashes should all be empty: each record exists and is referred
-        * to by one other. */
-       for (h = 0; h < 1+tdb->header.hash_size; h++) {
-               unsigned int i;
-               for (i = 0; i < BITMAP_BITS / CHAR_BIT; i++) {
-                       if (hashes[h][i] != 0) {
-                               tdb->ecode = TDB_ERR_CORRUPT;
-                               TDB_LOG((tdb, TDB_DEBUG_ERROR,
-                                        "Hashes do not match records\n"));
-                               goto free;
-                       }
-               }
-       }
-
-       /* We must have found recovery area if there was one. */
-       if (recovery_start != 0 && !found_recovery) {
-               TDB_LOG((tdb, TDB_DEBUG_ERROR,
-                        "Expected a recovery area at %u\n",
-                        recovery_start));
-               goto free;
-       }
-
-       free(hashes);
-       if (locked) {
-               tdb_unlockall_read(tdb);
-       }
-       return 0;
-
-free:
-       free(hashes);
-unlock:
-       if (locked) {
-               tdb_unlockall_read(tdb);
-       }
-       return -1;
-}
diff --git a/ccan/tdb/dump.c b/ccan/tdb/dump.c
deleted file mode 100644 (file)
index bdcbfab..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
- /* 
-   Unix SMB/CIFS implementation.
-
-   trivial database library
-
-   Copyright (C) Andrew Tridgell              1999-2005
-   Copyright (C) Paul `Rusty' Russell             2000
-   Copyright (C) Jeremy Allison                           2000-2003
-   
-     ** NOTE! The following LGPL license applies to the tdb
-     ** library. This does NOT imply that all of Samba is released
-     ** under the LGPL
-   
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "tdb_private.h"
-
-static tdb_off_t tdb_dump_record(struct tdb_context *tdb, int hash,
-                                tdb_off_t offset)
-{
-       struct tdb_record rec;
-       tdb_off_t tailer_ofs, tailer;
-
-       if (tdb->methods->tdb_read(tdb, offset, (char *)&rec, 
-                                  sizeof(rec), DOCONV()) == -1) {
-               printf("ERROR: failed to read record at %u\n", offset);
-               return 0;
-       }
-
-       printf(" rec: hash=%d offset=0x%08x next=0x%08x rec_len=%d "
-              "key_len=%d data_len=%d full_hash=0x%x magic=0x%x\n",
-              hash, offset, rec.next, rec.rec_len, rec.key_len, rec.data_len,
-              rec.full_hash, rec.magic);
-
-       tailer_ofs = offset + sizeof(rec) + rec.rec_len - sizeof(tdb_off_t);
-
-       if (tdb_ofs_read(tdb, tailer_ofs, &tailer) == -1) {
-               printf("ERROR: failed to read tailer at %u\n", tailer_ofs);
-               return rec.next;
-       }
-
-       if (tailer != rec.rec_len + sizeof(rec)) {
-               printf("ERROR: tailer does not match record! tailer=%u totalsize=%u\n",
-                               (unsigned int)tailer, (unsigned int)(rec.rec_len + sizeof(rec)));
-       }
-       return rec.next;
-}
-
-static int tdb_dump_chain(struct tdb_context *tdb, int i)
-{
-       tdb_off_t rec_ptr, top;
-
-       top = TDB_HASH_TOP(i);
-
-       if (tdb_lock(tdb, i, F_WRLCK) != 0)
-               return -1;
-
-       if (tdb_ofs_read(tdb, top, &rec_ptr) == -1)
-               return tdb_unlock(tdb, i, F_WRLCK);
-
-       if (rec_ptr)
-               printf("hash=%d\n", i);
-
-       while (rec_ptr) {
-               rec_ptr = tdb_dump_record(tdb, i, rec_ptr);
-       }
-
-       return tdb_unlock(tdb, i, F_WRLCK);
-}
-
-void tdb_dump_all(struct tdb_context *tdb)
-{
-       int i;
-       for (i=0;i<tdb->header.hash_size;i++) {
-               tdb_dump_chain(tdb, i);
-       }
-       printf("freelist:\n");
-       tdb_dump_chain(tdb, -1);
-}
-
-int tdb_printfreelist(struct tdb_context *tdb)
-{
-       int ret;
-       long total_free = 0;
-       tdb_off_t offset, rec_ptr;
-       struct tdb_record rec;
-
-       if ((ret = tdb_lock(tdb, -1, F_WRLCK)) != 0)
-               return ret;
-
-       offset = FREELIST_TOP;
-
-       /* read in the freelist top */
-       if (tdb_ofs_read(tdb, offset, &rec_ptr) == -1) {
-               tdb_unlock(tdb, -1, F_WRLCK);
-               return 0;
-       }
-
-       printf("freelist top=[0x%08x]\n", rec_ptr );
-       while (rec_ptr) {
-               if (tdb->methods->tdb_read(tdb, rec_ptr, (char *)&rec, 
-                                          sizeof(rec), DOCONV()) == -1) {
-                       tdb_unlock(tdb, -1, F_WRLCK);
-                       return -1;
-               }
-
-               if (rec.magic != TDB_FREE_MAGIC) {
-                       printf("bad magic 0x%08x in free list\n", rec.magic);
-                       tdb_unlock(tdb, -1, F_WRLCK);
-                       return -1;
-               }
-
-               printf("entry offset=[0x%08x], rec.rec_len = [0x%08x (%d)] (end = 0x%08x)\n", 
-                      rec_ptr, rec.rec_len, rec.rec_len, rec_ptr + rec.rec_len);
-               total_free += rec.rec_len;
-
-               /* move to the next record */
-               rec_ptr = rec.next;
-       }
-       printf("total rec_len = [0x%08x (%d)]\n", (int)total_free, 
-               (int)total_free);
-
-       return tdb_unlock(tdb, -1, F_WRLCK);
-}
-
diff --git a/ccan/tdb/error.c b/ccan/tdb/error.c
deleted file mode 100644 (file)
index 195ab23..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
- /* 
-   Unix SMB/CIFS implementation.
-
-   trivial database library
-
-   Copyright (C) Andrew Tridgell              1999-2005
-   Copyright (C) Paul `Rusty' Russell             2000
-   Copyright (C) Jeremy Allison                           2000-2003
-   
-     ** NOTE! The following LGPL license applies to the tdb
-     ** library. This does NOT imply that all of Samba is released
-     ** under the LGPL
-   
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "tdb_private.h"
-
-enum TDB_ERROR tdb_error(struct tdb_context *tdb)
-{
-       return tdb->ecode;
-}
-
-static struct tdb_errname {
-       enum TDB_ERROR ecode; const char *estring;
-} emap[] = { {TDB_SUCCESS, "Success"},
-            {TDB_ERR_CORRUPT, "Corrupt database"},
-            {TDB_ERR_IO, "IO Error"},
-            {TDB_ERR_LOCK, "Locking error"},
-            {TDB_ERR_OOM, "Out of memory"},
-            {TDB_ERR_EXISTS, "Record exists"},
-            {TDB_ERR_NOLOCK, "Lock exists on other keys"},
-            {TDB_ERR_EINVAL, "Invalid parameter"},
-            {TDB_ERR_NOEXIST, "Record does not exist"},
-            {TDB_ERR_RDONLY, "write not permitted"} };
-
-/* Error string for the last tdb error */
-const char *tdb_errorstr(struct tdb_context *tdb)
-{
-       uint32_t i;
-       for (i = 0; i < sizeof(emap) / sizeof(struct tdb_errname); i++)
-               if (tdb->ecode == emap[i].ecode)
-                       return emap[i].estring;
-       return "Invalid error code";
-}
-
diff --git a/ccan/tdb/freelist.c b/ccan/tdb/freelist.c
deleted file mode 100644 (file)
index c7d908e..0000000
+++ /dev/null
@@ -1,386 +0,0 @@
- /* 
-   Unix SMB/CIFS implementation.
-
-   trivial database library
-
-   Copyright (C) Andrew Tridgell              1999-2005
-   Copyright (C) Paul `Rusty' Russell             2000
-   Copyright (C) Jeremy Allison                           2000-2003
-   
-     ** NOTE! The following LGPL license applies to the tdb
-     ** library. This does NOT imply that all of Samba is released
-     ** under the LGPL
-   
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "tdb_private.h"
-
-/* 'right' merges can involve O(n^2) cost when combined with a
-   traverse, so they are disabled until we find a way to do them in 
-   O(1) time
-*/
-#define USE_RIGHT_MERGES 0
-
-/* read a freelist record and check for simple errors */
-int tdb_rec_free_read(struct tdb_context *tdb, tdb_off_t off, struct tdb_record *rec)
-{
-       if (tdb->methods->tdb_read(tdb, off, rec, sizeof(*rec),DOCONV()) == -1)
-               return -1;
-
-       if (rec->magic == TDB_MAGIC) {
-               /* this happens when a app is showdown while deleting a record - we should
-                  not completely fail when this happens */
-               TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_rec_free_read non-free magic 0x%x at offset=%d - fixing\n", 
-                        rec->magic, off));
-               rec->magic = TDB_FREE_MAGIC;
-               if (tdb->methods->tdb_write(tdb, off, rec, sizeof(*rec)) == -1)
-                       return -1;
-       }
-
-       if (rec->magic != TDB_FREE_MAGIC) {
-               /* Ensure ecode is set for log fn. */
-               tdb->ecode = TDB_ERR_CORRUPT;
-               TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_rec_free_read bad magic 0x%x at offset=%d\n", 
-                          rec->magic, off));
-               return -1;
-       }
-       if (tdb->methods->tdb_oob(tdb, rec->next+sizeof(*rec), 0) != 0)
-               return -1;
-       return 0;
-}
-
-
-#if USE_RIGHT_MERGES
-/* Remove an element from the freelist.  Must have alloc lock. */
-static int remove_from_freelist(struct tdb_context *tdb, tdb_off_t off, tdb_off_t next)
-{
-       tdb_off_t last_ptr, i;
-
-       /* read in the freelist top */
-       last_ptr = FREELIST_TOP;
-       while (tdb_ofs_read(tdb, last_ptr, &i) != -1 && i != 0) {
-               if (i == off) {
-                       /* We've found it! */
-                       return tdb_ofs_write(tdb, last_ptr, &next);
-               }
-               /* Follow chain (next offset is at start of record) */
-               last_ptr = i;
-       }
-       tdb->ecode = TDB_ERR_CORRUPT;
-       TDB_LOG((tdb, TDB_DEBUG_FATAL,"remove_from_freelist: not on list at off=%d\n", off));
-       return -1;
-}
-#endif
-
-
-/* update a record tailer (must hold allocation lock) */
-static int update_tailer(struct tdb_context *tdb, tdb_off_t offset,
-                        const struct tdb_record *rec)
-{
-       tdb_off_t totalsize;
-
-       /* Offset of tailer from record header */
-       totalsize = sizeof(*rec) + rec->rec_len;
-       return tdb_ofs_write(tdb, offset + totalsize - sizeof(tdb_off_t),
-                        &totalsize);
-}
-
-/* Add an element into the freelist. Merge adjacent records if
-   necessary. */
-int tdb_free(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec)
-{
-       /* Allocation and tailer lock */
-       if (tdb_lock(tdb, -1, F_WRLCK) != 0)
-               return -1;
-
-       /* set an initial tailer, so if we fail we don't leave a bogus record */
-       if (update_tailer(tdb, offset, rec) != 0) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_tailer failed!\n"));
-               goto fail;
-       }
-
-#if USE_RIGHT_MERGES
-       /* Look right first (I'm an Australian, dammit) */
-       if (offset + sizeof(*rec) + rec->rec_len + sizeof(*rec) <= tdb->map_size) {
-               tdb_off_t right = offset + sizeof(*rec) + rec->rec_len;
-               struct tdb_record r;
-
-               if (tdb->methods->tdb_read(tdb, right, &r, sizeof(r), DOCONV()) == -1) {
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: right read failed at %u\n", right));
-                       goto left;
-               }
-
-               /* If it's free, expand to include it. */
-               if (r.magic == TDB_FREE_MAGIC) {
-                       if (remove_from_freelist(tdb, right, r.next) == -1) {
-                               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: right free failed at %u\n", right));
-                               goto left;
-                       }
-                       rec->rec_len += sizeof(r) + r.rec_len;
-                       if (update_tailer(tdb, offset, rec) == -1) {
-                               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_tailer failed at %u\n", offset));
-                               goto fail;
-                       }
-               }
-       }
-left:
-#endif
-
-       /* Look left */
-       if (offset - sizeof(tdb_off_t) > TDB_DATA_START(tdb->header.hash_size)) {
-               tdb_off_t left = offset - sizeof(tdb_off_t);
-               struct tdb_record l;
-               tdb_off_t leftsize;
-               
-               /* Read in tailer and jump back to header */
-               if (tdb_ofs_read(tdb, left, &leftsize) == -1) {
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: left offset read failed at %u\n", left));
-                       goto update;
-               }
-
-               /* it could be uninitialised data */
-               if (leftsize == 0 || leftsize == TDB_PAD_U32) {
-                       goto update;
-               }
-
-               left = offset - leftsize;
-
-               if (leftsize > offset ||
-                   left < TDB_DATA_START(tdb->header.hash_size)) {
-                       goto update;
-               }
-
-               /* Now read in the left record */
-               if (tdb->methods->tdb_read(tdb, left, &l, sizeof(l), DOCONV()) == -1) {
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: left read failed at %u (%u)\n", left, leftsize));
-                       goto update;
-               }
-
-               /* If it's free, expand to include it. */
-               if (l.magic == TDB_FREE_MAGIC) {
-                       /* we now merge the new record into the left record, rather than the other 
-                          way around. This makes the operation O(1) instead of O(n). This change
-                          prevents traverse from being O(n^2) after a lot of deletes */
-                       l.rec_len += sizeof(*rec) + rec->rec_len;
-                       if (tdb_rec_write(tdb, left, &l) == -1) {
-                               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_left failed at %u\n", left));
-                               goto fail;
-                       }
-                       if (update_tailer(tdb, left, &l) == -1) {
-                               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_tailer failed at %u\n", offset));
-                               goto fail;
-                       }
-                       tdb_unlock(tdb, -1, F_WRLCK);
-                       return 0;
-               }
-       }
-
-update:
-
-       /* Now, prepend to free list */
-       rec->magic = TDB_FREE_MAGIC;
-
-       if (tdb_ofs_read(tdb, FREELIST_TOP, &rec->next) == -1 ||
-           tdb_rec_write(tdb, offset, rec) == -1 ||
-           tdb_ofs_write(tdb, FREELIST_TOP, &offset) == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free record write failed at offset=%d\n", offset));
-               goto fail;
-       }
-
-       /* And we're done. */
-       tdb_unlock(tdb, -1, F_WRLCK);
-       return 0;
-
- fail:
-       tdb_unlock(tdb, -1, F_WRLCK);
-       return -1;
-}
-
-
-
-/* 
-   the core of tdb_allocate - called when we have decided which
-   free list entry to use
-
-   Note that we try to allocate by grabbing data from the end of an existing record,
-   not the beginning. This is so the left merge in a free is more likely to be
-   able to free up the record without fragmentation
- */
-static tdb_off_t tdb_allocate_ofs(struct tdb_context *tdb, 
-                                 tdb_len_t length, tdb_off_t rec_ptr,
-                                 struct tdb_record *rec, tdb_off_t last_ptr)
-{
-#define MIN_REC_SIZE (sizeof(struct tdb_record) + sizeof(tdb_off_t) + 8)
-
-       if (rec->rec_len < length + MIN_REC_SIZE) {
-               /* we have to grab the whole record */
-
-               /* unlink it from the previous record */
-               if (tdb_ofs_write(tdb, last_ptr, &rec->next) == -1) {
-                       return 0;
-               }
-
-               /* mark it not free */
-               rec->magic = TDB_MAGIC;
-               if (tdb_rec_write(tdb, rec_ptr, rec) == -1) {
-                       return 0;
-               }
-               return rec_ptr;
-       }
-
-       /* we're going to just shorten the existing record */
-       rec->rec_len -= (length + sizeof(*rec));
-       if (tdb_rec_write(tdb, rec_ptr, rec) == -1) {
-               return 0;
-       }
-       if (update_tailer(tdb, rec_ptr, rec) == -1) {
-               return 0;
-       }
-
-       /* and setup the new record */
-       rec_ptr += sizeof(*rec) + rec->rec_len; 
-
-       memset(rec, '\0', sizeof(*rec));
-       rec->rec_len = length;
-       rec->magic = TDB_MAGIC;
-
-       if (tdb_rec_write(tdb, rec_ptr, rec) == -1) {
-               return 0;
-       }
-
-       if (update_tailer(tdb, rec_ptr, rec) == -1) {
-               return 0;
-       }
-
-       return rec_ptr;
-}
-
-/* allocate some space from the free list. The offset returned points
-   to a unconnected tdb_record within the database with room for at
-   least length bytes of total data
-
-   0 is returned if the space could not be allocated
- */
-tdb_off_t tdb_allocate(struct tdb_context *tdb, tdb_len_t length, struct tdb_record *rec)
-{
-       tdb_off_t rec_ptr, last_ptr, newrec_ptr;
-       struct {
-               tdb_off_t rec_ptr, last_ptr;
-               tdb_len_t rec_len;
-       } bestfit;
-       float multiplier = 1.0;
-
-       if (tdb_lock(tdb, -1, F_WRLCK) == -1)
-               return 0;
-
-       /* over-allocate to reduce fragmentation */
-       length *= 1.25;
-
-       /* Extra bytes required for tailer */
-       length += sizeof(tdb_off_t);
-       length = TDB_ALIGN(length, TDB_ALIGNMENT);
-
- again:
-       last_ptr = FREELIST_TOP;
-
-       /* read in the freelist top */
-       if (tdb_ofs_read(tdb, FREELIST_TOP, &rec_ptr) == -1)
-               goto fail;
-
-       bestfit.rec_ptr = 0;
-       bestfit.last_ptr = 0;
-       bestfit.rec_len = 0;
-
-       /* 
-          this is a best fit allocation strategy. Originally we used
-          a first fit strategy, but it suffered from massive fragmentation
-          issues when faced with a slowly increasing record size.
-        */
-       while (rec_ptr) {
-               if (tdb_rec_free_read(tdb, rec_ptr, rec) == -1) {
-                       goto fail;
-               }
-
-               if (rec->rec_len >= length) {
-                       if (bestfit.rec_ptr == 0 ||
-                           rec->rec_len < bestfit.rec_len) {
-                               bestfit.rec_len = rec->rec_len;
-                               bestfit.rec_ptr = rec_ptr;
-                               bestfit.last_ptr = last_ptr;
-                       }
-               }
-
-               /* move to the next record */
-               last_ptr = rec_ptr;
-               rec_ptr = rec->next;
-
-               /* if we've found a record that is big enough, then
-                  stop searching if its also not too big. The
-                  definition of 'too big' changes as we scan
-                  through */
-               if (bestfit.rec_len > 0 &&
-                   bestfit.rec_len < length * multiplier) {
-                       break;
-               }
-               
-               /* this multiplier means we only extremely rarely
-                  search more than 50 or so records. At 50 records we
-                  accept records up to 11 times larger than what we
-                  want */
-               multiplier *= 1.05;
-       }
-
-       if (bestfit.rec_ptr != 0) {
-               if (tdb_rec_free_read(tdb, bestfit.rec_ptr, rec) == -1) {
-                       goto fail;
-               }
-
-               newrec_ptr = tdb_allocate_ofs(tdb, length, bestfit.rec_ptr, 
-                                             rec, bestfit.last_ptr);
-               tdb_unlock(tdb, -1, F_WRLCK);
-               return newrec_ptr;
-       }
-
-       /* we didn't find enough space. See if we can expand the
-          database and if we can then try again */
-       if (tdb_expand(tdb, length + sizeof(*rec)) == 0)
-               goto again;
- fail:
-       tdb_unlock(tdb, -1, F_WRLCK);
-       return 0;
-}
-
-
-
-/* 
-   return the size of the freelist - used to decide if we should repack 
-*/
-int tdb_freelist_size(struct tdb_context *tdb)
-{
-       tdb_off_t ptr;
-       int count=0;
-
-       if (tdb_lock(tdb, -1, F_RDLCK) == -1) {
-               return -1;
-       }
-
-       ptr = FREELIST_TOP;
-       while (tdb_ofs_read(tdb, ptr, &ptr) == 0 && ptr != 0) {
-               count++;
-       }
-
-       tdb_unlock(tdb, -1, F_RDLCK);
-       return count;
-}
diff --git a/ccan/tdb/freelistcheck.c b/ccan/tdb/freelistcheck.c
deleted file mode 100644 (file)
index 5afcaa2..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
-   Unix SMB/CIFS implementation.
-
-   trivial database library
-
-   Copyright (C) Jeremy Allison                    2006
-
-     ** NOTE! The following LGPL license applies to the tdb
-     ** library. This does NOT imply that all of Samba is released
-     ** under the LGPL
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "tdb_private.h"
-
-/* Check the freelist is good and contains no loops.
-   Very memory intensive - only do this as a consistency
-   checker. Heh heh - uses an in memory tdb as the storage
-   for the "seen" record list. For some reason this strikes
-   me as extremely clever as I don't have to write another tree
-   data structure implementation :-).
- */
-
-static int seen_insert(struct tdb_context *mem_tdb, tdb_off_t rec_ptr)
-{
-       TDB_DATA key, data;
-
-       memset(&data, '\0', sizeof(data));
-       key.dptr = (unsigned char *)&rec_ptr;
-       key.dsize = sizeof(rec_ptr);
-       return tdb_store(mem_tdb, key, data, TDB_INSERT);
-}
-
-int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries)
-{
-       struct tdb_context *mem_tdb = NULL;
-       struct tdb_record rec;
-       tdb_off_t rec_ptr;
-       int ret = -1;
-
-       *pnum_entries = 0;
-
-       mem_tdb = tdb_open("flval", tdb->header.hash_size,
-                               TDB_INTERNAL, O_RDWR, 0600);
-       if (!mem_tdb) {
-               return -1;
-       }
-
-       if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
-               tdb_close(mem_tdb);
-               return 0;
-       }
-
-       /* Store the FREELIST_TOP record. */
-       if (seen_insert(mem_tdb, FREELIST_TOP) == -1) {
-               tdb->ecode = TDB_ERR_CORRUPT;
-               ret = -1;
-               goto fail;
-       }
-
-       /* read in the freelist top */
-       if (tdb_ofs_read(tdb, FREELIST_TOP, &rec_ptr) == -1) {
-               goto fail;
-       }
-
-       while (rec_ptr) {
-
-               /* If we can't store this record (we've seen it
-                  before) then the free list has a loop and must
-                  be corrupt. */
-
-               if (seen_insert(mem_tdb, rec_ptr)) {
-                       tdb->ecode = TDB_ERR_CORRUPT;
-                       ret = -1;
-                       goto fail;
-               }
-
-               if (tdb_rec_free_read(tdb, rec_ptr, &rec) == -1) {
-                       goto fail;
-               }
-
-               /* move to the next record */
-               rec_ptr = rec.next;
-               *pnum_entries += 1;
-       }
-
-       ret = 0;
-
-  fail:
-
-       tdb_close(mem_tdb);
-       tdb_unlock(tdb, -1, F_WRLCK);
-       return ret;
-}
diff --git a/ccan/tdb/hash.c b/ccan/tdb/hash.c
deleted file mode 100644 (file)
index 5d920bb..0000000
+++ /dev/null
@@ -1,382 +0,0 @@
- /*
-   Unix SMB/CIFS implementation.
-
-   trivial database library
-
-   Copyright (C) Rusty Russell            2010
-
-     ** NOTE! The following LGPL license applies to the tdb
-     ** library. This does NOT imply that all of Samba is released
-     ** under the LGPL
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-#include "tdb_private.h"
-
-/* This is based on the hash algorithm from gdbm */
-unsigned int tdb_old_hash(TDB_DATA *key)
-{
-       uint32_t value; /* Used to compute the hash value.  */
-       uint32_t   i;   /* Used to cycle through random values. */
-
-       /* Set the initial value from the key size. */
-       for (value = 0x238F13AF * key->dsize, i=0; i < key->dsize; i++)
-               value = (value + (key->dptr[i] << (i*5 % 24)));
-
-       return (1103515243 * value + 12345);  
-}
-
-#if HAVE_LITTLE_ENDIAN
-# define HASH_LITTLE_ENDIAN 1
-# define HASH_BIG_ENDIAN 0
-#elif HAVE_BIG_ENDIAN
-# define HASH_LITTLE_ENDIAN 0
-# define HASH_BIG_ENDIAN 1
-#else
-# error Unknown endian
-#endif
-
-/*
--------------------------------------------------------------------------------
-lookup3.c, by Bob Jenkins, May 2006, Public Domain.
-
-These are functions for producing 32-bit hashes for hash table lookup.
-hash_word(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() 
-are externally useful functions.  Routines to test the hash are included 
-if SELF_TEST is defined.  You can use this free for any purpose.  It's in
-the public domain.  It has no warranty.
-
-You probably want to use hashlittle().  hashlittle() and hashbig()
-hash byte arrays.  hashlittle() is is faster than hashbig() on
-little-endian machines.  Intel and AMD are little-endian machines.
-On second thought, you probably want hashlittle2(), which is identical to
-hashlittle() except it returns two 32-bit hashes for the price of one.  
-You could implement hashbig2() if you wanted but I haven't bothered here.
-
-If you want to find a hash of, say, exactly 7 integers, do
-  a = i1;  b = i2;  c = i3;
-  mix(a,b,c);
-  a += i4; b += i5; c += i6;
-  mix(a,b,c);
-  a += i7;
-  final(a,b,c);
-then use c as the hash value.  If you have a variable length array of
-4-byte integers to hash, use hash_word().  If you have a byte array (like
-a character string), use hashlittle().  If you have several byte arrays, or
-a mix of things, see the comments above hashlittle().  
-
-Why is this so big?  I read 12 bytes at a time into 3 4-byte integers, 
-then mix those integers.  This is fast (you can do a lot more thorough
-mixing with 12*3 instructions on 3 integers than you can with 3 instructions
-on 1 byte), but shoehorning those bytes into integers efficiently is messy.
-*/
-
-#define hashsize(n) ((uint32_t)1<<(n))
-#define hashmask(n) (hashsize(n)-1)
-#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
-
-/*
--------------------------------------------------------------------------------
-mix -- mix 3 32-bit values reversibly.
-
-This is reversible, so any information in (a,b,c) before mix() is
-still in (a,b,c) after mix().
-
-If four pairs of (a,b,c) inputs are run through mix(), or through
-mix() in reverse, there are at least 32 bits of the output that
-are sometimes the same for one pair and different for another pair.
-This was tested for:
-* pairs that differed by one bit, by two bits, in any combination
-  of top bits of (a,b,c), or in any combination of bottom bits of
-  (a,b,c).
-* "differ" is defined as +, -, ^, or ~^.  For + and -, I transformed
-  the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
-  is commonly produced by subtraction) look like a single 1-bit
-  difference.
-* the base values were pseudorandom, all zero but one bit set, or 
-  all zero plus a counter that starts at zero.
-
-Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that
-satisfy this are
-    4  6  8 16 19  4
-    9 15  3 18 27 15
-   14  9  3  7 17  3
-Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing
-for "differ" defined as + with a one-bit base and a two-bit delta.  I
-used http://burtleburtle.net/bob/hash/avalanche.html to choose 
-the operations, constants, and arrangements of the variables.
-
-This does not achieve avalanche.  There are input bits of (a,b,c)
-that fail to affect some output bits of (a,b,c), especially of a.  The
-most thoroughly mixed value is c, but it doesn't really even achieve
-avalanche in c.
-
-This allows some parallelism.  Read-after-writes are good at doubling
-the number of bits affected, so the goal of mixing pulls in the opposite
-direction as the goal of parallelism.  I did what I could.  Rotates
-seem to cost as much as shifts on every machine I could lay my hands
-on, and rotates are much kinder to the top and bottom bits, so I used
-rotates.
--------------------------------------------------------------------------------
-*/
-#define mix(a,b,c) \
-{ \
-  a -= c;  a ^= rot(c, 4);  c += b; \
-  b -= a;  b ^= rot(a, 6);  a += c; \
-  c -= b;  c ^= rot(b, 8);  b += a; \
-  a -= c;  a ^= rot(c,16);  c += b; \
-  b -= a;  b ^= rot(a,19);  a += c; \
-  c -= b;  c ^= rot(b, 4);  b += a; \
-}
-
-/*
--------------------------------------------------------------------------------
-final -- final mixing of 3 32-bit values (a,b,c) into c
-
-Pairs of (a,b,c) values differing in only a few bits will usually
-produce values of c that look totally different.  This was tested for
-* pairs that differed by one bit, by two bits, in any combination
-  of top bits of (a,b,c), or in any combination of bottom bits of
-  (a,b,c).
-* "differ" is defined as +, -, ^, or ~^.  For + and -, I transformed
-  the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
-  is commonly produced by subtraction) look like a single 1-bit
-  difference.
-* the base values were pseudorandom, all zero but one bit set, or 
-  all zero plus a counter that starts at zero.
-
-These constants passed:
- 14 11 25 16 4 14 24
- 12 14 25 16 4 14 24
-and these came close:
-  4  8 15 26 3 22 24
- 10  8 15 26 3 22 24
- 11  8 15 26 3 22 24
--------------------------------------------------------------------------------
-*/
-#define final(a,b,c) \
-{ \
-  c ^= b; c -= rot(b,14); \
-  a ^= c; a -= rot(c,11); \
-  b ^= a; b -= rot(a,25); \
-  c ^= b; c -= rot(b,16); \
-  a ^= c; a -= rot(c,4);  \
-  b ^= a; b -= rot(a,14); \
-  c ^= b; c -= rot(b,24); \
-}
-
-
-/*
--------------------------------------------------------------------------------
-hashlittle() -- hash a variable-length key into a 32-bit value
-  k       : the key (the unaligned variable-length array of bytes)
-  length  : the length of the key, counting by bytes
-  val2    : IN: can be any 4-byte value OUT: second 32 bit hash.
-Returns a 32-bit value.  Every bit of the key affects every bit of
-the return value.  Two keys differing by one or two bits will have
-totally different hash values.  Note that the return value is better
-mixed than val2, so use that first.
-
-The best hash table sizes are powers of 2.  There is no need to do
-mod a prime (mod is sooo slow!).  If you need less than 32 bits,
-use a bitmask.  For example, if you need only 10 bits, do
-  h = (h & hashmask(10));
-In which case, the hash table should have hashsize(10) elements.
-
-If you are hashing n strings (uint8_t **)k, do it like this:
-  for (i=0, h=0; i<n; ++i) h = hashlittle( k[i], len[i], h);
-
-By Bob Jenkins, 2006.  bob_jenkins@burtleburtle.net.  You may use this
-code any way you wish, private, educational, or commercial.  It's free.
-
-Use for hash table lookup, or anything where one collision in 2^^32 is
-acceptable.  Do NOT use for cryptographic purposes.
--------------------------------------------------------------------------------
-*/
-
-static uint32_t hashlittle( const void *key, size_t length )
-{
-  uint32_t a,b,c;                                          /* internal state */
-  union { const void *ptr; size_t i; } u;     /* needed for Mac Powerbook G4 */
-
-  /* Set up the internal state */
-  a = b = c = 0xdeadbeef + ((uint32_t)length);
-
-  u.ptr = key;
-  if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
-    const uint32_t *k = (const uint32_t *)key;         /* read 32-bit chunks */
-#ifdef VALGRIND
-    const uint8_t  *k8;
-#endif
-
-    /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
-    while (length > 12)
-    {
-      a += k[0];
-      b += k[1];
-      c += k[2];
-      mix(a,b,c);
-      length -= 12;
-      k += 3;
-    }
-
-    /*----------------------------- handle the last (probably partial) block */
-    /* 
-     * "k[2]&0xffffff" actually reads beyond the end of the string, but
-     * then masks off the part it's not allowed to read.  Because the
-     * string is aligned, the masked-off tail is in the same word as the
-     * rest of the string.  Every machine with memory protection I've seen
-     * does it on word boundaries, so is OK with this.  But VALGRIND will
-     * still catch it and complain.  The masking trick does make the hash
-     * noticably faster for short strings (like English words).
-     */
-#ifndef VALGRIND
-
-    switch(length)
-    {
-    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
-    case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
-    case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
-    case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
-    case 8 : b+=k[1]; a+=k[0]; break;
-    case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
-    case 6 : b+=k[1]&0xffff; a+=k[0]; break;
-    case 5 : b+=k[1]&0xff; a+=k[0]; break;
-    case 4 : a+=k[0]; break;
-    case 3 : a+=k[0]&0xffffff; break;
-    case 2 : a+=k[0]&0xffff; break;
-    case 1 : a+=k[0]&0xff; break;
-    case 0 : return c;              /* zero length strings require no mixing */
-    }
-
-#else /* make valgrind happy */
-
-    k8 = (const uint8_t *)k;
-    switch(length)
-    {
-    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
-    case 11: c+=((uint32_t)k8[10])<<16;  /* fall through */
-    case 10: c+=((uint32_t)k8[9])<<8;    /* fall through */
-    case 9 : c+=k8[8];                   /* fall through */
-    case 8 : b+=k[1]; a+=k[0]; break;
-    case 7 : b+=((uint32_t)k8[6])<<16;   /* fall through */
-    case 6 : b+=((uint32_t)k8[5])<<8;    /* fall through */
-    case 5 : b+=k8[4];                   /* fall through */
-    case 4 : a+=k[0]; break;
-    case 3 : a+=((uint32_t)k8[2])<<16;   /* fall through */
-    case 2 : a+=((uint32_t)k8[1])<<8;    /* fall through */
-    case 1 : a+=k8[0]; break;
-    case 0 : return c;
-    }
-
-#endif /* !valgrind */
-
-  } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
-    const uint16_t *k = (const uint16_t *)key;         /* read 16-bit chunks */
-    const uint8_t  *k8;
-
-    /*--------------- all but last block: aligned reads and different mixing */
-    while (length > 12)
-    {
-      a += k[0] + (((uint32_t)k[1])<<16);
-      b += k[2] + (((uint32_t)k[3])<<16);
-      c += k[4] + (((uint32_t)k[5])<<16);
-      mix(a,b,c);
-      length -= 12;
-      k += 6;
-    }
-
-    /*----------------------------- handle the last (probably partial) block */
-    k8 = (const uint8_t *)k;
-    switch(length)
-    {
-    case 12: c+=k[4]+(((uint32_t)k[5])<<16);
-             b+=k[2]+(((uint32_t)k[3])<<16);
-             a+=k[0]+(((uint32_t)k[1])<<16);
-             break;
-    case 11: c+=((uint32_t)k8[10])<<16;     /* fall through */
-    case 10: c+=k[4];
-             b+=k[2]+(((uint32_t)k[3])<<16);
-             a+=k[0]+(((uint32_t)k[1])<<16);
-             break;
-    case 9 : c+=k8[8];                      /* fall through */
-    case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
-             a+=k[0]+(((uint32_t)k[1])<<16);
-             break;
-    case 7 : b+=((uint32_t)k8[6])<<16;      /* fall through */
-    case 6 : b+=k[2];
-             a+=k[0]+(((uint32_t)k[1])<<16);
-             break;
-    case 5 : b+=k8[4];                      /* fall through */
-    case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
-             break;
-    case 3 : a+=((uint32_t)k8[2])<<16;      /* fall through */
-    case 2 : a+=k[0];
-             break;
-    case 1 : a+=k8[0];
-             break;
-    case 0 : return c;                     /* zero length requires no mixing */
-    }
-
-  } else {                        /* need to read the key one byte at a time */
-    const uint8_t *k = (const uint8_t *)key;
-
-    /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
-    while (length > 12)
-    {
-      a += k[0];
-      a += ((uint32_t)k[1])<<8;
-      a += ((uint32_t)k[2])<<16;
-      a += ((uint32_t)k[3])<<24;
-      b += k[4];
-      b += ((uint32_t)k[5])<<8;
-      b += ((uint32_t)k[6])<<16;
-      b += ((uint32_t)k[7])<<24;
-      c += k[8];
-      c += ((uint32_t)k[9])<<8;
-      c += ((uint32_t)k[10])<<16;
-      c += ((uint32_t)k[11])<<24;
-      mix(a,b,c);
-      length -= 12;
-      k += 12;
-    }
-
-    /*-------------------------------- last block: affect all 32 bits of (c) */
-    switch(length)                   /* all the case statements fall through */
-    {
-    case 12: c+=((uint32_t)k[11])<<24;
-    case 11: c+=((uint32_t)k[10])<<16;
-    case 10: c+=((uint32_t)k[9])<<8;
-    case 9 : c+=k[8];
-    case 8 : b+=((uint32_t)k[7])<<24;
-    case 7 : b+=((uint32_t)k[6])<<16;
-    case 6 : b+=((uint32_t)k[5])<<8;
-    case 5 : b+=k[4];
-    case 4 : a+=((uint32_t)k[3])<<24;
-    case 3 : a+=((uint32_t)k[2])<<16;
-    case 2 : a+=((uint32_t)k[1])<<8;
-    case 1 : a+=k[0];
-             break;
-    case 0 : return c;
-    }
-  }
-
-  final(a,b,c);
-  return c;
-}
-
-unsigned int tdb_jenkins_hash(TDB_DATA *key)
-{
-       return hashlittle(key->dptr, key->dsize);
-}
diff --git a/ccan/tdb/io.c b/ccan/tdb/io.c
deleted file mode 100644 (file)
index 77f26ad..0000000
+++ /dev/null
@@ -1,504 +0,0 @@
- /* 
-   Unix SMB/CIFS implementation.
-
-   trivial database library
-
-   Copyright (C) Andrew Tridgell              1999-2005
-   Copyright (C) Paul `Rusty' Russell             2000
-   Copyright (C) Jeremy Allison                           2000-2003
-   
-     ** NOTE! The following LGPL license applies to the tdb
-     ** library. This does NOT imply that all of Samba is released
-     ** under the LGPL
-   
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "tdb_private.h"
-#ifndef MAX
-#define MAX(a,b) ((a) > (b) ? (a) : (b))
-#endif
-
-/* check for an out of bounds access - if it is out of bounds then
-   see if the database has been expanded by someone else and expand
-   if necessary 
-   note that "len" is the minimum length needed for the db
-*/
-static int tdb_oob(struct tdb_context *tdb, tdb_off_t len, int probe)
-{
-       struct stat st;
-       if (len <= tdb->map_size)
-               return 0;
-       if (tdb->flags & TDB_INTERNAL) {
-               if (!probe) {
-                       /* Ensure ecode is set for log fn. */
-                       tdb->ecode = TDB_ERR_IO;
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob len %d beyond internal malloc size %d\n",
-                                (int)len, (int)tdb->map_size));
-               }
-               return -1;
-       }
-
-       if (fstat(tdb->fd, &st) == -1) {
-               tdb->ecode = TDB_ERR_IO;
-               return -1;
-       }
-
-       if (st.st_size < (size_t)len) {
-               if (!probe) {
-                       /* Ensure ecode is set for log fn. */
-                       tdb->ecode = TDB_ERR_IO;
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob len %d beyond eof at %d\n",
-                                (int)len, (int)st.st_size));
-               }
-               return -1;
-       }
-
-       /* Unmap, update size, remap */
-       if (tdb_munmap(tdb) == -1) {
-               tdb->ecode = TDB_ERR_IO;
-               return -1;
-       }
-       tdb->map_size = st.st_size;
-       tdb_mmap(tdb);
-       return 0;
-}
-
-/* write a lump of data at a specified offset */
-static int tdb_write(struct tdb_context *tdb, tdb_off_t off, 
-                    const void *buf, tdb_len_t len)
-{
-       if (len == 0) {
-               return 0;
-       }
-
-       if (tdb->read_only || tdb->traverse_read) {
-               tdb->ecode = TDB_ERR_RDONLY;
-               return -1;
-       }
-
-       if (tdb->methods->tdb_oob(tdb, off + len, 0) != 0)
-               return -1;
-
-       if (tdb->map_ptr) {
-               memcpy(off + (char *)tdb->map_ptr, buf, len);
-       } else {
-               ssize_t written = pwrite(tdb->fd, buf, len, off);
-               if ((written != (ssize_t)len) && (written != -1)) {
-                       /* try once more */
-                       tdb->ecode = TDB_ERR_IO;
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_write: wrote only "
-                                "%d of %d bytes at %d, trying once more\n",
-                                (int)written, len, off));
-                       written = pwrite(tdb->fd, (const char *)buf+written,
-                                        len-written,
-                                        off+written);
-               }
-               if (written == -1) {
-                       /* Ensure ecode is set for log fn. */
-                       tdb->ecode = TDB_ERR_IO;
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_write failed at %d "
-                                "len=%d (%s)\n", off, len, strerror(errno)));
-                       return -1;
-               } else if (written != (ssize_t)len) {
-                       tdb->ecode = TDB_ERR_IO;
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_write: failed to "
-                                "write %d bytes at %d in two attempts\n",
-                                len, off));
-                       return -1;
-               }
-       }
-       return 0;
-}
-
-/* Endian conversion: we only ever deal with 4 byte quantities */
-void *tdb_convert(void *buf, uint32_t size)
-{
-       uint32_t i;
-       unsigned char *p = buf, tmp;
-
-       for (i = 0; i < size; i += 4) {
-               tmp = p[i];
-               p[i] = p[i+3];
-               p[i+3] = tmp;
-               tmp = p[i+1];
-               p[i+1] = p[i+2];
-               p[i+2] = tmp;
-       }
-       return buf;
-}
-
-
-/* read a lump of data at a specified offset, maybe convert */
-static int tdb_read(struct tdb_context *tdb, tdb_off_t off, void *buf, 
-                   tdb_len_t len, int cv)
-{
-       if (tdb->methods->tdb_oob(tdb, off + len, 0) != 0) {
-               return -1;
-       }
-
-       if (tdb->map_ptr) {
-               memcpy(buf, off + (char *)tdb->map_ptr, len);
-       } else {
-               ssize_t ret = pread(tdb->fd, buf, len, off);
-               if (ret != (ssize_t)len) {
-                       /* Ensure ecode is set for log fn. */
-                       tdb->ecode = TDB_ERR_IO;
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_read failed at %d "
-                                "len=%d ret=%d (%s) map_size=%d\n",
-                                (int)off, (int)len, (int)ret, strerror(errno),
-                                (int)tdb->map_size));
-                       return -1;
-               }
-       }
-       if (cv) {
-               tdb_convert(buf, len);
-       }
-       return 0;
-}
-
-
-
-/*
-  do an unlocked scan of the hash table heads to find the next non-zero head. The value
-  will then be confirmed with the lock held
-*/             
-static void tdb_next_hash_chain(struct tdb_context *tdb, uint32_t *chain)
-{
-       uint32_t h = *chain;
-       if (tdb->map_ptr) {
-               for (;h < tdb->header.hash_size;h++) {
-                       if (0 != *(uint32_t *)(TDB_HASH_TOP(h) + (unsigned char *)tdb->map_ptr)) {
-                               break;
-                       }
-               }
-       } else {
-               uint32_t off=0;
-               for (;h < tdb->header.hash_size;h++) {
-                       if (tdb_ofs_read(tdb, TDB_HASH_TOP(h), &off) != 0 || off != 0) {
-                               break;
-                       }
-               }
-       }
-       (*chain) = h;
-}
-
-
-int tdb_munmap(struct tdb_context *tdb)
-{
-       if (tdb->flags & TDB_INTERNAL)
-               return 0;
-
-#if HAVE_MMAP
-       if (tdb->map_ptr) {
-               int ret;
-
-               ret = munmap(tdb->map_ptr, tdb->map_size);
-               if (ret != 0)
-                       return ret;
-       }
-#endif
-       tdb->map_ptr = NULL;
-       return 0;
-}
-
-void tdb_mmap(struct tdb_context *tdb)
-{
-       if (tdb->flags & TDB_INTERNAL)
-               return;
-
-#if HAVE_MMAP
-       if (!(tdb->flags & TDB_NOMMAP)) {
-               tdb->map_ptr = mmap(NULL, tdb->map_size, 
-                                   PROT_READ|(tdb->read_only? 0:PROT_WRITE), 
-                                   MAP_SHARED, tdb->fd, 0);
-
-               /*
-                * NB. When mmap fails it returns MAP_FAILED *NOT* NULL !!!!
-                */
-
-               if (tdb->map_ptr == MAP_FAILED) {
-                       tdb->map_ptr = NULL;
-                       TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_mmap failed for size %d (%s)\n", 
-                                tdb->map_size, strerror(errno)));
-               }
-       } else {
-               tdb->map_ptr = NULL;
-       }
-#else
-       tdb->map_ptr = NULL;
-#endif
-}
-
-/* expand a file.  we prefer to use ftruncate, as that is what posix
-  says to use for mmap expansion */
-static int tdb_expand_file(struct tdb_context *tdb, tdb_off_t size, tdb_off_t addition)
-{
-       char buf[8192];
-
-       if (tdb->read_only || tdb->traverse_read) {
-               tdb->ecode = TDB_ERR_RDONLY;
-               return -1;
-       }
-
-       if (ftruncate(tdb->fd, size+addition) == -1) {
-               char b = 0;
-               ssize_t written = pwrite(tdb->fd,  &b, 1, (size+addition) - 1);
-               if (written == 0) {
-                       /* try once more, potentially revealing errno */
-                       written = pwrite(tdb->fd,  &b, 1, (size+addition) - 1);
-               }
-               if (written == 0) {
-                       /* again - give up, guessing errno */
-                       errno = ENOSPC;
-               }
-               if (written != 1) {
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file to %d failed (%s)\n", 
-                                size+addition, strerror(errno)));
-                       return -1;
-               }
-       }
-
-       /* now fill the file with something. This ensures that the
-          file isn't sparse, which would be very bad if we ran out of
-          disk. This must be done with write, not via mmap */
-       memset(buf, TDB_PAD_BYTE, sizeof(buf));
-       while (addition) {
-               size_t n = addition>sizeof(buf)?sizeof(buf):addition;
-               ssize_t written = pwrite(tdb->fd, buf, n, size);
-               if (written == 0) {
-                       /* prevent infinite loops: try _once_ more */
-                       written = pwrite(tdb->fd, buf, n, size);
-               }
-               if (written == 0) {
-                       /* give up, trying to provide a useful errno */
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write "
-                               "returned 0 twice: giving up!\n"));
-                       errno = ENOSPC;
-                       return -1;
-               } else if (written == -1) {
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write of "
-                                "%d bytes failed (%s)\n", (int)n,
-                                strerror(errno)));
-                       return -1;
-               } else if (written != n) {
-                       TDB_LOG((tdb, TDB_DEBUG_WARNING, "expand_file: wrote "
-                                "only %d of %d bytes - retrying\n", (int)written,
-                                (int)n));
-               }
-               addition -= written;
-               size += written;
-       }
-       return 0;
-}
-
-/* You need 'size', this tells you how much you should expand by. */
-tdb_off_t tdb_expand_adjust(tdb_off_t map_size, tdb_off_t size, int page_size)
-{
-       tdb_off_t new_size, top_size;
-
-       /* limit size in order to avoid using up huge amounts of memory for
-        * in memory tdbs if an oddball huge record creeps in */
-       if (size > 100 * 1024) {
-               top_size = map_size + size * 2;
-       } else {
-               top_size = map_size + size * 100;
-       }
-
-       /* always make room for at least top_size more records, and at
-          least 25% more space. if the DB is smaller than 100MiB,
-          otherwise grow it by 10% only. */
-       if (map_size > 100 * 1024 * 1024) {
-               new_size = map_size * 1.10;
-       } else {
-               new_size = map_size * 1.25;
-       }
-
-       /* Round the database up to a multiple of the page size */
-       new_size = MAX(top_size, new_size);
-       return TDB_ALIGN(new_size, page_size) - map_size;
-}
-
-/* expand the database at least size bytes by expanding the underlying
-   file and doing the mmap again if necessary */
-int tdb_expand(struct tdb_context *tdb, tdb_off_t size)
-{
-       struct tdb_record rec;
-       tdb_off_t offset;
-
-       if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_ERROR, "lock failed in tdb_expand\n"));
-               return -1;
-       }
-
-       /* must know about any previous expansions by another process */
-       tdb->methods->tdb_oob(tdb, tdb->map_size + 1, 1);
-
-       size = tdb_expand_adjust(tdb->map_size, size, tdb->page_size);
-
-       if (!(tdb->flags & TDB_INTERNAL))
-               tdb_munmap(tdb);
-
-       /*
-        * We must ensure the file is unmapped before doing this
-        * to ensure consistency with systems like OpenBSD where
-        * writes and mmaps are not consistent.
-        */
-
-       /* expand the file itself */
-       if (!(tdb->flags & TDB_INTERNAL)) {
-               if (tdb->methods->tdb_expand_file(tdb, tdb->map_size, size) != 0)
-                       goto fail;
-       }
-
-       tdb->map_size += size;
-
-       if (tdb->flags & TDB_INTERNAL) {
-               char *new_map_ptr = (char *)realloc(tdb->map_ptr,
-                                                   tdb->map_size);
-               if (!new_map_ptr) {
-                       tdb->map_size -= size;
-                       goto fail;
-               }
-               tdb->map_ptr = new_map_ptr;
-       } else {
-               /*
-                * We must ensure the file is remapped before adding the space
-                * to ensure consistency with systems like OpenBSD where
-                * writes and mmaps are not consistent.
-                */
-
-               /* We're ok if the mmap fails as we'll fallback to read/write */
-               tdb_mmap(tdb);
-       }
-
-       /* form a new freelist record */
-       memset(&rec,'\0',sizeof(rec));
-       rec.rec_len = size - sizeof(rec);
-
-       /* link it into the free list */
-       offset = tdb->map_size - size;
-       if (tdb_free(tdb, offset, &rec) == -1)
-               goto fail;
-
-       tdb_unlock(tdb, -1, F_WRLCK);
-       return 0;
- fail:
-       tdb_unlock(tdb, -1, F_WRLCK);
-       return -1;
-}
-
-/* read/write a tdb_off_t */
-int tdb_ofs_read(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d)
-{
-       return tdb->methods->tdb_read(tdb, offset, (char*)d, sizeof(*d), DOCONV());
-}
-
-int tdb_ofs_write(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d)
-{
-       tdb_off_t off = *d;
-       return tdb->methods->tdb_write(tdb, offset, CONVERT(off), sizeof(*d));
-}
-
-
-/* read a lump of data, allocating the space for it */
-unsigned char *tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t len)
-{
-       unsigned char *buf;
-
-       /* some systems don't like zero length malloc */
-
-       if (!(buf = (unsigned char *)malloc(len ? len : 1))) {
-               /* Ensure ecode is set for log fn. */
-               tdb->ecode = TDB_ERR_OOM;
-               TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_alloc_read malloc failed len=%d (%s)\n",
-                          len, strerror(errno)));
-               return NULL;
-       }
-       if (tdb->methods->tdb_read(tdb, offset, buf, len, 0) == -1) {
-               SAFE_FREE(buf);
-               return NULL;
-       }
-       return buf;
-}
-
-/* Give a piece of tdb data to a parser */
-
-int tdb_parse_data(struct tdb_context *tdb, TDB_DATA key,
-                  tdb_off_t offset, tdb_len_t len,
-                  int (*parser)(TDB_DATA key, TDB_DATA data,
-                                void *private_data),
-                  void *private_data)
-{
-       TDB_DATA data;
-       int result;
-
-       data.dsize = len;
-
-       if ((tdb->transaction == NULL) && (tdb->map_ptr != NULL)) {
-               /*
-                * Optimize by avoiding the malloc/memcpy/free, point the
-                * parser directly at the mmap area.
-                */
-               if (tdb->methods->tdb_oob(tdb, offset+len, 0) != 0) {
-                       return -1;
-               }
-               data.dptr = offset + (unsigned char *)tdb->map_ptr;
-               return parser(key, data, private_data);
-       }
-
-       if (!(data.dptr = tdb_alloc_read(tdb, offset, len))) {
-               return -1;
-       }
-
-       result = parser(key, data, private_data);
-       free(data.dptr);
-       return result;
-}
-
-/* read/write a record */
-int tdb_rec_read(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec)
-{
-       if (tdb->methods->tdb_read(tdb, offset, rec, sizeof(*rec),DOCONV()) == -1)
-               return -1;
-       if (TDB_BAD_MAGIC(rec)) {
-               /* Ensure ecode is set for log fn. */
-               tdb->ecode = TDB_ERR_CORRUPT;
-               TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_rec_read bad magic 0x%x at offset=%d\n", rec->magic, offset));
-               return -1;
-       }
-       return tdb->methods->tdb_oob(tdb, rec->next+sizeof(*rec), 0);
-}
-
-int tdb_rec_write(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec)
-{
-       struct tdb_record r = *rec;
-       return tdb->methods->tdb_write(tdb, offset, CONVERT(r), sizeof(r));
-}
-
-static const struct tdb_methods io_methods = {
-       tdb_read,
-       tdb_write,
-       tdb_next_hash_chain,
-       tdb_oob,
-       tdb_expand_file,
-};
-
-/*
-  initialise the default methods table
-*/
-void tdb_io_init(struct tdb_context *tdb)
-{
-       tdb->methods = &io_methods;
-}
diff --git a/ccan/tdb/lock.c b/ccan/tdb/lock.c
deleted file mode 100644 (file)
index dfcac7a..0000000
+++ /dev/null
@@ -1,865 +0,0 @@
- /* 
-   Unix SMB/CIFS implementation.
-
-   trivial database library
-
-   Copyright (C) Andrew Tridgell              1999-2005
-   Copyright (C) Paul `Rusty' Russell             2000
-   Copyright (C) Jeremy Allison                           2000-2003
-   
-     ** NOTE! The following LGPL license applies to the tdb
-     ** library. This does NOT imply that all of Samba is released
-     ** under the LGPL
-   
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "tdb_private.h"
-
-void tdb_setalarm_sigptr(struct tdb_context *tdb, volatile sig_atomic_t *ptr)
-{
-       tdb->interrupt_sig_ptr = ptr;
-}
-
-static int fcntl_lock(struct tdb_context *tdb,
-                     int rw, off_t off, off_t len, bool waitflag)
-{
-       struct flock fl;
-
-       fl.l_type = rw;
-       fl.l_whence = SEEK_SET;
-       fl.l_start = off;
-       fl.l_len = len;
-       fl.l_pid = 0;
-
-       if (waitflag)
-               return fcntl(tdb->fd, F_SETLKW, &fl);
-       else
-               return fcntl(tdb->fd, F_SETLK, &fl);
-}
-
-static int fcntl_unlock(struct tdb_context *tdb, int rw, off_t off, off_t len)
-{
-       struct flock fl;
-#if 0 /* Check they matched up locks and unlocks correctly. */
-       char line[80];
-       FILE *locks;
-       bool found = false;
-
-       locks = fopen("/proc/locks", "r");
-
-       while (fgets(line, 80, locks)) {
-               char *p;
-               int type, start, l;
-
-               /* eg. 1: FLOCK  ADVISORY  WRITE 2440 08:01:2180826 0 EOF */
-               p = strchr(line, ':') + 1;
-               if (strncmp(p, " POSIX  ADVISORY  ", strlen(" POSIX  ADVISORY  ")))
-                       continue;
-               p += strlen(" FLOCK  ADVISORY  ");
-               if (strncmp(p, "READ  ", strlen("READ  ")) == 0)
-                       type = F_RDLCK;
-               else if (strncmp(p, "WRITE ", strlen("WRITE ")) == 0)
-                       type = F_WRLCK;
-               else
-                       abort();
-               p += 6;
-               if (atoi(p) != getpid())
-                       continue;
-               p = strchr(strchr(p, ' ') + 1, ' ') + 1;
-               start = atoi(p);
-               p = strchr(p, ' ') + 1;
-               if (strncmp(p, "EOF", 3) == 0)
-                       l = 0;
-               else
-                       l = atoi(p) - start + 1;
-
-               if (off == start) {
-                       if (len != l) {
-                               fprintf(stderr, "Len %u should be %u: %s",
-                                       (int)len, l, line);
-                               abort();
-                       }
-                       if (type != rw) {
-                               fprintf(stderr, "Type %s wrong: %s",
-                                       rw == F_RDLCK ? "READ" : "WRITE", line);
-                               abort();
-                       }
-                       found = true;
-                       break;
-               }
-       }
-
-       if (!found) {
-               fprintf(stderr, "Unlock on %u@%u not found!\n",
-                       (int)off, (int)len);
-               abort();
-       }
-
-       fclose(locks);
-#endif
-
-       fl.l_type = F_UNLCK;
-       fl.l_whence = SEEK_SET;
-       fl.l_start = off;
-       fl.l_len = len;
-       fl.l_pid = 0;
-
-       return fcntl(tdb->fd, F_SETLKW, &fl);
-}
-
-/* list -1 is the alloc list, otherwise a hash chain. */
-static tdb_off_t lock_offset(int list)
-{
-       return FREELIST_TOP + 4*list;
-}
-
-/* a byte range locking function - return 0 on success
-   this functions locks/unlocks 1 byte at the specified offset.
-
-   On error, errno is also set so that errors are passed back properly
-   through tdb_open(). 
-
-   note that a len of zero means lock to end of file
-*/
-int tdb_brlock(struct tdb_context *tdb,
-              int rw_type, tdb_off_t offset, size_t len,
-              enum tdb_lock_flags flags)
-{
-       int ret;
-
-       if (tdb->flags & TDB_NOLOCK) {
-               return 0;
-       }
-
-       if (flags & TDB_LOCK_MARK_ONLY) {
-               return 0;
-       }
-
-       if ((rw_type == F_WRLCK) && (tdb->read_only || tdb->traverse_read)) {
-               tdb->ecode = TDB_ERR_RDONLY;
-               return -1;
-       }
-
-       do {
-               ret = fcntl_lock(tdb, rw_type, offset, len,
-                                flags & TDB_LOCK_WAIT);
-               /* Check for a sigalarm break. */
-               if (ret == -1 && errno == EINTR &&
-                               tdb->interrupt_sig_ptr &&
-                               *tdb->interrupt_sig_ptr) {
-                       break;
-               }
-       } while (ret == -1 && errno == EINTR);
-
-       if (ret == -1) {
-               tdb->ecode = TDB_ERR_LOCK;
-               /* Generic lock error. errno set by fcntl.
-                * EAGAIN is an expected return from non-blocking
-                * locks. */
-               if (!(flags & TDB_LOCK_PROBE) && errno != EAGAIN) {
-                       TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brlock failed (fd=%d) at offset %d rw_type=%d flags=%d len=%d\n",
-                                tdb->fd, offset, rw_type, flags, (int)len));
-               }
-               return -1;
-       }
-       return 0;
-}
-
-int tdb_brunlock(struct tdb_context *tdb,
-                int rw_type, tdb_off_t offset, size_t len)
-{
-       int ret;
-
-       if (tdb->flags & TDB_NOLOCK) {
-               return 0;
-       }
-
-       do {
-               ret = fcntl_unlock(tdb, rw_type, offset, len);
-       } while (ret == -1 && errno == EINTR);
-
-       if (ret == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brunlock failed (fd=%d) at offset %d rw_type=%d len=%d\n",
-                        tdb->fd, offset, rw_type, (int)len));
-       }
-       return ret;
-}
-
-/*
-  upgrade a read lock to a write lock. This needs to be handled in a
-  special way as some OSes (such as solaris) have too conservative
-  deadlock detection and claim a deadlock when progress can be
-  made. For those OSes we may loop for a while.  
-*/
-int tdb_allrecord_upgrade(struct tdb_context *tdb)
-{
-       int count = 1000;
-
-       if (tdb->allrecord_lock.count != 1) {
-               TDB_LOG((tdb, TDB_DEBUG_ERROR,
-                        "tdb_allrecord_upgrade failed: count %u too high\n",
-                        tdb->allrecord_lock.count));
-               return -1;
-       }
-
-       if (tdb->allrecord_lock.off != 1) {
-               TDB_LOG((tdb, TDB_DEBUG_ERROR,
-                        "tdb_allrecord_upgrade failed: already upgraded?\n"));
-               return -1;
-       }
-
-       while (count--) {
-               struct timeval tv;
-               if (tdb_brlock(tdb, F_WRLCK, FREELIST_TOP, 0,
-                              TDB_LOCK_WAIT|TDB_LOCK_PROBE) == 0) {
-                       tdb->allrecord_lock.ltype = F_WRLCK;
-                       tdb->allrecord_lock.off = 0;
-                       return 0;
-               }
-               if (errno != EDEADLK) {
-                       break;
-               }
-               /* sleep for as short a time as we can - more portable than usleep() */
-               tv.tv_sec = 0;
-               tv.tv_usec = 1;
-               select(0, NULL, NULL, NULL, &tv);
-       }
-       TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_allrecord_upgrade failed\n"));
-       return -1;
-}
-
-static struct tdb_lock_type *find_nestlock(struct tdb_context *tdb,
-                                          tdb_off_t offset)
-{
-       unsigned int i;
-
-       for (i=0; i<tdb->num_lockrecs; i++) {
-               if (tdb->lockrecs[i].off == offset) {
-                       return &tdb->lockrecs[i];
-               }
-       }
-       return NULL;
-}
-
-/* lock an offset in the database. */
-int tdb_nest_lock(struct tdb_context *tdb, uint32_t offset, int ltype,
-                 enum tdb_lock_flags flags)
-{
-       struct tdb_lock_type *new_lck;
-
-       if (offset >= lock_offset(tdb->header.hash_size)) {
-               tdb->ecode = TDB_ERR_LOCK;
-               TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_lock: invalid offset %u for ltype=%d\n",
-                        offset, ltype));
-               return -1;
-       }
-       if (tdb->flags & TDB_NOLOCK)
-               return 0;
-
-       new_lck = find_nestlock(tdb, offset);
-       if (new_lck) {
-               /*
-                * Just increment the in-memory struct, posix locks
-                * don't stack.
-                */
-               new_lck->count++;
-               return 0;
-       }
-
-       new_lck = (struct tdb_lock_type *)realloc(
-               tdb->lockrecs,
-               sizeof(*tdb->lockrecs) * (tdb->num_lockrecs+1));
-       if (new_lck == NULL) {
-               errno = ENOMEM;
-               return -1;
-       }
-       tdb->lockrecs = new_lck;
-
-       /* Since fcntl locks don't nest, we do a lock for the first one,
-          and simply bump the count for future ones */
-       if (tdb_brlock(tdb, ltype, offset, 1, flags)) {
-               return -1;
-       }
-
-       tdb->lockrecs[tdb->num_lockrecs].off = offset;
-       tdb->lockrecs[tdb->num_lockrecs].count = 1;
-       tdb->lockrecs[tdb->num_lockrecs].ltype = ltype;
-       tdb->num_lockrecs++;
-
-       return 0;
-}
-
-static int tdb_lock_and_recover(struct tdb_context *tdb)
-{
-       int ret;
-
-       /* We need to match locking order in transaction commit. */
-       if (tdb_brlock(tdb, F_WRLCK, FREELIST_TOP, 0, TDB_LOCK_WAIT)) {
-               return -1;
-       }
-
-       if (tdb_brlock(tdb, F_WRLCK, OPEN_LOCK, 1, TDB_LOCK_WAIT)) {
-               tdb_brunlock(tdb, F_WRLCK, FREELIST_TOP, 0);
-               return -1;
-       }
-
-       ret = tdb_transaction_recover(tdb);
-
-       tdb_brunlock(tdb, F_WRLCK, OPEN_LOCK, 1);
-       tdb_brunlock(tdb, F_WRLCK, FREELIST_TOP, 0);
-
-       return ret;
-}
-
-static bool have_data_locks(const struct tdb_context *tdb)
-{
-       unsigned int i;
-
-       for (i = 0; i < tdb->num_lockrecs; i++) {
-               if (tdb->lockrecs[i].off >= lock_offset(-1))
-                       return true;
-       }
-       return false;
-}
-
-static int tdb_lock_list(struct tdb_context *tdb, int list, int ltype,
-                        enum tdb_lock_flags waitflag)
-{
-       int ret;
-       bool check = false;
-
-       /* a allrecord lock allows us to avoid per chain locks */
-       if (tdb->allrecord_lock.count &&
-           (ltype == tdb->allrecord_lock.ltype || ltype == F_RDLCK)) {
-               return 0;
-       }
-
-       if (tdb->allrecord_lock.count) {
-               tdb->ecode = TDB_ERR_LOCK;
-               ret = -1;
-       } else {
-               /* Only check when we grab first data lock. */
-               check = !have_data_locks(tdb);
-               ret = tdb_nest_lock(tdb, lock_offset(list), ltype, waitflag);
-
-               if (ret == 0 && check && tdb_needs_recovery(tdb)) {
-                       tdb_nest_unlock(tdb, lock_offset(list), ltype, false);
-
-                       if (tdb_lock_and_recover(tdb) == -1) {
-                               return -1;
-                       }
-                       return tdb_lock_list(tdb, list, ltype, waitflag);
-               }
-       }
-       return ret;
-}
-
-/* lock a list in the database. list -1 is the alloc list */
-int tdb_lock(struct tdb_context *tdb, int list, int ltype)
-{
-       int ret;
-
-       ret = tdb_lock_list(tdb, list, ltype, TDB_LOCK_WAIT);
-       if (ret) {
-               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lock failed on list %d "
-                        "ltype=%d (%s)\n",  list, ltype, strerror(errno)));
-       }
-       return ret;
-}
-
-/* lock a list in the database. list -1 is the alloc list. non-blocking lock */
-int tdb_lock_nonblock(struct tdb_context *tdb, int list, int ltype)
-{
-       return tdb_lock_list(tdb, list, ltype, TDB_LOCK_NOWAIT);
-}
-
-
-int tdb_nest_unlock(struct tdb_context *tdb, uint32_t offset, int ltype,
-                   bool mark_lock)
-{
-       int ret = -1;
-       struct tdb_lock_type *lck;
-
-       if (tdb->flags & TDB_NOLOCK)
-               return 0;
-
-       /* Sanity checks */
-       if (offset >= lock_offset(tdb->header.hash_size)) {
-               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: offset %u invalid (%d)\n", offset, tdb->header.hash_size));
-               return ret;
-       }
-
-       lck = find_nestlock(tdb, offset);
-       if ((lck == NULL) || (lck->count == 0)) {
-               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: count is 0\n"));
-               return -1;
-       }
-
-       if (lck->count > 1) {
-               lck->count--;
-               return 0;
-       }
-
-       /*
-        * This lock has count==1 left, so we need to unlock it in the
-        * kernel. We don't bother with decrementing the in-memory array
-        * element, we're about to overwrite it with the last array element
-        * anyway.
-        */
-
-       if (mark_lock) {
-               ret = 0;
-       } else {
-               ret = tdb_brunlock(tdb, ltype, offset, 1);
-       }
-
-       /*
-        * Shrink the array by overwriting the element just unlocked with the
-        * last array element.
-        */
-       *lck = tdb->lockrecs[--tdb->num_lockrecs];
-
-       /*
-        * We don't bother with realloc when the array shrinks, but if we have
-        * a completely idle tdb we should get rid of the locked array.
-        */
-
-       if (tdb->num_lockrecs == 0) {
-               SAFE_FREE(tdb->lockrecs);
-       }
-
-       if (ret)
-               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: An error occurred unlocking!\n")); 
-       return ret;
-}
-
-int tdb_unlock(struct tdb_context *tdb, int list, int ltype)
-{
-       /* a global lock allows us to avoid per chain locks */
-       if (tdb->allrecord_lock.count &&
-           (ltype == tdb->allrecord_lock.ltype || ltype == F_RDLCK)) {
-               return 0;
-       }
-
-       if (tdb->allrecord_lock.count) {
-               tdb->ecode = TDB_ERR_LOCK;
-               return -1;
-       }
-
-       return tdb_nest_unlock(tdb, lock_offset(list), ltype, false);
-}
-
-/*
-  get the transaction lock
- */
-int tdb_transaction_lock(struct tdb_context *tdb, int ltype)
-{
-       return tdb_nest_lock(tdb, TRANSACTION_LOCK, ltype, TDB_LOCK_WAIT);
-}
-
-/*
-  release the transaction lock
- */
-int tdb_transaction_unlock(struct tdb_context *tdb, int ltype)
-{
-       return tdb_nest_unlock(tdb, TRANSACTION_LOCK, ltype, false);
-}
-
-/* Returns 0 if all done, -1 if error, 1 if ok. */
-static int tdb_allrecord_check(struct tdb_context *tdb, int ltype,
-                              enum tdb_lock_flags flags, bool upgradable)
-{
-       /* There are no locks on read-only dbs */
-       if (tdb->read_only || tdb->traverse_read) {
-               tdb->ecode = TDB_ERR_LOCK;
-               return -1;
-       }
-
-       if (tdb->allrecord_lock.count && tdb->allrecord_lock.ltype == ltype) {
-               tdb->allrecord_lock.count++;
-               return 0;
-       }
-
-       if (tdb->allrecord_lock.count) {
-               /* a global lock of a different type exists */
-               tdb->ecode = TDB_ERR_LOCK;
-               return -1;
-       }
-
-       if (tdb_have_extra_locks(tdb)) {
-               /* can't combine global and chain locks */
-               tdb->ecode = TDB_ERR_LOCK;
-               return -1;
-       }
-
-       if (upgradable && ltype != F_RDLCK) {
-               /* tdb error: you can't upgrade a write lock! */
-               tdb->ecode = TDB_ERR_LOCK;
-               return -1;
-       }
-       return 1;
-}
-
-/* We only need to lock individual bytes, but Linux merges consecutive locks
- * so we lock in contiguous ranges. */
-static int tdb_chainlock_gradual(struct tdb_context *tdb,
-                                int ltype, enum tdb_lock_flags flags,
-                                size_t off, size_t len)
-{
-       int ret;
-       enum tdb_lock_flags nb_flags = (flags & ~TDB_LOCK_WAIT);
-
-       if (len <= 4) {
-               /* Single record.  Just do blocking lock. */
-               return tdb_brlock(tdb, ltype, off, len, flags);
-       }
-
-       /* First we try non-blocking. */
-       ret = tdb_brlock(tdb, ltype, off, len, nb_flags);
-       if (ret == 0) {
-               return 0;
-       }
-
-       /* Try locking first half, then second. */
-       ret = tdb_chainlock_gradual(tdb, ltype, flags, off, len / 2);
-       if (ret == -1)
-               return -1;
-
-       ret = tdb_chainlock_gradual(tdb, ltype, flags,
-                                   off + len / 2, len - len / 2);
-       if (ret == -1) {
-               tdb_brunlock(tdb, ltype, off, len / 2);
-               return -1;
-       }
-       return 0;
-}
-
-/* lock/unlock entire database.  It can only be upgradable if you have some
- * other way of guaranteeing exclusivity (ie. transaction write lock).
- * We do the locking gradually to avoid being starved by smaller locks. */
-int tdb_allrecord_lock(struct tdb_context *tdb, int ltype,
-                      enum tdb_lock_flags flags, bool upgradable)
-{
-       switch (tdb_allrecord_check(tdb, ltype, flags, upgradable)) {
-       case -1:
-               return -1;
-       case 0:
-               return 0;
-       }
-
-       /* We cover two kinds of locks:
-        * 1) Normal chain locks.  Taken for almost all operations.
-        * 3) Individual records locks.  Taken after normal or free
-        *    chain locks.
-        *
-        * It is (1) which cause the starvation problem, so we're only
-        * gradual for that. */
-       if (tdb_chainlock_gradual(tdb, ltype, flags, FREELIST_TOP,
-                                 tdb->header.hash_size * 4) == -1) {
-               return -1;
-       }
-
-       /* Grab individual record locks. */
-       if (tdb_brlock(tdb, ltype, lock_offset(tdb->header.hash_size), 0,
-                      flags) == -1) {
-               tdb_brunlock(tdb, ltype, FREELIST_TOP,
-                            tdb->header.hash_size * 4);
-               return -1;
-       }
-
-       tdb->allrecord_lock.count = 1;
-       /* If it's upgradable, it's actually exclusive so we can treat
-        * it as a write lock. */
-       tdb->allrecord_lock.ltype = upgradable ? F_WRLCK : ltype;
-       tdb->allrecord_lock.off = upgradable;
-
-       if (tdb_needs_recovery(tdb)) {
-               bool mark = flags & TDB_LOCK_MARK_ONLY;
-               tdb_allrecord_unlock(tdb, ltype, mark);
-               if (mark) {
-                       tdb->ecode = TDB_ERR_LOCK;
-                       TDB_LOG((tdb, TDB_DEBUG_ERROR,
-                                "tdb_lockall_mark cannot do recovery\n"));
-                       return -1;
-               }
-               if (tdb_lock_and_recover(tdb) == -1) {
-                       return -1;
-               }
-               return tdb_allrecord_lock(tdb, ltype, flags, upgradable);
-       }
-
-       return 0;
-}
-
-
-
-/* unlock entire db */
-int tdb_allrecord_unlock(struct tdb_context *tdb, int ltype, bool mark_lock)
-{
-       /* There are no locks on read-only dbs */
-       if (tdb->read_only || tdb->traverse_read) {
-               tdb->ecode = TDB_ERR_LOCK;
-               return -1;
-       }
-
-       if (tdb->allrecord_lock.count == 0) {
-               tdb->ecode = TDB_ERR_LOCK;
-               return -1;
-       }
-
-       /* Upgradable locks are marked as write locks. */
-       if (tdb->allrecord_lock.ltype != ltype
-           && (!tdb->allrecord_lock.off || ltype != F_RDLCK)) {
-               tdb->ecode = TDB_ERR_LOCK;
-               return -1;
-       }
-
-       if (tdb->allrecord_lock.count > 1) {
-               tdb->allrecord_lock.count--;
-               return 0;
-       }
-
-       if (!mark_lock && tdb_brunlock(tdb, ltype, FREELIST_TOP, 0)) {
-               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlockall failed (%s)\n", strerror(errno)));
-               return -1;
-       }
-
-       tdb->allrecord_lock.count = 0;
-       tdb->allrecord_lock.ltype = 0;
-
-       return 0;
-}
-
-/* lock entire database with write lock */
-int tdb_lockall(struct tdb_context *tdb)
-{
-       tdb_trace(tdb, "tdb_lockall");
-       return tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_WAIT, false);
-}
-
-/* lock entire database with write lock - mark only */
-int tdb_lockall_mark(struct tdb_context *tdb)
-{
-       tdb_trace(tdb, "tdb_lockall_mark");
-       return tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_MARK_ONLY, false);
-}
-
-/* unlock entire database with write lock - unmark only */
-int tdb_lockall_unmark(struct tdb_context *tdb)
-{
-       tdb_trace(tdb, "tdb_lockall_unmark");
-       return tdb_allrecord_unlock(tdb, F_WRLCK, true);
-}
-
-/* lock entire database with write lock - nonblocking varient */
-int tdb_lockall_nonblock(struct tdb_context *tdb)
-{
-       int ret = tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_NOWAIT, false);
-       tdb_trace_ret(tdb, "tdb_lockall_nonblock", ret);
-       return ret;
-}
-
-/* unlock entire database with write lock */
-int tdb_unlockall(struct tdb_context *tdb)
-{
-       tdb_trace(tdb, "tdb_unlockall");
-       return tdb_allrecord_unlock(tdb, F_WRLCK, false);
-}
-
-/* lock entire database with read lock */
-int tdb_lockall_read(struct tdb_context *tdb)
-{
-       tdb_trace(tdb, "tdb_lockall_read");
-       return tdb_allrecord_lock(tdb, F_RDLCK, TDB_LOCK_WAIT, false);
-}
-
-/* lock entire database with read lock - nonblock varient */
-int tdb_lockall_read_nonblock(struct tdb_context *tdb)
-{
-       int ret = tdb_allrecord_lock(tdb, F_RDLCK, TDB_LOCK_NOWAIT, false);
-       tdb_trace_ret(tdb, "tdb_lockall_read_nonblock", ret);
-       return ret;
-}
-
-/* unlock entire database with read lock */
-int tdb_unlockall_read(struct tdb_context *tdb)
-{
-       tdb_trace(tdb, "tdb_unlockall_read");
-       return tdb_allrecord_unlock(tdb, F_RDLCK, false);
-}
-
-/* lock/unlock one hash chain. This is meant to be used to reduce
-   contention - it cannot guarantee how many records will be locked */
-int tdb_chainlock(struct tdb_context *tdb, TDB_DATA key)
-{
-       int ret = tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK);
-       tdb_trace_1rec(tdb, "tdb_chainlock", key);
-       return ret;
-}
-
-/* lock/unlock one hash chain, non-blocking. This is meant to be used
-   to reduce contention - it cannot guarantee how many records will be
-   locked */
-int tdb_chainlock_nonblock(struct tdb_context *tdb, TDB_DATA key)
-{
-       int ret = tdb_lock_nonblock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK);
-       tdb_trace_1rec_ret(tdb, "tdb_chainlock_nonblock", key, ret);
-       return ret;
-}
-
-/* mark a chain as locked without actually locking it. Warning! use with great caution! */
-int tdb_chainlock_mark(struct tdb_context *tdb, TDB_DATA key)
-{
-       int ret = tdb_nest_lock(tdb, lock_offset(BUCKET(tdb->hash_fn(&key))),
-                               F_WRLCK, TDB_LOCK_MARK_ONLY);
-       tdb_trace_1rec(tdb, "tdb_chainlock_mark", key);
-       return ret;
-}
-
-/* unmark a chain as locked without actually locking it. Warning! use with great caution! */
-int tdb_chainlock_unmark(struct tdb_context *tdb, TDB_DATA key)
-{
-       tdb_trace_1rec(tdb, "tdb_chainlock_unmark", key);
-       return tdb_nest_unlock(tdb, lock_offset(BUCKET(tdb->hash_fn(&key))),
-                              F_WRLCK, true);
-}
-
-int tdb_chainunlock(struct tdb_context *tdb, TDB_DATA key)
-{
-       tdb_trace_1rec(tdb, "tdb_chainunlock", key);
-       return tdb_unlock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK);
-}
-
-int tdb_chainlock_read(struct tdb_context *tdb, TDB_DATA key)
-{
-       int ret;
-       ret = tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_RDLCK);
-       tdb_trace_1rec(tdb, "tdb_chainlock_read", key);
-       return ret;
-}
-
-int tdb_chainunlock_read(struct tdb_context *tdb, TDB_DATA key)
-{
-       tdb_trace_1rec(tdb, "tdb_chainunlock_read", key);
-       return tdb_unlock(tdb, BUCKET(tdb->hash_fn(&key)), F_RDLCK);
-}
-
-
-
-/* record lock stops delete underneath */
-int tdb_lock_record(struct tdb_context *tdb, tdb_off_t off)
-{
-       if (tdb->allrecord_lock.count) {
-               return 0;
-       }
-       return off ? tdb_brlock(tdb, F_RDLCK, off, 1, TDB_LOCK_WAIT) : 0;
-}
-
-/*
-  Write locks override our own fcntl readlocks, so check it here.
-  Note this is meant to be F_SETLK, *not* F_SETLKW, as it's not
-  an error to fail to get the lock here.
-*/
-int tdb_write_lock_record(struct tdb_context *tdb, tdb_off_t off)
-{
-       struct tdb_traverse_lock *i;
-       for (i = &tdb->travlocks; i; i = i->next)
-               if (i->off == off)
-                       return -1;
-       if (tdb->allrecord_lock.count) {
-               if (tdb->allrecord_lock.ltype == F_WRLCK) {
-                       return 0;
-               }
-               return -1;
-       }
-       return tdb_brlock(tdb, F_WRLCK, off, 1, TDB_LOCK_NOWAIT|TDB_LOCK_PROBE);
-}
-
-int tdb_write_unlock_record(struct tdb_context *tdb, tdb_off_t off)
-{
-       if (tdb->allrecord_lock.count) {
-               return 0;
-       }
-       return tdb_brunlock(tdb, F_WRLCK, off, 1);
-}
-
-/* fcntl locks don't stack: avoid unlocking someone else's */
-int tdb_unlock_record(struct tdb_context *tdb, tdb_off_t off)
-{
-       struct tdb_traverse_lock *i;
-       uint32_t count = 0;
-
-       if (tdb->allrecord_lock.count) {
-               return 0;
-       }
-
-       if (off == 0)
-               return 0;
-       for (i = &tdb->travlocks; i; i = i->next)
-               if (i->off == off)
-                       count++;
-       return (count == 1 ? tdb_brunlock(tdb, F_RDLCK, off, 1) : 0);
-}
-
-bool tdb_have_extra_locks(struct tdb_context *tdb)
-{
-       unsigned int extra = tdb->num_lockrecs;
-
-       /* A transaction holds the lock for all records. */
-       if (!tdb->transaction && tdb->allrecord_lock.count) {
-               return true;
-       }
-
-       /* We always hold the active lock if CLEAR_IF_FIRST. */
-       if (find_nestlock(tdb, ACTIVE_LOCK)) {
-               extra--;
-       }
-
-       /* In a transaction, we expect to hold the transaction lock */
-       if (tdb->transaction && find_nestlock(tdb, TRANSACTION_LOCK)) {
-               extra--;
-       }
-
-       return extra;
-}
-
-/* The transaction code uses this to remove all locks.  Note that this
-   may include OPEN_LOCK. */
-void tdb_release_extra_locks(struct tdb_context *tdb)
-{
-       unsigned int i, extra = 0;
-
-       if (tdb->allrecord_lock.count != 0) {
-               tdb_brunlock(tdb, tdb->allrecord_lock.ltype, FREELIST_TOP, 0);
-               tdb->allrecord_lock.count = 0;
-       }
-
-       for (i=0;i<tdb->num_lockrecs;i++) {
-               struct tdb_lock_type *lck = &tdb->lockrecs[i];
-
-               /* Don't release transaction or active locks! */
-               if (tdb->transaction && lck->off == TRANSACTION_LOCK) {
-                       tdb->lockrecs[extra++] = *lck;
-               } else if (lck->off == ACTIVE_LOCK) {
-                       tdb->lockrecs[extra++] = *lck;
-               } else {
-                       tdb_brunlock(tdb, lck->ltype, lck->off, 1);
-               }
-       }
-       tdb->num_lockrecs = extra;
-       if (tdb->num_lockrecs == 0) {
-               SAFE_FREE(tdb->lockrecs);
-       }
-}
diff --git a/ccan/tdb/open.c b/ccan/tdb/open.c
deleted file mode 100644 (file)
index aa97443..0000000
+++ /dev/null
@@ -1,617 +0,0 @@
- /* 
-   Unix SMB/CIFS implementation.
-
-   trivial database library
-
-   Copyright (C) Andrew Tridgell              1999-2005
-   Copyright (C) Paul `Rusty' Russell             2000
-   Copyright (C) Jeremy Allison                           2000-2003
-   
-     ** NOTE! The following LGPL license applies to the tdb
-     ** library. This does NOT imply that all of Samba is released
-     ** under the LGPL
-   
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "tdb_private.h"
-
-/* all contexts, to ensure no double-opens (fcntl locks don't nest!) */
-static struct tdb_context *tdbs = NULL;
-
-/* We use two hashes to double-check they're using the right hash function. */
-void tdb_header_hash(struct tdb_context *tdb,
-                    uint32_t *magic1_hash, uint32_t *magic2_hash)
-{
-       TDB_DATA hash_key;
-       uint32_t tdb_magic = TDB_MAGIC;
-
-       hash_key.dptr = (unsigned char *)TDB_MAGIC_FOOD;
-       hash_key.dsize = sizeof(TDB_MAGIC_FOOD);
-       *magic1_hash = tdb->hash_fn(&hash_key);
-
-       hash_key.dptr = CONVERT(tdb_magic);
-       hash_key.dsize = sizeof(tdb_magic);
-       *magic2_hash = tdb->hash_fn(&hash_key);
-
-       /* Make sure at least one hash is non-zero! */
-       if (*magic1_hash == 0 && *magic2_hash == 0)
-               *magic1_hash = 1;
-}
-
-/* initialise a new database with a specified hash size */
-static int tdb_new_database(struct tdb_context *tdb, int hash_size)
-{
-       struct tdb_header *newdb;
-       size_t size;
-       int ret = -1;
-       ssize_t written;
-
-       /* We make it up in memory, then write it out if not internal */
-       size = sizeof(struct tdb_header) + (hash_size+1)*sizeof(tdb_off_t);
-       if (!(newdb = (struct tdb_header *)calloc(size, 1))) {
-               tdb->ecode = TDB_ERR_OOM;
-               return -1;
-       }
-
-       /* Fill in the header */
-       newdb->version = TDB_VERSION;
-       newdb->hash_size = hash_size;
-
-       tdb_header_hash(tdb, &newdb->magic1_hash, &newdb->magic2_hash);
-
-       /* Make sure older tdbs (which don't check the magic hash fields)
-        * will refuse to open this TDB. */
-       if (tdb->flags & TDB_INCOMPATIBLE_HASH)
-               newdb->rwlocks = TDB_HASH_RWLOCK_MAGIC;
-
-       if (tdb->flags & TDB_INTERNAL) {
-               tdb->map_size = size;
-               tdb->map_ptr = (char *)newdb;
-               memcpy(&tdb->header, newdb, sizeof(tdb->header));
-               /* Convert the `ondisk' version if asked. */
-               CONVERT(*newdb);
-               return 0;
-       }
-       if (lseek(tdb->fd, 0, SEEK_SET) == -1)
-               goto fail;
-
-       if (ftruncate(tdb->fd, 0) == -1)
-               goto fail;
-
-       /* This creates an endian-converted header, as if read from disk */
-       CONVERT(*newdb);
-       memcpy(&tdb->header, newdb, sizeof(tdb->header));
-       /* Don't endian-convert the magic food! */
-       memcpy(newdb->magic_food, TDB_MAGIC_FOOD, strlen(TDB_MAGIC_FOOD)+1);
-       /* we still have "ret == -1" here */
-       written = write(tdb->fd, newdb, size);
-       if (written == size) {
-               ret = 0;
-       } else if (written != -1) {
-               /* call write once again, this usually should return -1 and
-                * set errno appropriately */
-               size -= written;
-               written = write(tdb->fd, newdb+written, size);
-               if (written == size) {
-               ret = 0;
-               } else if (written >= 0) {
-                       /* a second incomplete write - we give up.
-                        * guessing the errno... */
-                       errno = ENOSPC;
-               }
-       }
-
-  fail:
-       SAFE_FREE(newdb);
-       return ret;
-}
-
-
-
-static int tdb_already_open(dev_t device,
-                           ino_t ino)
-{
-       struct tdb_context *i;
-       
-       for (i = tdbs; i; i = i->next) {
-               if (i->device == device && i->inode == ino) {
-                       return 1;
-               }
-       }
-
-       return 0;
-}
-
-/* open the database, creating it if necessary 
-
-   The open_flags and mode are passed straight to the open call on the
-   database file. A flags value of O_WRONLY is invalid. The hash size
-   is advisory, use zero for a default value.
-
-   Return is NULL on error, in which case errno is also set.  Don't 
-   try to call tdb_error or tdb_errname, just do strerror(errno).
-
-   @param name may be NULL for internal databases. */
-struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags,
-                     int open_flags, mode_t mode)
-{
-       return tdb_open_ex(name, hash_size, tdb_flags, open_flags, mode, NULL, NULL);
-}
-
-/* a default logging function */
-static void null_log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...) PRINTF_FMT(3, 4);
-static void null_log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...)
-{
-}
-
-static bool check_header_hash(struct tdb_context *tdb,
-                             bool default_hash, uint32_t *m1, uint32_t *m2)
-{
-       tdb_header_hash(tdb, m1, m2);
-       if (tdb->header.magic1_hash == *m1 &&
-           tdb->header.magic2_hash == *m2) {
-               return true;
-       }
-
-       /* If they explicitly set a hash, always respect it. */
-       if (!default_hash)
-               return false;
-
-       /* Otherwise, try the other inbuilt hash. */
-       if (tdb->hash_fn == tdb_old_hash)
-               tdb->hash_fn = tdb_jenkins_hash;
-       else
-               tdb->hash_fn = tdb_old_hash;
-       return check_header_hash(tdb, false, m1, m2);
-}
-
-struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
-                               int open_flags, mode_t mode,
-                               const struct tdb_logging_context *log_ctx,
-                               tdb_hash_func hash_fn)
-{
-       struct tdb_context *tdb;
-       struct stat st;
-       int rev = 0, locked = 0;
-       unsigned char *vp;
-       uint32_t vertest;
-       unsigned v;
-       const char *hash_alg;
-       uint32_t magic1, magic2;
-
-       if (!(tdb = (struct tdb_context *)calloc(1, sizeof *tdb))) {
-               /* Can't log this */
-               errno = ENOMEM;
-               goto fail;
-       }
-       tdb_io_init(tdb);
-       tdb->fd = -1;
-#ifdef TDB_TRACE
-       tdb->tracefd = -1;
-#endif
-       tdb->name = NULL;
-       tdb->map_ptr = NULL;
-       tdb->flags = tdb_flags;
-       tdb->open_flags = open_flags;
-       if (log_ctx) {
-               tdb->log = *log_ctx;
-       } else {
-               tdb->log.log_fn = null_log_fn;
-               tdb->log.log_private = NULL;
-       }
-
-       if (hash_fn) {
-               tdb->hash_fn = hash_fn;
-               hash_alg = "the user defined";
-       } else {
-               /* This controls what we use when creating a tdb. */
-               if (tdb->flags & TDB_INCOMPATIBLE_HASH) {
-                       tdb->hash_fn = tdb_jenkins_hash;
-               } else {
-                       tdb->hash_fn = tdb_old_hash;
-               }
-               hash_alg = "either default";
-       }
-
-       /* cache the page size */
-       tdb->page_size = getpagesize();
-       if (tdb->page_size <= 0) {
-               tdb->page_size = 0x2000;
-       }
-
-       tdb->max_dead_records = (tdb_flags & TDB_VOLATILE) ? 5 : 0;
-
-       if ((open_flags & O_ACCMODE) == O_WRONLY) {
-               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: can't open tdb %s write-only\n",
-                        name));
-               errno = EINVAL;
-               goto fail;
-       }
-       
-       if (hash_size == 0)
-               hash_size = DEFAULT_HASH_SIZE;
-       if ((open_flags & O_ACCMODE) == O_RDONLY) {
-               tdb->read_only = 1;
-               /* read only databases don't do locking or clear if first */
-               tdb->flags |= TDB_NOLOCK;
-               tdb->flags &= ~TDB_CLEAR_IF_FIRST;
-       }
-
-       if ((tdb->flags & TDB_ALLOW_NESTING) &&
-           (tdb->flags & TDB_DISALLOW_NESTING)) {
-               tdb->ecode = TDB_ERR_NESTING;
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
-                       "allow_nesting and disallow_nesting are not allowed together!"));
-               errno = EINVAL;
-               goto fail;
-       }
-
-       /*
-        * TDB_DISALLOW_NESTING is the default behavior.
-        */
-       if (!(tdb->flags & TDB_ALLOW_NESTING)) {
-               tdb->flags |= TDB_DISALLOW_NESTING;
-       }
-
-       /* internal databases don't mmap or lock, and start off cleared */
-       if (tdb->flags & TDB_INTERNAL) {
-               tdb->flags |= (TDB_NOLOCK | TDB_NOMMAP);
-               tdb->flags &= ~TDB_CLEAR_IF_FIRST;
-               if (tdb_new_database(tdb, hash_size) != 0) {
-                       TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: tdb_new_database failed!"));
-                       goto fail;
-               }
-               goto internal;
-       }
-
-       if ((tdb->fd = open(name, open_flags, mode)) == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_open_ex: could not open file %s: %s\n",
-                        name, strerror(errno)));
-               goto fail;      /* errno set by open(2) */
-       }
-
-       /* on exec, don't inherit the fd */
-       v = fcntl(tdb->fd, F_GETFD, 0);
-        fcntl(tdb->fd, F_SETFD, v | FD_CLOEXEC);
-
-       /* ensure there is only one process initialising at once */
-       if (tdb_nest_lock(tdb, OPEN_LOCK, F_WRLCK, TDB_LOCK_WAIT) == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to get open lock on %s: %s\n",
-                        name, strerror(errno)));
-               goto fail;      /* errno set by tdb_brlock */
-       }
-
-       /* we need to zero database if we are the only one with it open */
-       if ((tdb_flags & TDB_CLEAR_IF_FIRST) &&
-           (!tdb->read_only) &&
-           (locked = (tdb_nest_lock(tdb, ACTIVE_LOCK, F_WRLCK, TDB_LOCK_NOWAIT|TDB_LOCK_PROBE) == 0))) {
-               open_flags |= O_CREAT;
-               if (ftruncate(tdb->fd, 0) == -1) {
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
-                                "failed to truncate %s: %s\n",
-                                name, strerror(errno)));
-                       goto fail; /* errno set by ftruncate */
-               }
-       }
-
-       errno = 0;
-       if (read(tdb->fd, &tdb->header, sizeof(tdb->header)) != sizeof(tdb->header)
-           || strcmp(tdb->header.magic_food, TDB_MAGIC_FOOD) != 0) {
-               if (!(open_flags & O_CREAT) || tdb_new_database(tdb, hash_size) == -1) {
-                       if (errno == 0) {
-                               errno = EIO; /* ie bad format or something */
-                       }
-                       goto fail;
-               }
-               rev = (tdb->flags & TDB_CONVERT);
-       } else if (tdb->header.version != TDB_VERSION
-                  && !(rev = (tdb->header.version==TDB_BYTEREV(TDB_VERSION)))) {
-               /* wrong version */
-               errno = EIO;
-               goto fail;
-       }
-       vp = (unsigned char *)&tdb->header.version;
-       vertest = (((uint32_t)vp[0]) << 24) | (((uint32_t)vp[1]) << 16) |
-                 (((uint32_t)vp[2]) << 8) | (uint32_t)vp[3];
-       tdb->flags |= (vertest==TDB_VERSION) ? TDB_BIGENDIAN : 0;
-       if (!rev)
-               tdb->flags &= ~TDB_CONVERT;
-       else {
-               tdb->flags |= TDB_CONVERT;
-               tdb_convert(&tdb->header, sizeof(tdb->header));
-       }
-       if (fstat(tdb->fd, &st) == -1)
-               goto fail;
-
-       if (tdb->header.rwlocks != 0 &&
-           tdb->header.rwlocks != TDB_HASH_RWLOCK_MAGIC) {
-               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: spinlocks no longer supported\n"));
-               goto fail;
-       }
-
-       if ((tdb->header.magic1_hash == 0) && (tdb->header.magic2_hash == 0)) {
-               /* older TDB without magic hash references */
-               tdb->hash_fn = tdb_old_hash;
-       } else if (!check_header_hash(tdb, !hash_fn, &magic1, &magic2)) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
-                        "%s was not created with %s hash function we are using\n"
-                        "magic1_hash[0x%08X %s 0x%08X] "
-                        "magic2_hash[0x%08X %s 0x%08X]\n",
-                        name, hash_alg,
-                        tdb->header.magic1_hash,
-                        (tdb->header.magic1_hash == magic1) ? "==" : "!=",
-                        magic1,
-                        tdb->header.magic2_hash,
-                        (tdb->header.magic2_hash == magic2) ? "==" : "!=",
-                        magic2));
-               errno = EINVAL;
-               goto fail;
-       }
-
-       /* Is it already in the open list?  If so, fail. */
-       if (tdb_already_open(st.st_dev, st.st_ino)) {
-               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
-                        "%s (%d,%d) is already open in this process\n",
-                        name, (int)st.st_dev, (int)st.st_ino));
-               errno = EBUSY;
-               goto fail;
-       }
-
-       if (!(tdb->name = (char *)strdup(name))) {
-               errno = ENOMEM;
-               goto fail;
-       }
-
-       tdb->map_size = st.st_size;
-       tdb->device = st.st_dev;
-       tdb->inode = st.st_ino;
-       tdb_mmap(tdb);
-       if (locked) {
-               if (tdb_nest_unlock(tdb, ACTIVE_LOCK, F_WRLCK, false) == -1) {
-                       TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
-                                "failed to take ACTIVE_LOCK on %s: %s\n",
-                                name, strerror(errno)));
-                       goto fail;
-               }
-
-       }
-
-       /* We always need to do this if the CLEAR_IF_FIRST flag is set, even if
-          we didn't get the initial exclusive lock as we need to let all other
-          users know we're using it. */
-
-       if (tdb_flags & TDB_CLEAR_IF_FIRST) {
-               /* leave this lock in place to indicate it's in use */
-               if (tdb_nest_lock(tdb, ACTIVE_LOCK, F_RDLCK, TDB_LOCK_WAIT) == -1) {
-                       goto fail;
-               }
-       }
-
-       /* if needed, run recovery */
-       if (tdb_transaction_recover(tdb) == -1) {
-               goto fail;
-       }
-
-#ifdef TDB_TRACE
-       {
-               char tracefile[strlen(name) + 32];
-
-               snprintf(tracefile, sizeof(tracefile),
-                        "%s.trace.%li", name, (long)getpid());
-               tdb->tracefd = open(tracefile, O_WRONLY|O_CREAT|O_EXCL, 0600);
-               if (tdb->tracefd >= 0) {
-                       tdb_enable_seqnum(tdb);
-                       tdb_trace_open(tdb, "tdb_open", hash_size, tdb_flags,
-                                      open_flags);
-               } else
-                       TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to open trace file %s!\n", tracefile));
-       }
-#endif
-
- internal:
-       /* Internal (memory-only) databases skip all the code above to
-        * do with disk files, and resume here by releasing their
-        * open lock and hooking into the active list. */
-       if (tdb_nest_unlock(tdb, OPEN_LOCK, F_WRLCK, false) == -1) {
-               goto fail;
-       }
-       tdb->next = tdbs;
-       tdbs = tdb;
-       return tdb;
-
- fail:
-       { int save_errno = errno;
-
-       if (!tdb)
-               return NULL;
-
-#ifdef TDB_TRACE
-       close(tdb->tracefd);
-#endif
-       if (tdb->map_ptr) {
-               if (tdb->flags & TDB_INTERNAL)
-                       SAFE_FREE(tdb->map_ptr);
-               else
-                       tdb_munmap(tdb);
-       }
-       SAFE_FREE(tdb->name);
-       if (tdb->fd != -1)
-               if (close(tdb->fd) != 0)
-                       TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to close tdb->fd on error!\n"));
-       SAFE_FREE(tdb->lockrecs);
-       SAFE_FREE(tdb);
-       errno = save_errno;
-       return NULL;
-       }
-}
-
-/*
- * Set the maximum number of dead records per hash chain
- */
-
-void tdb_set_max_dead(struct tdb_context *tdb, int max_dead)
-{
-       tdb->max_dead_records = max_dead;
-}
-
-/**
- * Close a database.
- *
- * @returns -1 for error; 0 for success.
- **/
-int tdb_close(struct tdb_context *tdb)
-{
-       struct tdb_context **i;
-       int ret = 0;
-
-       if (tdb->transaction) {
-               tdb_transaction_cancel(tdb);
-       }
-       tdb_trace(tdb, "tdb_close");
-
-       if (tdb->map_ptr) {
-               if (tdb->flags & TDB_INTERNAL)
-                       SAFE_FREE(tdb->map_ptr);
-               else
-                       tdb_munmap(tdb);
-       }
-       SAFE_FREE(tdb->name);
-       if (tdb->fd != -1) {
-               ret = close(tdb->fd);
-               tdb->fd = -1;
-       }
-       SAFE_FREE(tdb->lockrecs);
-
-       /* Remove from contexts list */
-       for (i = &tdbs; *i; i = &(*i)->next) {
-               if (*i == tdb) {
-                       *i = tdb->next;
-                       break;
-               }
-       }
-
-#ifdef TDB_TRACE
-       close(tdb->tracefd);
-#endif
-       memset(tdb, 0, sizeof(*tdb));
-       SAFE_FREE(tdb);
-
-       return ret;
-}
-
-/* register a loging function */
-void tdb_set_logging_function(struct tdb_context *tdb,
-                              const struct tdb_logging_context *log_ctx)
-{
-        tdb->log = *log_ctx;
-}
-
-void *tdb_get_logging_private(struct tdb_context *tdb)
-{
-       return tdb->log.log_private;
-}
-
-static int tdb_reopen_internal(struct tdb_context *tdb, bool active_lock)
-{
-       struct stat st;
-
-       if (tdb->flags & TDB_INTERNAL) {
-               return 0; /* Nothing to do. */
-       }
-
-       if (tdb_have_extra_locks(tdb)) {
-               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_reopen: reopen not allowed with locks held\n"));
-               goto fail;
-       }
-
-       if (tdb->transaction != 0) {
-               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_reopen: reopen not allowed inside a transaction\n"));
-               goto fail;
-       }
-
-       if (tdb_munmap(tdb) != 0) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: munmap failed (%s)\n", strerror(errno)));
-               goto fail;
-       }
-       if (close(tdb->fd) != 0)
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: WARNING closing tdb->fd failed!\n"));
-       tdb->fd = open(tdb->name, tdb->open_flags & ~(O_CREAT|O_TRUNC), 0);
-       if (tdb->fd == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: open failed (%s)\n", strerror(errno)));
-               goto fail;
-       }
-       if (fstat(tdb->fd, &st) != 0) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: fstat failed (%s)\n", strerror(errno)));
-               goto fail;
-       }
-       if (st.st_ino != tdb->inode || st.st_dev != tdb->device) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: file dev/inode has changed!\n"));
-               goto fail;
-       }
-       tdb_mmap(tdb);
-
-       /* We may still think we hold the active lock. */
-       tdb->num_lockrecs = 0;
-       SAFE_FREE(tdb->lockrecs);
-
-       if (active_lock && tdb_nest_lock(tdb, ACTIVE_LOCK, F_RDLCK, TDB_LOCK_WAIT) == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: failed to obtain active lock\n"));
-               goto fail;
-       }
-
-       return 0;
-
-fail:
-       tdb_close(tdb);
-       return -1;
-}
-
-/* reopen a tdb - this can be used after a fork to ensure that we have an independent
-   seek pointer from our parent and to re-establish locks */
-int tdb_reopen(struct tdb_context *tdb)
-{
-       return tdb_reopen_internal(tdb, tdb->flags & TDB_CLEAR_IF_FIRST);
-}
-
-/* reopen all tdb's */
-int tdb_reopen_all(int parent_longlived)
-{
-       struct tdb_context *tdb;
-
-       for (tdb=tdbs; tdb; tdb = tdb->next) {
-               bool active_lock = (tdb->flags & TDB_CLEAR_IF_FIRST);
-
-               /*
-                * If the parent is longlived (ie. a
-                * parent daemon architecture), we know
-                * it will keep it's active lock on a
-                * tdb opened with CLEAR_IF_FIRST. Thus
-                * for child processes we don't have to
-                * add an active lock. This is essential
-                * to improve performance on systems that
-                * keep POSIX locks as a non-scalable data
-                * structure in the kernel.
-                */
-               if (parent_longlived) {
-                       /* Ensure no clear-if-first. */
-                       active_lock = false;
-               }
-
-               if (tdb_reopen_internal(tdb, active_lock) != 0)
-                       return -1;
-       }
-
-       return 0;
-}
diff --git a/ccan/tdb/summary.c b/ccan/tdb/summary.c
deleted file mode 100644 (file)
index 8046a0c..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
- /* 
-   Trivial Database: human-readable summary code
-   Copyright (C) Rusty Russell 2010
-   
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-#include "tdb_private.h"
-
-#define SUMMARY_FORMAT \
-       "Size of file/data: %u/%zu\n" \
-       "Number of records: %zu\n" \
-       "Smallest/average/largest keys: %zu/%zu/%zu\n" \
-       "Smallest/average/largest data: %zu/%zu/%zu\n" \
-       "Smallest/average/largest padding: %zu/%zu/%zu\n" \
-       "Number of dead records: %zu\n" \
-       "Smallest/average/largest dead records: %zu/%zu/%zu\n" \
-       "Number of free records: %zu\n" \
-       "Smallest/average/largest free records: %zu/%zu/%zu\n" \
-       "Number of hash chains: %zu\n" \
-       "Smallest/average/largest hash chains: %zu/%zu/%zu\n" \
-       "Number of uncoalesced records: %zu\n" \
-       "Smallest/average/largest uncoalesced runs: %zu/%zu/%zu\n" \
-       "Percentage keys/data/padding/free/dead/rechdrs&tailers/hashes: %.0f/%.0f/%.0f/%.0f/%.0f/%.0f/%.0f\n"
-
-/* We don't use tally module, to keep upstream happy. */
-struct tally {
-       size_t min, max, total;
-       size_t num;
-};
-
-static void tally_init(struct tally *tally)
-{
-       tally->total = 0;
-       tally->num = 0;
-       tally->min = tally->max = 0;
-}
-
-static void tally_add(struct tally *tally, size_t len)
-{
-       if (tally->num == 0)
-               tally->max = tally->min = len;
-       else if (len > tally->max)
-               tally->max = len;
-       else if (len < tally->min)
-               tally->min = len;
-       tally->num++;
-       tally->total += len;
-}
-
-static size_t tally_mean(const struct tally *tally)
-{
-       if (!tally->num)
-               return 0;
-       return tally->total / tally->num;
-}
-
-static size_t get_hash_length(struct tdb_context *tdb, unsigned int i)
-{
-       tdb_off_t rec_ptr;
-       size_t count = 0;
-
-       if (tdb_ofs_read(tdb, TDB_HASH_TOP(i), &rec_ptr) == -1)
-               return 0;
-
-       /* keep looking until we find the right record */
-       while (rec_ptr) {
-               struct tdb_record r;
-               ++count;
-               if (tdb_rec_read(tdb, rec_ptr, &r) == -1)
-                       return 0;
-               rec_ptr = r.next;
-       }
-       return count;
-}
-
-char *tdb_summary(struct tdb_context *tdb)
-{
-       tdb_off_t off;
-       struct tally freet, keys, data, dead, extra, hash, uncoal;
-       struct tdb_record rec;
-       char *ret = NULL;
-       bool locked;
-       size_t len, unc = 0;
-
-       /* Read-only databases use no locking at all: it's best-effort.
-        * We may have a write lock already, so skip that case too. */
-       if (tdb->read_only || tdb->allrecord_lock.count != 0) {
-               locked = false;
-       } else {
-               if (tdb_lockall_read(tdb) == -1)
-                       return NULL;
-               locked = true;
-       }
-
-       tally_init(&freet);
-       tally_init(&keys);
-       tally_init(&data);
-       tally_init(&dead);
-       tally_init(&extra);
-       tally_init(&hash);
-       tally_init(&uncoal);
-
-       for (off = TDB_DATA_START(tdb->header.hash_size);
-            off < tdb->map_size - 1;
-            off += sizeof(rec) + rec.rec_len) {
-               if (tdb->methods->tdb_read(tdb, off, &rec, sizeof(rec),
-                                          DOCONV()) == -1)
-                       goto unlock;
-               switch (rec.magic) {
-               case TDB_MAGIC:
-                       tally_add(&keys, rec.key_len);
-                       tally_add(&data, rec.data_len);
-                       tally_add(&extra, rec.rec_len - (rec.key_len
-                                                        + rec.data_len));
-                       if (unc > 1)
-                               tally_add(&uncoal, unc - 1);
-                       unc = 0;
-                       break;
-               case TDB_FREE_MAGIC:
-                       tally_add(&freet, rec.rec_len);
-                       unc++;
-                       break;
-               /* If we crash after ftruncate, we can get zeroes or fill. */
-               case TDB_RECOVERY_INVALID_MAGIC:
-               case 0x42424242:
-                       unc++;
-                       rec.rec_len = tdb_dead_space(tdb, off) - sizeof(rec);
-                       /* Fall through */
-               case TDB_DEAD_MAGIC:
-                       tally_add(&dead, rec.rec_len);
-                       break;
-               default:
-                       TDB_LOG((tdb, TDB_DEBUG_ERROR,
-                                "Unexpected record magic 0x%x at offset %d\n",
-                                rec.magic, off));
-                       goto unlock;
-               }
-       }
-       if (unc > 1)
-               tally_add(&uncoal, unc - 1);
-
-       for (off = 0; off < tdb->header.hash_size; off++)
-               tally_add(&hash, get_hash_length(tdb, off));
-
-       /* 20 is max length of a %zu. */
-       len = strlen(SUMMARY_FORMAT) + 35*20 + 1;
-       ret = malloc(len);
-       if (!ret)
-               goto unlock;
-
-       sprintf(ret, SUMMARY_FORMAT,
-               tdb->map_size, keys.total+data.total,
-               keys.num,
-               keys.min, tally_mean(&keys), keys.max,
-               data.min, tally_mean(&data), data.max,
-               extra.min, tally_mean(&extra), extra.max,
-               dead.num,
-               dead.min, tally_mean(&dead), dead.max,
-               freet.num,
-               freet.min, tally_mean(&freet), freet.max,
-               hash.num,
-               hash.min, tally_mean(&hash), hash.max,
-               uncoal.total,
-               uncoal.min, tally_mean(&uncoal), uncoal.max,
-               keys.total * 100.0 / tdb->map_size,
-               data.total * 100.0 / tdb->map_size,
-               extra.total * 100.0 / tdb->map_size,
-               freet.total * 100.0 / tdb->map_size,
-               dead.total * 100.0 / tdb->map_size,
-               (keys.num + freet.num + dead.num)
-               * (sizeof(struct tdb_record) + sizeof(uint32_t))
-               * 100.0 / tdb->map_size,
-               tdb->header.hash_size * sizeof(tdb_off_t)
-               * 100.0 / tdb->map_size);
-
-unlock:
-       if (locked) {
-               tdb_unlockall_read(tdb);
-       }
-       return ret;
-}
diff --git a/ccan/tdb/tdb.c b/ccan/tdb/tdb.c
deleted file mode 100644 (file)
index 7317a3a..0000000
+++ /dev/null
@@ -1,1141 +0,0 @@
- /* 
-   Unix SMB/CIFS implementation.
-
-   trivial database library
-
-   Copyright (C) Andrew Tridgell              1999-2005
-   Copyright (C) Paul `Rusty' Russell             2000
-   Copyright (C) Jeremy Allison                           2000-2003
-   
-     ** NOTE! The following LGPL license applies to the tdb
-     ** library. This does NOT imply that all of Samba is released
-     ** under the LGPL
-   
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "tdb_private.h"
-
-TDB_DATA tdb_null;
-
-/*
-  non-blocking increment of the tdb sequence number if the tdb has been opened using
-  the TDB_SEQNUM flag
-*/
-void tdb_increment_seqnum_nonblock(struct tdb_context *tdb)
-{
-       tdb_off_t seqnum=0;
-       
-       if (!(tdb->flags & TDB_SEQNUM)) {
-               return;
-       }
-
-       /* we ignore errors from this, as we have no sane way of
-          dealing with them.
-       */
-       tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
-       seqnum++;
-       tdb_ofs_write(tdb, TDB_SEQNUM_OFS, &seqnum);
-}
-
-/*
-  increment the tdb sequence number if the tdb has been opened using
-  the TDB_SEQNUM flag
-*/
-static void tdb_increment_seqnum(struct tdb_context *tdb)
-{
-       if (!(tdb->flags & TDB_SEQNUM)) {
-               return;
-       }
-
-       if (tdb_nest_lock(tdb, TDB_SEQNUM_OFS, F_WRLCK,
-                         TDB_LOCK_WAIT|TDB_LOCK_PROBE) != 0) {
-               return;
-       }
-
-       tdb_increment_seqnum_nonblock(tdb);
-
-       tdb_nest_unlock(tdb, TDB_SEQNUM_OFS, F_WRLCK, false);
-}
-
-static int tdb_key_compare(TDB_DATA key, TDB_DATA data, void *private_data)
-{
-       return memcmp(data.dptr, key.dptr, data.dsize);
-}
-
-/* Returns 0 on fail.  On success, return offset of record, and fills
-   in rec */
-static tdb_off_t tdb_find(struct tdb_context *tdb, TDB_DATA key, uint32_t hash,
-                       struct tdb_record *r)
-{
-       tdb_off_t rec_ptr;
-       
-       /* read in the hash top */
-       if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
-               return 0;
-
-       /* keep looking until we find the right record */
-       while (rec_ptr) {
-               if (tdb_rec_read(tdb, rec_ptr, r) == -1)
-                       return 0;
-
-               if (!TDB_DEAD(r) && hash==r->full_hash
-                   && key.dsize==r->key_len
-                   && tdb_parse_data(tdb, key, rec_ptr + sizeof(*r),
-                                     r->key_len, tdb_key_compare,
-                                     NULL) == 0) {
-                       return rec_ptr;
-               }
-               /* detect tight infinite loop */
-               if (rec_ptr == r->next) {
-                       tdb->ecode = TDB_ERR_CORRUPT;
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_find: loop detected.\n"));
-                       return 0;
-               }
-               rec_ptr = r->next;
-       }
-       tdb->ecode = TDB_ERR_NOEXIST;
-       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, uint32_t hash, int locktype,
-                          struct tdb_record *rec)
-{
-       uint32_t 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;
-}
-
-static TDB_DATA _tdb_fetch(struct tdb_context *tdb, TDB_DATA key);
-
-/* 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_DATA data = _tdb_fetch(tdb, key);
-               if (data.dsize == dbuf.dsize &&
-                   memcmp(data.dptr, dbuf.dptr, data.dsize) == 0) {
-                       if (data.dptr) {
-                               free(data.dptr);
-                       }
-                       return 0;
-               }
-               if (data.dptr) {
-                       free(data.dptr);
-               }
-       }
-        
-
-       /* 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;
-}
-
-/* find an entry in the database given a key */
-/* If an entry doesn't exist tdb_err will be set to
- * TDB_ERR_NOEXIST. If a key has no data attached
- * then the TDB_DATA will have zero length but
- * a non-zero pointer
- */
-static TDB_DATA _tdb_fetch(struct tdb_context *tdb, TDB_DATA key)
-{
-       tdb_off_t rec_ptr;
-       struct tdb_record rec;
-       TDB_DATA ret;
-       uint32_t hash;
-
-       /* find which hash bucket it is in */
-       hash = tdb->hash_fn(&key);
-       if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec)))
-               return tdb_null;
-
-       ret.dptr = tdb_alloc_read(tdb, rec_ptr + sizeof(rec) + rec.key_len,
-                                 rec.data_len);
-       ret.dsize = rec.data_len;
-       tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
-       return ret;
-}
-
-TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key)
-{
-       TDB_DATA ret = _tdb_fetch(tdb, key);
-
-       tdb_trace_1rec_retrec(tdb, "tdb_fetch", key, ret);
-       return ret;
-}
-
-/*
- * Find an entry in the database and hand the record's data to a parsing
- * function. The parsing function is executed under the chain read lock, so it
- * should be fast and should not block on other syscalls.
- *
- * DON'T CALL OTHER TDB CALLS FROM THE PARSER, THIS MIGHT LEAD TO SEGFAULTS.
- *
- * For mmapped tdb's that do not have a transaction open it points the parsing
- * function directly at the mmap area, it avoids the malloc/memcpy in this
- * case. If a transaction is open or no mmap is available, it has to do
- * malloc/read/parse/free.
- *
- * This is interesting for all readers of potentially large data structures in
- * the tdb records, ldb indexes being one example.
- */
-
-int tdb_parse_record(struct tdb_context *tdb, TDB_DATA key,
-                    int (*parser)(TDB_DATA key, TDB_DATA data,
-                                  void *private_data),
-                    void *private_data)
-{
-       tdb_off_t rec_ptr;
-       struct tdb_record rec;
-       int ret;
-       uint32_t hash;
-
-       /* find which hash bucket it is in */
-       hash = tdb->hash_fn(&key);
-
-       if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec))) {
-               tdb_trace_1rec_ret(tdb, "tdb_parse_record", key, -1);
-               tdb->ecode = TDB_ERR_NOEXIST;
-               return 0;
-       }
-       tdb_trace_1rec_ret(tdb, "tdb_parse_record", key, 0);
-
-       ret = tdb_parse_data(tdb, key, rec_ptr + sizeof(rec) + rec.key_len,
-                            rec.data_len, parser, private_data);
-
-       tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
-
-       return ret;
-}
-
-/* check if an entry in the database exists 
-
-   note that 1 is returned if the key is found and 0 is returned if not found
-   this doesn't match the conventions in the rest of this module, but is
-   compatible with gdbm
-*/
-static int tdb_exists_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash)
-{
-       struct tdb_record rec;
-       
-       if (tdb_find_lock_hash(tdb, key, hash, F_RDLCK, &rec) == 0)
-               return 0;
-       tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
-       return 1;
-}
-
-int tdb_exists(struct tdb_context *tdb, TDB_DATA key)
-{
-       uint32_t hash = tdb->hash_fn(&key);
-       int ret;
-
-       ret = tdb_exists_hash(tdb, key, hash);
-       tdb_trace_1rec_ret(tdb, "tdb_exists", key, ret);
-       return ret;
-}
-
-/* actually delete an entry in the database given the offset */
-int tdb_do_delete(struct tdb_context *tdb, tdb_off_t rec_ptr, struct tdb_record *rec)
-{
-       tdb_off_t last_ptr, i;
-       struct tdb_record lastrec;
-
-       if (tdb->read_only || tdb->traverse_read) return -1;
-
-       if (((tdb->traverse_write != 0) && (!TDB_DEAD(rec))) ||
-           tdb_write_lock_record(tdb, rec_ptr) == -1) {
-               /* Someone traversing here: mark it as dead */
-               rec->magic = TDB_DEAD_MAGIC;
-               return tdb_rec_write(tdb, rec_ptr, rec);
-       }
-       if (tdb_write_unlock_record(tdb, rec_ptr) != 0)
-               return -1;
-
-       /* find previous record in hash chain */
-       if (tdb_ofs_read(tdb, TDB_HASH_TOP(rec->full_hash), &i) == -1)
-               return -1;
-       for (last_ptr = 0; i != rec_ptr; last_ptr = i, i = lastrec.next)
-               if (tdb_rec_read(tdb, i, &lastrec) == -1)
-                       return -1;
-
-       /* unlink it: next ptr is at start of record. */
-       if (last_ptr == 0)
-               last_ptr = TDB_HASH_TOP(rec->full_hash);
-       if (tdb_ofs_write(tdb, last_ptr, &rec->next) == -1)
-               return -1;
-
-       /* recover the space */
-       if (tdb_free(tdb, rec_ptr, rec) == -1)
-               return -1;
-       return 0;
-}
-
-static int tdb_count_dead(struct tdb_context *tdb, uint32_t hash)
-{
-       int res = 0;
-       tdb_off_t rec_ptr;
-       struct tdb_record rec;
-       
-       /* read in the hash top */
-       if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
-               return 0;
-
-       while (rec_ptr) {
-               if (tdb_rec_read(tdb, rec_ptr, &rec) == -1)
-                       return 0;
-
-               if (rec.magic == TDB_DEAD_MAGIC) {
-                       res += 1;
-               }
-               rec_ptr = rec.next;
-       }
-       return res;
-}
-
-/*
- * Purge all DEAD records from a hash chain
- */
-static int tdb_purge_dead(struct tdb_context *tdb, uint32_t hash)
-{
-       int res = -1;
-       struct tdb_record rec;
-       tdb_off_t rec_ptr;
-
-       if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
-               return -1;
-       }
-       
-       /* read in the hash top */
-       if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
-               goto fail;
-
-       while (rec_ptr) {
-               tdb_off_t next;
-
-               if (tdb_rec_read(tdb, rec_ptr, &rec) == -1) {
-                       goto fail;
-               }
-
-               next = rec.next;
-
-               if (rec.magic == TDB_DEAD_MAGIC
-                   && tdb_do_delete(tdb, rec_ptr, &rec) == -1) {
-                       goto fail;
-               }
-               rec_ptr = next;
-       }
-       res = 0;
- fail:
-       tdb_unlock(tdb, -1, F_WRLCK);
-       return res;
-}
-
-/* delete an entry in the database given a key */
-static int tdb_delete_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash)
-{
-       tdb_off_t rec_ptr;
-       struct tdb_record 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;
-}
-
-int tdb_delete(struct tdb_context *tdb, TDB_DATA key)
-{
-       uint32_t hash = tdb->hash_fn(&key);
-       int ret;
-
-       ret = tdb_delete_hash(tdb, key, hash);
-       tdb_trace_1rec_ret(tdb, "tdb_delete", key, ret);
-       return ret;
-}
-
-/*
- * See if we have a dead record around with enough space
- */
-static tdb_off_t tdb_find_dead(struct tdb_context *tdb, uint32_t hash,
-                              struct tdb_record *r, tdb_len_t length)
-{
-       tdb_off_t rec_ptr;
-       
-       /* read in the hash top */
-       if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
-               return 0;
-
-       /* keep looking until we find the right record */
-       while (rec_ptr) {
-               if (tdb_rec_read(tdb, rec_ptr, r) == -1)
-                       return 0;
-
-               if (TDB_DEAD(r) && r->rec_len >= length) {
-                       /*
-                        * First fit for simple coding, TODO: change to best
-                        * fit
-                        */
-                       return rec_ptr;
-               }
-               rec_ptr = r->next;
-       }
-       return 0;
-}
-
-static int _tdb_store(struct tdb_context *tdb, TDB_DATA key,
-                      TDB_DATA dbuf, int flag, uint32_t hash)
-{
-       struct tdb_record rec;
-       tdb_off_t rec_ptr;
-       char *p = NULL;
-       int ret = -1;
-
-       /* check for it existing, on insert. */
-       if (flag == TDB_INSERT) {
-               if (tdb_exists_hash(tdb, key, hash)) {
-                       tdb->ecode = TDB_ERR_EXISTS;
-                       goto fail;
-               }
-       } else {
-               /* first try in-place update, on modify or replace. */
-               if (tdb_update_hash(tdb, key, hash, dbuf) == 0) {
-                       goto done;
-               }
-               if (tdb->ecode == TDB_ERR_NOEXIST &&
-                   flag == TDB_MODIFY) {
-                       /* if the record doesn't exist and we are in TDB_MODIFY mode then
-                        we should fail the store */
-                       goto fail;
-               }
-       }
-       /* reset the error code potentially set by the tdb_update() */
-       tdb->ecode = TDB_SUCCESS;
-
-       /* delete any existing record - if it doesn't exist we don't
-           care.  Doing this first reduces fragmentation, and avoids
-           coalescing with `allocated' block before it's updated. */
-       if (flag != TDB_INSERT)
-               tdb_delete_hash(tdb, key, hash);
-
-       /* Copy key+value *before* allocating free space in case malloc
-          fails and we are left with a dead spot in the tdb. */
-
-       if (!(p = (char *)malloc(key.dsize + dbuf.dsize))) {
-               tdb->ecode = TDB_ERR_OOM;
-               goto fail;
-       }
-
-       memcpy(p, key.dptr, key.dsize);
-       if (dbuf.dsize)
-               memcpy(p+key.dsize, dbuf.dptr, dbuf.dsize);
-
-       if (tdb->max_dead_records != 0) {
-               /*
-                * Allow for some dead records per hash chain, look if we can
-                * find one that can hold the new record. We need enough space
-                * for key, data and tailer. If we find one, we don't have to
-                * consult the central freelist.
-                */
-               rec_ptr = tdb_find_dead(
-                       tdb, hash, &rec,
-                       key.dsize + dbuf.dsize + sizeof(tdb_off_t));
-
-               if (rec_ptr != 0) {
-                       rec.key_len = key.dsize;
-                       rec.data_len = dbuf.dsize;
-                       rec.full_hash = hash;
-                       rec.magic = TDB_MAGIC;
-                       if (tdb_rec_write(tdb, rec_ptr, &rec) == -1
-                           || tdb->methods->tdb_write(
-                                   tdb, rec_ptr + sizeof(rec),
-                                   p, key.dsize + dbuf.dsize) == -1) {
-                               goto fail;
-                       }
-                       goto done;
-               }
-       }
-
-       /*
-        * We have to allocate some space from the freelist, so this means we
-        * have to lock it. Use the chance to purge all the DEAD records from
-        * the hash chain under the freelist lock.
-        */
-
-       if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
-               goto fail;
-       }
-
-       if ((tdb->max_dead_records != 0)
-           && (tdb_purge_dead(tdb, hash) == -1)) {
-               tdb_unlock(tdb, -1, F_WRLCK);
-               goto fail;
-       }
-
-       /* we have to allocate some space */
-       rec_ptr = tdb_allocate(tdb, key.dsize + dbuf.dsize, &rec);
-
-       tdb_unlock(tdb, -1, F_WRLCK);
-
-       if (rec_ptr == 0) {
-               goto fail;
-       }
-
-       /* Read hash top into next ptr */
-       if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec.next) == -1)
-               goto fail;
-
-       rec.key_len = key.dsize;
-       rec.data_len = dbuf.dsize;
-       rec.full_hash = hash;
-       rec.magic = TDB_MAGIC;
-
-       /* write out and point the top of the hash chain at it */
-       if (tdb_rec_write(tdb, rec_ptr, &rec) == -1
-           || tdb->methods->tdb_write(tdb, rec_ptr+sizeof(rec), p, key.dsize+dbuf.dsize)==-1
-           || tdb_ofs_write(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) {
-               /* Need to tdb_unallocate() here */
-               goto fail;
-       }
-
- done:
-       ret = 0;
- fail:
-       if (ret == 0) {
-               tdb_increment_seqnum(tdb);
-       }
-
-       SAFE_FREE(p); 
-       return ret;
-}
-
-/* store an element in the database, replacing any existing element
-   with the same key
-
-   return 0 on success, -1 on failure
-*/
-int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag)
-{
-       uint32_t hash;
-       int ret;
-
-       if (tdb->read_only || tdb->traverse_read) {
-               tdb->ecode = TDB_ERR_RDONLY;
-               tdb_trace_2rec_flag_ret(tdb, "tdb_store", key, dbuf, flag, -1);
-               return -1;
-       }
-
-       /* find which hash bucket it is in */
-       hash = tdb->hash_fn(&key);
-       if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
-               return -1;
-
-       ret = _tdb_store(tdb, key, dbuf, flag, hash);
-       tdb_trace_2rec_flag_ret(tdb, "tdb_store", key, dbuf, flag, ret);
-       tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
-       return ret;
-}
-
-/* Append to an entry. Create if not exist. */
-int tdb_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf)
-{
-       uint32_t hash;
-       TDB_DATA dbuf;
-       int ret = -1;
-
-       /* find which hash bucket it is in */
-       hash = tdb->hash_fn(&key);
-       if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
-               return -1;
-
-       dbuf = _tdb_fetch(tdb, key);
-
-       if (dbuf.dptr == NULL) {
-               dbuf.dptr = (unsigned char *)malloc(new_dbuf.dsize);
-       } else {
-               unsigned int new_len = dbuf.dsize + new_dbuf.dsize;
-               unsigned char *new_dptr;
-
-               /* realloc '0' is special: don't do that. */
-               if (new_len == 0)
-                       new_len = 1;
-               new_dptr = (unsigned char *)realloc(dbuf.dptr, new_len);
-               if (new_dptr == NULL) {
-                       free(dbuf.dptr);
-               }
-               dbuf.dptr = new_dptr;
-       }
-
-       if (dbuf.dptr == NULL) {
-               tdb->ecode = TDB_ERR_OOM;
-               goto failed;
-       }
-
-       memcpy(dbuf.dptr + dbuf.dsize, new_dbuf.dptr, new_dbuf.dsize);
-       dbuf.dsize += new_dbuf.dsize;
-
-       ret = _tdb_store(tdb, key, dbuf, 0, hash);
-       tdb_trace_2rec_retrec(tdb, "tdb_append", key, new_dbuf, dbuf);
-       
-failed:
-       tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
-       SAFE_FREE(dbuf.dptr);
-       return ret;
-}
-
-
-/*
-  return the name of the current tdb file
-  useful for external logging functions
-*/
-const char *tdb_name(struct tdb_context *tdb)
-{
-       return tdb->name;
-}
-
-/*
-  return the underlying file descriptor being used by tdb, or -1
-  useful for external routines that want to check the device/inode
-  of the fd
-*/
-int tdb_fd(struct tdb_context *tdb)
-{
-       return tdb->fd;
-}
-
-/*
-  return the current logging function
-  useful for external tdb routines that wish to log tdb errors
-*/
-tdb_log_func tdb_log_fn(struct tdb_context *tdb)
-{
-       return tdb->log.log_fn;
-}
-
-
-/*
-  get the tdb sequence number. Only makes sense if the writers opened
-  with TDB_SEQNUM set. Note that this sequence number will wrap quite
-  quickly, so it should only be used for a 'has something changed'
-  test, not for code that relies on the count of the number of changes
-  made. If you want a counter then use a tdb record.
-
-  The aim of this sequence number is to allow for a very lightweight
-  test of a possible tdb change.
-*/
-int tdb_get_seqnum(struct tdb_context *tdb)
-{
-       tdb_off_t seqnum=0;
-
-       tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
-       return seqnum;
-}
-
-int tdb_hash_size(struct tdb_context *tdb)
-{
-       return tdb->header.hash_size;
-}
-
-size_t tdb_map_size(struct tdb_context *tdb)
-{
-       return tdb->map_size;
-}
-
-int tdb_get_flags(struct tdb_context *tdb)
-{
-       return tdb->flags;
-}
-
-void tdb_add_flags(struct tdb_context *tdb, unsigned flags)
-{
-       if ((flags & TDB_ALLOW_NESTING) &&
-           (flags & TDB_DISALLOW_NESTING)) {
-               tdb->ecode = TDB_ERR_NESTING;
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_add_flags: "
-                       "allow_nesting and disallow_nesting are not allowed together!"));
-               return;
-       }
-
-       if (flags & TDB_ALLOW_NESTING) {
-               tdb->flags &= ~TDB_DISALLOW_NESTING;
-       }
-       if (flags & TDB_DISALLOW_NESTING) {
-               tdb->flags &= ~TDB_ALLOW_NESTING;
-       }
-
-       tdb->flags |= flags;
-}
-
-void tdb_remove_flags(struct tdb_context *tdb, unsigned flags)
-{
-       if ((flags & TDB_ALLOW_NESTING) &&
-           (flags & TDB_DISALLOW_NESTING)) {
-               tdb->ecode = TDB_ERR_NESTING;
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_remove_flags: "
-                       "allow_nesting and disallow_nesting are not allowed together!"));
-               return;
-       }
-
-       if (flags & TDB_ALLOW_NESTING) {
-               tdb->flags |= TDB_DISALLOW_NESTING;
-       }
-       if (flags & TDB_DISALLOW_NESTING) {
-               tdb->flags |= TDB_ALLOW_NESTING;
-       }
-
-       tdb->flags &= ~flags;
-}
-
-
-/*
-  enable sequence number handling on an open tdb
-*/
-void tdb_enable_seqnum(struct tdb_context *tdb)
-{
-       tdb->flags |= TDB_SEQNUM;
-}
-
-
-/*
-  add a region of the file to the freelist. Length is the size of the region in bytes, 
-  which includes the free list header that needs to be added
- */
-static int tdb_free_region(struct tdb_context *tdb, tdb_off_t offset, ssize_t length)
-{
-       struct tdb_record rec;
-       if (length <= sizeof(rec)) {
-               /* the region is not worth adding */
-               return 0;
-       }
-       if (length + offset > tdb->map_size) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_free_region: adding region beyond end of file\n"));
-               return -1;              
-       }
-       memset(&rec,'\0',sizeof(rec));
-       rec.rec_len = length - sizeof(rec);
-       if (tdb_free(tdb, offset, &rec) == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_free_region: failed to add free record\n"));
-               return -1;
-       }
-       return 0;
-}
-
-/*
-  wipe the entire database, deleting all records. This can be done
-  very fast by using a allrecord lock. The entire data portion of the
-  file becomes a single entry in the freelist.
-
-  This code carefully steps around the recovery area, leaving it alone
- */
-int tdb_wipe_all(struct tdb_context *tdb)
-{
-       int i;
-       tdb_off_t offset = 0;
-       ssize_t data_len;
-       tdb_off_t recovery_head;
-       tdb_len_t recovery_size = 0;
-
-       if (tdb_lockall(tdb) != 0) {
-               return -1;
-       }
-
-       tdb_trace(tdb, "tdb_wipe_all");
-
-       /* see if the tdb has a recovery area, and remember its size
-          if so. We don't want to lose this as otherwise each
-          tdb_wipe_all() in a transaction will increase the size of
-          the tdb by the size of the recovery area */
-       if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_wipe_all: failed to read recovery head\n"));
-               goto failed;
-       }
-
-       if (recovery_head != 0) {
-               struct tdb_record rec;
-               if (tdb->methods->tdb_read(tdb, recovery_head, &rec, sizeof(rec), DOCONV()) == -1) {
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_wipe_all: failed to read recovery record\n"));
-                       return -1;
-               }       
-               recovery_size = rec.rec_len + sizeof(rec);
-       }
-
-       /* wipe the hashes */
-       for (i=0;i<tdb->header.hash_size;i++) {
-               if (tdb_ofs_write(tdb, TDB_HASH_TOP(i), &offset) == -1) {
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to write hash %d\n", i));
-                       goto failed;
-               }
-       }
-
-       /* wipe the freelist */
-       if (tdb_ofs_write(tdb, FREELIST_TOP, &offset) == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to write freelist\n"));
-               goto failed;
-       }
-
-       /* add all the rest of the file to the freelist, possibly leaving a gap 
-          for the recovery area */
-       if (recovery_size == 0) {
-               /* the simple case - the whole file can be used as a freelist */
-               data_len = (tdb->map_size - TDB_DATA_START(tdb->header.hash_size));
-               if (tdb_free_region(tdb, TDB_DATA_START(tdb->header.hash_size), data_len) != 0) {
-                       goto failed;
-               }
-       } else {
-               /* we need to add two freelist entries - one on either
-                  side of the recovery area 
-
-                  Note that we cannot shift the recovery area during
-                  this operation. Only the transaction.c code may
-                  move the recovery area or we risk subtle data
-                  corruption
-               */
-               data_len = (recovery_head - TDB_DATA_START(tdb->header.hash_size));
-               if (tdb_free_region(tdb, TDB_DATA_START(tdb->header.hash_size), data_len) != 0) {
-                       goto failed;
-               }
-               /* and the 2nd free list entry after the recovery area - if any */
-               data_len = tdb->map_size - (recovery_head+recovery_size);
-               if (tdb_free_region(tdb, recovery_head+recovery_size, data_len) != 0) {
-                       goto failed;
-               }
-       }
-
-       if (tdb_unlockall(tdb) != 0) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to unlock\n"));
-               goto failed;
-       }
-
-       return 0;
-
-failed:
-       tdb_unlockall(tdb);
-       return -1;
-}
-
-struct traverse_state {
-       bool error;
-       struct tdb_context *dest_db;
-};
-
-/*
-  traverse function for repacking
- */
-static int repack_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *private_data)
-{
-       struct traverse_state *state = (struct traverse_state *)private_data;
-       if (tdb_store(state->dest_db, key, data, TDB_INSERT) != 0) {
-               state->error = true;
-               return -1;
-       }
-       return 0;
-}
-
-/*
-  repack a tdb
- */
-int tdb_repack(struct tdb_context *tdb)
-{
-       struct tdb_context *tmp_db;
-       struct traverse_state state;
-
-       tdb_trace(tdb, "tdb_repack");
-
-       if (tdb_transaction_start(tdb) != 0) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to start transaction\n"));
-               return -1;
-       }
-
-       tmp_db = tdb_open("tmpdb", tdb_hash_size(tdb), TDB_INTERNAL, O_RDWR|O_CREAT, 0);
-       if (tmp_db == NULL) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to create tmp_db\n"));
-               tdb_transaction_cancel(tdb);
-               return -1;
-       }
-
-       state.error = false;
-       state.dest_db = tmp_db;
-
-       if (tdb_traverse_read(tdb, repack_traverse, &state) == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to traverse copying out\n"));
-               tdb_transaction_cancel(tdb);
-               tdb_close(tmp_db);
-               return -1;              
-       }
-
-       if (state.error) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Error during traversal\n"));
-               tdb_transaction_cancel(tdb);
-               tdb_close(tmp_db);
-               return -1;
-       }
-
-       if (tdb_wipe_all(tdb) != 0) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to wipe database\n"));
-               tdb_transaction_cancel(tdb);
-               tdb_close(tmp_db);
-               return -1;
-       }
-
-       state.error = false;
-       state.dest_db = tdb;
-
-       if (tdb_traverse_read(tmp_db, repack_traverse, &state) == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to traverse copying back\n"));
-               tdb_transaction_cancel(tdb);
-               tdb_close(tmp_db);
-               return -1;              
-       }
-
-       if (state.error) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Error during second traversal\n"));
-               tdb_transaction_cancel(tdb);
-               tdb_close(tmp_db);
-               return -1;
-       }
-
-       tdb_close(tmp_db);
-
-       if (tdb_transaction_commit(tdb) != 0) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to commit\n"));
-               return -1;
-       }
-
-       return 0;
-}
-
-#ifdef TDB_TRACE
-static void tdb_trace_write(struct tdb_context *tdb, const char *str)
-{
-       if (write(tdb->tracefd, str, strlen(str)) != strlen(str)) {
-               close(tdb->tracefd);
-               tdb->tracefd = -1;
-       }
-}
-
-static void tdb_trace_start(struct tdb_context *tdb)
-{
-       tdb_off_t seqnum=0;
-       char msg[sizeof(tdb_off_t) * 4 + 1];
-
-       tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
-       snprintf(msg, sizeof(msg), "%u ", seqnum);
-       tdb_trace_write(tdb, msg);
-}
-
-static void tdb_trace_end(struct tdb_context *tdb)
-{
-       tdb_trace_write(tdb, "\n");
-}
-
-static void tdb_trace_end_ret(struct tdb_context *tdb, int ret)
-{
-       char msg[sizeof(ret) * 4 + 4];
-       snprintf(msg, sizeof(msg), " = %i\n", ret);
-       tdb_trace_write(tdb, msg);
-}
-
-static void tdb_trace_record(struct tdb_context *tdb, TDB_DATA rec)
-{
-       char msg[20 + rec.dsize*2], *p;
-       unsigned int i;
-
-       /* We differentiate zero-length records from non-existent ones. */
-       if (rec.dptr == NULL) {
-               tdb_trace_write(tdb, " NULL");
-               return;
-       }
-
-       /* snprintf here is purely cargo-cult programming. */
-       p = msg;
-       p += snprintf(p, sizeof(msg), " %zu:", rec.dsize);
-       for (i = 0; i < rec.dsize; i++)
-               p += snprintf(p, 2, "%02x", rec.dptr[i]);
-
-       tdb_trace_write(tdb, msg);
-}
-
-void tdb_trace(struct tdb_context *tdb, const char *op)
-{
-       tdb_trace_start(tdb);
-       tdb_trace_write(tdb, op);
-       tdb_trace_end(tdb);
-}
-
-void tdb_trace_seqnum(struct tdb_context *tdb, uint32_t seqnum, const char *op)
-{
-       char msg[sizeof(tdb_off_t) * 4 + 1];
-
-       snprintf(msg, sizeof(msg), "%u ", seqnum);
-       tdb_trace_write(tdb, msg);
-       tdb_trace_write(tdb, op);
-       tdb_trace_end(tdb);
-}
-
-void tdb_trace_open(struct tdb_context *tdb, const char *op,
-                   unsigned hash_size, unsigned tdb_flags, unsigned open_flags)
-{
-       char msg[128];
-
-       snprintf(msg, sizeof(msg),
-                "%s %u 0x%x 0x%x", op, hash_size, tdb_flags, open_flags);
-       tdb_trace_start(tdb);
-       tdb_trace_write(tdb, msg);
-       tdb_trace_end(tdb);
-}
-
-void tdb_trace_ret(struct tdb_context *tdb, const char *op, int ret)
-{
-       tdb_trace_start(tdb);
-       tdb_trace_write(tdb, op);
-       tdb_trace_end_ret(tdb, ret);
-}
-
-void tdb_trace_retrec(struct tdb_context *tdb, const char *op, TDB_DATA ret)
-{
-       tdb_trace_start(tdb);
-       tdb_trace_write(tdb, op);
-       tdb_trace_write(tdb, " =");
-       tdb_trace_record(tdb, ret);
-       tdb_trace_end(tdb);
-}
-
-void tdb_trace_1rec(struct tdb_context *tdb, const char *op,
-                   TDB_DATA rec)
-{
-       tdb_trace_start(tdb);
-       tdb_trace_write(tdb, op);
-       tdb_trace_record(tdb, rec);
-       tdb_trace_end(tdb);
-}
-
-void tdb_trace_1rec_ret(struct tdb_context *tdb, const char *op,
-                       TDB_DATA rec, int ret)
-{
-       tdb_trace_start(tdb);
-       tdb_trace_write(tdb, op);
-       tdb_trace_record(tdb, rec);
-       tdb_trace_end_ret(tdb, ret);
-}
-
-void tdb_trace_1rec_retrec(struct tdb_context *tdb, const char *op,
-                          TDB_DATA rec, TDB_DATA ret)
-{
-       tdb_trace_start(tdb);
-       tdb_trace_write(tdb, op);
-       tdb_trace_record(tdb, rec);
-       tdb_trace_write(tdb, " =");
-       tdb_trace_record(tdb, ret);
-       tdb_trace_end(tdb);
-}
-
-void tdb_trace_2rec_flag_ret(struct tdb_context *tdb, const char *op,
-                            TDB_DATA rec1, TDB_DATA rec2, unsigned flag,
-                            int ret)
-{
-       char msg[1 + sizeof(ret) * 4];
-
-       snprintf(msg, sizeof(msg), " %#x", flag);
-       tdb_trace_start(tdb);
-       tdb_trace_write(tdb, op);
-       tdb_trace_record(tdb, rec1);
-       tdb_trace_record(tdb, rec2);
-       tdb_trace_write(tdb, msg);
-       tdb_trace_end_ret(tdb, ret);
-}
-
-void tdb_trace_2rec_retrec(struct tdb_context *tdb, const char *op,
-                          TDB_DATA rec1, TDB_DATA rec2, TDB_DATA ret)
-{
-       tdb_trace_start(tdb);
-       tdb_trace_write(tdb, op);
-       tdb_trace_record(tdb, rec1);
-       tdb_trace_record(tdb, rec2);
-       tdb_trace_write(tdb, " =");
-       tdb_trace_record(tdb, ret);
-       tdb_trace_end(tdb);
-}
-#endif
diff --git a/ccan/tdb/tdb.h b/ccan/tdb/tdb.h
deleted file mode 100644 (file)
index 6fd407a..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-#ifndef __TDB_H__
-#define __TDB_H__
-
-/* 
-   Unix SMB/CIFS implementation.
-
-   trivial database library
-
-   Copyright (C) Andrew Tridgell 1999-2004
-   
-     ** NOTE! The following LGPL license applies to the tdb
-     ** library. This does NOT imply that all of Samba is released
-     ** under the LGPL
-   
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifdef  __cplusplus
-extern "C" {
-#endif
-
-#ifndef _SAMBA_BUILD_
-/* For mode_t */
-#include <sys/types.h>
-/* For O_* flags. */
-#include <sys/stat.h>
-/* For sig_atomic_t. */
-#include <signal.h>
-#endif
-#include <ccan/compiler/compiler.h>
-
-/* flags to tdb_store() */
-#define TDB_REPLACE 1          /* Unused */
-#define TDB_INSERT 2           /* Don't overwrite an existing entry */
-#define TDB_MODIFY 3           /* Don't create an existing entry    */
-
-/* flags for tdb_open() */
-#define TDB_DEFAULT 0 /* just a readability place holder */
-#define TDB_CLEAR_IF_FIRST 1
-#define TDB_INTERNAL 2 /* don't store on disk */
-#define TDB_NOLOCK   4 /* don't do any locking */
-#define TDB_NOMMAP   8 /* don't use mmap */
-#define TDB_CONVERT 16 /* convert endian (internal use) */
-#define TDB_BIGENDIAN 32 /* header is big-endian (internal use) */
-#define TDB_NOSYNC   64 /* don't use synchronous transactions */
-#define TDB_SEQNUM   128 /* maintain a sequence number */
-#define TDB_VOLATILE   256 /* Activate the per-hashchain freelist, default 5 */
-#define TDB_ALLOW_NESTING 512 /* Allow transactions to nest */
-#define TDB_DISALLOW_NESTING 1024 /* Disallow transactions to nest */
-#define TDB_INCOMPATIBLE_HASH 2048 /* Better hashing: can't be opened by older tdb versions. */
-
-/* error codes */
-enum TDB_ERROR {TDB_SUCCESS=0, TDB_ERR_CORRUPT, TDB_ERR_IO, TDB_ERR_LOCK, 
-               TDB_ERR_OOM, TDB_ERR_EXISTS, TDB_ERR_NOLOCK, TDB_ERR_LOCK_TIMEOUT,
-               TDB_ERR_NOEXIST, TDB_ERR_EINVAL, TDB_ERR_RDONLY,
-               TDB_ERR_NESTING};
-
-/* debugging uses one of the following levels */
-enum tdb_debug_level {TDB_DEBUG_FATAL = 0, TDB_DEBUG_ERROR, 
-                     TDB_DEBUG_WARNING, TDB_DEBUG_TRACE};
-
-typedef struct TDB_DATA {
-       unsigned char *dptr;
-       size_t dsize;
-} TDB_DATA;
-
-/* this is the context structure that is returned from a db open */
-typedef struct tdb_context TDB_CONTEXT;
-
-typedef int (*tdb_traverse_func)(struct tdb_context *, TDB_DATA, TDB_DATA, void *);
-typedef void (*tdb_log_func)(struct tdb_context *, enum tdb_debug_level, const char *, ...) PRINTF_FMT(3, 4);
-typedef unsigned int (*tdb_hash_func)(TDB_DATA *key);
-
-struct tdb_logging_context {
-        tdb_log_func log_fn;
-        void *log_private;
-};
-
-struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags,
-                     int open_flags, mode_t mode);
-struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
-                        int open_flags, mode_t mode,
-                        const struct tdb_logging_context *log_ctx,
-                        tdb_hash_func hash_fn);
-void tdb_set_max_dead(struct tdb_context *tdb, int max_dead);
-
-int tdb_reopen(struct tdb_context *tdb);
-int tdb_reopen_all(int parent_longlived);
-void tdb_set_logging_function(struct tdb_context *tdb, const struct tdb_logging_context *log_ctx);
-enum TDB_ERROR tdb_error(struct tdb_context *tdb);
-const char *tdb_errorstr(struct tdb_context *tdb);
-TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key);
-int tdb_parse_record(struct tdb_context *tdb, TDB_DATA key,
-                    int (*parser)(TDB_DATA key, TDB_DATA data,
-                                  void *private_data),
-                    void *private_data);
-int tdb_delete(struct tdb_context *tdb, TDB_DATA key);
-int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag);
-int tdb_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf);
-int tdb_close(struct tdb_context *tdb);
-TDB_DATA tdb_firstkey(struct tdb_context *tdb);
-TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA key);
-int tdb_traverse(struct tdb_context *tdb, tdb_traverse_func fn, void *);
-int tdb_traverse_read(struct tdb_context *tdb, tdb_traverse_func fn, void *);
-int tdb_exists(struct tdb_context *tdb, TDB_DATA key);
-int tdb_lockall(struct tdb_context *tdb);
-int tdb_lockall_nonblock(struct tdb_context *tdb);
-int tdb_unlockall(struct tdb_context *tdb);
-int tdb_lockall_read(struct tdb_context *tdb);
-int tdb_lockall_read_nonblock(struct tdb_context *tdb);
-int tdb_unlockall_read(struct tdb_context *tdb);
-int tdb_lockall_mark(struct tdb_context *tdb);
-int tdb_lockall_unmark(struct tdb_context *tdb);
-const char *tdb_name(struct tdb_context *tdb);
-int tdb_fd(struct tdb_context *tdb);
-tdb_log_func tdb_log_fn(struct tdb_context *tdb);
-void *tdb_get_logging_private(struct tdb_context *tdb);
-int tdb_transaction_start(struct tdb_context *tdb);
-int tdb_transaction_prepare_commit(struct tdb_context *tdb);
-int tdb_transaction_commit(struct tdb_context *tdb);
-int tdb_transaction_cancel(struct tdb_context *tdb);
-int tdb_transaction_recover(struct tdb_context *tdb);
-int tdb_get_seqnum(struct tdb_context *tdb);
-int tdb_hash_size(struct tdb_context *tdb);
-size_t tdb_map_size(struct tdb_context *tdb);
-int tdb_get_flags(struct tdb_context *tdb);
-void tdb_add_flags(struct tdb_context *tdb, unsigned flag);
-void tdb_remove_flags(struct tdb_context *tdb, unsigned flag);
-void tdb_enable_seqnum(struct tdb_context *tdb);
-void tdb_increment_seqnum_nonblock(struct tdb_context *tdb);
-unsigned int tdb_jenkins_hash(TDB_DATA *key);
-int tdb_check(struct tdb_context *tdb,
-             int (*check)(TDB_DATA key, TDB_DATA data, void *private_data),
-             void *private_data);
-
-/* Low level locking functions: use with care */
-int tdb_chainlock(struct tdb_context *tdb, TDB_DATA key);
-int tdb_chainlock_nonblock(struct tdb_context *tdb, TDB_DATA key);
-int tdb_chainunlock(struct tdb_context *tdb, TDB_DATA key);
-int tdb_chainlock_read(struct tdb_context *tdb, TDB_DATA key);
-int tdb_chainunlock_read(struct tdb_context *tdb, TDB_DATA key);
-int tdb_chainlock_mark(struct tdb_context *tdb, TDB_DATA key);
-int tdb_chainlock_unmark(struct tdb_context *tdb, TDB_DATA key);
-
-void tdb_setalarm_sigptr(struct tdb_context *tdb, volatile sig_atomic_t *sigptr);
-
-/* wipe and repack */
-int tdb_wipe_all(struct tdb_context *tdb);
-int tdb_repack(struct tdb_context *tdb);
-
-/* Debug functions. Not used in production. */
-void tdb_dump_all(struct tdb_context *tdb);
-int tdb_printfreelist(struct tdb_context *tdb);
-int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries);
-int tdb_freelist_size(struct tdb_context *tdb);
-char *tdb_summary(struct tdb_context *tdb);
-
-extern TDB_DATA tdb_null;
-
-#ifdef  __cplusplus
-}
-#endif
-
-#endif /* tdb.h */
diff --git a/ccan/tdb/tdb_private.h b/ccan/tdb/tdb_private.h
deleted file mode 100644 (file)
index f1c841c..0000000
+++ /dev/null
@@ -1,308 +0,0 @@
-#ifndef TDB_PRIVATE_H
-#define TDB_PRIVATE_H
- /* 
-   Unix SMB/CIFS implementation.
-
-   trivial database library - private includes
-
-   Copyright (C) Andrew Tridgell              2005
-   
-     ** NOTE! The following LGPL license applies to the tdb
-     ** library. This does NOT imply that all of Samba is released
-     ** under the LGPL
-   
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifdef _SAMBA_BUILD_
-#include "replace.h"
-#include "system/filesys.h"
-#include "system/time.h"
-#include "system/shmem.h"
-#include "system/select.h"
-#include "system/wait.h"
-#else
-#include "config.h"
-#define _FILE_OFFSET_BITS 64
-#include <stdint.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <sys/time.h>
-#include <sys/mman.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
-#include <errno.h>
-#include <stdio.h>
-#include <utime.h>
-#endif
-#include "tdb.h"
-
-/* #define TDB_TRACE 1 */
-
-#ifndef __STRING
-#define __STRING(x)    #x
-#endif
-
-#ifndef __STRINGSTRING
-#define __STRINGSTRING(x) __STRING(x)
-#endif
-
-#ifndef __location__
-#define __location__ __FILE__ ":" __STRINGSTRING(__LINE__)
-#endif
-
-#if !HAVE_GETPAGESIZE
-#define getpagesize() 0x2000
-#endif
-
-typedef uint32_t tdb_len_t;
-typedef uint32_t tdb_off_t;
-
-#ifndef offsetof
-#define offsetof(t,f) ((size_t)&((t *)0)->f)
-#endif
-
-#define TDB_MAGIC_FOOD "TDB file\n"
-#define TDB_VERSION (0x26011967 + 6)
-#define TDB_MAGIC (0x26011999U)
-#define TDB_FREE_MAGIC (~TDB_MAGIC)
-#define TDB_DEAD_MAGIC (0xFEE1DEAD)
-#define TDB_RECOVERY_MAGIC (0xf53bc0e7U)
-#define TDB_RECOVERY_INVALID_MAGIC (0x0)
-#define TDB_HASH_RWLOCK_MAGIC (0xbad1a51U)
-#define TDB_ALIGNMENT 4
-#define DEFAULT_HASH_SIZE 131
-#define FREELIST_TOP (sizeof(struct tdb_header))
-#define TDB_ALIGN(x,a) (((x) + (a)-1) & ~((a)-1))
-#define TDB_BYTEREV(x) (((((x)&0xff)<<24)|((x)&0xFF00)<<8)|(((x)>>8)&0xFF00)|((x)>>24))
-#define TDB_DEAD(r) ((r)->magic == TDB_DEAD_MAGIC)
-#define TDB_BAD_MAGIC(r) ((r)->magic != TDB_MAGIC && !TDB_DEAD(r))
-#define TDB_HASH_TOP(hash) (FREELIST_TOP + (BUCKET(hash)+1)*sizeof(tdb_off_t))
-#define TDB_HASHTABLE_SIZE(tdb) ((tdb->header.hash_size+1)*sizeof(tdb_off_t))
-#define TDB_DATA_START(hash_size) (TDB_HASH_TOP(hash_size-1) + sizeof(tdb_off_t))
-#define TDB_RECOVERY_HEAD offsetof(struct tdb_header, recovery_start)
-#define TDB_SEQNUM_OFS    offsetof(struct tdb_header, sequence_number)
-#define TDB_PAD_BYTE 0x42
-#define TDB_PAD_U32  0x42424242
-
-/* NB assumes there is a local variable called "tdb" that is the
- * current context, also takes doubly-parenthesized print-style
- * argument. */
-#define TDB_LOG(x) tdb->log.log_fn x
-
-#ifdef TDB_TRACE
-void tdb_trace(struct tdb_context *tdb, const char *op);
-void tdb_trace_seqnum(struct tdb_context *tdb, uint32_t seqnum, const char *op);
-void tdb_trace_open(struct tdb_context *tdb, const char *op,
-                   unsigned hash_size, unsigned tdb_flags, unsigned open_flags);
-void tdb_trace_ret(struct tdb_context *tdb, const char *op, int ret);
-void tdb_trace_retrec(struct tdb_context *tdb, const char *op, TDB_DATA ret);
-void tdb_trace_1rec(struct tdb_context *tdb, const char *op,
-                   TDB_DATA rec);
-void tdb_trace_1rec_ret(struct tdb_context *tdb, const char *op,
-                       TDB_DATA rec, int ret);
-void tdb_trace_1rec_retrec(struct tdb_context *tdb, const char *op,
-                          TDB_DATA rec, TDB_DATA ret);
-void tdb_trace_2rec_flag_ret(struct tdb_context *tdb, const char *op,
-                            TDB_DATA rec1, TDB_DATA rec2, unsigned flag,
-                            int ret);
-void tdb_trace_2rec_retrec(struct tdb_context *tdb, const char *op,
-                          TDB_DATA rec1, TDB_DATA rec2, TDB_DATA ret);
-#else
-#define tdb_trace(tdb, op)
-#define tdb_trace_seqnum(tdb, seqnum, op)
-#define tdb_trace_open(tdb, op, hash_size, tdb_flags, open_flags)
-#define tdb_trace_ret(tdb, op, ret)
-#define tdb_trace_retrec(tdb, op, ret)
-#define tdb_trace_1rec(tdb, op, rec)
-#define tdb_trace_1rec_ret(tdb, op, rec, ret)
-#define tdb_trace_1rec_retrec(tdb, op, rec, ret)
-#define tdb_trace_2rec_flag_ret(tdb, op, rec1, rec2, flag, ret)
-#define tdb_trace_2rec_retrec(tdb, op, rec1, rec2, ret)
-#endif /* !TDB_TRACE */
-
-/* lock offsets */
-#define OPEN_LOCK        0
-#define ACTIVE_LOCK      4
-#define TRANSACTION_LOCK 8
-
-/* free memory if the pointer is valid and zero the pointer */
-#ifndef SAFE_FREE
-#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
-#endif
-
-#define BUCKET(hash) ((hash) % tdb->header.hash_size)
-
-#define DOCONV() (tdb->flags & TDB_CONVERT)
-#define CONVERT(x) (DOCONV() ? tdb_convert(&x, sizeof(x)) : &x)
-
-
-/* the body of the database is made of one tdb_record for the free space
-   plus a separate data list for each hash value */
-struct tdb_record {
-       tdb_off_t next; /* offset of the next record in the list */
-       tdb_len_t rec_len; /* total byte length of record */
-       tdb_len_t key_len; /* byte length of key */
-       tdb_len_t data_len; /* byte length of data */
-       uint32_t full_hash; /* the full 32 bit hash of the key */
-       uint32_t magic;   /* try to catch errors */
-       /* the following union is implied:
-               union {
-                       char record[rec_len];
-                       struct {
-                               char key[key_len];
-                               char data[data_len];
-                       }
-                       uint32_t totalsize; (tailer)
-               }
-       */
-};
-
-
-/* this is stored at the front of every database */
-struct tdb_header {
-       char magic_food[32]; /* for /etc/magic */
-       uint32_t version; /* version of the code */
-       uint32_t hash_size; /* number of hash entries */
-       tdb_off_t rwlocks; /* obsolete - kept to detect old formats */
-       tdb_off_t recovery_start; /* offset of transaction recovery region */
-       tdb_off_t sequence_number; /* used when TDB_SEQNUM is set */
-       uint32_t magic1_hash; /* hash of TDB_MAGIC_FOOD. */
-       uint32_t magic2_hash; /* hash of TDB_MAGIC. */
-       tdb_off_t reserved[27];
-};
-
-struct tdb_lock_type {
-       uint32_t off;
-       uint32_t count;
-       uint32_t ltype;
-};
-
-struct tdb_traverse_lock {
-       struct tdb_traverse_lock *next;
-       uint32_t off;
-       uint32_t hash;
-       int lock_rw;
-};
-
-enum tdb_lock_flags {
-       /* WAIT == F_SETLKW, NOWAIT == F_SETLK */
-       TDB_LOCK_NOWAIT = 0,
-       TDB_LOCK_WAIT = 1,
-       /* If set, don't log an error on failure. */
-       TDB_LOCK_PROBE = 2,
-       /* If set, don't actually lock at all. */
-       TDB_LOCK_MARK_ONLY = 4,
-};
-
-struct tdb_methods {
-       int (*tdb_read)(struct tdb_context *, tdb_off_t , void *, tdb_len_t , int );
-       int (*tdb_write)(struct tdb_context *, tdb_off_t, const void *, tdb_len_t);
-       void (*next_hash_chain)(struct tdb_context *, uint32_t *);
-       int (*tdb_oob)(struct tdb_context *, tdb_off_t , int );
-       int (*tdb_expand_file)(struct tdb_context *, tdb_off_t , tdb_off_t );
-};
-
-struct tdb_context {
-       char *name; /* the name of the database */
-       void *map_ptr; /* where it is currently mapped */
-       int fd; /* open file descriptor for the database */
-       tdb_len_t map_size; /* how much space has been mapped */
-       int read_only; /* opened read-only */
-       int traverse_read; /* read-only traversal */
-       int traverse_write; /* read-write traversal */
-       struct tdb_lock_type allrecord_lock; /* .offset == upgradable */
-       int num_lockrecs;
-       struct tdb_lock_type *lockrecs; /* only real locks, all with count>0 */
-       enum TDB_ERROR ecode; /* error code for last tdb error */
-       struct tdb_header header; /* a cached copy of the header */
-       uint32_t flags; /* the flags passed to tdb_open */
-       struct tdb_traverse_lock travlocks; /* current traversal locks */
-       struct tdb_context *next; /* all tdbs to avoid multiple opens */
-       dev_t device;   /* uniquely identifies this tdb */
-       ino_t inode;    /* uniquely identifies this tdb */
-       struct tdb_logging_context log;
-       unsigned int (*hash_fn)(TDB_DATA *key);
-       int open_flags; /* flags used in the open - needed by reopen */
-       const struct tdb_methods *methods;
-       struct tdb_transaction *transaction;
-       int page_size;
-       int max_dead_records;
-#ifdef TDB_TRACE
-       int tracefd;
-#endif
-       volatile sig_atomic_t *interrupt_sig_ptr;
-};
-
-
-/*
-  internal prototypes
-*/
-int tdb_munmap(struct tdb_context *tdb);
-void tdb_mmap(struct tdb_context *tdb);
-int tdb_lock(struct tdb_context *tdb, int list, int ltype);
-int tdb_lock_nonblock(struct tdb_context *tdb, int list, int ltype);
-int tdb_nest_lock(struct tdb_context *tdb, uint32_t offset, int ltype,
-                 enum tdb_lock_flags flags);
-int tdb_nest_unlock(struct tdb_context *tdb, uint32_t offset, int ltype,
-                   bool mark_lock);
-bool tdb_have_locks(struct tdb_context *tdb);
-int tdb_unlock(struct tdb_context *tdb, int list, int ltype);
-int tdb_brlock(struct tdb_context *tdb,
-              int rw_type, tdb_off_t offset, size_t len,
-              enum tdb_lock_flags flags);
-int tdb_brunlock(struct tdb_context *tdb,
-                int rw_type, tdb_off_t offset, size_t len);
-bool tdb_have_extra_locks(struct tdb_context *tdb);
-void tdb_release_extra_locks(struct tdb_context *tdb);
-int tdb_transaction_lock(struct tdb_context *tdb, int ltype);
-int tdb_transaction_unlock(struct tdb_context *tdb, int ltype);
-int tdb_allrecord_lock(struct tdb_context *tdb, int ltype,
-                      enum tdb_lock_flags flags, bool upgradable);
-int tdb_allrecord_unlock(struct tdb_context *tdb, int ltype, bool mark_lock);
-int tdb_allrecord_upgrade(struct tdb_context *tdb);
-int tdb_write_lock_record(struct tdb_context *tdb, tdb_off_t off);
-int tdb_write_unlock_record(struct tdb_context *tdb, tdb_off_t off);
-int tdb_ofs_read(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d);
-int tdb_ofs_write(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d);
-void *tdb_convert(void *buf, uint32_t size);
-int tdb_free(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec);
-tdb_off_t tdb_allocate(struct tdb_context *tdb, tdb_len_t length, struct tdb_record *rec);
-int tdb_ofs_read(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d);
-int tdb_ofs_write(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d);
-int tdb_lock_record(struct tdb_context *tdb, tdb_off_t off);
-int tdb_unlock_record(struct tdb_context *tdb, tdb_off_t off);
-bool tdb_needs_recovery(struct tdb_context *tdb);
-int tdb_rec_read(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec);
-int tdb_rec_write(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec);
-int tdb_do_delete(struct tdb_context *tdb, tdb_off_t rec_ptr, struct tdb_record *rec);
-unsigned char *tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t len);
-int tdb_parse_data(struct tdb_context *tdb, TDB_DATA key,
-                  tdb_off_t offset, tdb_len_t len,
-                  int (*parser)(TDB_DATA key, TDB_DATA data,
-                                void *private_data),
-                  void *private_data);
-tdb_off_t tdb_find_lock_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, int locktype,
-                          struct tdb_record *rec);
-void tdb_io_init(struct tdb_context *tdb);
-int tdb_expand(struct tdb_context *tdb, tdb_off_t size);
-tdb_off_t tdb_expand_adjust(tdb_off_t map_size, tdb_off_t size, int page_size);
-int tdb_rec_free_read(struct tdb_context *tdb, tdb_off_t off,
-                     struct tdb_record *rec);
-void tdb_header_hash(struct tdb_context *tdb,
-                    uint32_t *magic1_hash, uint32_t *magic2_hash);
-unsigned int tdb_old_hash(TDB_DATA *key);
-size_t tdb_dead_space(struct tdb_context *tdb, tdb_off_t off);
-#endif
diff --git a/ccan/tdb/test/external-agent.c b/ccan/tdb/test/external-agent.c
deleted file mode 100644 (file)
index 503b00d..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-#include "external-agent.h"
-#include "lock-tracking.h"
-#include "logging.h"
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <err.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <limits.h>
-#include <string.h>
-#include <errno.h>
-#include <ccan/tdb/tdb.h>
-#include <ccan/tdb/tdb_private.h>
-#include <ccan/tap/tap.h>
-#include <stdio.h>
-#include <stdarg.h>
-
-static struct tdb_context *tdb;
-
-static enum agent_return do_operation(enum operation op, const char *name)
-{
-       TDB_DATA k;
-       enum agent_return ret;
-       TDB_DATA data;
-
-       if (op != OPEN && op != OPEN_WITH_CLEAR_IF_FIRST && !tdb) {
-               diag("external: No tdb open!");
-               return OTHER_FAILURE;
-       }
-
-       k.dptr = (void *)name;
-       k.dsize = strlen(name);
-
-       locking_would_block = 0;
-       switch (op) {
-       case OPEN:
-               if (tdb) {
-                       diag("Already have tdb %s open", tdb_name(tdb));
-                       return OTHER_FAILURE;
-               }
-               tdb = tdb_open_ex(name, 0, TDB_DEFAULT, O_RDWR, 0,
-                                 &taplogctx, NULL);
-               if (!tdb) {
-                       if (!locking_would_block)
-                               diag("Opening tdb gave %s", strerror(errno));
-                       ret = OTHER_FAILURE;
-               } else
-                       ret = SUCCESS;
-               break;
-       case OPEN_WITH_CLEAR_IF_FIRST:
-               if (tdb)
-                       return OTHER_FAILURE;
-               tdb = tdb_open_ex(name, 0, TDB_CLEAR_IF_FIRST, O_RDWR, 0,
-                                 &taplogctx, NULL);
-               ret = tdb ? SUCCESS : OTHER_FAILURE;
-               break;
-       case TRANSACTION_START:
-               ret = tdb_transaction_start(tdb) == 0 ? SUCCESS : OTHER_FAILURE;
-               break;
-       case FETCH:
-               data = tdb_fetch(tdb, k);
-               if (data.dptr == NULL) {
-                       if (tdb_error(tdb) == TDB_ERR_NOEXIST)
-                               ret = FAILED;
-                       else
-                               ret = OTHER_FAILURE;
-               } else if (data.dsize != k.dsize
-                          || memcmp(data.dptr, k.dptr, k.dsize) != 0) {
-                       ret = OTHER_FAILURE;
-               } else {
-                       ret = SUCCESS;
-               }
-               free(data.dptr);
-               break;
-       case STORE:
-               ret = tdb_store(tdb, k, k, 0) == 0 ? SUCCESS : OTHER_FAILURE;
-               break;
-       case TRANSACTION_COMMIT:
-               ret = tdb_transaction_commit(tdb)==0 ? SUCCESS : OTHER_FAILURE;
-               break;
-       case CHECK:
-               ret = tdb_check(tdb, NULL, NULL) == 0 ? SUCCESS : OTHER_FAILURE;
-               break;
-       case NEEDS_RECOVERY:
-               ret = tdb_needs_recovery(tdb) ? SUCCESS : FAILED;
-               break;
-       case CLOSE:
-               ret = tdb_close(tdb) == 0 ? SUCCESS : OTHER_FAILURE;
-               tdb = NULL;
-               break;
-       default:
-               ret = OTHER_FAILURE;
-       }
-
-       if (locking_would_block)
-               ret = WOULD_HAVE_BLOCKED;
-
-       return ret;
-}
-
-struct agent {
-       int cmdfd, responsefd;
-};
-
-/* Do this before doing any tdb stuff.  Return handle, or NULL. */
-struct agent *prepare_external_agent(void)
-{
-       int pid, ret;
-       int command[2], response[2];
-       char name[1+PATH_MAX];
-
-       if (pipe(command) != 0 || pipe(response) != 0)
-               return NULL;
-
-       pid = fork();
-       if (pid < 0)
-               return NULL;
-
-       if (pid != 0) {
-               struct agent *agent = malloc(sizeof(*agent));
-
-               close(command[0]);
-               close(response[1]);
-               agent->cmdfd = command[1];
-               agent->responsefd = response[0];
-               return agent;
-       }
-
-       close(command[1]);
-       close(response[0]);
-
-       /* We want to fail, not block. */
-       nonblocking_locks = true;
-       log_prefix = "external: ";
-       while ((ret = read(command[0], name, sizeof(name))) > 0) {
-               enum agent_return result;
-
-               result = do_operation(name[0], name+1);
-               if (write(response[1], &result, sizeof(result))
-                   != sizeof(result))
-                       err(1, "Writing response");
-       }
-       exit(0);
-}
-
-/* Ask the external agent to try to do an operation. */
-enum agent_return external_agent_operation(struct agent *agent,
-                                          enum operation op,
-                                          const char *name)
-{
-       enum agent_return res;
-       unsigned int len;
-       char *string;
-
-       if (!name)
-               name = "";
-       len = 1 + strlen(name) + 1;
-       string = malloc(len);
-
-       string[0] = op;
-       strcpy(string+1, name);
-
-       if (write(agent->cmdfd, string, len) != len
-           || read(agent->responsefd, &res, sizeof(res)) != sizeof(res))
-               res = AGENT_DIED;
-
-       free(string);
-       return res;
-}
-
-const char *agent_return_name(enum agent_return ret)
-{
-       return ret == SUCCESS ? "SUCCESS"
-               : ret == WOULD_HAVE_BLOCKED ? "WOULD_HAVE_BLOCKED"
-               : ret == AGENT_DIED ? "AGENT_DIED"
-               : ret == FAILED ? "FAILED"
-               : ret == OTHER_FAILURE ? "OTHER_FAILURE"
-               : "**INVALID**";
-}
-
-const char *operation_name(enum operation op)
-{
-       switch (op) {
-       case OPEN: return "OPEN";
-       case OPEN_WITH_CLEAR_IF_FIRST: return "OPEN_WITH_CLEAR_IF_FIRST";
-       case TRANSACTION_START: return "TRANSACTION_START";
-       case FETCH: return "FETCH";
-       case STORE: return "STORE";
-       case TRANSACTION_COMMIT: return "TRANSACTION_COMMIT";
-       case CHECK: return "CHECK";
-       case NEEDS_RECOVERY: return "NEEDS_RECOVERY";
-       case CLOSE: return "CLOSE";
-       }
-       return "**INVALID**";
-}
diff --git a/ccan/tdb/test/external-agent.h b/ccan/tdb/test/external-agent.h
deleted file mode 100644 (file)
index ce3755e..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef TDB_TEST_EXTERNAL_AGENT_H
-#define TDB_TEST_EXTERNAL_AGENT_H
-
-/* For locking tests, we need a different process to try things at
- * various times. */
-enum operation {
-       OPEN,
-       OPEN_WITH_CLEAR_IF_FIRST,
-       TRANSACTION_START,
-       FETCH,
-       STORE,
-       TRANSACTION_COMMIT,
-       CHECK,
-       NEEDS_RECOVERY,
-       CLOSE,
-};
-
-/* Do this before doing any tdb stuff.  Return handle, or -1. */
-struct agent *prepare_external_agent(void);
-
-enum agent_return {
-       SUCCESS,
-       WOULD_HAVE_BLOCKED,
-       AGENT_DIED,
-       FAILED, /* For fetch, or NEEDS_RECOVERY */
-       OTHER_FAILURE,
-};
-
-/* Ask the external agent to try to do an operation. 
- * name == tdb name for OPEN/OPEN_WITH_CLEAR_IF_FIRST,
- * record name for FETCH/STORE (store stores name as data too)
- */
-enum agent_return external_agent_operation(struct agent *handle,
-                                          enum operation op,
-                                          const char *name);
-
-/* Mapping enum -> string. */
-const char *agent_return_name(enum agent_return ret);
-const char *operation_name(enum operation op);
-
-#endif /* TDB_TEST_EXTERNAL_AGENT_H */
diff --git a/ccan/tdb/test/jenkins-be-hash.tdb b/ccan/tdb/test/jenkins-be-hash.tdb
deleted file mode 100644 (file)
index b652840..0000000
Binary files a/ccan/tdb/test/jenkins-be-hash.tdb and /dev/null differ
diff --git a/ccan/tdb/test/jenkins-le-hash.tdb b/ccan/tdb/test/jenkins-le-hash.tdb
deleted file mode 100644 (file)
index 007e0a3..0000000
Binary files a/ccan/tdb/test/jenkins-le-hash.tdb and /dev/null differ
diff --git a/ccan/tdb/test/lock-tracking.c b/ccan/tdb/test/lock-tracking.c
deleted file mode 100644 (file)
index 8e8bb99..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/* We save the locks so we can reaquire them. */
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <ccan/tap/tap.h>
-#include <ccan/tdb/tdb_private.h>
-#include "lock-tracking.h"
-
-struct lock {
-       struct lock *next;
-       unsigned int off;
-       unsigned int len;
-       int type;
-};
-static struct lock *locks;
-int locking_errors = 0;
-bool suppress_lockcheck = false;
-bool nonblocking_locks;
-int locking_would_block = 0;
-void (*unlock_callback)(int fd);
-
-int fcntl_with_lockcheck(int fd, int cmd, ... /* arg */ )
-{
-       va_list ap;
-       int ret, arg3;
-       struct flock *fl;
-       bool may_block = false;
-
-       if (cmd != F_SETLK && cmd != F_SETLKW) {
-               /* This may be totally bogus, but we don't know in general. */
-               va_start(ap, cmd);
-               arg3 = va_arg(ap, int);
-               va_end(ap);
-
-               return fcntl(fd, cmd, arg3);
-       }
-
-       va_start(ap, cmd);
-       fl = va_arg(ap, struct flock *);
-       va_end(ap);
-
-       if (cmd == F_SETLKW && nonblocking_locks) {
-               cmd = F_SETLK;
-               may_block = true;
-       }
-       ret = fcntl(fd, cmd, fl);
-
-       /* Detect when we failed, but might have been OK if we waited. */
-       if (may_block && ret == -1 && (errno == EAGAIN || errno == EACCES)) {
-               locking_would_block++;
-       }
-
-       if (fl->l_type == F_UNLCK) {
-               struct lock **l;
-               struct lock *old = NULL;
-                       
-               for (l = &locks; *l; l = &(*l)->next) {
-                       if ((*l)->off == fl->l_start
-                           && (*l)->len == fl->l_len) {
-                               if (ret == 0) {
-                                       old = *l;
-                                       *l = (*l)->next;
-                                       free(old);
-                               }
-                               break;
-                       }
-               }
-               if (!old && !suppress_lockcheck) {
-                       diag("Unknown unlock %u@%u - %i",
-                            (int)fl->l_len, (int)fl->l_start, ret);
-                       locking_errors++;
-               }
-       } else {
-               struct lock *new, *i;
-               unsigned int fl_end = fl->l_start + fl->l_len;
-               if (fl->l_len == 0)
-                       fl_end = (unsigned int)-1;
-
-               /* Check for overlaps: we shouldn't do this. */
-               for (i = locks; i; i = i->next) {
-                       unsigned int i_end = i->off + i->len;
-                       if (i->len == 0)
-                               i_end = (unsigned int)-1;
-
-                       if (fl->l_start >= i->off && fl->l_start < i_end)
-                               break;
-                       if (fl_end >= i->off && fl_end < i_end)
-                               break;
-
-                       /* tdb_allrecord_lock does this, handle adjacent: */
-                       if (fl->l_start == i_end && fl->l_type == i->type) {
-                               if (ret == 0) {
-                                       i->len = fl->l_len 
-                                               ? i->len + fl->l_len
-                                               : 0;
-                               }
-                               goto done;
-                       }
-               }
-               if (i) {
-                       /* Special case: upgrade of allrecord lock. */
-                       if (i->type == F_RDLCK && fl->l_type == F_WRLCK
-                           && i->off == FREELIST_TOP
-                           && fl->l_start == FREELIST_TOP
-                           && i->len == 0
-                           && fl->l_len == 0) {
-                               if (ret == 0)
-                                       i->type = F_WRLCK;
-                               goto done;
-                       }
-                       if (!suppress_lockcheck) {
-                               diag("%s lock %u@%u overlaps %u@%u",
-                                    fl->l_type == F_WRLCK ? "write" : "read",
-                                    (int)fl->l_len, (int)fl->l_start,
-                                    i->len, (int)i->off);
-                               locking_errors++;
-                       }
-               }
-
-               if (ret == 0) {
-                       new = malloc(sizeof *new);
-                       new->off = fl->l_start;
-                       new->len = fl->l_len;
-                       new->type = fl->l_type;
-                       new->next = locks;
-                       locks = new;
-               }
-       }
-done:
-       if (ret == 0 && fl->l_type == F_UNLCK && unlock_callback)
-               unlock_callback(fd);
-       return ret;
-}
-
-unsigned int forget_locking(void)
-{
-       unsigned int num = 0;
-       while (locks) {
-               struct lock *next = locks->next;
-               free(locks);
-               locks = next;
-               num++;
-       }
-       return num;
-}
diff --git a/ccan/tdb/test/lock-tracking.h b/ccan/tdb/test/lock-tracking.h
deleted file mode 100644 (file)
index f2c9c44..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef LOCK_TRACKING_H
-#define LOCK_TRACKING_H
-#include <stdbool.h>
-
-/* Set this if you want a callback after fnctl unlock. */
-extern void (*unlock_callback)(int fd);
-
-/* Replacement fcntl. */
-int fcntl_with_lockcheck(int fd, int cmd, ... /* arg */ );
-
-/* Discard locking info: returns number of locks outstanding. */
-unsigned int forget_locking(void);
-
-/* Number of errors in locking. */
-extern int locking_errors;
-
-/* Suppress lock checking. */
-extern bool suppress_lockcheck;
-
-/* Make all locks non-blocking. */
-extern bool nonblocking_locks;
-
-/* Number of times we failed a lock because we made it non-blocking. */
-extern int locking_would_block;
-#endif /* LOCK_TRACKING_H */
diff --git a/ccan/tdb/test/logging.c b/ccan/tdb/test/logging.c
deleted file mode 100644 (file)
index ae598a9..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#include "logging.h"
-#include <ccan/tap/tap.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-bool suppress_logging = false;
-const char *log_prefix = "";
-
-/* Turn log messages into tap diag messages. */
-static void taplog(struct tdb_context *tdb,
-                  enum tdb_debug_level level,
-                  const char *fmt, ...)
-{
-       va_list ap;
-       char line[200];
-
-       if (suppress_logging)
-               return;
-
-       va_start(ap, fmt);
-       vsprintf(line, fmt, ap);
-       va_end(ap);
-
-       /* Strip trailing \n: diag adds it. */
-       if (line[0] && line[strlen(line)-1] == '\n')
-               diag("%s%.*s", log_prefix, (unsigned)strlen(line)-1, line);
-       else
-               diag("%s%s", log_prefix, line);
-}
-
-struct tdb_logging_context taplogctx = { taplog, NULL };
diff --git a/ccan/tdb/test/logging.h b/ccan/tdb/test/logging.h
deleted file mode 100644 (file)
index 6745a32..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef TDB_TEST_LOGGING_H
-#define TDB_TEST_LOGGING_H
-#include <ccan/tdb/tdb.h>
-#include <stdbool.h>
-
-extern bool suppress_logging;
-extern const char *log_prefix;
-extern struct tdb_logging_context taplogctx;
-
-#endif /* TDB_TEST_LOGGING_H */
diff --git a/ccan/tdb/test/old-nohash-be.tdb b/ccan/tdb/test/old-nohash-be.tdb
deleted file mode 100644 (file)
index 1c49116..0000000
Binary files a/ccan/tdb/test/old-nohash-be.tdb and /dev/null differ
diff --git a/ccan/tdb/test/old-nohash-le.tdb b/ccan/tdb/test/old-nohash-le.tdb
deleted file mode 100644 (file)
index 0655072..0000000
Binary files a/ccan/tdb/test/old-nohash-le.tdb and /dev/null differ
diff --git a/ccan/tdb/test/run-3G-file.c b/ccan/tdb/test/run-3G-file.c
deleted file mode 100644 (file)
index d56aed5..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/* We need this otherwise fcntl locking fails. */
-#define _FILE_OFFSET_BITS 64
-#define _XOPEN_SOURCE 500
-#include <ccan/tdb/tdb.h>
-#include <ccan/tdb/io.c>
-#include <ccan/tdb/tdb.c>
-#include <ccan/tdb/lock.c>
-#include <ccan/tdb/freelist.c>
-#include <ccan/tdb/traverse.c>
-#include <ccan/tdb/transaction.c>
-#include <ccan/tdb/error.c>
-#include <ccan/tdb/open.c>
-#include <ccan/tdb/check.c>
-#include <ccan/tdb/hash.c>
-#include <ccan/tap/tap.h>
-#include <stdlib.h>
-#include <err.h>
-#include "logging.h"
-
-static int tdb_expand_file_sparse(struct tdb_context *tdb,
-                                 tdb_off_t size,
-                                 tdb_off_t addition)
-{
-       if (tdb->read_only || tdb->traverse_read) {
-               tdb->ecode = TDB_ERR_RDONLY;
-               return -1;
-       }
-
-       if (ftruncate(tdb->fd, size+addition) == -1) {
-               char b = 0;
-               ssize_t written = pwrite(tdb->fd,  &b, 1, (size+addition) - 1);
-               if (written == 0) {
-                       /* try once more, potentially revealing errno */
-                       written = pwrite(tdb->fd,  &b, 1, (size+addition) - 1);
-               }
-               if (written == 0) {
-                       /* again - give up, guessing errno */
-                       errno = ENOSPC;
-               }
-               if (written != 1) {
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file to %d failed (%s)\n", 
-                                size+addition, strerror(errno)));
-                       return -1;
-               }
-       }
-
-       return 0;
-}
-
-static const struct tdb_methods large_io_methods = {
-       tdb_read,
-       tdb_write,
-       tdb_next_hash_chain,
-       tdb_oob,
-       tdb_expand_file_sparse
-};
-
-static int test_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data,
-                        void *_data)
-{
-       TDB_DATA *expect = _data;
-       ok1(key.dsize == strlen("hi"));
-       ok1(memcmp(key.dptr, "hi", strlen("hi")) == 0);
-       ok1(data.dsize == expect->dsize);
-       ok1(memcmp(data.dptr, expect->dptr, data.dsize) == 0);
-       return 0;
-}
-
-int main(int argc, char *argv[])
-{
-       struct tdb_context *tdb;
-       TDB_DATA key, orig_data, data;
-       uint32_t hash;
-       tdb_off_t rec_ptr;
-       struct tdb_record rec;
-
-       plan_tests(24);
-       tdb = tdb_open_ex("run-36-file.tdb", 1024, TDB_CLEAR_IF_FIRST,
-                         O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL);
-
-       ok1(tdb);
-       tdb->methods = &large_io_methods;
-
-       /* Enlarge the file (internally multiplies by 100). */
-       ok1(tdb_expand(tdb, 30000000) == 0);
-
-       /* Put an entry in, and check it. */
-       key.dsize = strlen("hi");
-       key.dptr = (void *)"hi";
-       orig_data.dsize = strlen("world");
-       orig_data.dptr = (void *)"world";
-
-       ok1(tdb_store(tdb, key, orig_data, TDB_INSERT) == 0);
-
-       data = tdb_fetch(tdb, key);
-       ok1(data.dsize == strlen("world"));
-       ok1(memcmp(data.dptr, "world", strlen("world")) == 0);
-       free(data.dptr);
-
-       /* That currently fills at the end, make sure that's true. */
-       hash = tdb->hash_fn(&key);
-       rec_ptr = tdb_find_lock_hash(tdb, key, hash, F_RDLCK, &rec);
-       ok1(rec_ptr);
-       ok1(rec_ptr > 2U*1024*1024*1024);
-       tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
-
-       /* Traverse must work. */
-       ok1(tdb_traverse(tdb, test_traverse, &orig_data) == 1);
-
-       /* Delete should work. */
-       ok1(tdb_delete(tdb, key) == 0);
-
-       ok1(tdb_traverse(tdb, test_traverse, NULL) == 0);
-
-       /* Transactions should work. */
-       ok1(tdb_transaction_start(tdb) == 0);
-       ok1(tdb_store(tdb, key, orig_data, TDB_INSERT) == 0);
-
-       data = tdb_fetch(tdb, key);
-       ok1(data.dsize == strlen("world"));
-       ok1(memcmp(data.dptr, "world", strlen("world")) == 0);
-       free(data.dptr);
-       ok1(tdb_transaction_commit(tdb) == 0);
-
-       ok1(tdb_traverse(tdb, test_traverse, &orig_data) == 1);
-       tdb_close(tdb);
-
-       return exit_status();
-}
diff --git a/ccan/tdb/test/run-bad-tdb-header.c b/ccan/tdb/test/run-bad-tdb-header.c
deleted file mode 100644 (file)
index 330381b..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-#define _XOPEN_SOURCE 500
-#include <ccan/tdb/tdb.h>
-#include <ccan/tdb/io.c>
-#include <ccan/tdb/tdb.c>
-#include <ccan/tdb/lock.c>
-#include <ccan/tdb/freelist.c>
-#include <ccan/tdb/traverse.c>
-#include <ccan/tdb/transaction.c>
-#include <ccan/tdb/error.c>
-#include <ccan/tdb/open.c>
-#include <ccan/tdb/check.c>
-#include <ccan/tdb/hash.c>
-#include <ccan/tap/tap.h>
-#include <stdlib.h>
-#include <err.h>
-#include "logging.h"
-
-int main(int argc, char *argv[])
-{
-       struct tdb_context *tdb;
-       struct tdb_header hdr;
-       int fd;
-
-       plan_tests(11);
-       /* Can open fine if complete crap, as long as O_CREAT. */
-       fd = open("run-bad-tdb-header.tdb", O_RDWR|O_CREAT|O_TRUNC, 0600);
-       ok1(fd >= 0);
-       ok1(write(fd, "hello world", 11) == 11);
-       close(fd);
-       tdb = tdb_open_ex("run-bad-tdb-header.tdb", 1024, 0, O_RDWR, 0,
-                         &taplogctx, NULL);
-       ok1(!tdb);
-       tdb = tdb_open_ex("run-bad-tdb-header.tdb", 1024, 0, O_CREAT|O_RDWR,
-                         0600, &taplogctx, NULL);
-       ok1(tdb);
-       tdb_close(tdb);
-
-       /* Now, with wrong version it should *not* overwrite. */
-       fd = open("run-bad-tdb-header.tdb", O_RDWR);
-       ok1(fd >= 0);
-       ok1(read(fd, &hdr, sizeof(hdr)) == sizeof(hdr));
-       ok1(hdr.version == TDB_VERSION);
-       hdr.version++;
-       lseek(fd, 0, SEEK_SET);
-       ok1(write(fd, &hdr, sizeof(hdr)) == sizeof(hdr));
-       close(fd);
-
-       tdb = tdb_open_ex("run-bad-tdb-header.tdb", 1024, 0, O_RDWR|O_CREAT,
-                         0600, &taplogctx, NULL);
-       ok1(errno == EIO);
-       ok1(!tdb);
-
-       /* With truncate, will be fine. */
-       tdb = tdb_open_ex("run-bad-tdb-header.tdb", 1024, 0,
-                         O_RDWR|O_CREAT|O_TRUNC, 0600, &taplogctx, NULL);
-       ok1(tdb);
-       tdb_close(tdb);
-
-       return exit_status();
-}
diff --git a/ccan/tdb/test/run-check.c b/ccan/tdb/test/run-check.c
deleted file mode 100644 (file)
index f96647b..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-#define _XOPEN_SOURCE 500
-#include <ccan/tdb/tdb.h>
-#include <ccan/tdb/io.c>
-#include <ccan/tdb/tdb.c>
-#include <ccan/tdb/lock.c>
-#include <ccan/tdb/freelist.c>
-#include <ccan/tdb/traverse.c>
-#include <ccan/tdb/transaction.c>
-#include <ccan/tdb/error.c>
-#include <ccan/tdb/open.c>
-#include <ccan/tdb/check.c>
-#include <ccan/tdb/hash.c>
-#include <ccan/tap/tap.h>
-#include <stdlib.h>
-#include <err.h>
-#include "logging.h"
-
-int main(int argc, char *argv[])
-{
-       struct tdb_context *tdb;
-       TDB_DATA key, data;
-
-       plan_tests(13);
-       tdb = tdb_open_ex("run-check.tdb", 1, TDB_CLEAR_IF_FIRST,
-                         O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL);
-
-       ok1(tdb);
-       ok1(tdb_check(tdb, NULL, NULL) == 0);
-       
-       key.dsize = strlen("hi");
-       key.dptr = (void *)"hi";
-       data.dsize = strlen("world");
-       data.dptr = (void *)"world";
-
-       ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
-       ok1(tdb_check(tdb, NULL, NULL) == 0);
-       tdb_close(tdb);
-
-       tdb = tdb_open_ex("run-check.tdb", 1024, 0, O_RDWR, 0,
-                         &taplogctx, NULL);
-       ok1(tdb);
-       ok1(tdb_check(tdb, NULL, NULL) == 0);
-       tdb_close(tdb);
-
-       tdb = tdb_open_ex("test/tdb.corrupt", 1024, 0, O_RDWR, 0,
-                         &taplogctx, NULL);
-       ok1(tdb);
-       ok1(tdb_check(tdb, NULL, NULL) == -1);
-       ok1(tdb_error(tdb) == TDB_ERR_CORRUPT);
-       tdb_close(tdb);
-
-       /* Big and little endian should work! */
-       tdb = tdb_open_ex("test/old-nohash-le.tdb", 1024, 0, O_RDWR, 0,
-                         &taplogctx, NULL);
-       ok1(tdb);
-       ok1(tdb_check(tdb, NULL, NULL) == 0);
-       tdb_close(tdb);
-
-       tdb = tdb_open_ex("test/old-nohash-be.tdb", 1024, 0, O_RDWR, 0,
-                         &taplogctx, NULL);
-       ok1(tdb);
-       ok1(tdb_check(tdb, NULL, NULL) == 0);
-       tdb_close(tdb);
-
-       return exit_status();
-}
diff --git a/ccan/tdb/test/run-corrupt.c b/ccan/tdb/test/run-corrupt.c
deleted file mode 100644 (file)
index 6f753ea..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-#define _XOPEN_SOURCE 500
-#include <ccan/tdb/tdb.h>
-#include <ccan/tdb/io.c>
-#include <ccan/tdb/tdb.c>
-#include <ccan/tdb/lock.c>
-#include <ccan/tdb/freelist.c>
-#include <ccan/tdb/traverse.c>
-#include <ccan/tdb/transaction.c>
-#include <ccan/tdb/error.c>
-#include <ccan/tdb/open.c>
-#include <ccan/tdb/check.c>
-#include <ccan/tdb/hash.c>
-#include <ccan/tap/tap.h>
-#include <stdlib.h>
-#include <err.h>
-#include "logging.h"
-
-static int check(TDB_DATA key, TDB_DATA data, void *private)
-{
-       unsigned int *sizes = private;
-
-       if (key.dsize > strlen("hello"))
-               return -1;
-       if (memcmp(key.dptr, "hello", key.dsize) != 0)
-               return -1;
-
-       if (data.dsize != strlen("world"))
-               return -1;
-       if (memcmp(data.dptr, "world", data.dsize) != 0)
-               return -1;
-
-       sizes[0] += key.dsize;
-       sizes[1] += data.dsize;
-       return 0;
-}
-
-static void tdb_flip_bit(struct tdb_context *tdb, unsigned int bit)
-{
-       unsigned int off = bit / CHAR_BIT;
-       unsigned char mask = (1 << (bit % CHAR_BIT));
-
-       if (tdb->map_ptr)
-               ((unsigned char *)tdb->map_ptr)[off] ^= mask;
-       else {
-               unsigned char c;
-               if (pread(tdb->fd, &c, 1, off) != 1)
-                       err(1, "pread");
-               c ^= mask;
-               if (pwrite(tdb->fd, &c, 1, off) != 1)
-                       err(1, "pwrite");
-       }
-}
-
-static void check_test(struct tdb_context *tdb)
-{
-       TDB_DATA key, data;
-       unsigned int i, verifiable, corrupt, sizes[2], dsize, ksize;
-
-       ok1(tdb_check(tdb, NULL, NULL) == 0);
-       
-       key.dptr = (void *)"hello";
-       data.dsize = strlen("world");
-       data.dptr = (void *)"world";
-
-       /* Key and data size respectively. */
-       dsize = ksize = 0;
-
-       /* 5 keys in hash size 2 means we'll have multichains. */
-       for (key.dsize = 1; key.dsize <= 5; key.dsize++) {
-               ksize += key.dsize;
-               dsize += data.dsize;
-               if (tdb_store(tdb, key, data, TDB_INSERT) != 0)
-                       abort();
-       }
-
-       /* This is how many bytes we expect to be verifiable. */
-       /* From the file header. */
-       verifiable = strlen(TDB_MAGIC_FOOD) + 1
-               + 2 * sizeof(uint32_t) + 2 * sizeof(tdb_off_t)
-               + 2 * sizeof(uint32_t);
-       /* From the free list chain and hash chains. */
-       verifiable += 3 * sizeof(tdb_off_t);
-       /* From the record headers & tailer */
-       verifiable += 5 * (sizeof(struct tdb_record) + sizeof(uint32_t));
-       /* The free block: we ignore datalen, keylen, full_hash. */
-       verifiable += sizeof(struct tdb_record) - 3*sizeof(uint32_t) +
-               sizeof(uint32_t);
-       /* Our check function verifies the key and data. */
-       verifiable += ksize + dsize;
-
-       /* Flip one bit at a time, make sure it detects verifiable bytes. */
-       for (i = 0, corrupt = 0; i < tdb->map_size * CHAR_BIT; i++) {
-               tdb_flip_bit(tdb, i);
-               memset(sizes, 0, sizeof(sizes));
-               if (tdb_check(tdb, check, sizes) != 0)
-                       corrupt++;
-               else if (sizes[0] != ksize || sizes[1] != dsize)
-                       corrupt++;
-               tdb_flip_bit(tdb, i);
-       }
-       ok(corrupt == verifiable * CHAR_BIT, "corrupt %u should be %u",
-          corrupt, verifiable * CHAR_BIT);
-}
-
-int main(int argc, char *argv[])
-{
-       struct tdb_context *tdb;
-
-       plan_tests(4);
-       /* This should use mmap. */
-       tdb = tdb_open_ex("run-corrupt.tdb", 2, TDB_CLEAR_IF_FIRST,
-                         O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL);
-
-       if (!tdb)
-               abort();
-       check_test(tdb);
-       tdb_close(tdb);
-
-       /* This should not. */
-       tdb = tdb_open_ex("run-corrupt.tdb", 2, TDB_CLEAR_IF_FIRST|TDB_NOMMAP,
-                         O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL);
-
-       if (!tdb)
-               abort();
-       check_test(tdb);
-       tdb_close(tdb);
-
-       return exit_status();
-}
diff --git a/ccan/tdb/test/run-die-during-transaction.c b/ccan/tdb/test/run-die-during-transaction.c
deleted file mode 100644 (file)
index aa6b40f..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-#define _XOPEN_SOURCE 500
-#include <unistd.h>
-#include "lock-tracking.h"
-static ssize_t pwrite_check(int fd, const void *buf, size_t count, off_t offset);
-static ssize_t write_check(int fd, const void *buf, size_t count);
-static int ftruncate_check(int fd, off_t length);
-
-#define pwrite pwrite_check
-#define write write_check
-#define fcntl fcntl_with_lockcheck
-#define ftruncate ftruncate_check
-
-#include <ccan/tdb/tdb.h>
-#include <ccan/tdb/io.c>
-#include <ccan/tdb/tdb.c>
-#include <ccan/tdb/lock.c>
-#include <ccan/tdb/freelist.c>
-#include <ccan/tdb/traverse.c>
-#include <ccan/tdb/transaction.c>
-#include <ccan/tdb/error.c>
-#include <ccan/tdb/open.c>
-#include <ccan/tdb/check.c>
-#include <ccan/tdb/hash.c>
-#include <ccan/tap/tap.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <stdarg.h>
-#include <err.h>
-#include <setjmp.h>
-#include "external-agent.h"
-#include "logging.h"
-
-#undef write
-#undef pwrite
-#undef fcntl
-#undef ftruncate
-
-static bool in_transaction;
-static int target, current;
-static jmp_buf jmpbuf;
-#define TEST_DBNAME "run-die-during-transaction.tdb"
-#define KEY_STRING "helloworld"
-
-static void maybe_die(int fd)
-{
-       if (in_transaction && current++ == target) {
-               longjmp(jmpbuf, 1);
-       }
-}
-
-static ssize_t pwrite_check(int fd,
-                           const void *buf, size_t count, off_t offset)
-{
-       ssize_t ret;
-
-       maybe_die(fd);
-
-       ret = pwrite(fd, buf, count, offset);
-       if (ret != count)
-               return ret;
-
-       maybe_die(fd);
-       return ret;
-}
-
-static ssize_t write_check(int fd, const void *buf, size_t count)
-{
-       ssize_t ret;
-
-       maybe_die(fd);
-
-       ret = write(fd, buf, count);
-       if (ret != count)
-               return ret;
-
-       maybe_die(fd);
-       return ret;
-}
-
-static int ftruncate_check(int fd, off_t length)
-{
-       int ret;
-
-       maybe_die(fd);
-
-       ret = ftruncate(fd, length);
-
-       maybe_die(fd);
-       return ret;
-}
-
-static bool test_death(enum operation op, struct agent *agent)
-{
-       struct tdb_context *tdb = NULL;
-       TDB_DATA key;
-       enum agent_return ret;
-       int needed_recovery = 0;
-
-       current = target = 0;
-reset:
-       unlink(TEST_DBNAME);
-       tdb = tdb_open_ex(TEST_DBNAME, 1024, TDB_NOMMAP,
-                         O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL);
-
-       if (setjmp(jmpbuf) != 0) {
-               /* We're partway through.  Simulate our death. */
-               close(tdb->fd);
-               forget_locking();
-               in_transaction = false;
-
-               ret = external_agent_operation(agent, NEEDS_RECOVERY, "");
-               if (ret == SUCCESS)
-                       needed_recovery++;
-               else if (ret != FAILED) {
-                       diag("Step %u agent NEEDS_RECOVERY = %s", current,
-                            agent_return_name(ret));
-                       return false;
-               }
-
-               ret = external_agent_operation(agent, op, KEY_STRING);
-               if (ret != SUCCESS) {
-                       diag("Step %u op %s failed = %s", current,
-                            operation_name(op),
-                            agent_return_name(ret));
-                       return false;
-               }
-
-               ret = external_agent_operation(agent, NEEDS_RECOVERY, "");
-               if (ret != FAILED) {
-                       diag("Still needs recovery after step %u = %s",
-                            current, agent_return_name(ret));
-                       return false;
-               }
-
-               ret = external_agent_operation(agent, CHECK, "");
-               if (ret != SUCCESS) {
-                       diag("Step %u check failed = %s", current,
-                            agent_return_name(ret));
-                       return false;
-               }
-
-               ret = external_agent_operation(agent, CLOSE, "");
-               if (ret != SUCCESS) {
-                       diag("Step %u close failed = %s", current,
-                            agent_return_name(ret));
-                       return false;
-               }
-
-               /* Suppress logging as this tries to use closed fd. */
-               suppress_logging = true;
-               suppress_lockcheck = true;
-               tdb_close(tdb);
-               suppress_logging = false;
-               suppress_lockcheck = false;
-               target++;
-               current = 0;
-               goto reset;
-       }
-
-       /* Put key for agent to fetch. */
-       key.dsize = strlen(KEY_STRING);
-       key.dptr = (void *)KEY_STRING;
-       if (tdb_store(tdb, key, key, TDB_INSERT) != 0)
-               return false;
-
-       /* This is the key we insert in transaction. */
-       key.dsize--;
-
-       ret = external_agent_operation(agent, OPEN, TEST_DBNAME);
-       if (ret != SUCCESS)
-               errx(1, "Agent failed to open: %s", agent_return_name(ret));
-
-       ret = external_agent_operation(agent, FETCH, KEY_STRING);
-       if (ret != SUCCESS)
-               errx(1, "Agent failed find key: %s", agent_return_name(ret));
-
-       in_transaction = true;
-       if (tdb_transaction_start(tdb) != 0)
-               return false;
-
-       if (tdb_store(tdb, key, key, TDB_INSERT) != 0)
-               return false;
-
-       if (tdb_transaction_commit(tdb) != 0)
-               return false;
-
-       in_transaction = false;
-
-       /* We made it! */
-       diag("Completed %u runs", current);
-       tdb_close(tdb);
-       ret = external_agent_operation(agent, CLOSE, "");
-       if (ret != SUCCESS) {
-               diag("Step %u close failed = %s", current,
-                    agent_return_name(ret));
-               return false;
-       }
-
-       ok1(needed_recovery);
-       ok1(locking_errors == 0);
-       ok1(forget_locking() == 0);
-       locking_errors = 0;
-       return true;
-}
-
-int main(int argc, char *argv[])
-{
-       enum operation ops[] = { FETCH, STORE, TRANSACTION_START };
-       struct agent *agent;
-       int i;
-
-       plan_tests(12);
-       unlock_callback = maybe_die;
-
-       agent = prepare_external_agent();
-       if (!agent)
-               err(1, "preparing agent");
-
-       for (i = 0; i < sizeof(ops)/sizeof(ops[0]); i++) {
-               diag("Testing %s after death", operation_name(ops[i]));
-               ok1(test_death(ops[i], agent));
-       }
-
-       return exit_status();
-}
diff --git a/ccan/tdb/test/run-endian.c b/ccan/tdb/test/run-endian.c
deleted file mode 100644 (file)
index 0fae162..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-#define _XOPEN_SOURCE 500
-#include <ccan/tdb/tdb.h>
-#include <ccan/tdb/io.c>
-#include <ccan/tdb/tdb.c>
-#include <ccan/tdb/lock.c>
-#include <ccan/tdb/freelist.c>
-#include <ccan/tdb/traverse.c>
-#include <ccan/tdb/transaction.c>
-#include <ccan/tdb/error.c>
-#include <ccan/tdb/open.c>
-#include <ccan/tdb/check.c>
-#include <ccan/tdb/hash.c>
-#include <ccan/tap/tap.h>
-#include <stdlib.h>
-#include <err.h>
-#include "logging.h"
-
-int main(int argc, char *argv[])
-{
-       struct tdb_context *tdb;
-       TDB_DATA key, data;
-
-       plan_tests(13);
-       tdb = tdb_open_ex("run-endian.tdb", 1024,
-                         TDB_CLEAR_IF_FIRST|TDB_CONVERT,
-                         O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL);
-
-       ok1(tdb);
-       key.dsize = strlen("hi");
-       key.dptr = (void *)"hi";
-       data.dsize = strlen("world");
-       data.dptr = (void *)"world";
-
-       ok1(tdb_store(tdb, key, data, TDB_MODIFY) < 0);
-       ok1(tdb_error(tdb) == TDB_ERR_NOEXIST);
-       ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
-       ok1(tdb_store(tdb, key, data, TDB_INSERT) < 0);
-       ok1(tdb_error(tdb) == TDB_ERR_EXISTS);
-       ok1(tdb_store(tdb, key, data, TDB_MODIFY) == 0);
-
-       data = tdb_fetch(tdb, key);
-       ok1(data.dsize == strlen("world"));
-       ok1(memcmp(data.dptr, "world", strlen("world")) == 0);
-       free(data.dptr);
-
-       key.dsize++;
-       data = tdb_fetch(tdb, key);
-       ok1(data.dptr == NULL);
-       tdb_close(tdb);
-
-       /* Reopen: should read it */
-       tdb = tdb_open_ex("run-endian.tdb", 1024, 0, O_RDWR, 0,
-                         &taplogctx, NULL);
-       ok1(tdb);
-       
-       key.dsize = strlen("hi");
-       key.dptr = (void *)"hi";
-       data = tdb_fetch(tdb, key);
-       ok1(data.dsize == strlen("world"));
-       ok1(memcmp(data.dptr, "world", strlen("world")) == 0);
-       free(data.dptr);
-       tdb_close(tdb);
-
-       return exit_status();
-}
diff --git a/ccan/tdb/test/run-incompatible.c b/ccan/tdb/test/run-incompatible.c
deleted file mode 100644 (file)
index 339d403..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-#define _XOPEN_SOURCE 500
-#include <ccan/tdb/tdb.h>
-#include <ccan/tdb/io.c>
-#include <ccan/tdb/tdb.c>
-#include <ccan/tdb/lock.c>
-#include <ccan/tdb/freelist.c>
-#include <ccan/tdb/traverse.c>
-#include <ccan/tdb/transaction.c>
-#include <ccan/tdb/error.c>
-#include <ccan/tdb/open.c>
-#include <ccan/tdb/check.c>
-#include <ccan/tdb/hash.c>
-#include <ccan/tap/tap.h>
-#include <stdlib.h>
-#include <err.h>
-
-static unsigned int tdb_dumb_hash(TDB_DATA *key)
-{
-       return key->dsize;
-}
-
-static void log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...)
-{
-       unsigned int *count = tdb_get_logging_private(tdb);
-       if (strstr(fmt, "hash"))
-               (*count)++;
-}
-
-static unsigned int hdr_rwlocks(const char *fname)
-{
-       struct tdb_header hdr;
-
-       int fd = open(fname, O_RDONLY);
-       if (fd == -1)
-               return -1;
-
-       if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr))
-               return -1;
-
-       close(fd);
-       return hdr.rwlocks;
-}
-
-int main(int argc, char *argv[])
-{
-       struct tdb_context *tdb;
-       unsigned int log_count, flags;
-       TDB_DATA d, r;
-       struct tdb_logging_context log_ctx = { log_fn, &log_count };
-
-       plan_tests(38 * 2);
-
-       for (flags = 0; flags <= TDB_CONVERT; flags += TDB_CONVERT) {
-               unsigned int rwmagic = TDB_HASH_RWLOCK_MAGIC;
-
-               if (flags & TDB_CONVERT)
-                       tdb_convert(&rwmagic, sizeof(rwmagic));
-
-               /* Create an old-style hash. */
-               log_count = 0;
-               tdb = tdb_open_ex("run-incompatible.tdb", 0, flags,
-                                 O_CREAT|O_RDWR|O_TRUNC, 0600, &log_ctx,
-                                 NULL);
-               ok1(tdb);
-               ok1(log_count == 0);
-               d.dptr = (void *)"Hello";
-               d.dsize = 5;
-               ok1(tdb_store(tdb, d, d, TDB_INSERT) == 0);
-               tdb_close(tdb);
-
-               /* Should not have marked rwlocks field. */
-               ok1(hdr_rwlocks("run-incompatible.tdb") == 0);
-
-               /* We can still open any old-style with incompat flag. */
-               log_count = 0;
-               tdb = tdb_open_ex("run-incompatible.tdb", 0,
-                                 TDB_INCOMPATIBLE_HASH,
-                                 O_RDWR, 0600, &log_ctx, NULL);
-               ok1(tdb);
-               ok1(log_count == 0);
-               r = tdb_fetch(tdb, d);
-               ok1(r.dsize == 5);
-               free(r.dptr);
-               ok1(tdb_check(tdb, NULL, NULL) == 0);
-               tdb_close(tdb);
-
-               log_count = 0;
-               tdb = tdb_open_ex("test/jenkins-le-hash.tdb", 0, 0, O_RDONLY,
-                                 0, &log_ctx, tdb_jenkins_hash);
-               ok1(tdb);
-               ok1(log_count == 0);
-               ok1(tdb_check(tdb, NULL, NULL) == 0);
-               tdb_close(tdb);
-
-               log_count = 0;
-               tdb = tdb_open_ex("test/jenkins-be-hash.tdb", 0, 0, O_RDONLY,
-                                 0, &log_ctx, tdb_jenkins_hash);
-               ok1(tdb);
-               ok1(log_count == 0);
-               ok1(tdb_check(tdb, NULL, NULL) == 0);
-               tdb_close(tdb);
-
-               /* OK, now create with incompatible flag, default hash. */
-               log_count = 0;
-               tdb = tdb_open_ex("run-incompatible.tdb", 0,
-                                 flags|TDB_INCOMPATIBLE_HASH,
-                                 O_CREAT|O_RDWR|O_TRUNC, 0600, &log_ctx,
-                                 NULL);
-               ok1(tdb);
-               ok1(log_count == 0);
-               d.dptr = (void *)"Hello";
-               d.dsize = 5;
-               ok1(tdb_store(tdb, d, d, TDB_INSERT) == 0);
-               tdb_close(tdb);
-
-               /* Should have marked rwlocks field. */
-               ok1(hdr_rwlocks("run-incompatible.tdb") == rwmagic);
-
-               /* Cannot open with old hash. */
-               log_count = 0;
-               tdb = tdb_open_ex("run-incompatible.tdb", 0, 0,
-                                 O_RDWR, 0600, &log_ctx, tdb_old_hash);
-               ok1(!tdb);
-               ok1(log_count == 1);
-
-               /* Can open with jenkins hash. */
-               log_count = 0;
-               tdb = tdb_open_ex("run-incompatible.tdb", 0, 0,
-                                 O_RDWR, 0600, &log_ctx, tdb_jenkins_hash);
-               ok1(tdb);
-               ok1(log_count == 0);
-               r = tdb_fetch(tdb, d);
-               ok1(r.dsize == 5);
-               free(r.dptr);
-               ok1(tdb_check(tdb, NULL, NULL) == 0);
-               tdb_close(tdb);
-
-               /* Can open by letting it figure it out itself. */
-               log_count = 0;
-               tdb = tdb_open_ex("run-incompatible.tdb", 0, 0,
-                                 O_RDWR, 0600, &log_ctx, NULL);
-               ok1(tdb);
-               ok1(log_count == 0);
-               r = tdb_fetch(tdb, d);
-               ok1(r.dsize == 5);
-               free(r.dptr);
-               ok1(tdb_check(tdb, NULL, NULL) == 0);
-               tdb_close(tdb);
-
-               /* We can also use incompatible hash with other hashes. */
-               log_count = 0;
-               tdb = tdb_open_ex("run-incompatible.tdb", 0,
-                                 flags|TDB_INCOMPATIBLE_HASH,
-                                 O_CREAT|O_RDWR|O_TRUNC, 0600, &log_ctx,
-                                 tdb_dumb_hash);
-               ok1(tdb);
-               ok1(log_count == 0);
-               d.dptr = (void *)"Hello";
-               d.dsize = 5;
-               ok1(tdb_store(tdb, d, d, TDB_INSERT) == 0);
-               tdb_close(tdb);
-
-               /* Should have marked rwlocks field. */
-               ok1(hdr_rwlocks("run-incompatible.tdb") == rwmagic);
-
-               /* It should not open if we don't specify. */
-               log_count = 0;
-               tdb = tdb_open_ex("run-incompatible.tdb", 0, 0, O_RDWR, 0,
-                                 &log_ctx, NULL);
-               ok1(!tdb);
-               ok1(log_count == 1);
-
-               /* Should reopen with correct hash. */
-               log_count = 0;
-               tdb = tdb_open_ex("run-incompatible.tdb", 0, 0, O_RDWR, 0,
-                                 &log_ctx, tdb_dumb_hash);
-               ok1(tdb);
-               ok1(log_count == 0);
-               r = tdb_fetch(tdb, d);
-               ok1(r.dsize == 5);
-               free(r.dptr);
-               ok1(tdb_check(tdb, NULL, NULL) == 0);
-               tdb_close(tdb);
-       }
-
-       return exit_status();
-}
diff --git a/ccan/tdb/test/run-nested-transactions.c b/ccan/tdb/test/run-nested-transactions.c
deleted file mode 100644 (file)
index d13977c..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-#define _XOPEN_SOURCE 500
-#include <ccan/tdb/tdb.h>
-#include <ccan/tdb/io.c>
-#include <ccan/tdb/tdb.c>
-#include <ccan/tdb/lock.c>
-#include <ccan/tdb/freelist.c>
-#include <ccan/tdb/traverse.c>
-#include <ccan/tdb/transaction.c>
-#include <ccan/tdb/error.c>
-#include <ccan/tdb/open.c>
-#include <ccan/tdb/check.c>
-#include <ccan/tdb/hash.c>
-#include <ccan/tap/tap.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <err.h>
-#include "logging.h"
-
-int main(int argc, char *argv[])
-{
-       struct tdb_context *tdb;
-       TDB_DATA key, data;
-
-       plan_tests(27);
-       key.dsize = strlen("hi");
-       key.dptr = (void *)"hi";
-
-       tdb = tdb_open_ex("run-nested-transactions.tdb",
-                         1024, TDB_CLEAR_IF_FIRST,
-                         O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL);
-       ok1(tdb);
-
-       /* No nesting by default. */
-       ok1(tdb_transaction_start(tdb) == 0);
-       data.dptr = (void *)"world";
-       data.dsize = strlen("world");
-       ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
-       data = tdb_fetch(tdb, key);
-       ok1(data.dsize == strlen("world"));
-       ok1(memcmp(data.dptr, "world", strlen("world")) == 0);
-       free(data.dptr);
-       ok1(tdb_transaction_start(tdb) != 0);
-       ok1(tdb_error(tdb) == TDB_ERR_NESTING);
-
-       data = tdb_fetch(tdb, key);
-       ok1(data.dsize == strlen("world"));
-       ok1(memcmp(data.dptr, "world", strlen("world")) == 0);
-       free(data.dptr);
-       ok1(tdb_transaction_commit(tdb) == 0);
-       data = tdb_fetch(tdb, key);
-       ok1(data.dsize == strlen("world"));
-       ok1(memcmp(data.dptr, "world", strlen("world")) == 0);
-       free(data.dptr);
-       tdb_close(tdb);
-
-       tdb = tdb_open_ex("run-nested-transactions.tdb",
-                         1024, TDB_ALLOW_NESTING, O_RDWR, 0, &taplogctx, NULL);
-       ok1(tdb);
-
-       ok1(tdb_transaction_start(tdb) == 0);
-       ok1(tdb_transaction_start(tdb) == 0);
-       ok1(tdb_delete(tdb, key) == 0);
-       ok1(tdb_transaction_commit(tdb) == 0);
-       ok1(!tdb_exists(tdb, key));
-       ok1(tdb_transaction_cancel(tdb) == 0);
-       /* Surprise! Kills inner "committed" transaction. */
-       ok1(tdb_exists(tdb, key));
-
-       ok1(tdb_transaction_start(tdb) == 0);
-       ok1(tdb_transaction_start(tdb) == 0);
-       ok1(tdb_delete(tdb, key) == 0);
-       ok1(tdb_transaction_commit(tdb) == 0);
-       ok1(!tdb_exists(tdb, key));
-       ok1(tdb_transaction_commit(tdb) == 0);
-       ok1(!tdb_exists(tdb, key));
-       tdb_close(tdb);
-
-       return exit_status();
-}
diff --git a/ccan/tdb/test/run-nested-traverse.c b/ccan/tdb/test/run-nested-traverse.c
deleted file mode 100644 (file)
index c58b24c..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-#define _XOPEN_SOURCE 500
-#include "lock-tracking.h"
-#define fcntl fcntl_with_lockcheck
-#include <ccan/tdb/tdb.h>
-#include <ccan/tdb/io.c>
-#include <ccan/tdb/tdb.c>
-#include <ccan/tdb/lock.c>
-#include <ccan/tdb/freelist.c>
-#include <ccan/tdb/traverse.c>
-#include <ccan/tdb/transaction.c>
-#include <ccan/tdb/error.c>
-#include <ccan/tdb/open.c>
-#include <ccan/tdb/check.c>
-#include <ccan/tdb/hash.c>
-#include <ccan/tap/tap.h>
-#undef fcntl
-#include <stdlib.h>
-#include <stdbool.h>
-#include <err.h>
-#include "external-agent.h"
-#include "logging.h"
-
-static struct agent *agent;
-
-static bool correct_key(TDB_DATA key)
-{
-       return key.dsize == strlen("hi")
-               && memcmp(key.dptr, "hi", key.dsize) == 0;
-}
-
-static bool correct_data(TDB_DATA data)
-{
-       return data.dsize == strlen("world")
-               && memcmp(data.dptr, "world", data.dsize) == 0;
-}
-
-static int traverse2(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data,
-                    void *p)
-{
-       ok1(correct_key(key));
-       ok1(correct_data(data));
-       return 0;
-}
-
-static int traverse1(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data,
-                    void *p)
-{
-       ok1(correct_key(key));
-       ok1(correct_data(data));
-       ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb))
-           == WOULD_HAVE_BLOCKED);
-       tdb_traverse(tdb, traverse2, NULL);
-
-       /* That should *not* release the transaction lock! */
-       ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb))
-           == WOULD_HAVE_BLOCKED);
-       return 0;
-}
-
-int main(int argc, char *argv[])
-{
-       struct tdb_context *tdb;
-       TDB_DATA key, data;
-
-       plan_tests(17);
-       agent = prepare_external_agent();
-       if (!agent)
-               err(1, "preparing agent");
-
-       tdb = tdb_open_ex("run-nested-traverse.tdb", 1024, TDB_CLEAR_IF_FIRST,
-                         O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL);
-       ok1(tdb);
-
-       ok1(external_agent_operation(agent, OPEN, tdb_name(tdb)) == SUCCESS);
-       ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb))
-           == SUCCESS);
-       ok1(external_agent_operation(agent, TRANSACTION_COMMIT, tdb_name(tdb))
-           == SUCCESS);
-
-       key.dsize = strlen("hi");
-       key.dptr = (void *)"hi";
-       data.dptr = (void *)"world";
-       data.dsize = strlen("world");
-
-       ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
-       tdb_traverse(tdb, traverse1, NULL);
-       tdb_traverse_read(tdb, traverse1, NULL);
-       tdb_close(tdb);
-
-       return exit_status();
-}
diff --git a/ccan/tdb/test/run-no-lock-during-traverse.c b/ccan/tdb/test/run-no-lock-during-traverse.c
deleted file mode 100644 (file)
index df089f9..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-#define _XOPEN_SOURCE 500
-#include <unistd.h>
-#include "lock-tracking.h"
-
-#define fcntl fcntl_with_lockcheck
-
-#include <ccan/tdb/tdb.h>
-#include <ccan/tdb/io.c>
-#include <ccan/tdb/tdb.c>
-#include <ccan/tdb/lock.c>
-#include <ccan/tdb/freelist.c>
-#include <ccan/tdb/traverse.c>
-#include <ccan/tdb/transaction.c>
-#include <ccan/tdb/error.c>
-#include <ccan/tdb/open.c>
-#include <ccan/tdb/check.c>
-#include <ccan/tdb/hash.c>
-#include <ccan/tap/tap.h>
-#include <stdlib.h>
-#include <err.h>
-#include "logging.h"
-
-#undef fcntl
-
-#define NUM_ENTRIES 10
-
-static bool prepare_entries(struct tdb_context *tdb)
-{
-       unsigned int i;
-       TDB_DATA key, data;
-       
-       for (i = 0; i < NUM_ENTRIES; i++) {
-               key.dsize = sizeof(i);
-               key.dptr = (void *)&i;
-               data.dsize = strlen("world");
-               data.dptr = (void *)"world";
-
-               if (tdb_store(tdb, key, data, 0) != 0)
-                       return false;
-       }
-       return true;
-}
-
-static void delete_entries(struct tdb_context *tdb)
-{
-       unsigned int i;
-       TDB_DATA key;
-
-       for (i = 0; i < NUM_ENTRIES; i++) {
-               key.dsize = sizeof(i);
-               key.dptr = (void *)&i;
-
-               ok1(tdb_delete(tdb, key) == 0);
-       }
-}
-
-/* We don't know how many times this will run. */
-static int delete_other(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data,
-                       void *private_data)
-{
-       unsigned int i;
-       memcpy(&i, key.dptr, 4);
-       i = (i + 1) % NUM_ENTRIES;
-       key.dptr = (void *)&i;
-       if (tdb_delete(tdb, key) != 0)
-               (*(int *)private_data)++;
-       return 0;
-}
-
-static int delete_self(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data,
-                       void *private_data)
-{
-       ok1(tdb_delete(tdb, key) == 0);
-       return 0;
-}
-
-int main(int argc, char *argv[])
-{
-       struct tdb_context *tdb;
-       int errors = 0;
-
-       plan_tests(41);
-       tdb = tdb_open_ex("run-no-lock-during-traverse.tdb",
-                         1024, TDB_CLEAR_IF_FIRST, O_CREAT|O_TRUNC|O_RDWR,
-                         0600, &taplogctx, NULL);
-
-       ok1(tdb);
-       ok1(prepare_entries(tdb));
-       ok1(locking_errors == 0);
-       ok1(tdb_lockall(tdb) == 0);
-       ok1(locking_errors == 0);
-       tdb_traverse(tdb, delete_other, &errors);
-       ok1(errors == 0);
-       ok1(locking_errors == 0);
-       ok1(tdb_unlockall(tdb) == 0);
-
-       ok1(prepare_entries(tdb));
-       ok1(locking_errors == 0);
-       ok1(tdb_lockall(tdb) == 0);
-       ok1(locking_errors == 0);
-       tdb_traverse(tdb, delete_self, NULL);
-       ok1(locking_errors == 0);
-       ok1(tdb_unlockall(tdb) == 0);
-
-       ok1(prepare_entries(tdb));
-       ok1(locking_errors == 0);
-       ok1(tdb_lockall(tdb) == 0);
-       ok1(locking_errors == 0);
-       delete_entries(tdb);
-       ok1(locking_errors == 0);
-       ok1(tdb_unlockall(tdb) == 0);
-
-       ok1(tdb_close(tdb) == 0);       
-
-       return exit_status();
-}
diff --git a/ccan/tdb/test/run-oldhash.c b/ccan/tdb/test/run-oldhash.c
deleted file mode 100644 (file)
index a40600f..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-#define _XOPEN_SOURCE 500
-#include <ccan/tdb/tdb.h>
-#include <ccan/tdb/io.c>
-#include <ccan/tdb/tdb.c>
-#include <ccan/tdb/lock.c>
-#include <ccan/tdb/freelist.c>
-#include <ccan/tdb/traverse.c>
-#include <ccan/tdb/transaction.c>
-#include <ccan/tdb/error.c>
-#include <ccan/tdb/open.c>
-#include <ccan/tdb/check.c>
-#include <ccan/tdb/hash.c>
-#include <ccan/tap/tap.h>
-#include <stdlib.h>
-#include <err.h>
-#include "logging.h"
-
-int main(int argc, char *argv[])
-{
-       struct tdb_context *tdb;
-
-       plan_tests(8);
-
-       /* Old format (with zeroes in the hash magic fields) should
-        * open with any hash (since we don't know what hash they used). */
-       tdb = tdb_open_ex("test/old-nohash-le.tdb", 0, 0, O_RDWR, 0,
-                         &taplogctx, NULL);
-       ok1(tdb);
-       ok1(tdb_check(tdb, NULL, NULL) == 0);
-       tdb_close(tdb);
-
-       tdb = tdb_open_ex("test/old-nohash-be.tdb", 0, 0, O_RDWR, 0,
-                         &taplogctx, NULL);
-       ok1(tdb);
-       ok1(tdb_check(tdb, NULL, NULL) == 0);
-       tdb_close(tdb);
-
-       tdb = tdb_open_ex("test/old-nohash-le.tdb", 0, 0, O_RDWR, 0,
-                         &taplogctx, tdb_jenkins_hash);
-       ok1(tdb);
-       ok1(tdb_check(tdb, NULL, NULL) == 0);
-       tdb_close(tdb);
-
-       tdb = tdb_open_ex("test/old-nohash-be.tdb", 0, 0, O_RDWR, 0,
-                         &taplogctx, tdb_jenkins_hash);
-       ok1(tdb);
-       ok1(tdb_check(tdb, NULL, NULL) == 0);
-       tdb_close(tdb);
-
-       return exit_status();
-}
diff --git a/ccan/tdb/test/run-open-during-transaction.c b/ccan/tdb/test/run-open-during-transaction.c
deleted file mode 100644 (file)
index e7feb03..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-#define _XOPEN_SOURCE 500
-#include <unistd.h>
-#include "lock-tracking.h"
-
-static ssize_t pwrite_check(int fd, const void *buf, size_t count, off_t offset);
-static ssize_t write_check(int fd, const void *buf, size_t count);
-static int ftruncate_check(int fd, off_t length);
-
-#define pwrite pwrite_check
-#define write write_check
-#define fcntl fcntl_with_lockcheck
-#define ftruncate ftruncate_check
-
-#include <ccan/tdb/tdb.h>
-#include <ccan/tdb/io.c>
-#include <ccan/tdb/tdb.c>
-#include <ccan/tdb/lock.c>
-#include <ccan/tdb/freelist.c>
-#include <ccan/tdb/traverse.c>
-#include <ccan/tdb/transaction.c>
-#include <ccan/tdb/error.c>
-#include <ccan/tdb/open.c>
-#include <ccan/tdb/check.c>
-#include <ccan/tdb/hash.c>
-#include <ccan/tap/tap.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <stdarg.h>
-#include <err.h>
-#include "external-agent.h"
-#include "logging.h"
-
-static struct agent *agent;
-static bool opened;
-static int errors = 0;
-static bool clear_if_first;
-#define TEST_DBNAME "run-open-during-transaction.tdb"
-
-#undef write
-#undef pwrite
-#undef fcntl
-#undef ftruncate
-
-static bool is_same(const char *snapshot, const char *latest, off_t len)
-{
-       unsigned i;
-
-       for (i = 0; i < len; i++) {
-               if (snapshot[i] != latest[i])
-                       return false;
-       }
-       return true;
-}
-
-static bool compare_file(int fd, const char *snapshot, off_t snapshot_len)
-{
-       char *contents;
-       bool same;
-
-       /* over-length read serves as length check. */
-       contents = malloc(snapshot_len+1);
-       same = pread(fd, contents, snapshot_len+1, 0) == snapshot_len
-               && is_same(snapshot, contents, snapshot_len);
-       free(contents);
-       return same;
-}
-
-static void check_file_intact(int fd)
-{
-       enum agent_return ret;
-       struct stat st;
-       char *contents;
-
-       fstat(fd, &st);
-       contents = malloc(st.st_size);
-       if (pread(fd, contents, st.st_size, 0) != st.st_size) {
-               diag("Read fail");
-               errors++;
-               return;
-       }
-
-       /* Ask agent to open file. */
-       ret = external_agent_operation(agent, clear_if_first ?
-                                      OPEN_WITH_CLEAR_IF_FIRST :
-                                      OPEN,
-                                      TEST_DBNAME);
-
-       /* It's OK to open it, but it must not have changed! */
-       if (!compare_file(fd, contents, st.st_size)) {
-               diag("Agent changed file after opening %s",
-                    agent_return_name(ret));
-               errors++;
-       }
-
-       if (ret == SUCCESS) {
-               ret = external_agent_operation(agent, CLOSE, NULL);
-               if (ret != SUCCESS) {
-                       diag("Agent failed to close tdb: %s",
-                            agent_return_name(ret));
-                       errors++;
-               }
-       } else if (ret != WOULD_HAVE_BLOCKED) {
-               diag("Agent opening file gave %s",
-                    agent_return_name(ret));
-               errors++;
-       }
-
-       free(contents);
-}
-
-static void after_unlock(int fd)
-{
-       if (opened)
-               check_file_intact(fd);
-}
-       
-static ssize_t pwrite_check(int fd,
-                           const void *buf, size_t count, off_t offset)
-{
-       if (opened)
-               check_file_intact(fd);
-
-       return pwrite(fd, buf, count, offset);
-}
-
-static ssize_t write_check(int fd, const void *buf, size_t count)
-{
-       if (opened)
-               check_file_intact(fd);
-
-       return write(fd, buf, count);
-}
-
-static int ftruncate_check(int fd, off_t length)
-{
-       if (opened)
-               check_file_intact(fd);
-
-       return ftruncate(fd, length);
-
-}
-
-int main(int argc, char *argv[])
-{
-       const int flags[] = { TDB_DEFAULT,
-                             TDB_CLEAR_IF_FIRST,
-                             TDB_NOMMAP, 
-                             TDB_CLEAR_IF_FIRST | TDB_NOMMAP };
-       int i;
-       struct tdb_context *tdb;
-       TDB_DATA key, data;
-
-       plan_tests(20);
-       agent = prepare_external_agent();
-       if (!agent)
-               err(1, "preparing agent");
-
-       unlock_callback = after_unlock;
-       for (i = 0; i < sizeof(flags)/sizeof(flags[0]); i++) {
-               clear_if_first = (flags[i] & TDB_CLEAR_IF_FIRST);
-               diag("Test with %s and %s\n",
-                    clear_if_first ? "CLEAR" : "DEFAULT",
-                    (flags[i] & TDB_NOMMAP) ? "no mmap" : "mmap");
-               unlink(TEST_DBNAME);
-               tdb = tdb_open_ex(TEST_DBNAME, 1024, flags[i],
-                                 O_CREAT|O_TRUNC|O_RDWR, 0600,
-                                 &taplogctx, NULL);
-               ok1(tdb);
-
-               opened = true;
-               ok1(tdb_transaction_start(tdb) == 0);
-               key.dsize = strlen("hi");
-               key.dptr = (void *)"hi";
-               data.dptr = (void *)"world";
-               data.dsize = strlen("world");
-
-               ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
-               ok1(tdb_transaction_commit(tdb) == 0);
-               ok(!errors, "We had %u open errors", errors);
-
-               opened = false;
-               tdb_close(tdb);
-       }
-
-       return exit_status();
-}
diff --git a/ccan/tdb/test/run-readonly-check.c b/ccan/tdb/test/run-readonly-check.c
deleted file mode 100644 (file)
index 6e92cde..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/* We should be able to tdb_check a O_RDONLY tdb, and we were previously allowed
- * to tdb_check() inside a transaction (though that's paranoia!). */
-#define _XOPEN_SOURCE 500
-#include <ccan/tdb/tdb.h>
-#include <ccan/tdb/io.c>
-#include <ccan/tdb/tdb.c>
-#include <ccan/tdb/lock.c>
-#include <ccan/tdb/freelist.c>
-#include <ccan/tdb/traverse.c>
-#include <ccan/tdb/transaction.c>
-#include <ccan/tdb/error.c>
-#include <ccan/tdb/open.c>
-#include <ccan/tdb/check.c>
-#include <ccan/tdb/hash.c>
-#include <ccan/tap/tap.h>
-#include <stdlib.h>
-#include <err.h>
-#include "logging.h"
-
-int main(int argc, char *argv[])
-{
-       struct tdb_context *tdb;
-       TDB_DATA key, data;
-
-       plan_tests(11);
-       tdb = tdb_open_ex("run-readonly-check.tdb", 1024,
-                         TDB_DEFAULT,
-                         O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL);
-
-       ok1(tdb);
-       key.dsize = strlen("hi");
-       key.dptr = (void *)"hi";
-       data.dsize = strlen("world");
-       data.dptr = (void *)"world";
-
-       ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
-       ok1(tdb_check(tdb, NULL, NULL) == 0);
-
-       /* We are also allowed to do a check inside a transaction. */
-       ok1(tdb_transaction_start(tdb) == 0);
-       ok1(tdb_check(tdb, NULL, NULL) == 0);
-       ok1(tdb_close(tdb) == 0);
-
-       tdb = tdb_open_ex("run-readonly-check.tdb", 1024,
-                         TDB_DEFAULT, O_RDONLY, 0, &taplogctx, NULL);
-
-       ok1(tdb);
-       ok1(tdb_store(tdb, key, data, TDB_MODIFY) == -1);
-       ok1(tdb_error(tdb) == TDB_ERR_RDONLY);
-       ok1(tdb_check(tdb, NULL, NULL) == 0);
-       ok1(tdb_close(tdb) == 0);
-
-       return exit_status();
-}
diff --git a/ccan/tdb/test/run-rwlock-check.c b/ccan/tdb/test/run-rwlock-check.c
deleted file mode 100644 (file)
index aa8b471..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-#define _XOPEN_SOURCE 500
-#include <ccan/tdb/tdb.h>
-#include <ccan/tdb/io.c>
-#include <ccan/tdb/tdb.c>
-#include <ccan/tdb/lock.c>
-#include <ccan/tdb/freelist.c>
-#include <ccan/tdb/traverse.c>
-#include <ccan/tdb/transaction.c>
-#include <ccan/tdb/error.c>
-#include <ccan/tdb/open.c>
-#include <ccan/tdb/check.c>
-#include <ccan/tdb/hash.c>
-#include <ccan/tap/tap.h>
-#include <stdlib.h>
-#include <err.h>
-
-static void log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...)
-{
-       unsigned int *count = tdb_get_logging_private(tdb);
-       if (strstr(fmt, "spinlocks"))
-               (*count)++;
-}
-
-/* The code should barf on TDBs created with rwlocks. */
-int main(int argc, char *argv[])
-{
-       struct tdb_context *tdb;
-       unsigned int log_count;
-       struct tdb_logging_context log_ctx = { log_fn, &log_count };
-
-       plan_tests(4);
-
-       /* We should fail to open rwlock-using tdbs of either endian. */
-       log_count = 0;
-       tdb = tdb_open_ex("test/rwlock-le.tdb", 0, 0, O_RDWR, 0,
-                         &log_ctx, NULL);
-       ok1(!tdb);
-       ok1(log_count == 1);
-
-       log_count = 0;
-       tdb = tdb_open_ex("test/rwlock-be.tdb", 0, 0, O_RDWR, 0,
-                         &log_ctx, NULL);
-       ok1(!tdb);
-       ok1(log_count == 1);
-
-       return exit_status();
-}
diff --git a/ccan/tdb/test/run-summary.c b/ccan/tdb/test/run-summary.c
deleted file mode 100644 (file)
index 89fbfec..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-#include <ccan/tdb/tdb.h>
-#include <ccan/tdb/io.c>
-#include <ccan/tdb/tdb.c>
-#include <ccan/tdb/lock.c>
-#include <ccan/tdb/freelist.c>
-#include <ccan/tdb/traverse.c>
-#include <ccan/tdb/transaction.c>
-#include <ccan/tdb/error.c>
-#include <ccan/tdb/open.c>
-#include <ccan/tdb/check.c>
-#include <ccan/tdb/hash.c>
-#include <ccan/tdb/summary.c>
-#include <ccan/tap/tap.h>
-#include <stdlib.h>
-#include <err.h>
-
-int main(int argc, char *argv[])
-{
-       unsigned int i, j;
-       struct tdb_context *tdb;
-       int flags[] = { TDB_INTERNAL, TDB_DEFAULT, TDB_NOMMAP,
-                       TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT,
-                       TDB_NOMMAP|TDB_CONVERT };
-       TDB_DATA key = { (unsigned char *)&j, sizeof(j) };
-       TDB_DATA data = { (unsigned char *)&j, sizeof(j) };
-       char *summary;
-
-       plan_tests(sizeof(flags) / sizeof(flags[0]) * 14);
-       for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
-               tdb = tdb_open("run-summary.tdb", 131, flags[i],
-                              O_RDWR|O_CREAT|O_TRUNC, 0600);
-               ok1(tdb);
-               if (!tdb)
-                       continue;
-
-               /* Put some stuff in there. */
-               for (j = 0; j < 500; j++) {
-                       /* Make sure padding varies to we get some graphs! */
-                       data.dsize = j % (sizeof(j) + 1);
-                       if (tdb_store(tdb, key, data, TDB_REPLACE) != 0)
-                               fail("Storing in tdb");
-               }
-
-               summary = tdb_summary(tdb);
-               diag("%s", summary);
-               ok1(strstr(summary, "Size of file/data: "));
-               ok1(strstr(summary, "Number of records: 500\n"));
-               ok1(strstr(summary, "Smallest/average/largest keys: 4/4/4\n"));
-               ok1(strstr(summary, "Smallest/average/largest data: 0/2/4\n"));
-               ok1(strstr(summary, "Smallest/average/largest padding: "));
-               ok1(strstr(summary, "Number of dead records: 0\n"));
-               ok1(strstr(summary, "Number of free records: 1\n"));
-               ok1(strstr(summary, "Smallest/average/largest free records: "));
-               ok1(strstr(summary, "Number of hash chains: 131\n"));
-               ok1(strstr(summary, "Smallest/average/largest hash chains: "));
-               ok1(strstr(summary, "Number of uncoalesced records: 0\n"));
-               ok1(strstr(summary, "Smallest/average/largest uncoalesced runs: 0/0/0\n"));
-               ok1(strstr(summary, "Percentage keys/data/padding/free/dead/rechdrs&tailers/hashes: "));
-               
-               free(summary);
-               tdb_close(tdb);
-       }
-
-       return exit_status();
-}
diff --git a/ccan/tdb/test/run-transaction-expand.c b/ccan/tdb/test/run-transaction-expand.c
deleted file mode 100644 (file)
index 26426b2..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/* We need this otherwise fcntl locking fails. */
-#define _FILE_OFFSET_BITS 64
-#define _XOPEN_SOURCE 500
-#include <ccan/tdb/tdb_private.h>
-
-/* Speed up the tests: setting TDB_NOSYNC removed recovery altogether. */
-static inline int fake_fsync(int fd)
-{
-       return 0;
-}
-#define fsync fake_fsync
-
-#ifdef MS_SYNC
-static inline int fake_msync(void *addr, size_t length, int flags)
-{
-       return 0;
-}
-#define msync fake_msync
-#endif
-
-#include <ccan/tdb/tdb.h>
-#include <ccan/tdb/io.c>
-#include <ccan/tdb/tdb.c>
-#include <ccan/tdb/lock.c>
-#include <ccan/tdb/freelist.c>
-#include <ccan/tdb/traverse.c>
-#include <ccan/tdb/transaction.c>
-#include <ccan/tdb/error.c>
-#include <ccan/tdb/open.c>
-#include <ccan/tdb/check.c>
-#include <ccan/tdb/hash.c>
-#include <ccan/tap/tap.h>
-#include <stdlib.h>
-#include <err.h>
-#include "logging.h"
-
-static void write_record(struct tdb_context *tdb, size_t extra_len,
-                        TDB_DATA *data)
-{
-       TDB_DATA key;
-       key.dsize = strlen("hi");
-       key.dptr = (void *)"hi";
-
-       data->dsize += extra_len;
-       tdb_transaction_start(tdb);
-       tdb_store(tdb, key, *data, TDB_REPLACE);
-       tdb_transaction_commit(tdb);
-}
-
-int main(int argc, char *argv[])
-{
-       struct tdb_context *tdb;
-       size_t i;
-       TDB_DATA data;
-       struct tdb_record rec;
-       tdb_off_t off;
-
-       plan_tests(4);
-       tdb = tdb_open_ex("run-transaction-expand.tdb",
-                         1024, TDB_CLEAR_IF_FIRST,
-                         O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL);
-       ok1(tdb);
-
-       data.dsize = 0;
-       data.dptr = calloc(1000, getpagesize());
-
-       /* Simulate a slowly growing record. */
-       for (i = 0; i < 1000; i++)
-               write_record(tdb, getpagesize(), &data);
-
-       tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &off);
-       tdb_read(tdb, off, &rec, sizeof(rec), DOCONV());
-       diag("TDB size = %zu, recovery = %u-%u",
-            (size_t)tdb->map_size, off, off + sizeof(rec) + rec.rec_len);
-
-       /* We should only be about 5 times larger than largest record. */
-       ok1(tdb->map_size < 6 * i * getpagesize());
-       tdb_close(tdb);
-
-       tdb = tdb_open_ex("run-transaction-expand.tdb",
-                         1024, TDB_CLEAR_IF_FIRST,
-                         O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL);
-       ok1(tdb);
-
-       data.dsize = 0;
-
-       /* Simulate a slowly growing record, repacking to keep
-        * recovery area at end. */
-       for (i = 0; i < 1000; i++) {
-               write_record(tdb, getpagesize(), &data);
-               if (i % 10 == 0)
-                       tdb_repack(tdb);
-       }
-
-       tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &off);
-       tdb_read(tdb, off, &rec, sizeof(rec), DOCONV());
-       diag("TDB size = %zu, recovery = %u-%u",
-            (size_t)tdb->map_size, off, off + sizeof(rec) + rec.rec_len);
-
-       /* We should only be about 4 times larger than largest record. */
-       ok1(tdb->map_size < 5 * i * getpagesize());
-       tdb_close(tdb);
-       free(data.dptr);
-
-       return exit_status();
-}
diff --git a/ccan/tdb/test/run-traverse-in-transaction.c b/ccan/tdb/test/run-traverse-in-transaction.c
deleted file mode 100644 (file)
index 61cb131..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-#define _XOPEN_SOURCE 500
-#include "lock-tracking.h"
-#define fcntl fcntl_with_lockcheck
-#include <ccan/tdb/tdb.h>
-#include <ccan/tdb/io.c>
-#include <ccan/tdb/tdb.c>
-#include <ccan/tdb/lock.c>
-#include <ccan/tdb/freelist.c>
-#include <ccan/tdb/traverse.c>
-#include <ccan/tdb/transaction.c>
-#include <ccan/tdb/error.c>
-#include <ccan/tdb/open.c>
-#include <ccan/tdb/check.c>
-#include <ccan/tdb/hash.c>
-#include <ccan/tap/tap.h>
-#undef fcntl_with_lockcheck
-#include <stdlib.h>
-#include <stdbool.h>
-#include <err.h>
-#include "external-agent.h"
-#include "logging.h"
-
-static struct agent *agent;
-
-static bool correct_key(TDB_DATA key)
-{
-       return key.dsize == strlen("hi")
-               && memcmp(key.dptr, "hi", key.dsize) == 0;
-}
-
-static bool correct_data(TDB_DATA data)
-{
-       return data.dsize == strlen("world")
-               && memcmp(data.dptr, "world", data.dsize) == 0;
-}
-
-static int traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data,
-                    void *p)
-{
-       ok1(correct_key(key));
-       ok1(correct_data(data));
-       return 0;
-}
-
-int main(int argc, char *argv[])
-{
-       struct tdb_context *tdb;
-       TDB_DATA key, data;
-
-       plan_tests(13);
-       agent = prepare_external_agent();
-       if (!agent)
-               err(1, "preparing agent");
-
-       tdb = tdb_open_ex("run-traverse-in-transaction.tdb",
-                         1024, TDB_CLEAR_IF_FIRST, O_CREAT|O_TRUNC|O_RDWR,
-                         0600, &taplogctx, NULL);
-       ok1(tdb);
-
-       key.dsize = strlen("hi");
-       key.dptr = (void *)"hi";
-       data.dptr = (void *)"world";
-       data.dsize = strlen("world");
-
-       ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
-
-       ok1(external_agent_operation(agent, OPEN, tdb_name(tdb)) == SUCCESS);
-
-       ok1(tdb_transaction_start(tdb) == 0);
-       ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb))
-           == WOULD_HAVE_BLOCKED);
-       tdb_traverse(tdb, traverse, NULL);
-
-       /* That should *not* release the transaction lock! */
-       ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb))
-           == WOULD_HAVE_BLOCKED);
-       tdb_traverse_read(tdb, traverse, NULL);
-
-       /* That should *not* release the transaction lock! */
-       ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb))
-           == WOULD_HAVE_BLOCKED);
-       ok1(tdb_transaction_commit(tdb) == 0);
-       /* Now we should be fine. */
-       ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb))
-           == SUCCESS);
-
-       tdb_close(tdb);
-
-       return exit_status();
-}
diff --git a/ccan/tdb/test/run-wronghash-fail.c b/ccan/tdb/test/run-wronghash-fail.c
deleted file mode 100644 (file)
index 17fd867..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-#define _XOPEN_SOURCE 500
-#include <ccan/tdb/tdb.h>
-#include <ccan/tdb/io.c>
-#include <ccan/tdb/tdb.c>
-#include <ccan/tdb/lock.c>
-#include <ccan/tdb/freelist.c>
-#include <ccan/tdb/traverse.c>
-#include <ccan/tdb/transaction.c>
-#include <ccan/tdb/error.c>
-#include <ccan/tdb/open.c>
-#include <ccan/tdb/check.c>
-#include <ccan/tdb/hash.c>
-#include <ccan/tap/tap.h>
-#include <stdlib.h>
-#include <err.h>
-
-static void log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...)
-{
-       unsigned int *count = tdb_get_logging_private(tdb);
-       if (strstr(fmt, "hash"))
-               (*count)++;
-}
-
-int main(int argc, char *argv[])
-{
-       struct tdb_context *tdb;
-       unsigned int log_count;
-       TDB_DATA d;
-       struct tdb_logging_context log_ctx = { log_fn, &log_count };
-
-       plan_tests(28);
-
-       /* Create with default hash. */
-       log_count = 0;
-       tdb = tdb_open_ex("run-wronghash-fail.tdb", 0, 0,
-                         O_CREAT|O_RDWR|O_TRUNC, 0600, &log_ctx, NULL);
-       ok1(tdb);
-       ok1(log_count == 0);
-       d.dptr = (void *)"Hello";
-       d.dsize = 5;
-       ok1(tdb_store(tdb, d, d, TDB_INSERT) == 0);
-       tdb_close(tdb);
-
-       /* Fail to open with different hash. */
-       tdb = tdb_open_ex("run-wronghash-fail.tdb", 0, 0, O_RDWR, 0,
-                         &log_ctx, tdb_jenkins_hash);
-       ok1(!tdb);
-       ok1(log_count == 1);
-
-       /* Create with different hash. */
-       log_count = 0;
-       tdb = tdb_open_ex("run-wronghash-fail.tdb", 0, 0,
-                         O_CREAT|O_RDWR|O_TRUNC,
-                         0600, &log_ctx, tdb_jenkins_hash);
-       ok1(tdb);
-       ok1(log_count == 0);
-       tdb_close(tdb);
-
-       /* Endian should be no problem. */
-       log_count = 0;
-       tdb = tdb_open_ex("test/jenkins-le-hash.tdb", 0, 0, O_RDWR, 0,
-                         &log_ctx, tdb_old_hash);
-       ok1(!tdb);
-       ok1(log_count == 1);
-
-       log_count = 0;
-       tdb = tdb_open_ex("test/jenkins-be-hash.tdb", 0, 0, O_RDWR, 0,
-                         &log_ctx, tdb_old_hash);
-       ok1(!tdb);
-       ok1(log_count == 1);
-
-       log_count = 0;
-       /* Fail to open with old default hash. */
-       tdb = tdb_open_ex("run-wronghash-fail.tdb", 0, 0, O_RDWR, 0,
-                         &log_ctx, tdb_old_hash);
-       ok1(!tdb);
-       ok1(log_count == 1);
-
-       log_count = 0;
-       tdb = tdb_open_ex("test/jenkins-le-hash.tdb", 0, 0, O_RDONLY,
-                         0, &log_ctx, tdb_jenkins_hash);
-       ok1(tdb);
-       ok1(log_count == 0);
-       ok1(tdb_check(tdb, NULL, NULL) == 0);
-       tdb_close(tdb);
-
-       log_count = 0;
-       tdb = tdb_open_ex("test/jenkins-be-hash.tdb", 0, 0, O_RDONLY,
-                         0, &log_ctx, tdb_jenkins_hash);
-       ok1(tdb);
-       ok1(log_count == 0);
-       ok1(tdb_check(tdb, NULL, NULL) == 0);
-       tdb_close(tdb);
-
-       /* It should open with jenkins hash if we don't specify. */
-       log_count = 0;
-       tdb = tdb_open_ex("test/jenkins-le-hash.tdb", 0, 0, O_RDWR, 0,
-                         &log_ctx, NULL);
-       ok1(tdb);
-       ok1(log_count == 0);
-       ok1(tdb_check(tdb, NULL, NULL) == 0);
-       tdb_close(tdb);
-
-       log_count = 0;
-       tdb = tdb_open_ex("test/jenkins-be-hash.tdb", 0, 0, O_RDWR, 0,
-                         &log_ctx, NULL);
-       ok1(tdb);
-       ok1(log_count == 0);
-       ok1(tdb_check(tdb, NULL, NULL) == 0);
-       tdb_close(tdb);
-
-       log_count = 0;
-       tdb = tdb_open_ex("run-wronghash-fail.tdb", 0, 0, O_RDONLY,
-                         0, &log_ctx, NULL);
-       ok1(tdb);
-       ok1(log_count == 0);
-       ok1(tdb_check(tdb, NULL, NULL) == 0);
-       tdb_close(tdb);
-
-
-       return exit_status();
-}
diff --git a/ccan/tdb/test/run-zero-append.c b/ccan/tdb/test/run-zero-append.c
deleted file mode 100644 (file)
index a869adc..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-#define _XOPEN_SOURCE 500
-#include <ccan/tdb/tdb.h>
-#include <ccan/tdb/io.c>
-#include <ccan/tdb/tdb.c>
-#include <ccan/tdb/lock.c>
-#include <ccan/tdb/freelist.c>
-#include <ccan/tdb/traverse.c>
-#include <ccan/tdb/transaction.c>
-#include <ccan/tdb/error.c>
-#include <ccan/tdb/open.c>
-#include <ccan/tdb/check.c>
-#include <ccan/tdb/hash.c>
-#include <ccan/tap/tap.h>
-#include <stdlib.h>
-#include <err.h>
-#include "logging.h"
-
-int main(int argc, char *argv[])
-{
-       struct tdb_context *tdb;
-       TDB_DATA key, data;
-
-       plan_tests(4);
-       tdb = tdb_open_ex(NULL, 1024, TDB_INTERNAL, O_CREAT|O_TRUNC|O_RDWR,
-                         0600, &taplogctx, NULL);
-       ok1(tdb);
-
-       /* Tickle bug on appending zero length buffer to zero length buffer. */
-       key.dsize = strlen("hi");
-       key.dptr = (void *)"hi";
-       data.dptr = (void *)"world";
-       data.dsize = 0;
-
-       ok1(tdb_append(tdb, key, data) == 0);
-       ok1(tdb_append(tdb, key, data) == 0);
-       data = tdb_fetch(tdb, key);
-       ok1(data.dsize == 0);
-       tdb_close(tdb);
-       free(data.dptr);
-
-       return exit_status();
-}
diff --git a/ccan/tdb/test/run.c b/ccan/tdb/test/run.c
deleted file mode 100644 (file)
index 6ef3c4d..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-#define _XOPEN_SOURCE 500
-#include <ccan/tdb/tdb.h>
-#include <ccan/tdb/io.c>
-#include <ccan/tdb/tdb.c>
-#include <ccan/tdb/lock.c>
-#include <ccan/tdb/freelist.c>
-#include <ccan/tdb/traverse.c>
-#include <ccan/tdb/transaction.c>
-#include <ccan/tdb/error.c>
-#include <ccan/tdb/open.c>
-#include <ccan/tdb/check.c>
-#include <ccan/tdb/hash.c>
-#include <ccan/tap/tap.h>
-#include <stdlib.h>
-#include <err.h>
-#include "logging.h"
-
-int main(int argc, char *argv[])
-{
-       struct tdb_context *tdb;
-       TDB_DATA key, data;
-
-       plan_tests(10);
-       tdb = tdb_open_ex("run.tdb", 1024, TDB_CLEAR_IF_FIRST,
-                         O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL);
-
-       ok1(tdb);
-       key.dsize = strlen("hi");
-       key.dptr = (void *)"hi";
-       data.dsize = strlen("world");
-       data.dptr = (void *)"world";
-
-       ok1(tdb_store(tdb, key, data, TDB_MODIFY) < 0);
-       ok1(tdb_error(tdb) == TDB_ERR_NOEXIST);
-       ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
-       ok1(tdb_store(tdb, key, data, TDB_INSERT) < 0);
-       ok1(tdb_error(tdb) == TDB_ERR_EXISTS);
-       ok1(tdb_store(tdb, key, data, TDB_MODIFY) == 0);
-
-       data = tdb_fetch(tdb, key);
-       ok1(data.dsize == strlen("world"));
-       ok1(memcmp(data.dptr, "world", strlen("world")) == 0);
-       free(data.dptr);
-
-       key.dsize++;
-       data = tdb_fetch(tdb, key);
-       ok1(data.dptr == NULL);
-       tdb_close(tdb);
-
-       return exit_status();
-}
diff --git a/ccan/tdb/test/rwlock-be.tdb b/ccan/tdb/test/rwlock-be.tdb
deleted file mode 100644 (file)
index 45b5f09..0000000
Binary files a/ccan/tdb/test/rwlock-be.tdb and /dev/null differ
diff --git a/ccan/tdb/test/rwlock-le.tdb b/ccan/tdb/test/rwlock-le.tdb
deleted file mode 100644 (file)
index 45b5f09..0000000
Binary files a/ccan/tdb/test/rwlock-le.tdb and /dev/null differ
diff --git a/ccan/tdb/test/tdb.corrupt b/ccan/tdb/test/tdb.corrupt
deleted file mode 100644 (file)
index 83d6677..0000000
Binary files a/ccan/tdb/test/tdb.corrupt and /dev/null differ
diff --git a/ccan/tdb/tools/Makefile b/ccan/tdb/tools/Makefile
deleted file mode 100644 (file)
index 6ba6f99..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-LDLIBS:=../../tdb.o ../../tally.o
-CFLAGS:=-I../../.. -Wall -O3 #-g -pg
-LDFLAGS:=-L../../..
-
-default: replay_trace tdbtorture tdbdump tdbtool starvation mktdb speed
-
-benchmark: replay_trace
-       @trap "rm -f /tmp/trace.$$$$" 0; for f in benchmarks/*.rz; do if runzip -k $$f -o /tmp/trace.$$$$ && echo -n "$$f": && ./replay_trace --quiet -n 5 replay.tdb /tmp/trace.$$$$ && rm /tmp/trace.$$$$; then rm -f /tmp/trace.$$$$; else exit 1; fi; done
-
-REPLAY_LIBS=$(LDLIBS) ../../str_talloc.o ../../grab_file.o  ../../talloc.o ../../noerr.o
-replay_trace: replay_trace.c keywords.c $(REPLAY_LIBS)
-       $(LINK.c) $< $(LOADLIBES) $(REPLAY_LIBS) -o $@
-
-keywords.c: keywords.gperf
-       gperf $< > $@
-
-check: replay_trace
-       @rm -f *.reduced_trace
-       @set -e; for f in tests/*.trace.tar.bz2; do             \
-               tar xvfj $$f;                                   \
-               ./replay_trace replay.tdb *.reduced_trace;      \
-               rm -f *.reduced_trace;                          \
-       done
-
-# Usage: make mytest.trace.tar.bz2 TRACEFILES=*.trace
-%.trace.tar.bz2: $(patsubst %.trace,%.reduced_trace,$(wildcard $(TRACEFILES)))
-       tar cvfj $@ $^
-
-%.reduced_trace: %.trace
-       @sed 's/\(^[0-9]* traverse\) .*/\1fn/' < $^ > $@
-
-clean:
-       rm -f replay_trace tdbtorture tdbdump tdbtool speed *.o
diff --git a/ccan/tdb/tools/benchmarks/configuration.ldb.trace.19774.rz b/ccan/tdb/tools/benchmarks/configuration.ldb.trace.19774.rz
deleted file mode 100644 (file)
index 6225079..0000000
Binary files a/ccan/tdb/tools/benchmarks/configuration.ldb.trace.19774.rz and /dev/null differ
diff --git a/ccan/tdb/tools/benchmarks/sam.ldb.trace.19774.rz b/ccan/tdb/tools/benchmarks/sam.ldb.trace.19774.rz
deleted file mode 100644 (file)
index 24a45d9..0000000
Binary files a/ccan/tdb/tools/benchmarks/sam.ldb.trace.19774.rz and /dev/null differ
diff --git a/ccan/tdb/tools/benchmarks/schema.ldb.trace.19774.rz b/ccan/tdb/tools/benchmarks/schema.ldb.trace.19774.rz
deleted file mode 100644 (file)
index f44bb0a..0000000
Binary files a/ccan/tdb/tools/benchmarks/schema.ldb.trace.19774.rz and /dev/null differ
diff --git a/ccan/tdb/tools/benchmarks/templates.ldb.trace.19774.rz b/ccan/tdb/tools/benchmarks/templates.ldb.trace.19774.rz
deleted file mode 100644 (file)
index bad0796..0000000
Binary files a/ccan/tdb/tools/benchmarks/templates.ldb.trace.19774.rz and /dev/null differ
diff --git a/ccan/tdb/tools/benchmarks/users.ldb.trace.19774.rz b/ccan/tdb/tools/benchmarks/users.ldb.trace.19774.rz
deleted file mode 100644 (file)
index e08ed0d..0000000
Binary files a/ccan/tdb/tools/benchmarks/users.ldb.trace.19774.rz and /dev/null differ
diff --git a/ccan/tdb/tools/keywords.c b/ccan/tdb/tools/keywords.c
deleted file mode 100644 (file)
index a238d5f..0000000
+++ /dev/null
@@ -1,203 +0,0 @@
-/* ANSI-C code produced by gperf version 3.0.3 */
-/* Command-line: gperf keywords.gperf  */
-/* Computed positions: -k'5,$' */
-
-#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
-      && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
-      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
-      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
-      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
-      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
-      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
-      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
-      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
-      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
-      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
-      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
-      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
-      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
-      && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
-      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
-      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
-      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
-      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
-      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
-      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
-      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
-      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
-/* The character set is not based on ISO-646.  */
-#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
-#endif
-
-#line 1 "keywords.gperf"
-
-#line 4 "keywords.gperf"
-struct op_table {
-       const char *name;
-       enum op_type type;
-       void (*enhance_op)(char *filename[], struct op op[],
-                          unsigned file, unsigned op_num, char *words[]);
-};
-/* maximum key range = 53, duplicates = 0 */
-
-#ifdef __GNUC__
-__inline
-#else
-#ifdef __cplusplus
-inline
-#endif
-#endif
-static unsigned int
-hash_keyword (register const char *str, register unsigned int len)
-{
-  static const unsigned char asso_values[] =
-    {
-      61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
-      61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
-      61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
-      61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
-      61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
-      61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
-      61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
-      61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
-      61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
-      61, 61, 61, 61, 61, 61, 61, 45, 61, 30,
-       5,  0,  0,  5,  5, 61, 61,  0,  0,  0,
-      20, 61, 20, 61, 25,  0,  5,  0, 61,  0,
-      61,  5, 61, 61, 61, 61, 61, 61, 61, 61,
-      61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
-      61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
-      61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
-      61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
-      61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
-      61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
-      61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
-      61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
-      61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
-      61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
-      61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
-      61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
-      61, 61, 61, 61, 61, 61
-    };
-  return len + asso_values[(unsigned char)str[4]] + asso_values[(unsigned char)str[len - 1]];
-}
-
-#ifdef __GNUC__
-__inline
-#ifdef __GNUC_STDC_INLINE__
-__attribute__ ((__gnu_inline__))
-#endif
-#endif
-const struct op_table *
-find_keyword (register const char *str, register unsigned int len)
-{
-  enum
-    {
-      TOTAL_KEYWORDS = 35,
-      MIN_WORD_LENGTH = 8,
-      MAX_WORD_LENGTH = 30,
-      MIN_HASH_VALUE = 8,
-      MAX_HASH_VALUE = 60
-    };
-
-  static const struct op_table wordlist[] =
-    {
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-#line 44 "keywords.gperf"
-      {"traverse", OP_TDB_TRAVERSE, op_add_traverse,},
-#line 33 "keywords.gperf"
-      {"tdb_store", OP_TDB_STORE, op_add_store,},
-#line 32 "keywords.gperf"
-      {"tdb_exists", OP_TDB_EXISTS, op_add_key_ret,},
-#line 16 "keywords.gperf"
-      {"tdb_lockall", OP_TDB_LOCKALL, op_add_nothing,},
-#line 36 "keywords.gperf"
-      {"tdb_wipe_all", OP_TDB_WIPE_ALL, op_add_wipe_all,},
-#line 20 "keywords.gperf"
-      {"tdb_unlockall", OP_TDB_UNLOCKALL, op_add_nothing,},
-#line 48 "keywords.gperf"
-      {"tdb_fetch", OP_TDB_FETCH, op_add_key_data,},
-#line 49 "keywords.gperf"
-      {"tdb_delete", OP_TDB_DELETE, op_add_key_ret,},
-#line 17 "keywords.gperf"
-      {"tdb_lockall_mark", OP_TDB_LOCKALL_MARK, op_add_nothing,},
-#line 46 "keywords.gperf"
-      {"tdb_firstkey", OP_TDB_FIRSTKEY, op_add_key,},
-#line 18 "keywords.gperf"
-      {"tdb_lockall_unmark", OP_TDB_LOCKALL_UNMARK, op_add_nothing,},
-#line 35 "keywords.gperf"
-      {"tdb_get_seqnum", OP_TDB_GET_SEQNUM, op_add_seqnum,},
-#line 19 "keywords.gperf"
-      {"tdb_lockall_nonblock", OP_TDB_LOCKALL_NONBLOCK, op_add_nothing,},
-#line 21 "keywords.gperf"
-      {"tdb_lockall_read", OP_TDB_LOCKALL_READ, op_add_nothing,},
-      {""},
-#line 23 "keywords.gperf"
-      {"tdb_unlockall_read", OP_TDB_UNLOCKALL_READ, op_add_nothing,},
-      {""},
-#line 22 "keywords.gperf"
-      {"tdb_lockall_read_nonblock", OP_TDB_LOCKALL_READ_NONBLOCK, op_add_nothing,},
-#line 43 "keywords.gperf"
-      {"tdb_traverse_end", OP_TDB_TRAVERSE_END, op_analyze_traverse,},
-#line 38 "keywords.gperf"
-      {"tdb_transaction_cancel", OP_TDB_TRANSACTION_CANCEL, op_analyze_transaction,},
-#line 42 "keywords.gperf"
-      {"tdb_traverse_start", OP_TDB_TRAVERSE_START, op_add_traverse_start,},
-      {""},
-#line 45 "keywords.gperf"
-      {"traversefn", OP_TDB_TRAVERSE, op_add_traversefn,},
-#line 37 "keywords.gperf"
-      {"tdb_transaction_start", OP_TDB_TRANSACTION_START, op_add_transaction,},
-#line 39 "keywords.gperf"
-      {"tdb_transaction_commit", OP_TDB_TRANSACTION_COMMIT, op_analyze_transaction,},
-#line 41 "keywords.gperf"
-      {"tdb_traverse_read_start", OP_TDB_TRAVERSE_READ_START, op_add_traverse_start,},
-      {""},
-#line 50 "keywords.gperf"
-      {"tdb_repack", OP_TDB_REPACK, op_add_nothing,},
-#line 47 "keywords.gperf"
-      {"tdb_nextkey", OP_TDB_NEXTKEY, op_add_key_data,},
-      {""}, {""}, {""},
-#line 40 "keywords.gperf"
-      {"tdb_transaction_prepare_commit", OP_TDB_TRANSACTION_PREPARE_COMMIT, op_add_nothing,},
-#line 31 "keywords.gperf"
-      {"tdb_parse_record", OP_TDB_PARSE_RECORD, op_add_key_ret,},
-      {""},
-#line 24 "keywords.gperf"
-      {"tdb_chainlock", OP_TDB_CHAINLOCK, op_add_chainlock,},
-      {""},
-#line 28 "keywords.gperf"
-      {"tdb_chainunlock", OP_TDB_CHAINUNLOCK, op_analyze_chainlock,},
-      {""}, {""},
-#line 26 "keywords.gperf"
-      {"tdb_chainlock_mark", OP_TDB_CHAINLOCK_MARK, op_add_key,},
-      {""},
-#line 27 "keywords.gperf"
-      {"tdb_chainlock_unmark", OP_TDB_CHAINLOCK_UNMARK, op_add_key,},
-      {""},
-#line 25 "keywords.gperf"
-      {"tdb_chainlock_nonblock", OP_TDB_CHAINLOCK_NONBLOCK, op_add_chainlock_ret,},
-#line 29 "keywords.gperf"
-      {"tdb_chainlock_read", OP_TDB_CHAINLOCK_READ, op_add_chainlock,},
-      {""},
-#line 30 "keywords.gperf"
-      {"tdb_chainunlock_read", OP_TDB_CHAINUNLOCK_READ, op_analyze_chainlock,},
-      {""}, {""}, {""}, {""},
-#line 34 "keywords.gperf"
-      {"tdb_append", OP_TDB_APPEND, op_add_append,}
-    };
-
-  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
-    {
-      register int key = hash_keyword (str, len);
-
-      if (key <= MAX_HASH_VALUE && key >= 0)
-        {
-          register const char *s = wordlist[key].name;
-
-          if (*str == *s && !strcmp (str + 1, s + 1))
-            return &wordlist[key];
-        }
-    }
-  return 0;
-}
diff --git a/ccan/tdb/tools/keywords.gperf b/ccan/tdb/tools/keywords.gperf
deleted file mode 100644 (file)
index 4edaf00..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-%{
-%}
-%language=ANSI-C
-struct op_table {
-       const char *name;
-       enum op_type type;
-       void (*enhance_op)(char *filename[], struct op op[],
-                          unsigned file, unsigned op_num, char *words[]);
-};
-%define hash-function-name hash_keyword
-%define lookup-function-name find_keyword
-%readonly-tables
-%struct-type
-%enum
-%%
-tdb_lockall, OP_TDB_LOCKALL, op_add_nothing,
-tdb_lockall_mark, OP_TDB_LOCKALL_MARK, op_add_nothing,
-tdb_lockall_unmark, OP_TDB_LOCKALL_UNMARK, op_add_nothing,
-tdb_lockall_nonblock, OP_TDB_LOCKALL_NONBLOCK, op_add_nothing,
-tdb_unlockall, OP_TDB_UNLOCKALL, op_add_nothing,
-tdb_lockall_read, OP_TDB_LOCKALL_READ, op_add_nothing,
-tdb_lockall_read_nonblock, OP_TDB_LOCKALL_READ_NONBLOCK, op_add_nothing,
-tdb_unlockall_read, OP_TDB_UNLOCKALL_READ, op_add_nothing,
-tdb_chainlock, OP_TDB_CHAINLOCK, op_add_chainlock,
-tdb_chainlock_nonblock, OP_TDB_CHAINLOCK_NONBLOCK, op_add_chainlock_ret,
-tdb_chainlock_mark, OP_TDB_CHAINLOCK_MARK, op_add_key,
-tdb_chainlock_unmark, OP_TDB_CHAINLOCK_UNMARK, op_add_key,
-tdb_chainunlock, OP_TDB_CHAINUNLOCK, op_analyze_chainlock,
-tdb_chainlock_read, OP_TDB_CHAINLOCK_READ, op_add_chainlock,
-tdb_chainunlock_read, OP_TDB_CHAINUNLOCK_READ, op_analyze_chainlock,
-tdb_parse_record, OP_TDB_PARSE_RECORD, op_add_key_ret,
-tdb_exists, OP_TDB_EXISTS, op_add_key_ret,
-tdb_store, OP_TDB_STORE, op_add_store,
-tdb_append, OP_TDB_APPEND, op_add_append,
-tdb_get_seqnum, OP_TDB_GET_SEQNUM, op_add_seqnum,
-tdb_wipe_all, OP_TDB_WIPE_ALL, op_add_wipe_all,
-tdb_transaction_start, OP_TDB_TRANSACTION_START, op_add_transaction,
-tdb_transaction_cancel, OP_TDB_TRANSACTION_CANCEL, op_analyze_transaction,
-tdb_transaction_commit, OP_TDB_TRANSACTION_COMMIT, op_analyze_transaction,
-tdb_transaction_prepare_commit, OP_TDB_TRANSACTION_PREPARE_COMMIT, op_add_nothing,
-tdb_traverse_read_start, OP_TDB_TRAVERSE_READ_START, op_add_traverse_start,
-tdb_traverse_start, OP_TDB_TRAVERSE_START, op_add_traverse_start,
-tdb_traverse_end, OP_TDB_TRAVERSE_END, op_analyze_traverse,
-traverse, OP_TDB_TRAVERSE, op_add_traverse,
-traversefn, OP_TDB_TRAVERSE, op_add_traversefn,
-tdb_firstkey, OP_TDB_FIRSTKEY, op_add_key,
-tdb_nextkey, OP_TDB_NEXTKEY, op_add_key_data,
-tdb_fetch, OP_TDB_FETCH, op_add_key_data,
-tdb_delete, OP_TDB_DELETE, op_add_key_ret,
-tdb_repack, OP_TDB_REPACK, op_add_nothing,
diff --git a/ccan/tdb/tools/mktdb.c b/ccan/tdb/tools/mktdb.c
deleted file mode 100644 (file)
index ed0efcd..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#include <ccan/tdb/tdb.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <err.h>
-
-int main(int argc, char *argv[])
-{
-       unsigned int i, num_recs;
-       struct tdb_context *tdb;
-
-       if (argc != 3 || (num_recs = atoi(argv[2])) == 0)
-               errx(1, "Usage: mktdb <tdbfile> <numrecords>");
-
-       tdb = tdb_open(argv[1], 10007, TDB_DEFAULT, O_CREAT|O_TRUNC|O_RDWR, 0600);
-       if (!tdb)
-               err(1, "Opening %s", argv[1]);
-
-       for (i = 0; i < num_recs; i++) {
-               TDB_DATA d;
-
-               d.dptr = (void *)&i;
-               d.dsize = sizeof(i);
-               if (tdb_store(tdb, d, d, TDB_INSERT) != 0)
-                       err(1, "Failed to store record %i", i);
-       }
-       printf("Done\n");
-       return 0;
-}
diff --git a/ccan/tdb/tools/replay_trace.c b/ccan/tdb/tools/replay_trace.c
deleted file mode 100644 (file)
index 0e799a6..0000000
+++ /dev/null
@@ -1,1955 +0,0 @@
-#include <ccan/tdb/tdb.h>
-#include <ccan/grab_file/grab_file.h>
-#include <ccan/hash/hash.h>
-#include <ccan/talloc/talloc.h>
-#include <ccan/str_talloc/str_talloc.h>
-#include <ccan/str/str.h>
-#include <ccan/list/list.h>
-#include <err.h>
-#include <ctype.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/time.h>
-#include <errno.h>
-#include <signal.h>
-#include <assert.h>
-#include <fcntl.h>
-
-#define STRINGIFY2(x) #x
-#define STRINGIFY(x) STRINGIFY2(x)
-
-static bool quiet = false;
-
-/* Avoid mod by zero */
-static unsigned int total_keys = 1;
-
-/* All the wipe_all ops. */
-static struct op_desc *wipe_alls = NULL;
-static unsigned int num_wipe_alls = 0;
-
-/* #define DEBUG_DEPS 1 */
-
-/* Traversals block transactions in the current implementation. */
-#define TRAVERSALS_TAKE_TRANSACTION_LOCK 1
-
-struct pipe {
-       int fd[2];
-};
-static struct pipe *pipes;
-static int backoff_fd = -1;
-
-static void __attribute__((noreturn)) fail(const char *filename,
-                                          unsigned int line,
-                                          const char *fmt, ...)
-{
-       va_list ap;
-
-       va_start(ap, fmt);
-       fprintf(stderr, "%s:%u: FAIL: ", filename, line);
-       vfprintf(stderr, fmt, ap);
-       fprintf(stderr, "\n");
-       va_end(ap);
-       exit(1);
-}
-       
-/* Try or die. */
-#define try(expr, expect)                                              \
-       do {                                                            \
-               int ret = (expr);                                       \
-               if (ret != (expect))                                    \
-                       fail(filename[file], i+1,                       \
-                            STRINGIFY(expr) "= %i", ret);              \
-       } while (0)
-
-/* Try or imitate results. */
-#define unreliable(expr, expect, force, undo)                          \
-       do {                                                            \
-               int ret = expr;                                         \
-               if (ret != expect) {                                    \
-                       fprintf(stderr, "%s:%u: %s gave %i not %i",     \
-                               filename[file], i+1, STRINGIFY(expr),   \
-                               ret, expect);                           \
-                       if (expect == 0)                                \
-                               force;                                  \
-                       else                                            \
-                               undo;                                   \
-               }                                                       \
-       } while (0)
-
-static bool key_eq(TDB_DATA a, TDB_DATA b)
-{
-       if (a.dsize != b.dsize)
-               return false;
-       return memcmp(a.dptr, b.dptr, a.dsize) == 0;
-}
-
-/* This is based on the hash algorithm from gdbm */
-static unsigned int hash_key(TDB_DATA *key)
-{
-       uint32_t value; /* Used to compute the hash value.  */
-       uint32_t   i;   /* Used to cycle through random values. */
-
-       /* Set the initial value from the key size. */
-       for (value = 0x238F13AF ^ key->dsize, i=0; i < key->dsize; i++)
-               value = (value + (key->dptr[i] << (i*5 % 24)));
-
-       return (1103515243 * value + 12345);  
-}
-
-enum op_type {
-       OP_TDB_LOCKALL,
-       OP_TDB_LOCKALL_MARK,
-       OP_TDB_LOCKALL_UNMARK,
-       OP_TDB_LOCKALL_NONBLOCK,
-       OP_TDB_UNLOCKALL,
-       OP_TDB_LOCKALL_READ,
-       OP_TDB_LOCKALL_READ_NONBLOCK,
-       OP_TDB_UNLOCKALL_READ,
-       OP_TDB_CHAINLOCK,
-       OP_TDB_CHAINLOCK_NONBLOCK,
-       OP_TDB_CHAINLOCK_MARK,
-       OP_TDB_CHAINLOCK_UNMARK,
-       OP_TDB_CHAINUNLOCK,
-       OP_TDB_CHAINLOCK_READ,
-       OP_TDB_CHAINUNLOCK_READ,
-       OP_TDB_PARSE_RECORD,
-       OP_TDB_EXISTS,
-       OP_TDB_STORE,
-       OP_TDB_APPEND,
-       OP_TDB_GET_SEQNUM,
-       OP_TDB_WIPE_ALL,
-       OP_TDB_TRANSACTION_START,
-       OP_TDB_TRANSACTION_CANCEL,
-       OP_TDB_TRANSACTION_PREPARE_COMMIT,
-       OP_TDB_TRANSACTION_COMMIT,
-       OP_TDB_TRAVERSE_READ_START,
-       OP_TDB_TRAVERSE_START,
-       OP_TDB_TRAVERSE_END,
-       OP_TDB_TRAVERSE,
-       OP_TDB_TRAVERSE_END_EARLY,
-       OP_TDB_FIRSTKEY,
-       OP_TDB_NEXTKEY,
-       OP_TDB_FETCH,
-       OP_TDB_DELETE,
-       OP_TDB_REPACK,
-};
-
-struct op {
-       unsigned int seqnum;
-       enum op_type type;
-       TDB_DATA key;
-       TDB_DATA data;
-       int ret;
-
-       /* Who is waiting for us? */
-       struct list_head post;
-       /* What are we waiting for? */
-       struct list_head pre;
-
-       /* If I'm part of a group (traverse/transaction) where is
-        * start?  (Otherwise, 0) */
-       unsigned int group_start;
-
-       union {
-               int flag; /* open and store */
-               struct {  /* append */
-                       TDB_DATA pre;
-                       TDB_DATA post;
-               } append;
-               /* transaction/traverse start/chainlock */
-               unsigned int group_len;
-       };
-};
-
-struct op_desc {
-       unsigned int file;
-       unsigned int op_num;
-};
-
-static unsigned char hex_char(const char *filename, unsigned int line, char c)
-{
-       c = toupper(c);
-       if (c >= 'A' && c <= 'F')
-               return c - 'A' + 10;
-       if (c >= '0' && c <= '9')
-               return c - '0';
-       fail(filename, line, "invalid hex character '%c'", c);
-}
-
-/* TDB data is <size>:<%02x>* */
-static TDB_DATA make_tdb_data(const void *ctx,
-                             const char *filename, unsigned int line,
-                             const char *word)
-{
-       TDB_DATA data;
-       unsigned int i;
-       const char *p;
-
-       if (streq(word, "NULL"))
-               return tdb_null;
-
-       data.dsize = atoi(word);
-       data.dptr = talloc_array(ctx, unsigned char, data.dsize);
-       p = strchr(word, ':');
-       if (!p)
-               fail(filename, line, "invalid tdb data '%s'", word);
-       p++;
-       for (i = 0; i < data.dsize; i++)
-               data.dptr[i] = hex_char(filename, line, p[i*2])*16
-                       + hex_char(filename, line, p[i*2+1]);
-
-       return data;
-}
-
-static void add_op(const char *filename, struct op **op, unsigned int i,
-                  unsigned int seqnum, enum op_type type)
-{
-       struct op *new;
-       *op = talloc_realloc(NULL, *op, struct op, i+1);
-       new = (*op) + i;
-       new->type = type;
-       new->seqnum = seqnum;
-       new->ret = 0;
-       new->group_start = 0;
-}
-
-static void op_add_nothing(char *filename[], struct op op[],
-                          unsigned file, unsigned op_num, char *words[])
-{
-       if (words[2])
-               fail(filename[file], op_num+1, "Expected no arguments");
-       op[op_num].key = tdb_null;
-}
-
-static void op_add_key(char *filename[], struct op op[],
-                      unsigned file, unsigned op_num, char *words[])
-{
-       if (words[2] == NULL || words[3])
-               fail(filename[file], op_num+1, "Expected just a key");
-
-       op[op_num].key = make_tdb_data(op, filename[file], op_num+1, words[2]);
-       total_keys++;
-}
-
-static void op_add_key_ret(char *filename[], struct op op[],
-                          unsigned file, unsigned op_num, char *words[])
-{
-       if (!words[2] || !words[3] || !words[4] || words[5]
-           || !streq(words[3], "="))
-               fail(filename[file], op_num+1, "Expected <key> = <ret>");
-       op[op_num].ret = atoi(words[4]);
-       op[op_num].key = make_tdb_data(op, filename[file], op_num+1, words[2]);
-       /* May only be a unique key if it fails */
-       if (op[op_num].ret != 0)
-               total_keys++;
-}
-
-static void op_add_key_data(char *filename[], struct op op[],
-                           unsigned file, unsigned op_num, char *words[])
-{
-       if (!words[2] || !words[3] || !words[4] || words[5]
-           || !streq(words[3], "="))
-               fail(filename[file], op_num+1, "Expected <key> = <data>");
-       op[op_num].key = make_tdb_data(op, filename[file], op_num+1, words[2]);
-       op[op_num].data = make_tdb_data(op, filename[file], op_num+1, words[4]);
-       /* Likely only be a unique key if it fails */
-       if (!op[op_num].data.dptr)
-               total_keys++;
-       else if (random() % 2)
-               total_keys++;
-}
-
-/* We don't record the keys or data for a traverse, as we don't use them. */
-static void op_add_traverse(char *filename[], struct op op[],
-                           unsigned file, unsigned op_num, char *words[])
-{
-       if (!words[2] || !words[3] || !words[4] || words[5]
-           || !streq(words[3], "="))
-               fail(filename[file], op_num+1, "Expected <key> = <data>");
-       op[op_num].key = tdb_null;
-}
-
-/* Full traverse info is useful for debugging, but changing it to
- * "traversefn" without the data makes the traces *much* smaller! */
-static void op_add_traversefn(char *filename[], struct op op[],
-                           unsigned file, unsigned op_num, char *words[])
-{
-       if (words[2])
-               fail(filename[file], op_num+1, "Expected no values");
-       op[op_num].key = tdb_null;
-}
-
-/* <seqnum> tdb_store <rec> <rec> <flag> = <ret> */
-static void op_add_store(char *filename[], struct op op[],
-                        unsigned file, unsigned op_num, char *words[])
-{
-       if (!words[2] || !words[3] || !words[4] || !words[5] || !words[6]
-           || words[7] || !streq(words[5], "="))
-               fail(filename[file], op_num+1, "Expect <key> <data> <flag> = <ret>");
-
-       op[op_num].flag = strtoul(words[4], NULL, 0);
-       op[op_num].ret = atoi(words[6]);
-       op[op_num].key = make_tdb_data(op, filename[file], op_num+1, words[2]);
-       op[op_num].data = make_tdb_data(op, filename[file], op_num+1, words[3]);
-       total_keys++;
-}
-
-/* <seqnum> tdb_append <rec> <rec> = <rec> */
-static void op_add_append(char *filename[], struct op op[],
-                         unsigned file, unsigned op_num, char *words[])
-{
-       if (!words[2] || !words[3] || !words[4] || !words[5] || words[6]
-           || !streq(words[4], "="))
-               fail(filename[file], op_num+1, "Expect <key> <data> = <rec>");
-
-       op[op_num].key = make_tdb_data(op, filename[file], op_num+1, words[2]);
-       op[op_num].data = make_tdb_data(op, filename[file], op_num+1, words[3]);
-
-       op[op_num].append.post
-               = make_tdb_data(op, filename[file], op_num+1, words[5]);
-
-       /* By subtraction, figure out what previous data was. */
-       op[op_num].append.pre.dptr = op[op_num].append.post.dptr;
-       op[op_num].append.pre.dsize
-               = op[op_num].append.post.dsize - op[op_num].data.dsize;
-       total_keys++;
-}
-
-/* <seqnum> tdb_get_seqnum = <ret> */
-static void op_add_seqnum(char *filename[], struct op op[],
-                         unsigned file, unsigned op_num, char *words[])
-{
-       if (!words[2] || !words[3] || words[4] || !streq(words[2], "="))
-               fail(filename[file], op_num+1, "Expect = <ret>");
-
-       op[op_num].key = tdb_null;
-       op[op_num].ret = atoi(words[3]);
-}
-
-static void op_add_traverse_start(char *filename[], struct op op[],
-                                 unsigned file, unsigned op_num, char *words[])
-{
-       if (words[2])
-               fail(filename[file], op_num+1, "Expect no arguments");
-
-       op[op_num].key = tdb_null;
-       op[op_num].group_len = 0;
-}
-
-static void op_add_transaction(char *filename[], struct op op[],
-                              unsigned file, unsigned op_num, char *words[])
-{
-       if (words[2])
-               fail(filename[file], op_num+1, "Expect no arguments");
-
-       op[op_num].key = tdb_null;
-       op[op_num].group_len = 0;
-}
-
-static void op_add_chainlock(char *filename[], struct op op[],
-                            unsigned file, unsigned op_num, char *words[])
-{
-       if (words[2] == NULL || words[3])
-               fail(filename[file], op_num+1, "Expected just a key");
-
-       /* A chainlock key isn't a key in the normal sense; it doesn't
-        * have to be in the db at all.  Also, we don't want to hash this op. */
-       op[op_num].data = make_tdb_data(op, filename[file], op_num+1, words[2]);
-       op[op_num].key = tdb_null;
-       op[op_num].group_len = 0;
-}
-
-static void op_add_chainlock_ret(char *filename[], struct op op[],
-                                unsigned file, unsigned op_num, char *words[])
-{
-       if (!words[2] || !words[3] || !words[4] || words[5]
-           || !streq(words[3], "="))
-               fail(filename[file], op_num+1, "Expected <key> = <ret>");
-       op[op_num].ret = atoi(words[4]);
-       op[op_num].data = make_tdb_data(op, filename[file], op_num+1, words[2]);
-       op[op_num].key = tdb_null;
-       op[op_num].group_len = 0;
-       total_keys++;
-}
-
-static void op_add_wipe_all(char *filename[], struct op op[],
-                           unsigned file, unsigned op_num, char *words[])
-{
-       if (words[2])
-               fail(filename[file], op_num+1, "Expected no arguments");
-       op[op_num].key = tdb_null;
-       wipe_alls = talloc_realloc(NULL, wipe_alls, struct op_desc,
-                                  num_wipe_alls+1);
-       wipe_alls[num_wipe_alls].file = file;
-       wipe_alls[num_wipe_alls].op_num = op_num;
-       num_wipe_alls++;
-}
-
-static int op_find_start(struct op op[], unsigned int op_num, enum op_type type)
-{
-       unsigned int i;
-
-       for (i = op_num-1; i > 0; i--) {
-               if (op[i].type == type && !op[i].group_len)
-                       return i;
-       }
-       return 0;
-}
-
-static void op_analyze_transaction(char *filename[], struct op op[],
-                                  unsigned file, unsigned op_num,
-                                  char *words[])
-{
-       unsigned int start, i;
-
-       op[op_num].key = tdb_null;
-
-       if (words[2])
-               fail(filename[file], op_num+1, "Expect no arguments");
-
-       start = op_find_start(op, op_num, OP_TDB_TRANSACTION_START);
-       if (!start)
-               fail(filename[file], op_num+1, "no transaction start found");
-
-       op[start].group_len = op_num - start;
-
-       /* This rolls in nested transactions.  I think that's right. */
-       for (i = start; i <= op_num; i++)
-               op[i].group_start = start;
-}
-
-/* We treat chainlocks a lot like transactions, even though that's overkill */
-static void op_analyze_chainlock(char *filename[], struct op op[],
-                                unsigned file, unsigned op_num, char *words[])
-{
-       unsigned int i, start;
-
-       if (words[2] == NULL || words[3])
-               fail(filename[file], op_num+1, "Expected just a key");
-
-       op[op_num].data = make_tdb_data(op, filename[file], op_num+1, words[2]);
-       op[op_num].key = tdb_null;
-       total_keys++;
-
-       start = op_find_start(op, op_num, OP_TDB_CHAINLOCK);
-       if (!start)
-               start = op_find_start(op, op_num, OP_TDB_CHAINLOCK_READ);
-       if (!start)
-               fail(filename[file], op_num+1, "no initial chainlock found");
-
-       /* FIXME: We'd have to do something clever to make this work
-        * vs. deadlock. */
-       if (!key_eq(op[start].data, op[op_num].data))
-               fail(filename[file], op_num+1, "nested chainlock calls?");
-
-       op[start].group_len = op_num - start;
-       for (i = start; i <= op_num; i++)
-               op[i].group_start = start;
-}
-
-static void op_analyze_traverse(char *filename[], struct op op[],
-                               unsigned file, unsigned op_num, char *words[])
-{
-       int i, start;
-
-       op[op_num].key = tdb_null;
-
-       /* = %u means traverse function terminated. */
-       if (words[2]) {
-               if (!streq(words[2], "=") || !words[3] || words[4])
-                       fail(filename[file], op_num+1, "expect = <num>");
-               op[op_num].ret = atoi(words[3]);
-       } else
-               op[op_num].ret = 0;
-
-       start = op_find_start(op, op_num, OP_TDB_TRAVERSE_START);
-       if (!start)
-               start = op_find_start(op, op_num, OP_TDB_TRAVERSE_READ_START);
-       if (!start)
-               fail(filename[file], op_num+1, "no traversal start found");
-
-       op[start].group_len = op_num - start;
-
-       /* Don't roll in nested traverse/chainlock */
-       for (i = start; i <= op_num; i++)
-               if (!op[i].group_start)
-                       op[i].group_start = start;
-}
-
-/* Keep -Wmissing-declarations happy: */
-const struct op_table *
-find_keyword (register const char *str, register unsigned int len);
-
-#include "keywords.c"
-
-struct depend {
-       /* We can have more than one */
-       struct list_node pre_list;
-       struct list_node post_list;
-       struct op_desc needs;
-       struct op_desc prereq;
-};
-
-static void check_deps(const char *filename, struct op op[], unsigned int num)
-{
-#ifdef DEBUG_DEPS
-       unsigned int i;
-
-       for (i = 1; i < num; i++)
-               if (!list_empty(&op[i].pre))
-                       fail(filename, i+1, "Still has dependencies");
-#endif
-}
-
-static void dump_pre(char *filename[], struct op *op[],
-                    unsigned int file, unsigned int i)
-{
-       struct depend *dep;
-
-       if (!quiet) {
-               printf("%s:%u (%u) still waiting for:\n", filename[file], i+1,
-                      op[file][i].seqnum);
-               list_for_each(&op[file][i].pre, dep, pre_list)
-                       printf("    %s:%u (%u)\n",
-                              filename[dep->prereq.file], dep->prereq.op_num+1,
-                              op[dep->prereq.file][dep->prereq.op_num].seqnum);
-       }
-       check_deps(filename[file], op[file], i);
-}
-
-/* We simply read/write pointers, since we all are children. */
-static bool do_pre(struct tdb_context *tdb,
-                  char *filename[], struct op *op[],
-                  unsigned int file, int pre_fd, unsigned int i,
-                  bool backoff)
-{
-       while (!list_empty(&op[file][i].pre)) {
-               struct depend *dep;
-
-#if DEBUG_DEPS
-               printf("%s:%u:waiting for pre\n", filename[file], i+1);
-               fflush(stdout);
-#endif
-               if (backoff)
-                       alarm(2);
-               else
-                       alarm(10);
-               while (read(pre_fd, &dep, sizeof(dep)) != sizeof(dep)) {
-                       if (errno == EINTR) {
-                               if (backoff) {
-                                       struct op_desc desc = { file,i };
-                                       warnx("%s:%u:avoiding deadlock",
-                                             filename[file], i+1);
-                                       if (write(backoff_fd, &desc,
-                                                 sizeof(desc)) != sizeof(desc))
-                                               err(1, "writing backoff_fd");
-                                       return false;
-                               }
-                               dump_pre(filename, op, file, i);
-                               exit(1);
-                       } else
-                               errx(1, "Reading from pipe");
-               }
-               alarm(0);
-
-#if DEBUG_DEPS
-               printf("%s:%u:got pre %u from %s:%u\n", filename[file], i+1,
-                      dep->needs.op_num+1, filename[dep->prereq.file],
-                      dep->prereq.op_num+1);
-               fflush(stdout);
-#endif
-               /* This could be any op, not just this one. */
-               talloc_free(dep);
-       }
-       return true;
-}
-
-static void do_post(char *filename[], struct op *op[],
-                   unsigned int file, unsigned int i)
-{
-       struct depend *dep;
-
-       list_for_each(&op[file][i].post, dep, post_list) {
-#if DEBUG_DEPS
-               printf("%s:%u:sending to file %s:%u\n", filename[file], i+1,
-                      filename[dep->needs.file], dep->needs.op_num+1);
-#endif
-               if (write(pipes[dep->needs.file].fd[1], &dep, sizeof(dep))
-                   != sizeof(dep))
-                       err(1, "%s:%u failed to tell file %s",
-                           filename[file], i+1, filename[dep->needs.file]);
-       }
-}
-
-static int get_len(TDB_DATA key, TDB_DATA data, void *private_data)
-{
-       return data.dsize;
-}
-
-static unsigned run_ops(struct tdb_context *tdb,
-                       int pre_fd,
-                       char *filename[],
-                       struct op *op[],
-                       unsigned int file,
-                       unsigned int start, unsigned int stop,
-                       bool backoff);
-
-struct traverse_info {
-       struct op **op;
-       char **filename;
-       unsigned file;
-       int pre_fd;
-       unsigned int start;
-       unsigned int i;
-};
-
-/* More complex.  Just do whatever's they did at the n'th entry. */
-static int nontrivial_traverse(struct tdb_context *tdb,
-                              TDB_DATA key, TDB_DATA data,
-                              void *_tinfo)
-{
-       struct traverse_info *tinfo = _tinfo;
-       unsigned int trav_len = tinfo->op[tinfo->file][tinfo->start].group_len;
-       bool avoid_deadlock = false;
-
-       if (tinfo->i == tinfo->start + trav_len) {
-               /* This can happen if traverse expects to be empty. */
-               if (trav_len == 1)
-                       return 1;
-               fail(tinfo->filename[tinfo->file], tinfo->start + 1,
-                    "traverse did not terminate");
-       }
-
-       if (tinfo->op[tinfo->file][tinfo->i].type != OP_TDB_TRAVERSE)
-               fail(tinfo->filename[tinfo->file], tinfo->start + 1,
-                    "%s:%u:traverse terminated early");
-
-#if TRAVERSALS_TAKE_TRANSACTION_LOCK
-       avoid_deadlock = true;
-#endif
-
-       /* Run any normal ops. */
-       tinfo->i = run_ops(tdb, tinfo->pre_fd, tinfo->filename, tinfo->op,
-                          tinfo->file, tinfo->i+1, tinfo->start + trav_len,
-                          avoid_deadlock);
-
-       /* We backed off, or we hit OP_TDB_TRAVERSE_END/EARLY. */
-       if (tinfo->op[tinfo->file][tinfo->i].type != OP_TDB_TRAVERSE)
-               return 1;
-
-       return 0;
-}
-
-static unsigned op_traverse(struct tdb_context *tdb,
-                           int pre_fd,
-                           char *filename[],
-                           unsigned int file,
-                           int (*traversefn)(struct tdb_context *,
-                                             tdb_traverse_func, void *),
-                           struct op *op[],
-                           unsigned int start)
-{
-       struct traverse_info tinfo = { op, filename, file, pre_fd,
-                                      start, start+1 };
-
-       traversefn(tdb, nontrivial_traverse, &tinfo);
-
-       /* Traversing in wrong order can have strange effects: eg. if
-        * original traverse went A (delete A), B, we might do B
-        * (delete A).  So if we have ops left over, we do it now. */
-       while (tinfo.i != start + op[file][start].group_len) {
-               if (op[file][tinfo.i].type == OP_TDB_TRAVERSE
-                   || op[file][tinfo.i].type == OP_TDB_TRAVERSE_END_EARLY)
-                       tinfo.i++;
-               else
-                       tinfo.i = run_ops(tdb, pre_fd, filename, op, file,
-                                         tinfo.i,
-                                         start + op[file][start].group_len,
-                                         false);
-       }
-
-       return tinfo.i;
-}
-
-static void break_out(int sig)
-{
-}
-
-static __attribute__((noinline))
-unsigned run_ops(struct tdb_context *tdb,
-                int pre_fd,
-                char *filename[],
-                struct op *op[],
-                unsigned int file,
-                unsigned int start, unsigned int stop,
-                bool backoff)
-{
-       unsigned int i;
-       struct sigaction sa;
-
-       sa.sa_handler = break_out;
-       sa.sa_flags = 0;
-
-       sigaction(SIGALRM, &sa, NULL);
-       for (i = start; i < stop; i++) {
-               if (!do_pre(tdb, filename, op, file, pre_fd, i, backoff))
-                       return i;
-
-               switch (op[file][i].type) {
-               case OP_TDB_LOCKALL:
-                       try(tdb_lockall(tdb), op[file][i].ret);
-                       break;
-               case OP_TDB_LOCKALL_MARK:
-                       try(tdb_lockall_mark(tdb), op[file][i].ret);
-                       break;
-               case OP_TDB_LOCKALL_UNMARK:
-                       try(tdb_lockall_unmark(tdb), op[file][i].ret);
-                       break;
-               case OP_TDB_LOCKALL_NONBLOCK:
-                       unreliable(tdb_lockall_nonblock(tdb), op[file][i].ret,
-                                  tdb_lockall(tdb), tdb_unlockall(tdb));
-                       break;
-               case OP_TDB_UNLOCKALL:
-                       try(tdb_unlockall(tdb), op[file][i].ret);
-                       break;
-               case OP_TDB_LOCKALL_READ:
-                       try(tdb_lockall_read(tdb), op[file][i].ret);
-                       break;
-               case OP_TDB_LOCKALL_READ_NONBLOCK:
-                       unreliable(tdb_lockall_read_nonblock(tdb),
-                                  op[file][i].ret,
-                                  tdb_lockall_read(tdb),
-                                  tdb_unlockall_read(tdb));
-                       break;
-               case OP_TDB_UNLOCKALL_READ:
-                       try(tdb_unlockall_read(tdb), op[file][i].ret);
-                       break;
-               case OP_TDB_CHAINLOCK:
-                       try(tdb_chainlock(tdb, op[file][i].key),
-                           op[file][i].ret);
-                       break;
-               case OP_TDB_CHAINLOCK_NONBLOCK:
-                       unreliable(tdb_chainlock_nonblock(tdb, op[file][i].key),
-                                  op[file][i].ret,
-                                  tdb_chainlock(tdb, op[file][i].key),
-                                  tdb_chainunlock(tdb, op[file][i].key));
-                       break;
-               case OP_TDB_CHAINLOCK_MARK:
-                       try(tdb_chainlock_mark(tdb, op[file][i].key),
-                           op[file][i].ret);
-                       break;
-               case OP_TDB_CHAINLOCK_UNMARK:
-                       try(tdb_chainlock_unmark(tdb, op[file][i].key),
-                           op[file][i].ret);
-                       break;
-               case OP_TDB_CHAINUNLOCK:
-                       try(tdb_chainunlock(tdb, op[file][i].key),
-                           op[file][i].ret);
-                       break;
-               case OP_TDB_CHAINLOCK_READ:
-                       try(tdb_chainlock_read(tdb, op[file][i].key),
-                           op[file][i].ret);
-                       break;
-               case OP_TDB_CHAINUNLOCK_READ:
-                       try(tdb_chainunlock_read(tdb, op[file][i].key),
-                           op[file][i].ret);
-                       break;
-               case OP_TDB_PARSE_RECORD:
-                       try(tdb_parse_record(tdb, op[file][i].key, get_len,
-                                            NULL),
-                           op[file][i].ret);
-                       break;
-               case OP_TDB_EXISTS:
-                       try(tdb_exists(tdb, op[file][i].key), op[file][i].ret);
-                       break;
-               case OP_TDB_STORE:
-                       try(tdb_store(tdb, op[file][i].key, op[file][i].data,
-                                     op[file][i].flag),
-                           op[file][i].ret);
-                       break;
-               case OP_TDB_APPEND:
-                       try(tdb_append(tdb, op[file][i].key, op[file][i].data),
-                           op[file][i].ret);
-                       break;
-               case OP_TDB_GET_SEQNUM:
-                       try(tdb_get_seqnum(tdb), op[file][i].ret);
-                       break;
-               case OP_TDB_WIPE_ALL:
-                       try(tdb_wipe_all(tdb), op[file][i].ret);
-                       break;
-               case OP_TDB_TRANSACTION_START:
-                       try(tdb_transaction_start(tdb), op[file][i].ret);
-                       break;
-               case OP_TDB_TRANSACTION_CANCEL:
-                       try(tdb_transaction_cancel(tdb), op[file][i].ret);
-                       break;
-               case OP_TDB_TRANSACTION_PREPARE_COMMIT:
-                       try(tdb_transaction_prepare_commit(tdb),
-                           op[file][i].ret);
-                       break;
-               case OP_TDB_TRANSACTION_COMMIT:
-                       try(tdb_transaction_commit(tdb), op[file][i].ret);
-                       break;
-               case OP_TDB_TRAVERSE_READ_START:
-                       i = op_traverse(tdb, pre_fd, filename, file,
-                                       tdb_traverse_read, op, i);
-                       break;
-               case OP_TDB_TRAVERSE_START:
-                       i = op_traverse(tdb, pre_fd, filename, file,
-                                       tdb_traverse, op, i);
-                       break;
-               case OP_TDB_TRAVERSE:
-               case OP_TDB_TRAVERSE_END_EARLY:
-                       /* Terminate: we're in a traverse, and we've
-                        * done our ops. */
-                       return i;
-               case OP_TDB_TRAVERSE_END:
-                       fail(filename[file], i+1, "unexpected end traverse");
-               /* FIXME: These must be treated like traverse. */
-               case OP_TDB_FIRSTKEY:
-                       if (!key_eq(tdb_firstkey(tdb), op[file][i].data))
-                               fail(filename[file], i+1, "bad firstkey");
-                       break;
-               case OP_TDB_NEXTKEY:
-                       if (!key_eq(tdb_nextkey(tdb, op[file][i].key),
-                                   op[file][i].data))
-                               fail(filename[file], i+1, "bad nextkey");
-                       break;
-               case OP_TDB_FETCH: {
-                       TDB_DATA f = tdb_fetch(tdb, op[file][i].key);
-                       if (!key_eq(f, op[file][i].data))
-                               fail(filename[file], i+1, "bad fetch %u",
-                                    f.dsize);
-                       break;
-               }
-               case OP_TDB_DELETE:
-                       try(tdb_delete(tdb, op[file][i].key), op[file][i].ret);
-                       break;
-               case OP_TDB_REPACK:
-                       /* We do nothing here: the transaction and traverse are
-                        * traced.  It's in the trace to mark it, since it
-                        * may become unnecessary in future. */
-                       break;
-               }
-               do_post(filename, op, file, i);
-       }
-       return i;
-}
-
-/* tdbtorture, in particular, can do a tdb_close with a transaction in
- * progress. */
-static struct op *maybe_cancel_transaction(char *filename[], unsigned int file,
-                                          struct op *op, unsigned int *num)
-{
-       unsigned int start = op_find_start(op, *num, OP_TDB_TRANSACTION_START);
-
-       if (start) {
-               char *words[] = { "<unknown>", "tdb_close", NULL };
-               add_op(filename[file], &op, *num, op[start].seqnum,
-                      OP_TDB_TRANSACTION_CANCEL);
-               op_analyze_transaction(filename, op, file, *num, words);
-               (*num)++;
-       }
-       return op;
-}
-
-static struct op *load_tracefile(char *filename[],
-                                unsigned int file,
-                                unsigned int *num,
-                                unsigned int *hashsize,
-                                unsigned int *tdb_flags,
-                                unsigned int *open_flags)
-{
-       unsigned int i;
-       struct op *op = talloc_array(NULL, struct op, 1);
-       char **words;
-       char **lines;
-       char *contents;
-
-       contents = grab_file(NULL, filename[file], NULL);
-       if (!contents)
-               err(1, "Reading %s", filename[file]);
-
-       lines = strsplit(contents, contents, "\n");
-       if (!lines[0])
-               errx(1, "%s is empty", filename[file]);
-
-       words = strsplit(lines, lines[0], " ");
-       if (!streq(words[1], "tdb_open"))
-               fail(filename[file], 1, "does not start with tdb_open");
-
-       *hashsize = atoi(words[2]);
-       *tdb_flags = strtoul(words[3], NULL, 0);
-       *open_flags = strtoul(words[4], NULL, 0);
-
-       for (i = 1; lines[i]; i++) {
-               const struct op_table *opt;
-
-               words = strsplit(lines, lines[i], " ");
-               if (!words[0] || !words[1])
-                       fail(filename[file], i+1,
-                            "Expected seqnum number and op");
-              
-               opt = find_keyword(words[1], strlen(words[1]));
-               if (!opt) {
-                       if (streq(words[1], "tdb_close")) {
-                               if (lines[i+1])
-                                       fail(filename[file], i+2,
-                                            "lines after tdb_close");
-                               *num = i;
-                               talloc_free(lines);
-                               return maybe_cancel_transaction(filename, file,
-                                                               op, num);
-                       }
-                       fail(filename[file], i+1,
-                            "Unknown operation '%s'", words[1]);
-               }
-
-               add_op(filename[file], &op, i, atoi(words[0]), opt->type);
-               opt->enhance_op(filename, op, file, i, words);
-       }
-
-       if (!quiet)
-               fprintf(stderr,
-                       "%s:%u:last operation is not tdb_close: incomplete?",
-                       filename[file], i);
-
-       talloc_free(contents);
-       *num = i - 1;
-       return maybe_cancel_transaction(filename, file, op, num);
-}
-
-/* We remember all the keys we've ever seen, and who has them. */
-struct keyinfo {
-       TDB_DATA key;
-       unsigned int num_users;
-       struct op_desc *user;
-};
-
-static bool starts_transaction(const struct op *op)
-{
-       return op->type == OP_TDB_TRANSACTION_START;
-}
-
-static bool in_transaction(const struct op op[], unsigned int i)
-{
-       return op[i].group_start && starts_transaction(&op[op[i].group_start]);
-}
-
-static bool successful_transaction(const struct op *op)
-{
-       return starts_transaction(op)
-               && op[op->group_len].type == OP_TDB_TRANSACTION_COMMIT;
-}
-
-static bool starts_traverse(const struct op *op)
-{
-       return op->type == OP_TDB_TRAVERSE_START
-               || op->type == OP_TDB_TRAVERSE_READ_START;
-}
-
-static bool in_traverse(const struct op op[], unsigned int i)
-{
-       return op[i].group_start && starts_traverse(&op[op[i].group_start]);
-}
-
-static bool starts_chainlock(const struct op *op)
-{
-       return op->type == OP_TDB_CHAINLOCK_READ
-               || op->type == OP_TDB_CHAINLOCK;
-}
-
-static bool in_chainlock(const struct op op[], unsigned int i)
-{
-       return op[i].group_start && starts_chainlock(&op[op[i].group_start]);
-}
-
-static const TDB_DATA must_not_exist;
-static const TDB_DATA must_exist;
-static const TDB_DATA not_exists_or_empty;
-
-/* NULL means doesn't care if it exists or not, &must_exist means
- * it must exist but we don't care what, &must_not_exist means it must
- * not exist, otherwise the data it needs. */
-static const TDB_DATA *needs(const TDB_DATA *key, const struct op *op)
-{
-       /* Look through for an op in this transaction which needs this key. */
-       if (starts_transaction(op) || starts_chainlock(op)) {
-               unsigned int i;
-               const TDB_DATA *need = NULL;
-
-               for (i = 1; i < op->group_len; i++) {
-                       if (key_eq(op[i].key, *key)
-                           || op[i].type == OP_TDB_WIPE_ALL) {
-                               need = needs(key, &op[i]);
-                               /* tdb_exists() is special: there might be
-                                * something in the transaction with more
-                                * specific requirements.  Other ops don't have
-                                * specific requirements (eg. store or delete),
-                                * but they change the value so we can't get
-                                * more information from future ops. */
-                               if (op[i].type != OP_TDB_EXISTS)
-                                       break;
-                       }
-               }
-
-               return need;
-       }
-
-       switch (op->type) {
-       /* FIXME: Pull forward deps, since we can deadlock */
-       case OP_TDB_CHAINLOCK:
-       case OP_TDB_CHAINLOCK_NONBLOCK:
-       case OP_TDB_CHAINLOCK_MARK:
-       case OP_TDB_CHAINLOCK_UNMARK:
-       case OP_TDB_CHAINUNLOCK:
-       case OP_TDB_CHAINLOCK_READ:
-       case OP_TDB_CHAINUNLOCK_READ:
-               return NULL;
-
-       case OP_TDB_APPEND:
-               if (op->append.pre.dsize == 0)
-                       return &not_exists_or_empty;
-               return &op->append.pre;
-
-       case OP_TDB_STORE:
-               if (op->flag == TDB_INSERT) {
-                       if (op->ret < 0)
-                               return &must_exist;
-                       else
-                               return &must_not_exist;
-               } else if (op->flag == TDB_MODIFY) {
-                       if (op->ret < 0)
-                               return &must_not_exist;
-                       else
-                               return &must_exist;
-               }
-               /* No flags?  Don't care */
-               return NULL;
-
-       case OP_TDB_EXISTS:
-               if (op->ret == 1)
-                       return &must_exist;
-               else
-                       return &must_not_exist;
-
-       case OP_TDB_PARSE_RECORD:
-               if (op->ret < 0)
-                       return &must_not_exist;
-               return &must_exist;
-
-       /* FIXME: handle these. */
-       case OP_TDB_WIPE_ALL:
-       case OP_TDB_FIRSTKEY:
-       case OP_TDB_NEXTKEY:
-       case OP_TDB_GET_SEQNUM:
-       case OP_TDB_TRAVERSE:
-       case OP_TDB_TRANSACTION_COMMIT:
-       case OP_TDB_TRANSACTION_CANCEL:
-       case OP_TDB_TRANSACTION_START:
-               return NULL;
-
-       case OP_TDB_FETCH:
-               if (!op->data.dptr)
-                       return &must_not_exist;
-               return &op->data;
-
-       case OP_TDB_DELETE:
-               if (op->ret < 0)
-                       return &must_not_exist;
-               return &must_exist;
-
-       default:
-               errx(1, "Unexpected op type %i", op->type);
-       }
-       
-}
-
-/* What's the data after this op?  pre if nothing changed. */
-static const TDB_DATA *gives(const TDB_DATA *key, const TDB_DATA *pre,
-                            const struct op *op)
-{
-       if (starts_transaction(op) || starts_chainlock(op)) {
-               unsigned int i;
-
-               /* Cancelled transactions don't change anything. */
-               if (op[op->group_len].type == OP_TDB_TRANSACTION_CANCEL)
-                       return pre;
-               assert(op[op->group_len].type == OP_TDB_TRANSACTION_COMMIT
-                      || op[op->group_len].type == OP_TDB_CHAINUNLOCK_READ
-                      || op[op->group_len].type == OP_TDB_CHAINUNLOCK);
-
-               for (i = 1; i < op->group_len; i++) {
-                       /* This skips nested transactions, too */
-                       if (key_eq(op[i].key, *key)
-                           || op[i].type == OP_TDB_WIPE_ALL)
-                               pre = gives(key, pre, &op[i]);
-               }
-               return pre;
-       }
-
-       /* Failed ops don't change state of db. */
-       if (op->ret < 0)
-               return pre;
-
-       if (op->type == OP_TDB_DELETE || op->type == OP_TDB_WIPE_ALL)
-               return &tdb_null;
-
-       if (op->type == OP_TDB_APPEND)
-               return &op->append.post;
-
-       if (op->type == OP_TDB_STORE)
-               return &op->data;
-
-       return pre;
-}
-
-static void add_hash_user(struct keyinfo *hash,
-                         unsigned int h,
-                         struct op *op[],
-                         unsigned int file,
-                         unsigned int op_num)
-{
-       hash[h].user = talloc_realloc(hash, hash[h].user,
-                                     struct op_desc, hash[h].num_users+1);
-
-       /* If it's in a transaction, it's the transaction which
-        * matters from an analysis POV. */
-       if (in_transaction(op[file], op_num)
-           || in_chainlock(op[file], op_num)) {
-               unsigned i;
-
-               op_num = op[file][op_num].group_start;
-
-               /* Don't include twice. */
-               for (i = 0; i < hash[h].num_users; i++) {
-                       if (hash[h].user[i].file == file
-                           && hash[h].user[i].op_num == op_num)
-                               return;
-               }
-       }
-       hash[h].user[hash[h].num_users].op_num = op_num;
-       hash[h].user[hash[h].num_users].file = file;
-       hash[h].num_users++;
-}
-
-static struct keyinfo *hash_ops(struct op *op[], unsigned int num_ops[],
-                               unsigned int num)
-{
-       unsigned int i, j, h;
-       struct keyinfo *hash;
-
-       hash = talloc_zero_array(op[0], struct keyinfo, total_keys*2);
-       for (i = 0; i < num; i++) {
-               for (j = 1; j < num_ops[i]; j++) {
-                       /* We can't do this on allocation, due to realloc. */
-                       list_head_init(&op[i][j].post);
-                       list_head_init(&op[i][j].pre);
-
-                       if (!op[i][j].key.dptr)
-                               continue;
-
-                       h = hash_key(&op[i][j].key) % (total_keys * 2);
-                       while (!key_eq(hash[h].key, op[i][j].key)) {
-                               if (!hash[h].key.dptr) {
-                                       hash[h].key = op[i][j].key;
-                                       break;
-                               }
-                               h = (h + 1) % (total_keys * 2);
-                       }
-                       /* Might as well save some memory if we can. */
-                       if (op[i][j].key.dptr != hash[h].key.dptr) {
-                               talloc_free(op[i][j].key.dptr);
-                               op[i][j].key.dptr = hash[h].key.dptr;
-                       }
-
-                       add_hash_user(hash, h, op, i, j);
-               }
-       }
-
-       /* Any wipe all entries need adding to all hash entries. */
-       for (h = 0; h < total_keys*2; h++) {
-               if (!hash[h].num_users)
-                       continue;
-
-               for (i = 0; i < num_wipe_alls; i++)
-                       add_hash_user(hash, h, op,
-                                     wipe_alls[i].file, wipe_alls[i].op_num);
-       }
-
-       return hash;
-}
-
-static bool satisfies(const TDB_DATA *key, const TDB_DATA *data,
-                     const struct op *op)
-{
-       const TDB_DATA *need = needs(key, op);
-
-       /* Don't need anything?  Cool. */
-       if (!need)
-               return true;
-
-       /* This should be tdb_null or a real value. */
-       assert(data != &must_exist);
-       assert(data != &must_not_exist);
-       assert(data != &not_exists_or_empty);
-
-       /* Must not exist?  data must not exist. */
-       if (need == &must_not_exist)
-               return data == &tdb_null;
-
-       /* Must exist? */
-       if (need == &must_exist)
-               return data != &tdb_null;
-
-       /* Either noexist or empty. */
-       if (need == &not_exists_or_empty)
-               return data->dsize == 0;
-
-       /* Needs something specific. */
-       return key_eq(*data, *need);
-}
-
-static void move_to_front(struct op_desc res[], unsigned off, unsigned elem)
-{
-       if (elem != off) {
-               struct op_desc tmp = res[elem];
-               memmove(res + off + 1, res + off, (elem - off)*sizeof(res[0]));
-               res[off] = tmp;
-       }
-}
-
-static void restore_to_pos(struct op_desc res[], unsigned off, unsigned elem)
-{
-       if (elem != off) {
-               struct op_desc tmp = res[off];
-               memmove(res + off, res + off + 1, (elem - off)*sizeof(res[0]));
-               res[elem] = tmp;
-       }
-}
-
-static bool sort_deps(char *filename[], struct op *op[],
-                     struct op_desc res[],
-                     unsigned off, unsigned num,
-                     const TDB_DATA *key, const TDB_DATA *data,
-                     unsigned num_files, unsigned fuzz)
-{
-       unsigned int i, files_done;
-       struct op *this_op;
-       bool done[num_files];
-
-       /* None left?  We're sorted. */
-       if (off == num)
-               return true;
-
-       /* Does this make sequence number go backwards?  Allow a little fuzz. */
-       if (off > 0) {
-               int seqnum1 = op[res[off-1].file][res[off-1].op_num].seqnum;
-               int seqnum2 = op[res[off].file][res[off].op_num].seqnum;
-
-               if (seqnum1 - seqnum2 > (int)fuzz) {
-#if DEBUG_DEPS
-                       printf("Seqnum jump too far (%u -> %u)\n",
-                              seqnum1, seqnum2);
-#endif
-                       return false;
-               }
-       }
-
-       memset(done, 0, sizeof(done));
-
-       /* Since ops within a trace file are ordered, we just need to figure
-        * out which file to try next.  Since we don't take into account
-        * inter-key relationships (which exist by virtue of trace file order),
-        * we minimize the chance of harm by trying to keep in seqnum order. */
-       for (files_done = 0, i = off; i < num && files_done < num_files; i++) {
-               if (done[res[i].file])
-                       continue;
-
-               this_op = &op[res[i].file][res[i].op_num];
-
-               /* Is what we have good enough for this op? */
-               if (satisfies(key, data, this_op)) {
-                       move_to_front(res, off, i);
-                       if (sort_deps(filename, op, res, off+1, num,
-                                     key, gives(key, data, this_op),
-                                     num_files, fuzz))
-                               return true;
-                       restore_to_pos(res, off, i);
-               }
-               done[res[i].file] = true;
-               files_done++;
-       }
-
-       /* No combination worked. */
-       return false;
-}
-
-static void check_dep_sorting(struct op_desc user[], unsigned num_users,
-                             unsigned num_files)
-{
-#if DEBUG_DEPS
-       unsigned int i;
-       unsigned minima[num_files];
-
-       memset(minima, 0, sizeof(minima));
-       for (i = 0; i < num_users; i++) {
-               assert(minima[user[i].file] < user[i].op_num);
-               minima[user[i].file] = user[i].op_num;
-       }
-#endif
-}
-
-/* All these ops happen on the same key.  Which comes first?
- *
- * This can happen both because read ops or failed write ops don't
- * change sequence number, and also due to race since we access the
- * number unlocked (the race can cause less detectable ordering problems,
- * in which case we'll deadlock and report: fix manually in that case).
- */
-static bool figure_deps(char *filename[], struct op *op[],
-                       const TDB_DATA *key, const TDB_DATA *data,
-                       struct op_desc user[],
-                       unsigned num_users, unsigned num_files)
-{
-       unsigned int fuzz;
-
-       /* We prefer to keep strict seqnum order if possible: it's the
-        * most likely.  We get more lax if that fails. */
-       for (fuzz = 0; fuzz < 100; fuzz = (fuzz + 1)*2) {
-               if (sort_deps(filename, op, user, 0, num_users, key, data,
-                             num_files, fuzz))
-                       break;
-       }
-
-       if (fuzz >= 100)
-               return false;
-
-       check_dep_sorting(user, num_users, num_files);
-       return true;
-}
-
-/* We're having trouble sorting out dependencies for this key.  Assume that it's
- * a pre-existing record in the db, so determine a likely value. */
-static const TDB_DATA *preexisting_data(char *filename[], struct op *op[],
-                                       const TDB_DATA *key,
-                                       struct op_desc *user,
-                                       unsigned int num_users)
-{
-       unsigned int i;
-       const TDB_DATA *data;
-
-       for (i = 0; i < num_users; i++) {
-               data = needs(key, &op[user->file][user->op_num]);
-               if (data && data != &must_not_exist) {
-                       if (!quiet)
-                               printf("%s:%u: needs pre-existing record\n",
-                                      filename[user->file], user->op_num+1);
-                       return data;
-               }
-       }
-       return &tdb_null;
-}
-
-static void sort_ops(struct tdb_context *tdb,
-                    struct keyinfo hash[], char *filename[], struct op *op[],
-                    unsigned int num)
-{
-       unsigned int h;
-
-       /* Gcc nexted function extension.  How cool is this? */
-       int compare_seqnum(const void *_a, const void *_b)
-       {
-               const struct op_desc *a = _a, *b = _b;
-
-               /* First, maintain order within any trace file. */
-               if (a->file == b->file)
-                       return a->op_num - b->op_num;
-
-               /* Otherwise, arrange by seqnum order. */
-               if (op[a->file][a->op_num].seqnum !=
-                   op[b->file][b->op_num].seqnum)
-                       return op[a->file][a->op_num].seqnum
-                               - op[b->file][b->op_num].seqnum;
-
-               /* Cancelled transactions are assumed to happen first. */
-               if (starts_transaction(&op[a->file][a->op_num])
-                   && !successful_transaction(&op[a->file][a->op_num]))
-                       return -1;
-               if (starts_transaction(&op[b->file][b->op_num])
-                   && !successful_transaction(&op[b->file][b->op_num]))
-                       return 1;
-
-               /* No idea. */
-               return 0;
-       }
-
-       /* Now sort into seqnum order. */
-       for (h = 0; h < total_keys * 2; h++) {
-               struct op_desc *user = hash[h].user;
-
-               qsort(user, hash[h].num_users, sizeof(user[0]), compare_seqnum);
-               if (!figure_deps(filename, op, &hash[h].key, &tdb_null, user,
-                                hash[h].num_users, num)) {
-                       const TDB_DATA *data;
-
-                       data = preexisting_data(filename, op, &hash[h].key,
-                                               user, hash[h].num_users);
-                       /* Give the first op what it wants: does that help? */
-                       if (!figure_deps(filename, op, &hash[h].key, data, user,
-                                        hash[h].num_users, num))
-                               fail(filename[user[0].file], user[0].op_num+1,
-                                    "Could not resolve inter-dependencies");
-                       if (tdb_store(tdb, hash[h].key, *data, TDB_INSERT) != 0)
-                               errx(1, "Could not store initial value");
-               }
-       }
-}
-
-static int destroy_depend(struct depend *dep)
-{
-       list_del(&dep->pre_list);
-       list_del(&dep->post_list);
-       return 0;
-}
-
-static void add_dependency(void *ctx,
-                          struct op *op[],
-                          char *filename[],
-                          const struct op_desc *needs,
-                          const struct op_desc *prereq)
-{
-       struct depend *dep;
-
-       /* We don't depend on ourselves. */
-       if (needs->file == prereq->file) {
-               assert(prereq->op_num < needs->op_num);
-               return;
-       }
-
-#if DEBUG_DEPS
-       printf("%s:%u: depends on %s:%u\n",
-              filename[needs->file], needs->op_num+1,
-              filename[prereq->file], prereq->op_num+1);
-#endif
-
-       dep = talloc(ctx, struct depend);
-       dep->needs = *needs;
-       dep->prereq = *prereq;
-
-#if TRAVERSALS_TAKE_TRANSACTION_LOCK
-       /* If something in a traverse depends on something in another
-        * traverse/transaction, it creates a dependency between the
-        * two groups. */
-       if ((in_traverse(op[prereq->file], prereq->op_num)
-            && (starts_transaction(&op[needs->file][needs->op_num])
-                || starts_traverse(&op[needs->file][needs->op_num])))
-           || (in_traverse(op[needs->file], needs->op_num)
-               && (starts_transaction(&op[prereq->file][prereq->op_num])
-                   || starts_traverse(&op[prereq->file][prereq->op_num])))) {
-               unsigned int start;
-
-               /* We are satisfied by end of group. */
-               start = op[prereq->file][prereq->op_num].group_start;
-               dep->prereq.op_num = start + op[prereq->file][start].group_len;
-               /* And we need that done by start of our group. */
-               dep->needs.op_num = op[needs->file][needs->op_num].group_start;
-       }
-
-       /* There is also this case:
-        *  <traverse> <read foo> ...
-        *  <transaction> ... </transaction> <create foo>
-        * Where if we start the traverse then wait, we could block
-        * the transaction and deadlock.
-        *
-        * We try to address this by ensuring that where seqnum indicates it's
-        * possible, we wait for <create foo> before *starting* traverse.
-        */
-       else if (in_traverse(op[needs->file], needs->op_num)) {
-               struct op *need = &op[needs->file][needs->op_num];
-               if (op[needs->file][need->group_start].seqnum >
-                   op[prereq->file][prereq->op_num].seqnum) {
-                       dep->needs.op_num = need->group_start;
-               }
-       }
-#endif
-
-       /* If you depend on a transaction or chainlock, you actually
-        * depend on it ending. */
-       if (starts_transaction(&op[prereq->file][dep->prereq.op_num])
-           || starts_chainlock(&op[prereq->file][dep->prereq.op_num])) {
-               dep->prereq.op_num
-                       += op[dep->prereq.file][dep->prereq.op_num].group_len;
-#if DEBUG_DEPS
-               printf("-> Actually end of transaction %s:%u\n",
-                      filename[dep->prereq->file], dep->prereq->op_num+1);
-#endif
-       } else
-               /* We should never create a dependency from middle of
-                * a transaction. */
-               assert(!in_transaction(op[prereq->file], dep->prereq.op_num)
-                      || op[prereq->file][dep->prereq.op_num].type
-                      == OP_TDB_TRANSACTION_COMMIT
-                      || op[prereq->file][dep->prereq.op_num].type
-                      == OP_TDB_TRANSACTION_CANCEL);
-
-       list_add(&op[dep->prereq.file][dep->prereq.op_num].post,
-                &dep->post_list);
-       list_add(&op[dep->needs.file][dep->needs.op_num].pre,
-                &dep->pre_list);
-       talloc_set_destructor(dep, destroy_depend);
-}
-
-static bool changes_db(const TDB_DATA *key, const struct op *op)
-{
-       return gives(key, NULL, op) != NULL;
-}
-
-static void depend_on_previous(struct op *op[],
-                              char *filename[],
-                              unsigned int num,
-                              struct op_desc user[],
-                              unsigned int i,
-                              int prev)
-{
-       bool deps[num];
-       int j;
-
-       if (i == 0)
-               return;
-
-       if (prev == i - 1) {
-               /* Just depend on previous. */
-               add_dependency(NULL, op, filename, &user[i], &user[prev]);
-               return;
-       }
-
-       /* We have to wait for the readers.  Find last one in *each* file. */
-       memset(deps, 0, sizeof(deps));
-       deps[user[i].file] = true;
-       for (j = i - 1; j > prev; j--) {
-               if (!deps[user[j].file]) {
-                       add_dependency(NULL, op, filename, &user[i], &user[j]);
-                       deps[user[j].file] = true;
-               }
-       }
-}
-
-/* This is simple, but not complete.  We don't take into account
- * indirect dependencies. */
-static void optimize_dependencies(struct op *op[], unsigned int num_ops[],
-                                 unsigned int num)
-{
-       unsigned int i, j;
-
-       /* There can only be one real dependency on each file */
-       for (i = 0; i < num; i++) {
-               for (j = 1; j < num_ops[i]; j++) {
-                       struct depend *dep, *next;
-                       struct depend *prev[num];
-
-                       memset(prev, 0, sizeof(prev));
-
-                       list_for_each_safe(&op[i][j].pre, dep, next, pre_list) {
-                               if (!prev[dep->prereq.file]) {
-                                       prev[dep->prereq.file] = dep;
-                                       continue;
-                               }
-                               if (prev[dep->prereq.file]->prereq.op_num
-                                   < dep->prereq.op_num) {
-                                       talloc_free(prev[dep->prereq.file]);
-                                       prev[dep->prereq.file] = dep;
-                               } else
-                                       talloc_free(dep);
-                       }
-               }
-       }
-
-       for (i = 0; i < num; i++) {
-               int deps[num];
-
-               for (j = 0; j < num; j++)
-                       deps[j] = -1;
-
-               for (j = 1; j < num_ops[i]; j++) {
-                       struct depend *dep, *next;
-
-                       list_for_each_safe(&op[i][j].pre, dep, next, pre_list) {
-                               if (deps[dep->prereq.file]
-                                   >= (int)dep->prereq.op_num)
-                                       talloc_free(dep);
-                               else
-                                       deps[dep->prereq.file]
-                                               = dep->prereq.op_num;
-                       }
-               }
-       }
-}
-
-#if TRAVERSALS_TAKE_TRANSACTION_LOCK
-/* Force an order among the traversals, so they don't deadlock (as much) */
-static void make_traverse_depends(char *filename[],
-                                 struct op *op[], unsigned int num_ops[],
-                                 unsigned int num)
-{
-       unsigned int i, num_traversals = 0;
-       int j;
-       struct op_desc *desc;
-
-       /* Sort by which one runs first. */
-       int compare_traverse_desc(const void *_a, const void *_b)
-       {
-               const struct op_desc *da = _a, *db = _b;
-               const struct op *a = &op[da->file][da->op_num],
-                       *b = &op[db->file][db->op_num];
-
-               if (a->seqnum != b->seqnum)
-                       return a->seqnum - b->seqnum;
-
-               /* If they have same seqnum, it means one didn't make any
-                * changes.  Thus sort by end in that case. */
-               return a[a->group_len].seqnum - b[b->group_len].seqnum;
-       }
-
-       desc = talloc_array(NULL, struct op_desc, 1);
-
-       /* Count them. */
-       for (i = 0; i < num; i++) {
-               for (j = 1; j < num_ops[i]; j++) {
-                       /* Traverse start (ignore those in
-                        * transactions; they're already covered by
-                        * transaction dependencies). */
-                       if (starts_traverse(&op[i][j])
-                           && !in_transaction(op[i], j)) {
-                               desc = talloc_realloc(NULL, desc,
-                                                     struct op_desc,
-                                                     num_traversals+1);
-                               desc[num_traversals].file = i;
-                               desc[num_traversals].op_num = j;
-                               num_traversals++;
-                       }
-               }
-       }
-       qsort(desc, num_traversals, sizeof(desc[0]), compare_traverse_desc);
-
-       for (i = 1; i < num_traversals; i++) {
-               const struct op *prev = &op[desc[i-1].file][desc[i-1].op_num];
-               const struct op *curr = &op[desc[i].file][desc[i].op_num];
-
-               /* Read traverses don't depend on each other (read lock). */
-               if (prev->type == OP_TDB_TRAVERSE_READ_START
-                   && curr->type == OP_TDB_TRAVERSE_READ_START)
-                       continue;
-
-               /* Only make dependency if it's clear. */
-               if (compare_traverse_desc(&desc[i], &desc[i-1])) {
-                       /* i depends on end of traverse i-1. */
-                       struct op_desc end = desc[i-1];
-                       end.op_num += prev->group_len;
-                       add_dependency(NULL, op, filename, &desc[i], &end);
-               }
-       }
-       talloc_free(desc);
-}
-
-static void set_nonblock(int fd)
-{
-       if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL)|O_NONBLOCK) != 0)
-               err(1, "Setting pipe nonblocking");
-}
-
-static bool handle_backoff(struct op *op[], int fd)
-{
-       struct op_desc desc;
-       bool handled = false;
-
-       /* Sloppy coding: we assume PIPEBUF never fills. */
-       while (read(fd, &desc, sizeof(desc)) != -1) {
-               unsigned int i;
-               handled = true;
-               for (i = desc.op_num; i > 0; i--) {
-                       if (op[desc.file][i].type == OP_TDB_TRAVERSE) {
-                               /* We insert a fake end here. */
-                               op[desc.file][i].type
-                                       = OP_TDB_TRAVERSE_END_EARLY;
-                               break;
-                       } else if (starts_traverse(&op[desc.file][i])) {
-                               unsigned int start = i;
-                               struct op tmp = op[desc.file][i];
-                               /* Move the ops outside traverse. */
-                               memmove(&op[desc.file][i],
-                                       &op[desc.file][i+1],
-                                       (desc.op_num-i-1) * sizeof(op[0][0]));
-                               op[desc.file][desc.op_num] = tmp;
-                               while (op[desc.file][i].group_start == start) {
-                                       op[desc.file][i++].group_start
-                                               = desc.op_num;
-                               }
-                               break;
-                       }
-               }
-       }
-       return handled;
-}
-
-#else /* !TRAVERSALS_TAKE_TRANSACTION_LOCK */
-static bool handle_backoff(struct op *op[], int fd)
-{
-       return false;
-}
-#endif
-
-static void derive_dependencies(struct tdb_context *tdb,
-                               char *filename[],
-                               struct op *op[], unsigned int num_ops[],
-                               unsigned int num)
-{
-       struct keyinfo *hash;
-       unsigned int h, i;
-
-       /* Create hash table for faster key lookup. */
-       hash = hash_ops(op, num_ops, num);
-
-       /* Sort them by sequence number. */
-       sort_ops(tdb, hash, filename, op, num);
-
-       /* Create dependencies back to the last change, rather than
-        * creating false dependencies by naively making each one
-        * depend on the previous.  This has two purposes: it makes
-        * later optimization simpler, and it also avoids deadlock with
-        * same sequence number ops inside traversals (if one
-        * traversal doesn't write anything, two ops can have the same
-        * sequence number yet we can create a traversal dependency
-        * the other way). */
-       for (h = 0; h < total_keys * 2; h++) {
-               int prev = -1;
-
-               if (hash[h].num_users < 2)
-                       continue;
-
-               for (i = 0; i < hash[h].num_users; i++) {
-                       if (changes_db(&hash[h].key, &op[hash[h].user[i].file]
-                                      [hash[h].user[i].op_num])) {
-                               depend_on_previous(op, filename, num,
-                                                  hash[h].user, i, prev);
-                               prev = i;
-                       } else if (prev >= 0)
-                               add_dependency(hash, op, filename,
-                                              &hash[h].user[i],
-                                              &hash[h].user[prev]);
-               }
-       }
-
-#if TRAVERSALS_TAKE_TRANSACTION_LOCK
-       make_traverse_depends(filename, op, num_ops, num);
-#endif
-
-       optimize_dependencies(op, num_ops, num);
-}
-
-static struct timeval run_test(char *argv[],
-                              unsigned int num_ops[],
-                              unsigned int hashsize[],
-                              unsigned int tdb_flags[],
-                              unsigned int open_flags[],
-                              struct op *op[],
-                              int fds[2])
-{
-       unsigned int i;
-       struct timeval start, end, diff;
-       bool ok = true;
-
-       for (i = 0; argv[i+2]; i++) {
-               struct tdb_context *tdb;
-               char c;
-
-               switch (fork()) {
-               case -1:
-                       err(1, "fork failed");
-               case 0:
-                       close(fds[1]);
-                       tdb = tdb_open(argv[1], hashsize[i],
-                                      tdb_flags[i], open_flags[i], 0600);
-                       if (!tdb)
-                               err(1, "Opening tdb %s", argv[1]);
-
-                       /* This catches parent exiting. */
-                       if (read(fds[0], &c, 1) != 1)
-                               exit(1);
-                       run_ops(tdb, pipes[i].fd[0], argv+2, op, i, 1,
-                               num_ops[i], false);
-                       check_deps(argv[2+i], op[i], num_ops[i]);
-                       exit(0);
-               default:
-                       break;
-               }
-       }
-
-       /* Let everything settle. */
-       sleep(1);
-
-       if (!quiet)
-               printf("Starting run...");
-       fflush(stdout);
-       gettimeofday(&start, NULL);
-       /* Tell them all to go!  Any write of sufficient length will do. */
-       if (write(fds[1], hashsize, i) != i)
-               err(1, "Writing to wakeup pipe");
-
-       for (i = 0; argv[i + 2]; i++) {
-               int status;
-               wait(&status);
-               if (!WIFEXITED(status)) {
-                       warnx("Child died with signal %i", WTERMSIG(status));
-                       ok = false;
-               } else if (WEXITSTATUS(status) != 0)
-                       /* Assume child spat out error. */
-                       ok = false;
-       }
-       if (!ok)
-               exit(1);
-
-       gettimeofday(&end, NULL);
-       if (!quiet)
-               printf("done\n");
-
-       if (end.tv_usec < start.tv_usec) {
-               end.tv_usec += 1000000;
-               end.tv_sec--;
-       }
-       diff.tv_sec = end.tv_sec - start.tv_sec;
-       diff.tv_usec = end.tv_usec - start.tv_usec;
-       return diff;
-}
-
-static void init_tdb(struct tdb_context *master_tdb,
-                    const char *name, unsigned int hashsize)
-{
-       TDB_DATA key, data;
-       struct tdb_context *tdb;
-
-       tdb = tdb_open(name, hashsize, TDB_CLEAR_IF_FIRST|TDB_NOSYNC,
-                      O_CREAT|O_TRUNC|O_RDWR, 0600);
-       if (!tdb)
-               errx(1, "opening tdb %s", name);
-
-       for (key = tdb_firstkey(master_tdb);
-            key.dptr;
-            key = tdb_nextkey(master_tdb, key)) {
-               data = tdb_fetch(master_tdb, key);
-               if (tdb_store(tdb, key, data, TDB_INSERT) != 0)
-                       errx(1, "Failed to store initial key");
-       }
-       tdb_close(tdb);
-}
-
-int main(int argc, char *argv[])
-{
-       struct timeval diff;
-       unsigned int i, num_ops[argc], hashsize[argc], tdb_flags[argc], open_flags[argc];
-       struct op *op[argc];
-       int fds[2];
-       struct tdb_context *master;
-       unsigned int runs = 1;
-
-       if (argc < 3)
-               errx(1, "Usage: %s [--quiet] [-n <number>] <tdbfile> <tracefile>...", argv[0]);
-
-       if (streq(argv[1], "--quiet")) {
-               quiet = true;
-               argv++;
-               argc--;
-       }
-       if (streq(argv[1], "-n")) {
-               runs = atoi(argv[2]);
-               argv += 2;
-               argc -= 2;
-       }
-
-       pipes = talloc_array(NULL, struct pipe, argc - 1);
-       for (i = 0; i < argc - 2; i++) {
-               if (!quiet)
-                       printf("Loading tracefile %s...", argv[2+i]);
-               fflush(stdout);
-               op[i] = load_tracefile(argv+2, i, &num_ops[i], &hashsize[i],
-                                      &tdb_flags[i], &open_flags[i]);
-               if (pipe(pipes[i].fd) != 0)
-                       err(1, "creating pipe");
-               /* Don't truncate, or clear if first: we do that. */
-               open_flags[i] &= ~(O_TRUNC);
-               tdb_flags[i] &= ~(TDB_CLEAR_IF_FIRST);
-               /* Open NOSYNC, to save time. */
-               tdb_flags[i] |= TDB_NOSYNC;
-               if (!quiet)
-                       printf("done\n");
-       }
-
-       /* Dependency may figure we need to create seed records. */
-       master = tdb_open(NULL, 0, TDB_INTERNAL, O_RDWR, 0);
-       if (!quiet) {
-               printf("Calculating inter-dependencies...");
-               fflush(stdout);
-       }
-       derive_dependencies(master, argv+2, op, num_ops, i);
-       if (!quiet)
-               printf("done\n");
-
-       for (i = 0; i < runs; i++) {
-               init_tdb(master, argv[1], hashsize[0]);
-
-               /* Don't fork for single arg case: simple debugging. */
-               if (argc == 3) {
-                       struct timeval start, end;
-                       struct tdb_context *tdb;
-
-                       tdb = tdb_open(argv[1], hashsize[0], tdb_flags[0],
-                                      open_flags[0], 0600);
-                       if (!quiet) {
-                               printf("Single threaded run...");
-                               fflush(stdout);
-                       }
-                       gettimeofday(&start, NULL);
-
-                       run_ops(tdb, pipes[0].fd[0], argv+2, op, 0, 1,
-                               num_ops[0], false);
-                       gettimeofday(&end, NULL);
-                       if (!quiet)
-                               printf("done\n");
-                       tdb_close(tdb);
-
-                       check_deps(argv[2], op[0], num_ops[0]);
-                       if (end.tv_usec < start.tv_usec) {
-                               end.tv_usec += 1000000;
-                               end.tv_sec--;
-                       }
-                       diff.tv_sec = end.tv_sec - start.tv_sec;
-                       diff.tv_usec = end.tv_usec - start.tv_usec;
-                       goto print_time;
-               }
-
-               if (pipe(fds) != 0)
-                       err(1, "creating pipe");
-
-#if TRAVERSALS_TAKE_TRANSACTION_LOCK
-               if (pipe(pipes[argc-2].fd) != 0)
-                       err(1, "creating pipe");
-               backoff_fd = pipes[argc-2].fd[1];
-               set_nonblock(pipes[argc-2].fd[1]);
-               set_nonblock(pipes[argc-2].fd[0]);
-#endif
-
-               do {
-                       diff = run_test(argv, num_ops, hashsize, tdb_flags,
-                                       open_flags, op, fds);
-               } while (handle_backoff(op, pipes[argc-2].fd[0]));
-
-       print_time:
-               if (!quiet)
-                       printf("Time replaying: ");
-               printf("%lu usec\n", diff.tv_sec * 1000000UL + diff.tv_usec);
-       }
-
-       exit(0);
-}
diff --git a/ccan/tdb/tools/speed.c b/ccan/tdb/tools/speed.c
deleted file mode 100644 (file)
index cf4b718..0000000
+++ /dev/null
@@ -1,247 +0,0 @@
-/* Simple speed test for TDB */
-#include <err.h>
-#include <time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <sys/time.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdbool.h>
-#include <ccan/tdb/tdb.h>
-
-/* Nanoseconds per operation */
-static size_t normalize(const struct timeval *start,
-                       const struct timeval *stop,
-                       unsigned int num)
-{
-       struct timeval diff;
-
-       timersub(stop, start, &diff);
-
-       /* Floating point is more accurate here. */
-       return (double)(diff.tv_sec * 1000000 + diff.tv_usec)
-               / num * 1000;
-}
-
-static size_t file_size(void)
-{
-       struct stat st;
-
-       if (stat("/tmp/speed.tdb", &st) != 0)
-               return -1;
-       return st.st_size;
-}
-
-static int count_record(struct tdb_context *tdb,
-                       TDB_DATA key, TDB_DATA data, void *p)
-{
-       int *total = p;
-       *total += *(int *)data.dptr;
-       return 0;
-}
-
-int main(int argc, char *argv[])
-{
-       unsigned int i, j, num = 1000, stage = 0, stopat = -1;
-       int flags = TDB_DEFAULT;
-       TDB_DATA key, data;
-       struct tdb_context *tdb;
-       struct timeval start, stop;
-       bool transaction = false;
-
-       if (argv[1] && strcmp(argv[1], "--internal") == 0) {
-               flags = TDB_INTERNAL;
-               argc--;
-               argv++;
-       }
-
-       if (argv[1] && strcmp(argv[1], "--transaction") == 0) {
-               transaction = true;
-               argc--;
-               argv++;
-       }
-
-       tdb = tdb_open("/tmp/speed.tdb", 100003, flags, O_RDWR|O_CREAT|O_TRUNC,
-                      0600);
-       if (!tdb)
-               err(1, "Opening /tmp/speed.tdb");
-
-       key.dptr = (void *)&i;
-       key.dsize = sizeof(i);
-       data = key;
-
-       if (argv[1]) {
-               num = atoi(argv[1]);
-               argv++;
-               argc--;
-       }
-
-       if (argv[1]) {
-               stopat = atoi(argv[1]);
-               argv++;
-               argc--;
-       }
-
-       if (transaction && tdb_transaction_start(tdb))
-               errx(1, "starting transaction: %s", tdb_errorstr(tdb));
-
-       /* Add 1000 records. */
-       printf("Adding %u records: ", num); fflush(stdout);
-       gettimeofday(&start, NULL);
-       for (i = 0; i < num; i++)
-               if (tdb_store(tdb, key, data, TDB_INSERT) != 0)
-                       errx(1, "Inserting key %u in tdb: %s",
-                            i, tdb_errorstr(tdb));
-       gettimeofday(&stop, NULL);
-       if (transaction && tdb_transaction_commit(tdb))
-               errx(1, "committing transaction: %s", tdb_errorstr(tdb));
-       printf(" %zu ns (%zu bytes)\n",
-              normalize(&start, &stop, num), file_size());
-       if (++stage == stopat)
-               exit(0);
-
-       if (transaction && tdb_transaction_start(tdb))
-               errx(1, "starting transaction: %s", tdb_errorstr(tdb));
-
-       /* Finding 1000 records. */
-       printf("Finding %u records: ", num); fflush(stdout);
-       gettimeofday(&start, NULL);
-       for (i = 0; i < num; i++) {
-               int *dptr;
-               dptr = (int *)tdb_fetch(tdb, key).dptr;
-               if (!dptr || *dptr != i)
-                       errx(1, "Fetching key %u in tdb gave %u",
-                            i, dptr ? *dptr : -1);
-       }
-       gettimeofday(&stop, NULL);
-       if (transaction && tdb_transaction_commit(tdb))
-               errx(1, "committing transaction: %s", tdb_errorstr(tdb));
-       printf(" %zu ns (%zu bytes)\n",
-              normalize(&start, &stop, num), file_size());
-       if (++stage == stopat)
-               exit(0);
-
-       if (transaction && tdb_transaction_start(tdb))
-               errx(1, "starting transaction: %s", tdb_errorstr(tdb));
-
-       /* Missing 1000 records. */
-       printf("Missing %u records: ", num); fflush(stdout);
-       gettimeofday(&start, NULL);
-       for (i = num; i < num*2; i++) {
-               int *dptr;
-               dptr = (int *)tdb_fetch(tdb, key).dptr;
-               if (dptr)
-                       errx(1, "Fetching key %u in tdb gave %u", i, *dptr);
-       }
-       gettimeofday(&stop, NULL);
-       if (transaction && tdb_transaction_commit(tdb))
-               errx(1, "committing transaction: %s", tdb_errorstr(tdb));
-       printf(" %zu ns (%zu bytes)\n",
-              normalize(&start, &stop, num), file_size());
-       if (++stage == stopat)
-               exit(0);
-
-       if (transaction && tdb_transaction_start(tdb))
-               errx(1, "starting transaction: %s", tdb_errorstr(tdb));
-
-       /* Traverse 1000 records. */
-       printf("Traversing %u records: ", num); fflush(stdout);
-       i = 0;
-       gettimeofday(&start, NULL);
-       if (tdb_traverse(tdb, count_record, &i) != num)
-               errx(1, "Traverse returned wrong number of records");
-       if (i != (num - 1) * (num / 2))
-               errx(1, "Traverse tallied to %u", i);
-       gettimeofday(&stop, NULL);
-       if (transaction && tdb_transaction_commit(tdb))
-               errx(1, "committing transaction: %s", tdb_errorstr(tdb));
-       printf(" %zu ns (%zu bytes)\n",
-              normalize(&start, &stop, num), file_size());
-       if (++stage == stopat)
-               exit(0);
-
-       if (transaction && tdb_transaction_start(tdb))
-               errx(1, "starting transaction: %s", tdb_errorstr(tdb));
-
-       /* Delete 1000 records (not in order). */
-       printf("Deleting %u records: ", num); fflush(stdout);
-       gettimeofday(&start, NULL);
-       for (j = 0; j < num; j++) {
-               i = (j + 100003) % num;
-               if (tdb_delete(tdb, key) != 0)
-                       errx(1, "Deleting key %u in tdb: %s",
-                            i, tdb_errorstr(tdb));
-       }
-       gettimeofday(&stop, NULL);
-       if (transaction && tdb_transaction_commit(tdb))
-               errx(1, "committing transaction: %s", tdb_errorstr(tdb));
-       printf(" %zu ns (%zu bytes)\n",
-              normalize(&start, &stop, num), file_size());
-       if (++stage == stopat)
-               exit(0);
-
-       if (transaction && tdb_transaction_start(tdb))
-               errx(1, "starting transaction: %s", tdb_errorstr(tdb));
-
-       /* Re-add 1000 records (not in order). */
-       printf("Re-adding %u records: ", num); fflush(stdout);
-       gettimeofday(&start, NULL);
-       for (j = 0; j < num; j++) {
-               i = (j + 100003) % num;
-               if (tdb_store(tdb, key, data, TDB_INSERT) != 0)
-                       errx(1, "Inserting key %u in tdb: %s",
-                            i, tdb_errorstr(tdb));
-       }
-       gettimeofday(&stop, NULL);
-       if (transaction && tdb_transaction_commit(tdb))
-               errx(1, "committing transaction: %s", tdb_errorstr(tdb));
-       printf(" %zu ns (%zu bytes)\n",
-              normalize(&start, &stop, num), file_size());
-       if (++stage == stopat)
-               exit(0);
-
-       if (transaction && tdb_transaction_start(tdb))
-               errx(1, "starting transaction: %s", tdb_errorstr(tdb));
-
-       /* Append 1000 records. */
-       printf("Appending %u records: ", num); fflush(stdout);
-       gettimeofday(&start, NULL);
-       for (i = 0; i < num; i++)
-               if (tdb_append(tdb, key, data) != 0)
-                       errx(1, "Appending key %u in tdb: %s",
-                            i, tdb_errorstr(tdb));
-       gettimeofday(&stop, NULL);
-       if (transaction && tdb_transaction_commit(tdb))
-               errx(1, "committing transaction: %s", tdb_errorstr(tdb));
-       printf(" %zu ns (%zu bytes)\n",
-              normalize(&start, &stop, num), file_size());
-       if (++stage == stopat)
-               exit(0);
-
-       if (transaction && tdb_transaction_start(tdb))
-               errx(1, "starting transaction: %s", tdb_errorstr(tdb));
-
-       /* Churn 1000 records: not in order! */
-       printf("Churning %u records: ", num); fflush(stdout);
-       gettimeofday(&start, NULL);
-       for (j = 0; j < num; j++) {
-               i = (j + 1000019) % num;
-               if (tdb_delete(tdb, key) != 0)
-                       errx(1, "Deleting key %u in tdb: %s",
-                            i, tdb_errorstr(tdb));
-               i += num;
-               if (tdb_store(tdb, key, data, TDB_INSERT) != 0)
-                       errx(1, "Inserting key %u in tdb: %s",
-                            i, tdb_errorstr(tdb));
-       }
-       gettimeofday(&stop, NULL);
-       if (transaction && tdb_transaction_commit(tdb))
-               errx(1, "committing transaction: %s", tdb_errorstr(tdb));
-       printf(" %zu ns (%zu bytes)\n",
-              normalize(&start, &stop, num), file_size());
-
-       return 0;
-}
diff --git a/ccan/tdb/tools/starvation.c b/ccan/tdb/tools/starvation.c
deleted file mode 100644 (file)
index 1baeab6..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-/* Demonstrate starvation of tdb_lockall */
-#include <ccan/tdb/tdb.h>
-#include <err.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <time.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/time.h>
-
-static void usage(const char *extra)
-{
-       errx(1, "%s%s"
-            "Usage: starvation [lockall|gradual] <num> <worktime-in-ms>\n"
-            "  Each locker holds lock for between 1/2 and 1 1/2 times\n"
-            "  worktime, then sleeps for one second.\n\n"
-            "  Main process tries tdb_lockall or tdb_lockall_gradual.",
-            extra ? extra : "", extra ? "\n" : "");
-}
-
-static void run_and_sleep(struct tdb_context *tdb, int parentfd, unsigned time)
-{
-       char c;
-       struct timespec hold;
-       unsigned rand, randtime;
-       TDB_DATA key;
-
-       key.dptr = (void *)&rand;
-       key.dsize = sizeof(rand);
-
-       while (read(parentfd, &c, 1) != 0) {
-               /* Lock a random key. */
-               rand = random();
-               if (tdb_chainlock(tdb, key) != 0)
-                       errx(1, "chainlock failed: %s", tdb_errorstr(tdb));
-
-               /* Hold it for some variable time. */
-               randtime = time / 2 + (random() % time);
-               hold.tv_sec = randtime / 1000;
-               hold.tv_nsec = (randtime % 1000) * 1000000;
-               nanosleep(&hold, NULL);
-
-               if (tdb_chainunlock(tdb, key) != 0)
-                       errx(1, "chainunlock failed: %s", tdb_errorstr(tdb));
-
-               /* Wait for a second without the lock. */
-               sleep(1);
-       }
-       exit(0);
-}
-
-static void logfn(struct tdb_context *tdb,
-                 enum tdb_debug_level level,
-                 const char *fmt, ...)
-{
-           va_list ap;
-
-           va_start(ap, fmt);
-          vfprintf(stderr, fmt, ap);
-          va_end(ap);
-}
-
-int main(int argc, char *argv[])
-{
-       int (*lockall)(struct tdb_context *);
-       unsigned int num, worktime, i;
-       int pfd[2];
-       struct tdb_context *tdb;
-       struct tdb_logging_context log = { logfn, NULL };
-       struct timeval start, end, duration;
-
-       if (argc != 4)
-               usage(NULL);
-
-       if (strcmp(argv[1], "lockall") == 0)
-               lockall = tdb_lockall;
-       else if (strcmp(argv[1], "gradual") == 0) {
-#if 0
-               lockall = tdb_lockall_gradual;
-#else
-               errx(1, "gradual is now the default implementation");
-#endif
-       } else
-               usage("Arg1 should be 'lockall' or 'gradual'");
-
-       num = atoi(argv[2]);
-       worktime = atoi(argv[3]);
-
-       if (!num || !worktime)
-               usage("Number of threads and worktime must be non-zero");
-
-       if (pipe(pfd) != 0)
-               err(1, "Creating pipe");
-
-       tdb = tdb_open_ex("/tmp/starvation.tdb", 10000, TDB_DEFAULT,
-                         O_RDWR|O_CREAT|O_TRUNC, 0600, &log, NULL);
-       if (!tdb)
-               err(1, "Opening tdb /tmp/starvation.tdb");
-
-       for (i = 0; i < num; i++) {
-               switch (fork()) {
-               case 0:
-                       close(pfd[1]);
-                       fcntl(pfd[0], F_SETFL,
-                             fcntl(pfd[0], F_GETFL)|O_NONBLOCK);
-                       srandom(getpid() + i);
-                       if (tdb_reopen(tdb) != 0)
-                               err(1, "Reopening tdb %s", tdb_name(tdb));
-
-                       run_and_sleep(tdb, pfd[0], worktime);
-               case -1:
-                       err(1, "forking");
-               }
-               /* Stagger the children. */
-               usleep(random() % (1000000 / num));
-       }
-
-       close(pfd[0]);
-       sleep(1);
-       gettimeofday(&start, NULL);
-       if (lockall(tdb) != 0)
-               errx(1, "lockall failed: %s", tdb_errorstr(tdb));
-       gettimeofday(&end, NULL);
-
-       duration.tv_sec = end.tv_sec - start.tv_sec;
-       duration.tv_usec = end.tv_usec - start.tv_usec;
-       if (duration.tv_usec < 0) {
-               --duration.tv_sec;
-               duration.tv_usec += 1000000;
-       }
-
-       if (tdb_unlockall(tdb) != 0)
-               errx(1, "unlockall failed: %s", tdb_errorstr(tdb));
-       tdb_close(tdb);
-       unlink("/tmp/starvation.tdb");
-
-       printf("Took %lu.%06lu seconds\n", duration.tv_sec, duration.tv_usec);
-       return 0;
-}
diff --git a/ccan/tdb/tools/tdbdump.c b/ccan/tdb/tools/tdbdump.c
deleted file mode 100644 (file)
index 38f3de9..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/* 
-   Unix SMB/CIFS implementation.
-   simple tdb dump util
-   Copyright (C) Andrew Tridgell              2001
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-   
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-   
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <ccan/tdb/tdb.h>
-#include <stdlib.h>
-#include <getopt.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <ctype.h>
-
-static void print_data(TDB_DATA d)
-{
-       unsigned char *p = (unsigned char *)d.dptr;
-       int len = d.dsize;
-       while (len--) {
-               if (isprint(*p) && !strchr("\"\\", *p)) {
-                       fputc(*p, stdout);
-               } else {
-                       printf("\\%02X", *p);
-               }
-               p++;
-       }
-}
-
-static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
-{
-       printf("{\n");
-       printf("key(%d) = \"", (int)key.dsize);
-       print_data(key);
-       printf("\"\n");
-       printf("data(%d) = \"", (int)dbuf.dsize);
-       print_data(dbuf);
-       printf("\"\n");
-       printf("}\n");
-       return 0;
-}
-
-static int dump_tdb(const char *fname, const char *keyname)
-{
-       TDB_CONTEXT *tdb;
-       TDB_DATA key, value;
-       
-       tdb = tdb_open(fname, 0, 0, O_RDONLY, 0);
-       if (!tdb) {
-               printf("Failed to open %s\n", fname);
-               return 1;
-       }
-
-       if (!keyname) {
-               tdb_traverse(tdb, traverse_fn, NULL);
-       } else {
-               key.dptr = (void *)keyname;
-               key.dsize = strlen( keyname);
-               value = tdb_fetch(tdb, key);
-               if (!value.dptr) {
-                       return 1;
-               } else {
-                       print_data(value);
-                       free(value.dptr);
-               }
-       }
-
-       return 0;
-}
-
-static void usage( void)
-{
-       printf( "Usage: tdbdump [options] <filename>\n\n");
-       printf( "   -h          this help message\n");
-       printf( "   -k keyname  dumps value of keyname\n");
-}
-
- int main(int argc, char *argv[])
-{
-       char *fname, *keyname=NULL;
-       int c;
-
-       if (argc < 2) {
-               printf("Usage: tdbdump <fname>\n");
-               exit(1);
-       }
-
-       while ((c = getopt( argc, argv, "hk:")) != -1) {
-               switch (c) {
-               case 'h':
-                       usage();
-                       exit( 0);
-               case 'k':
-                       keyname = optarg;
-                       break;
-               default:
-                       usage();
-                       exit( 1);
-               }
-       }
-
-       fname = argv[optind];
-
-       return dump_tdb(fname, keyname);
-}
diff --git a/ccan/tdb/tools/tdbtool.c b/ccan/tdb/tools/tdbtool.c
deleted file mode 100644 (file)
index 3093efa..0000000
+++ /dev/null
@@ -1,777 +0,0 @@
-/* 
-   Unix SMB/CIFS implementation.
-   Samba database functions
-   Copyright (C) Andrew Tridgell              1999-2000
-   Copyright (C) Paul `Rusty' Russell             2000
-   Copyright (C) Jeremy Allison                           2000
-   Copyright (C) Andrew Esh                        2001
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-   
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-   
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <ccan/tdb/tdb.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <string.h>
-#include <stdarg.h>
-
-static int do_command(void);
-const char *cmdname;
-char *arg1, *arg2;
-size_t arg1len, arg2len;
-int bIterate = 0;
-char *line;
-TDB_DATA iterate_kbuf;
-char cmdline[1024];
-static int disable_mmap;
-
-enum commands {
-       CMD_CREATE_TDB,
-       CMD_OPEN_TDB,
-       CMD_TRANSACTION_START,
-       CMD_TRANSACTION_COMMIT,
-       CMD_TRANSACTION_CANCEL,
-       CMD_ERASE,
-       CMD_DUMP,
-       CMD_INSERT,
-       CMD_MOVE,
-       CMD_STORE,
-       CMD_SHOW,
-       CMD_KEYS,
-       CMD_HEXKEYS,
-       CMD_DELETE,
-       CMD_LIST_HASH_FREE,
-       CMD_LIST_FREE,
-       CMD_INFO,
-       CMD_MMAP,
-       CMD_SPEED,
-       CMD_FIRST,
-       CMD_NEXT,
-       CMD_SYSTEM,
-       CMD_CHECK,
-       CMD_QUIT,
-       CMD_HELP
-};
-
-typedef struct {
-       const char *name;
-       enum commands cmd;
-} COMMAND_TABLE;
-
-COMMAND_TABLE cmd_table[] = {
-       {"create",      CMD_CREATE_TDB},
-       {"open",        CMD_OPEN_TDB},
-       {"transaction_start",   CMD_TRANSACTION_START},
-       {"transaction_commit",  CMD_TRANSACTION_COMMIT},
-       {"transaction_cancel",  CMD_TRANSACTION_CANCEL},
-       {"erase",       CMD_ERASE},
-       {"dump",        CMD_DUMP},
-       {"insert",      CMD_INSERT},
-       {"move",        CMD_MOVE},
-       {"store",       CMD_STORE},
-       {"show",        CMD_SHOW},
-       {"keys",        CMD_KEYS},
-       {"hexkeys",     CMD_HEXKEYS},
-       {"delete",      CMD_DELETE},
-       {"list",        CMD_LIST_HASH_FREE},
-       {"free",        CMD_LIST_FREE},
-       {"info",        CMD_INFO},
-       {"speed",       CMD_SPEED},
-       {"mmap",        CMD_MMAP},
-       {"first",       CMD_FIRST},
-       {"1",           CMD_FIRST},
-       {"next",        CMD_NEXT},
-       {"n",           CMD_NEXT},
-       {"check",       CMD_CHECK},
-       {"quit",        CMD_QUIT},
-       {"q",           CMD_QUIT},
-       {"!",           CMD_SYSTEM},
-       {NULL,          CMD_HELP}
-};
-
-struct timeval tp1,tp2;
-
-static void _start_timer(void)
-{
-       gettimeofday(&tp1,NULL);
-}
-
-static double _end_timer(void)
-{
-       gettimeofday(&tp2,NULL);
-       return((tp2.tv_sec - tp1.tv_sec) + 
-              (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
-}
-
-static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...)
-{
-       va_list ap;
-    
-       va_start(ap, format);
-       vfprintf(stderr, format, ap);
-       va_end(ap);
-}
-
-/* a tdb tool for manipulating a tdb database */
-
-static TDB_CONTEXT *tdb;
-
-static int print_rec(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state);
-static int print_key(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state);
-static int print_hexkey(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state);
-
-static void print_asc(const char *buf,int len)
-{
-       int i;
-
-       /* We're probably printing ASCII strings so don't try to display
-          the trailing NULL character. */
-
-       if (buf[len - 1] == 0)
-               len--;
-
-       for (i=0;i<len;i++)
-               printf("%c",isprint(buf[i])?buf[i]:'.');
-}
-
-static void print_data(const char *buf,int len)
-{
-       int i=0;
-       if (len<=0) return;
-       printf("[%03X] ",i);
-       for (i=0;i<len;) {
-               printf("%02X ",(int)((unsigned char)buf[i]));
-               i++;
-               if (i%8 == 0) printf(" ");
-               if (i%16 == 0) {      
-                       print_asc(&buf[i-16],8); printf(" ");
-                       print_asc(&buf[i-8],8); printf("\n");
-                       if (i<len) printf("[%03X] ",i);
-               }
-       }
-       if (i%16) {
-               int n;
-               
-               n = 16 - (i%16);
-               printf(" ");
-               if (n>8) printf(" ");
-               while (n--) printf("   ");
-               
-               n = i%16;
-               if (n > 8) n = 8;
-               print_asc(&buf[i-(i%16)],n); printf(" ");
-               n = (i%16) - n;
-               if (n>0) print_asc(&buf[i-n],n); 
-               printf("\n");    
-       }
-}
-
-static void help(void)
-{
-       printf("\n"
-"tdbtool: \n"
-"  create    dbname     : create a database\n"
-"  open      dbname     : open an existing database\n"
-"  openjh    dbname     : open an existing database (jenkins hash)\n"
-"  transaction_start    : start a transaction\n"
-"  transaction_commit   : commit a transaction\n"
-"  transaction_cancel   : cancel a transaction\n"
-"  erase                : erase the database\n"
-"  dump                 : dump the database as strings\n"
-"  keys                 : dump the database keys as strings\n"
-"  hexkeys              : dump the database keys as hex values\n"
-"  info                 : print summary info about the database\n"
-"  insert    key  data  : insert a record\n"
-"  move      key  file  : move a record to a destination tdb\n"
-"  store     key  data  : store a record (replace)\n"
-"  show      key        : show a record by key\n"
-"  delete    key        : delete a record by key\n"
-"  list                 : print the database hash table and freelist\n"
-"  free                 : print the database freelist\n"
-"  check                : check the integrity of an opened database\n"
-"  speed                : perform speed tests on the database\n"
-"  ! command            : execute system command\n"
-"  1 | first            : print the first record\n"
-"  n | next             : print the next record\n"
-"  q | quit             : terminate\n"
-"  \\n                   : repeat 'next' command\n"
-"\n");
-}
-
-static void terror(const char *why)
-{
-       printf("%s\n", why);
-}
-
-static void create_tdb(const char *tdbname)
-{
-       struct tdb_logging_context log_ctx;
-       log_ctx.log_fn = tdb_log;
-
-       if (tdb) tdb_close(tdb);
-       tdb = tdb_open_ex(tdbname, 0, TDB_CLEAR_IF_FIRST | (disable_mmap?TDB_NOMMAP:0),
-                         O_RDWR | O_CREAT | O_TRUNC, 0600, &log_ctx, NULL);
-       if (!tdb) {
-               printf("Could not create %s: %s\n", tdbname, strerror(errno));
-       }
-}
-
-static void open_tdb(const char *tdbname)
-{
-       struct tdb_logging_context log_ctx;
-       log_ctx.log_fn = tdb_log;
-
-       if (tdb) tdb_close(tdb);
-       tdb = tdb_open_ex(tdbname, 0, disable_mmap?TDB_NOMMAP:0, O_RDWR, 0600,
-                         &log_ctx, NULL);
-       if (!tdb) {
-               printf("Could not open %s: %s\n", tdbname, strerror(errno));
-       }
-}
-
-static void insert_tdb(char *keyname, size_t keylen, char* data, size_t datalen)
-{
-       TDB_DATA key, dbuf;
-
-       if ((keyname == NULL) || (keylen == 0)) {
-               terror("need key");
-               return;
-       }
-
-       key.dptr = (unsigned char *)keyname;
-       key.dsize = keylen;
-       dbuf.dptr = (unsigned char *)data;
-       dbuf.dsize = datalen;
-
-       if (tdb_store(tdb, key, dbuf, TDB_INSERT) == -1) {
-               terror("insert failed");
-       }
-}
-
-static void store_tdb(char *keyname, size_t keylen, char* data, size_t datalen)
-{
-       TDB_DATA key, dbuf;
-
-       if ((keyname == NULL) || (keylen == 0)) {
-               terror("need key");
-               return;
-       }
-
-       if ((data == NULL) || (datalen == 0)) {
-               terror("need data");
-               return;
-       }
-
-       key.dptr = (unsigned char *)keyname;
-       key.dsize = keylen;
-       dbuf.dptr = (unsigned char *)data;
-       dbuf.dsize = datalen;
-
-       printf("Storing key:\n");
-       print_rec(tdb, key, dbuf, NULL);
-
-       if (tdb_store(tdb, key, dbuf, TDB_REPLACE) == -1) {
-               terror("store failed");
-       }
-}
-
-static void show_tdb(char *keyname, size_t keylen)
-{
-       TDB_DATA key, dbuf;
-
-       if ((keyname == NULL) || (keylen == 0)) {
-               terror("need key");
-               return;
-       }
-
-       key.dptr = (unsigned char *)keyname;
-       key.dsize = keylen;
-
-       dbuf = tdb_fetch(tdb, key);
-       if (!dbuf.dptr) {
-           terror("fetch failed");
-           return;
-       }
-       
-       print_rec(tdb, key, dbuf, NULL);
-       
-       free( dbuf.dptr );
-       
-       return;
-}
-
-static void delete_tdb(char *keyname, size_t keylen)
-{
-       TDB_DATA key;
-
-       if ((keyname == NULL) || (keylen == 0)) {
-               terror("need key");
-               return;
-       }
-
-       key.dptr = (unsigned char *)keyname;
-       key.dsize = keylen;
-
-       if (tdb_delete(tdb, key) != 0) {
-               terror("delete failed");
-       }
-}
-
-static void move_rec(char *keyname, size_t keylen, char* tdbname)
-{
-       TDB_DATA key, dbuf;
-       TDB_CONTEXT *dst_tdb;
-
-       if ((keyname == NULL) || (keylen == 0)) {
-               terror("need key");
-               return;
-       }
-
-       if ( !tdbname ) {
-               terror("need destination tdb name");
-               return;
-       }
-
-       key.dptr = (unsigned char *)keyname;
-       key.dsize = keylen;
-
-       dbuf = tdb_fetch(tdb, key);
-       if (!dbuf.dptr) {
-               terror("fetch failed");
-               return;
-       }
-       
-       print_rec(tdb, key, dbuf, NULL);
-       
-       dst_tdb = tdb_open(tdbname, 0, 0, O_RDWR, 0600);
-       if ( !dst_tdb ) {
-               terror("unable to open destination tdb");
-               return;
-       }
-       
-       if ( tdb_store( dst_tdb, key, dbuf, TDB_REPLACE ) == -1 ) {
-               terror("failed to move record");
-       }
-       else
-               printf("record moved\n");
-       
-       tdb_close( dst_tdb );
-       
-       return;
-}
-
-static int print_rec(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
-{
-       printf("\nkey %d bytes\n", (int)key.dsize);
-       print_asc((const char *)key.dptr, key.dsize);
-       printf("\ndata %d bytes\n", (int)dbuf.dsize);
-       print_data((const char *)dbuf.dptr, dbuf.dsize);
-       return 0;
-}
-
-static int print_key(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
-{
-       printf("key %d bytes: ", (int)key.dsize);
-       print_asc((const char *)key.dptr, key.dsize);
-       printf("\n");
-       return 0;
-}
-
-static int print_hexkey(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
-{
-       printf("key %d bytes\n", (int)key.dsize);
-       print_data((const char *)key.dptr, key.dsize);
-       printf("\n");
-       return 0;
-}
-
-static int total_bytes;
-
-static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
-{
-       total_bytes += dbuf.dsize;
-       return 0;
-}
-
-static void info_tdb(void)
-{
-       char *summary = tdb_summary(tdb);
-
-       if (!summary) {
-               printf("Error = %s\n", tdb_errorstr(tdb));
-       } else {
-               printf("%s", summary);
-               free(summary);
-       }
-}
-
-static void speed_tdb(const char *tlimit)
-{
-       unsigned timelimit = tlimit?atoi(tlimit):0;
-       double t;
-       int ops;
-       if (timelimit == 0) timelimit = 5;
-
-       ops = 0;
-       printf("Testing store speed for %u seconds\n", timelimit);
-       _start_timer();
-       do {
-               long int r = random();
-               TDB_DATA key, dbuf;
-               key.dptr = (unsigned char *)"store test";
-               key.dsize = strlen((char *)key.dptr);
-               dbuf.dptr = (unsigned char *)&r;
-               dbuf.dsize = sizeof(r);
-               tdb_store(tdb, key, dbuf, TDB_REPLACE);
-               t = _end_timer();
-               ops++;
-       } while (t < timelimit);
-       printf("%10.3f ops/sec\n", ops/t);
-
-       ops = 0;
-       printf("Testing fetch speed for %u seconds\n", timelimit);
-       _start_timer();
-       do {
-               long int r = random();
-               TDB_DATA key, dbuf;
-               key.dptr = (unsigned char *)"store test";
-               key.dsize = strlen((char *)key.dptr);
-               dbuf.dptr = (unsigned char *)&r;
-               dbuf.dsize = sizeof(r);
-               tdb_fetch(tdb, key);
-               t = _end_timer();
-               ops++;
-       } while (t < timelimit);
-       printf("%10.3f ops/sec\n", ops/t);
-
-       ops = 0;
-       printf("Testing transaction speed for %u seconds\n", timelimit);
-       _start_timer();
-       do {
-               long int r = random();
-               TDB_DATA key, dbuf;
-               key.dptr = (unsigned char *)"transaction test";
-               key.dsize = strlen((char *)key.dptr);
-               dbuf.dptr = (unsigned char *)&r;
-               dbuf.dsize = sizeof(r);
-               tdb_transaction_start(tdb);
-               tdb_store(tdb, key, dbuf, TDB_REPLACE);
-               tdb_transaction_commit(tdb);
-               t = _end_timer();
-               ops++;
-       } while (t < timelimit);
-       printf("%10.3f ops/sec\n", ops/t);
-
-       ops = 0;
-       printf("Testing traverse speed for %u seconds\n", timelimit);
-       _start_timer();
-       do {
-               tdb_traverse(tdb, traverse_fn, NULL);
-               t = _end_timer();
-               ops++;
-       } while (t < timelimit);
-       printf("%10.3f ops/sec\n", ops/t);
-}
-
-static void toggle_mmap(void)
-{
-       disable_mmap = !disable_mmap;
-       if (disable_mmap) {
-               printf("mmap is disabled\n");
-       } else {
-               printf("mmap is enabled\n");
-       }
-}
-
-static char *tdb_getline(const char *prompt)
-{
-       static char thisline[1024];
-       char *p;
-       fputs(prompt, stdout);
-       thisline[0] = 0;
-       p = fgets(thisline, sizeof(thisline)-1, stdin);
-       if (p) p = strchr(p, '\n');
-       if (p) *p = 0;
-       return p?thisline:NULL;
-}
-
-static int do_delete_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf,
-                     void *state)
-{
-    return tdb_delete(the_tdb, key);
-}
-
-static void first_record(TDB_CONTEXT *the_tdb, TDB_DATA *pkey)
-{
-       TDB_DATA dbuf;
-       *pkey = tdb_firstkey(the_tdb);
-       
-       dbuf = tdb_fetch(the_tdb, *pkey);
-       if (!dbuf.dptr) terror("fetch failed");
-       else {
-               print_rec(the_tdb, *pkey, dbuf, NULL);
-       }
-}
-
-static void next_record(TDB_CONTEXT *the_tdb, TDB_DATA *pkey)
-{
-       TDB_DATA dbuf;
-       *pkey = tdb_nextkey(the_tdb, *pkey);
-       
-       dbuf = tdb_fetch(the_tdb, *pkey);
-       if (!dbuf.dptr) 
-               terror("fetch failed");
-       else
-               print_rec(the_tdb, *pkey, dbuf, NULL);
-}
-
-static void check_db(TDB_CONTEXT *the_tdb)
-{
-       if (!the_tdb) {
-               printf("Error: No database opened!\n");
-       } else {
-               if (tdb_check(the_tdb, NULL, NULL) == -1)
-                       printf("Integrity check for the opened database failed.\n");
-               else
-                       printf("Database integrity is OK.\n");
-       }
-}
-
-static int do_command(void)
-{
-       COMMAND_TABLE *ctp = cmd_table;
-       enum commands mycmd = CMD_HELP;
-       int cmd_len;
-
-       if (cmdname && strlen(cmdname) == 0) {
-               mycmd = CMD_NEXT;
-       } else {
-               while (ctp->name) {
-                       cmd_len = strlen(ctp->name);
-                       if (strncmp(ctp->name,cmdname,cmd_len) == 0) {
-                               mycmd = ctp->cmd;
-                               break;
-                       }
-                       ctp++;
-               }
-       }
-
-       switch (mycmd) {
-       case CMD_CREATE_TDB:
-               bIterate = 0;
-               create_tdb(arg1);
-               return 0;
-       case CMD_OPEN_TDB:
-               bIterate = 0;
-               open_tdb(arg1);
-               return 0;
-       case CMD_SYSTEM:
-               /* Shell command */
-               if (system(arg1) == -1) {
-                       terror("system() call failed\n");
-               }
-               return 0;
-       case CMD_QUIT:
-               return 1;
-       default:
-               /* all the rest require a open database */
-               if (!tdb) {
-                       bIterate = 0;
-                       terror("database not open");
-                       help();
-                       return 0;
-               }
-               switch (mycmd) {
-               case CMD_TRANSACTION_START:
-                       bIterate = 0;
-                       tdb_transaction_start(tdb);
-                       return 0;
-               case CMD_TRANSACTION_COMMIT:
-                       bIterate = 0;
-                       tdb_transaction_commit(tdb);
-                       return 0;
-               case CMD_TRANSACTION_CANCEL:
-                       bIterate = 0;
-                       tdb_transaction_cancel(tdb);
-                       return 0;
-               case CMD_ERASE:
-                       bIterate = 0;
-                       tdb_traverse(tdb, do_delete_fn, NULL);
-                       return 0;
-               case CMD_DUMP:
-                       bIterate = 0;
-                       tdb_traverse(tdb, print_rec, NULL);
-                       return 0;
-               case CMD_INSERT:
-                       bIterate = 0;
-                       insert_tdb(arg1, arg1len,arg2,arg2len);
-                       return 0;
-               case CMD_MOVE:
-                       bIterate = 0;
-                       move_rec(arg1,arg1len,arg2);
-                       return 0;
-               case CMD_STORE:
-                       bIterate = 0;
-                       store_tdb(arg1,arg1len,arg2,arg2len);
-                       return 0;
-               case CMD_SHOW:
-                       bIterate = 0;
-                       show_tdb(arg1, arg1len);
-                       return 0;
-               case CMD_KEYS:
-                       tdb_traverse(tdb, print_key, NULL);
-                       return 0;
-               case CMD_HEXKEYS:
-                       tdb_traverse(tdb, print_hexkey, NULL);
-                       return 0;
-               case CMD_DELETE:
-                       bIterate = 0;
-                       delete_tdb(arg1,arg1len);
-                       return 0;
-               case CMD_LIST_HASH_FREE:
-                       tdb_dump_all(tdb);
-                       return 0;
-               case CMD_LIST_FREE:
-                       tdb_printfreelist(tdb);
-                       return 0;
-               case CMD_INFO:
-                       info_tdb();
-                       return 0;
-               case CMD_SPEED:
-                       speed_tdb(arg1);
-                       return 0;
-               case CMD_MMAP:
-                       toggle_mmap();
-                       return 0;
-               case CMD_FIRST:
-                       bIterate = 1;
-                       first_record(tdb, &iterate_kbuf);
-                       return 0;
-               case CMD_NEXT:
-                       if (bIterate)
-                               next_record(tdb, &iterate_kbuf);
-                       return 0;
-               case CMD_CHECK:
-                       check_db(tdb);
-                       return 0;
-               case CMD_HELP:
-                       help();
-                       return 0;
-               case CMD_CREATE_TDB:
-               case CMD_OPEN_TDB:
-               case CMD_SYSTEM:
-               case CMD_QUIT:
-                       /*
-                        * unhandled commands.  cases included here to avoid compiler
-                        * warnings.
-                        */
-                       return 0;
-               }
-       }
-
-       return 0;
-}
-
-static char *convert_string(char *instring, size_t *sizep)
-{
-       size_t length = 0;
-       char *outp, *inp;
-       char temp[3];
-
-       outp = inp = instring;
-
-       while (*inp) {
-               if (*inp == '\\') {
-                       inp++;
-                       if (*inp && strchr("0123456789abcdefABCDEF",(int)*inp)) {
-                               temp[0] = *inp++;
-                               temp[1] = '\0';
-                               if (*inp && strchr("0123456789abcdefABCDEF",(int)*inp)) {
-                                       temp[1] = *inp++;
-                                       temp[2] = '\0';
-                               }
-                               *outp++ = (char)strtol((const char *)temp,NULL,16);
-                       } else {
-                               *outp++ = *inp++;
-                       }
-               } else {
-                       *outp++ = *inp++;
-               }
-               length++;
-       }
-       *sizep = length;
-       return instring;
-}
-
-int main(int argc, char *argv[])
-{
-       cmdname = "";
-       arg1 = NULL;
-       arg1len = 0;
-       arg2 = NULL;
-       arg2len = 0;
-
-       if (argv[1]) {
-               cmdname = "open";
-               arg1 = argv[1];
-               do_command();
-               cmdname =  "";
-               arg1 = NULL;
-       }
-
-       switch (argc) {
-       case 1:
-       case 2:
-               /* Interactive mode */
-               while ((cmdname = tdb_getline("tdb> "))) {
-                       arg2 = arg1 = NULL;
-                       if ((arg1 = strchr((const char *)cmdname,' ')) != NULL) {
-                               arg1++;
-                               arg2 = arg1;
-                               while (*arg2) {
-                                       if (*arg2 == ' ') {
-                                               *arg2++ = '\0';
-                                               break;
-                                       }
-                                       if ((*arg2++ == '\\') && (*arg2 == ' ')) {
-                                               arg2++;
-                                       }
-                               }
-                       }
-                       if (arg1) arg1 = convert_string(arg1,&arg1len);
-                       if (arg2) arg2 = convert_string(arg2,&arg2len);
-                       if (do_command()) break;
-               }
-               break;
-       case 5:
-               arg2 = convert_string(argv[4],&arg2len);
-       case 4:
-               arg1 = convert_string(argv[3],&arg1len);
-       case 3:
-               cmdname = argv[2];
-       default:
-               do_command();
-               break;
-       }
-
-       if (tdb) tdb_close(tdb);
-
-       return 0;
-}
diff --git a/ccan/tdb/tools/tdbtorture.c b/ccan/tdb/tools/tdbtorture.c
deleted file mode 100644 (file)
index fc219b8..0000000
+++ /dev/null
@@ -1,453 +0,0 @@
-/* this tests tdb by doing lots of ops from several simultaneous
-   writers - that stresses the locking code. 
-*/
-
-#include <ccan/tdb/tdb.h>
-#include <stdlib.h>
-#include <err.h>
-#include <getopt.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <time.h>
-#include <sys/wait.h>
-
-#define REOPEN_PROB 30
-#define DELETE_PROB 8
-#define STORE_PROB 4
-#define APPEND_PROB 6
-#define TRANSACTION_PROB 10
-#define TRANSACTION_PREPARE_PROB 2
-#define LOCKSTORE_PROB 5
-#define TRAVERSE_PROB 20
-#define TRAVERSE_READ_PROB 20
-#define TRAVERSE_MOD_PROB 100
-#define TRAVERSE_ABORT_PROB 500
-#define CULL_PROB 100
-#define KEYLEN 3
-#define DATALEN 100
-
-static struct tdb_context *db;
-static int in_transaction;
-static int in_traverse;
-static int error_count;
-static int always_transaction = 0;
-static int hash_size = 2;
-static int loopnum;
-static int count_pipe;
-static struct tdb_logging_context log_ctx;
-
-#ifdef PRINTF_FMT
-static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...) PRINTF_FMT(3,4);
-#endif
-static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...)
-{
-       va_list ap;
-
-       if (level != TDB_DEBUG_TRACE)
-               error_count++;
-
-       va_start(ap, format);
-       vfprintf(stdout, format, ap);
-       va_end(ap);
-       fflush(stdout);
-#if 0
-       if (level != TDB_DEBUG_TRACE) {
-               char *ptr;
-               signal(SIGUSR1, SIG_IGN);
-               asprintf(&ptr,"xterm -e gdb /proc/%d/exe %d", getpid(), getpid());
-               system(ptr);
-               free(ptr);
-       }
-#endif 
-}
-
-static void fatal(const char *why)
-{
-       perror(why);
-       error_count++;
-}
-
-static char *randbuf(int len)
-{
-       char *buf;
-       int i;
-       buf = (char *)malloc(len+1);
-
-       for (i=0;i<len;i++) {
-               buf[i] = 'a' + (rand() % 26);
-       }
-       buf[i] = 0;
-       return buf;
-}
-
-static void addrec_db(void);
-static int modify_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf,
-                          void *state)
-{
-#if CULL_PROB
-       if (random() % CULL_PROB == 0) {
-               tdb_delete(tdb, key);
-       }
-#endif
-
-#if TRAVERSE_MOD_PROB
-       if (random() % TRAVERSE_MOD_PROB == 0) {
-               addrec_db();
-       }
-#endif
-
-#if TRAVERSE_ABORT_PROB
-       if (random() % TRAVERSE_ABORT_PROB == 0)
-               return 1;
-#endif
-
-       return 0;
-}
-
-static void addrec_db(void)
-{
-       int klen, dlen;
-       char *k, *d;
-       TDB_DATA key, data;
-
-       klen = 1 + (rand() % KEYLEN);
-       dlen = 1 + (rand() % DATALEN);
-
-       k = randbuf(klen);
-       d = randbuf(dlen);
-
-       key.dptr = (unsigned char *)k;
-       key.dsize = klen+1;
-
-       data.dptr = (unsigned char *)d;
-       data.dsize = dlen+1;
-
-#if REOPEN_PROB
-       if (in_traverse == 0 && in_transaction == 0 && random() % REOPEN_PROB == 0) {
-               tdb_reopen_all(0);
-               goto next;
-       } 
-#endif
-
-#if TRANSACTION_PROB
-       if (in_traverse == 0 && in_transaction == 0 && (always_transaction || random() % TRANSACTION_PROB == 0)) {
-               if (tdb_transaction_start(db) != 0) {
-                       fatal("tdb_transaction_start failed");
-               }
-               in_transaction++;
-               goto next;
-       }
-       if (in_traverse == 0 && in_transaction && random() % TRANSACTION_PROB == 0) {
-               if (random() % TRANSACTION_PREPARE_PROB == 0) {
-                       if (tdb_transaction_prepare_commit(db) != 0) {
-                               fatal("tdb_transaction_prepare_commit failed");
-                       }
-               }
-               if (tdb_transaction_commit(db) != 0) {
-                       fatal("tdb_transaction_commit failed");
-               }
-               in_transaction--;
-               goto next;
-       }
-
-       if (in_traverse == 0 && in_transaction && random() % TRANSACTION_PROB == 0) {
-               if (tdb_transaction_cancel(db) != 0) {
-                       fatal("tdb_transaction_cancel failed");
-               }
-               in_transaction--;
-               goto next;
-       }
-#endif
-
-#if DELETE_PROB
-       if (random() % DELETE_PROB == 0) {
-               tdb_delete(db, key);
-               goto next;
-       }
-#endif
-
-#if STORE_PROB
-       if (random() % STORE_PROB == 0) {
-               if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
-                       fatal("tdb_store failed");
-               }
-               goto next;
-       }
-#endif
-
-#if APPEND_PROB
-       if (random() % APPEND_PROB == 0) {
-               if (tdb_append(db, key, data) != 0) {
-                       fatal("tdb_append failed");
-               }
-               goto next;
-       }
-#endif
-
-#if LOCKSTORE_PROB
-       if (random() % LOCKSTORE_PROB == 0) {
-               tdb_chainlock(db, key);
-               data = tdb_fetch(db, key);
-               if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
-                       fatal("tdb_store failed");
-               }
-               if (data.dptr) free(data.dptr);
-               tdb_chainunlock(db, key);
-               goto next;
-       } 
-#endif
-
-#if TRAVERSE_PROB
-       /* FIXME: recursive traverses break transactions? */
-       if (in_traverse == 0 && random() % TRAVERSE_PROB == 0) {
-               in_traverse++;
-               tdb_traverse(db, modify_traverse, NULL);
-               in_traverse--;
-               goto next;
-       }
-#endif
-
-#if TRAVERSE_READ_PROB
-       if (in_traverse == 0 && random() % TRAVERSE_READ_PROB == 0) {
-               in_traverse++;
-               tdb_traverse_read(db, NULL, NULL);
-               in_traverse--;
-               goto next;
-       }
-#endif
-
-       data = tdb_fetch(db, key);
-       if (data.dptr) free(data.dptr);
-
-next:
-       free(k);
-       free(d);
-}
-
-static int traverse_fn(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf,
-                       void *state)
-{
-       tdb_delete(tdb, key);
-       return 0;
-}
-
-static void usage(void)
-{
-       printf("Usage: tdbtorture [-t] [-k] [-n NUM_PROCS] [-l NUM_LOOPS] [-s SEED] [-H HASH_SIZE]\n");
-       exit(0);
-}
-
-static void send_count_and_suicide(int sig)
-{
-       /* This ensures our successor can continue where we left off. */
-       write(count_pipe, &loopnum, sizeof(loopnum));
-       /* This gives a unique signature. */
-       kill(getpid(), SIGUSR2);
-}
-
-static int run_child(int i, int seed, unsigned num_loops, unsigned start)
-{
-       db = tdb_open_ex("torture.tdb", hash_size, TDB_DEFAULT, 
-                        O_RDWR | O_CREAT, 0600, &log_ctx, NULL);
-       if (!db) {
-               fatal("db open failed");
-       }
-
-       srand(seed + i);
-       srandom(seed + i);
-
-       /* Set global, then we're ready to handle being killed. */
-       loopnum = start;
-       signal(SIGUSR1, send_count_and_suicide);
-
-       for (;loopnum<num_loops && error_count == 0;loopnum++) {
-               addrec_db();
-       }
-
-       if (error_count == 0) {
-               tdb_traverse_read(db, NULL, NULL);
-               if (always_transaction) {
-                       while (in_transaction) {
-                               tdb_transaction_cancel(db);
-                               in_transaction--;
-                       }
-                       if (tdb_transaction_start(db) != 0)
-                               fatal("tdb_transaction_start failed");
-               }
-               tdb_traverse(db, traverse_fn, NULL);
-               tdb_traverse(db, traverse_fn, NULL);
-               if (always_transaction) {
-                       if (tdb_transaction_commit(db) != 0)
-                               fatal("tdb_transaction_commit failed");
-               }
-       }
-
-       tdb_close(db);
-
-       return (error_count < 100 ? error_count : 100);
-}
-
-int main(int argc, char * const *argv)
-{
-       int i, seed = -1;
-       int num_loops = 5000;
-       int num_procs = 3;
-       int c, pfds[2];
-       extern char *optarg;
-       pid_t *pids;
-       int kill_random = 0;
-       int *done;
-
-       log_ctx.log_fn = tdb_log;
-
-       while ((c = getopt(argc, argv, "n:l:s:H:thk")) != -1) {
-               switch (c) {
-               case 'n':
-                       num_procs = strtol(optarg, NULL, 0);
-                       break;
-               case 'l':
-                       num_loops = strtol(optarg, NULL, 0);
-                       break;
-               case 'H':
-                       hash_size = strtol(optarg, NULL, 0);
-                       break;
-               case 's':
-                       seed = strtol(optarg, NULL, 0);
-                       break;
-               case 't':
-                       always_transaction = 1;
-                       break;
-               case 'k':
-                       kill_random = 1;
-                       break;
-               default:
-                       usage();
-               }
-       }
-
-       unlink("torture.tdb");
-
-       if (seed == -1) {
-               seed = (getpid() + time(NULL)) & 0x7FFFFFFF;
-       }
-
-       if (num_procs == 1 && !kill_random) {
-               /* Don't fork for this case, makes debugging easier. */
-               error_count = run_child(0, seed, num_loops, 0);
-               goto done;
-       }
-
-       pids = (pid_t *)calloc(sizeof(pid_t), num_procs);
-       done = (int *)calloc(sizeof(int), num_procs);
-
-       if (pipe(pfds) != 0) {
-               perror("Creating pipe");
-               exit(1);
-       }
-       count_pipe = pfds[1];
-
-       for (i=0;i<num_procs;i++) {
-               if ((pids[i]=fork()) == 0) {
-                       close(pfds[0]);
-                       if (i == 0) {
-                               printf("testing with %d processes, %d loops, %d hash_size, seed=%d%s\n", 
-                                      num_procs, num_loops, hash_size, seed, always_transaction ? " (all within transactions)" : "");
-                       }
-                       exit(run_child(i, seed, num_loops, 0));
-               }
-       }
-
-       while (num_procs) {
-               int status, j;
-               pid_t pid;
-
-               if (error_count != 0) {
-                       /* try and stop the test on any failure */
-                       for (j=0;j<num_procs;j++) {
-                               if (pids[j] != 0) {
-                                       kill(pids[j], SIGTERM);
-                               }
-                       }
-               }
-
-               pid = waitpid(-1, &status, kill_random ? WNOHANG : 0);
-               if (pid == 0) {
-                       struct timespec ts;
-
-                       /* Sleep for 1/10 second. */
-                       ts.tv_sec = 0;
-                       ts.tv_nsec = 100000000;
-                       nanosleep(&ts, NULL);
-
-                       /* Kill someone. */
-                       kill(pids[random() % num_procs], SIGUSR1);
-                       continue;
-               }
-
-               if (pid == -1) {
-                       perror("failed to wait for child\n");
-                       exit(1);
-               }
-
-               for (j=0;j<num_procs;j++) {
-                       if (pids[j] == pid) break;
-               }
-               if (j == num_procs) {
-                       printf("unknown child %d exited!?\n", (int)pid);
-                       exit(1);
-               }
-               if (WIFSIGNALED(status)) {
-                       if (WTERMSIG(status) == SIGUSR2
-                           || WTERMSIG(status) == SIGUSR1) {
-                               /* SIGUSR2 means they wrote to pipe. */
-                               if (WTERMSIG(status) == SIGUSR2) {
-                                       read(pfds[0], &done[j],
-                                            sizeof(done[j]));
-                               }
-                               pids[j] = fork();
-                               if (pids[j] == 0)
-                                       exit(run_child(j, seed, num_loops,
-                                                      done[j]));
-                               printf("Restarting child %i for %u-%u\n",
-                                      j, done[j], num_loops);
-                               continue;
-                       }
-                       printf("child %d exited with signal %d\n",
-                              (int)pid, WTERMSIG(status));
-                       error_count++;
-               } else {
-                       if (WEXITSTATUS(status) != 0) {
-                               printf("child %d exited with status %d\n",
-                                      (int)pid, WEXITSTATUS(status));
-                               error_count++;
-                       }
-               }
-               memmove(&pids[j], &pids[j+1],
-                       (num_procs - j - 1)*sizeof(pids[0]));
-               num_procs--;
-       }
-
-       free(pids);
-
-done:
-       if (error_count == 0) {
-               db = tdb_open_ex("torture.tdb", hash_size, TDB_DEFAULT, 
-                                O_RDWR, 0, &log_ctx, NULL);
-               if (!db) {
-                       fatal("db open failed");
-               }
-               if (tdb_check(db, NULL, NULL) == -1) {
-                       printf("db check failed");
-                       exit(1);
-               }
-               tdb_close(db);
-               printf("OK\n");
-       }
-
-       return error_count;
-}
diff --git a/ccan/tdb/tools/tests/1-torture.trace.tar.bz2 b/ccan/tdb/tools/tests/1-torture.trace.tar.bz2
deleted file mode 100644 (file)
index 272ea29..0000000
Binary files a/ccan/tdb/tools/tests/1-torture.trace.tar.bz2 and /dev/null differ
diff --git a/ccan/tdb/tools/tests/2-torture.trace.tar.bz2 b/ccan/tdb/tools/tests/2-torture.trace.tar.bz2
deleted file mode 100644 (file)
index 20bd5d3..0000000
Binary files a/ccan/tdb/tools/tests/2-torture.trace.tar.bz2 and /dev/null differ
diff --git a/ccan/tdb/tools/tests/3-torture.trace.tar.bz2 b/ccan/tdb/tools/tests/3-torture.trace.tar.bz2
deleted file mode 100644 (file)
index b039ca0..0000000
Binary files a/ccan/tdb/tools/tests/3-torture.trace.tar.bz2 and /dev/null differ
diff --git a/ccan/tdb/tools/tests/4-torture.trace.tar.bz2 b/ccan/tdb/tools/tests/4-torture.trace.tar.bz2
deleted file mode 100644 (file)
index e2307f7..0000000
Binary files a/ccan/tdb/tools/tests/4-torture.trace.tar.bz2 and /dev/null differ
diff --git a/ccan/tdb/tools/tests/5-torture.trace.tar.bz2 b/ccan/tdb/tools/tests/5-torture.trace.tar.bz2
deleted file mode 100644 (file)
index a3d590e..0000000
Binary files a/ccan/tdb/tools/tests/5-torture.trace.tar.bz2 and /dev/null differ
diff --git a/ccan/tdb/tools/tests/6-torture.trace.tar.bz2 b/ccan/tdb/tools/tests/6-torture.trace.tar.bz2
deleted file mode 100644 (file)
index dc55cc9..0000000
Binary files a/ccan/tdb/tools/tests/6-torture.trace.tar.bz2 and /dev/null differ
diff --git a/ccan/tdb/tools/tests/7-torture.trace.tar.bz2 b/ccan/tdb/tools/tests/7-torture.trace.tar.bz2
deleted file mode 100644 (file)
index e77abaf..0000000
Binary files a/ccan/tdb/tools/tests/7-torture.trace.tar.bz2 and /dev/null differ
diff --git a/ccan/tdb/tools/tests/8-torture.trace.tar.bz2 b/ccan/tdb/tools/tests/8-torture.trace.tar.bz2
deleted file mode 100644 (file)
index 5358d1a..0000000
Binary files a/ccan/tdb/tools/tests/8-torture.trace.tar.bz2 and /dev/null differ
diff --git a/ccan/tdb/tools/tests/9-torture.trace.tar.bz2 b/ccan/tdb/tools/tests/9-torture.trace.tar.bz2
deleted file mode 100644 (file)
index edd88ea..0000000
Binary files a/ccan/tdb/tools/tests/9-torture.trace.tar.bz2 and /dev/null differ
diff --git a/ccan/tdb/transaction.c b/ccan/tdb/transaction.c
deleted file mode 100644 (file)
index e34dee0..0000000
+++ /dev/null
@@ -1,1238 +0,0 @@
- /* 
-   Unix SMB/CIFS implementation.
-
-   trivial database library
-
-   Copyright (C) Andrew Tridgell              2005
-
-     ** NOTE! The following LGPL license applies to the tdb
-     ** library. This does NOT imply that all of Samba is released
-     ** under the LGPL
-   
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "tdb_private.h"
-
-/*
-  transaction design:
-
-  - only allow a single transaction at a time per database. This makes
-    using the transaction API simpler, as otherwise the caller would
-    have to cope with temporary failures in transactions that conflict
-    with other current transactions
-
-  - keep the transaction recovery information in the same file as the
-    database, using a special 'transaction recovery' record pointed at
-    by the header. This removes the need for extra journal files as
-    used by some other databases
-
-  - dynamically allocated the transaction recover record, re-using it
-    for subsequent transactions. If a larger record is needed then
-    tdb_free() the old record to place it on the normal tdb freelist
-    before allocating the new record
-
-  - during transactions, keep a linked list of writes all that have
-    been performed by intercepting all tdb_write() calls. The hooked
-    transaction versions of tdb_read() and tdb_write() check this
-    linked list and try to use the elements of the list in preference
-    to the real database.
-
-  - don't allow any locks to be held when a transaction starts,
-    otherwise we can end up with deadlock (plus lack of lock nesting
-    in posix locks would mean the lock is lost)
-
-  - if the caller gains a lock during the transaction but doesn't
-    release it then fail the commit
-
-  - allow for nested calls to tdb_transaction_start(), re-using the
-    existing transaction record. If the inner transaction is cancelled
-    then a subsequent commit will fail
-  - keep a mirrored copy of the tdb hash chain heads to allow for the
-    fast hash heads scan on traverse, updating the mirrored copy in
-    the transaction version of tdb_write
-
-  - allow callers to mix transaction and non-transaction use of tdb,
-    although once a transaction is started then an exclusive lock is
-    gained until the transaction is committed or cancelled
-
-  - the commit stategy involves first saving away all modified data
-    into a linearised buffer in the transaction recovery area, then
-    marking the transaction recovery area with a magic value to
-    indicate a valid recovery record. In total 4 fsync/msync calls are
-    needed per commit to prevent race conditions. It might be possible
-    to reduce this to 3 or even 2 with some more work.
-
-  - check for a valid recovery record on open of the tdb, while the
-    open lock is held. Automatically recover from the transaction
-    recovery area if needed, then continue with the open as
-    usual. This allows for smooth crash recovery with no administrator
-    intervention.
-
-  - if TDB_NOSYNC is passed to flags in tdb_open then transactions are
-    still available, but no transaction recovery area is used and no
-    fsync/msync calls are made.
-
-  - if TDB_ALLOW_NESTING is passed to flags in tdb open, or added using
-    tdb_add_flags() transaction nesting is enabled.
-    It resets the TDB_DISALLOW_NESTING flag, as both cannot be used together.
-    The default is that transaction nesting is allowed.
-    Note: this default may change in future versions of tdb.
-
-    Beware. when transactions are nested a transaction successfully
-    completed with tdb_transaction_commit() can be silently unrolled later.
-
-  - if TDB_DISALLOW_NESTING is passed to flags in tdb open, or added using
-    tdb_add_flags() transaction nesting is disabled.
-    It resets the TDB_ALLOW_NESTING flag, as both cannot be used together.
-    An attempt create a nested transaction will fail with TDB_ERR_NESTING.
-    The default is that transaction nesting is allowed.
-    Note: this default may change in future versions of tdb.
-*/
-
-
-/*
-  hold the context of any current transaction
-*/
-struct tdb_transaction {
-       /* we keep a mirrored copy of the tdb hash heads here so
-          tdb_next_hash_chain() can operate efficiently */
-       uint32_t *hash_heads;
-
-       /* the original io methods - used to do IOs to the real db */
-       const struct tdb_methods *io_methods;
-
-       /* the list of transaction blocks. When a block is first
-          written to, it gets created in this list */
-       uint8_t **blocks;
-       uint32_t num_blocks;
-       uint32_t block_size;      /* bytes in each block */
-       uint32_t last_block_size; /* number of valid bytes in the last block */
-
-       /* non-zero when an internal transaction error has
-          occurred. All write operations will then fail until the
-          transaction is ended */
-       int transaction_error;
-
-       /* when inside a transaction we need to keep track of any
-          nested tdb_transaction_start() calls, as these are allowed,
-          but don't create a new transaction */
-       int nesting;
-
-       /* set when a prepare has already occurred */
-       bool prepared;
-       tdb_off_t magic_offset;
-
-       /* old file size before transaction */
-       tdb_len_t old_map_size;
-
-       /* we should re-pack on commit */
-       bool need_repack;
-};
-
-
-/*
-  read while in a transaction. We need to check first if the data is in our list
-  of transaction elements, then if not do a real read
-*/
-static int transaction_read(struct tdb_context *tdb, tdb_off_t off, void *buf, 
-                           tdb_len_t len, int cv)
-{
-       uint32_t blk;
-
-       /* break it down into block sized ops */
-       while (len + (off % tdb->transaction->block_size) > tdb->transaction->block_size) {
-               tdb_len_t len2 = tdb->transaction->block_size - (off % tdb->transaction->block_size);
-               if (transaction_read(tdb, off, buf, len2, cv) != 0) {
-                       return -1;
-               }
-               len -= len2;
-               off += len2;
-               buf = (void *)(len2 + (char *)buf);
-       }
-
-       if (len == 0) {
-               return 0;
-       }
-
-       blk = off / tdb->transaction->block_size;
-
-       /* see if we have it in the block list */
-       if (tdb->transaction->num_blocks <= blk ||
-           tdb->transaction->blocks[blk] == NULL) {
-               /* nope, do a real read */
-               if (tdb->transaction->io_methods->tdb_read(tdb, off, buf, len, cv) != 0) {
-                       goto fail;
-               }
-               return 0;
-       }
-
-       /* it is in the block list. Now check for the last block */
-       if (blk == tdb->transaction->num_blocks-1) {
-               if (len > tdb->transaction->last_block_size) {
-                       goto fail;
-               }
-       }
-       
-       /* now copy it out of this block */
-       memcpy(buf, tdb->transaction->blocks[blk] + (off % tdb->transaction->block_size), len);
-       if (cv) {
-               tdb_convert(buf, len);
-       }
-       return 0;
-
-fail:
-       TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_read: failed at off=%d len=%d\n", off, len));
-       tdb->ecode = TDB_ERR_IO;
-       tdb->transaction->transaction_error = 1;
-       return -1;
-}
-
-
-/*
-  write while in a transaction
-*/
-static int transaction_write(struct tdb_context *tdb, tdb_off_t off, 
-                            const void *buf, tdb_len_t len)
-{
-       uint32_t blk;
-
-       /* Only a commit is allowed on a prepared transaction */
-       if (tdb->transaction->prepared) {
-               tdb->ecode = TDB_ERR_EINVAL;
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_write: transaction already prepared, write not allowed\n"));
-               tdb->transaction->transaction_error = 1;
-               return -1;
-       }
-
-       /* if the write is to a hash head, then update the transaction
-          hash heads */
-       if (len == sizeof(tdb_off_t) && off >= FREELIST_TOP &&
-           off < FREELIST_TOP+TDB_HASHTABLE_SIZE(tdb)) {
-               uint32_t chain = (off-FREELIST_TOP) / sizeof(tdb_off_t);
-               memcpy(&tdb->transaction->hash_heads[chain], buf, len);
-       }
-
-       /* break it up into block sized chunks */
-       while (len + (off % tdb->transaction->block_size) > tdb->transaction->block_size) {
-               tdb_len_t len2 = tdb->transaction->block_size - (off % tdb->transaction->block_size);
-               if (transaction_write(tdb, off, buf, len2) != 0) {
-                       return -1;
-               }
-               len -= len2;
-               off += len2;
-               if (buf != NULL) {
-                       buf = (const void *)(len2 + (const char *)buf);
-               }
-       }
-
-       if (len == 0) {
-               return 0;
-       }
-
-       blk = off / tdb->transaction->block_size;
-       off = off % tdb->transaction->block_size;
-
-       if (tdb->transaction->num_blocks <= blk) {
-               uint8_t **new_blocks;
-               /* expand the blocks array */
-               if (tdb->transaction->blocks == NULL) {
-                       new_blocks = (uint8_t **)malloc(
-                               (blk+1)*sizeof(uint8_t *));
-               } else {
-                       new_blocks = (uint8_t **)realloc(
-                               tdb->transaction->blocks,
-                               (blk+1)*sizeof(uint8_t *));
-               }
-               if (new_blocks == NULL) {
-                       tdb->ecode = TDB_ERR_OOM;
-                       goto fail;
-               }
-               memset(&new_blocks[tdb->transaction->num_blocks], 0, 
-                      (1+(blk - tdb->transaction->num_blocks))*sizeof(uint8_t *));
-               tdb->transaction->blocks = new_blocks;
-               tdb->transaction->num_blocks = blk+1;
-               tdb->transaction->last_block_size = 0;
-       }
-
-       /* allocate and fill a block? */
-       if (tdb->transaction->blocks[blk] == NULL) {
-               tdb->transaction->blocks[blk] = (uint8_t *)calloc(tdb->transaction->block_size, 1);
-               if (tdb->transaction->blocks[blk] == NULL) {
-                       tdb->ecode = TDB_ERR_OOM;
-                       tdb->transaction->transaction_error = 1;
-                       return -1;                      
-               }
-               if (tdb->transaction->old_map_size > blk * tdb->transaction->block_size) {
-                       tdb_len_t len2 = tdb->transaction->block_size;
-                       if (len2 + (blk * tdb->transaction->block_size) > tdb->transaction->old_map_size) {
-                               len2 = tdb->transaction->old_map_size - (blk * tdb->transaction->block_size);
-                       }
-                       if (tdb->transaction->io_methods->tdb_read(tdb, blk * tdb->transaction->block_size, 
-                                                                  tdb->transaction->blocks[blk], 
-                                                                  len2, 0) != 0) {
-                               SAFE_FREE(tdb->transaction->blocks[blk]);                               
-                               tdb->ecode = TDB_ERR_IO;
-                               goto fail;
-                       }
-                       if (blk == tdb->transaction->num_blocks-1) {
-                               tdb->transaction->last_block_size = len2;
-                       }                       
-               }
-       }
-       
-       /* overwrite part of an existing block */
-       if (buf == NULL) {
-               memset(tdb->transaction->blocks[blk] + off, 0, len);
-       } else {
-               memcpy(tdb->transaction->blocks[blk] + off, buf, len);
-       }
-       if (blk == tdb->transaction->num_blocks-1) {
-               if (len + off > tdb->transaction->last_block_size) {
-                       tdb->transaction->last_block_size = len + off;
-               }
-       }
-
-       return 0;
-
-fail:
-       TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_write: failed at off=%d len=%d\n", 
-                (blk*tdb->transaction->block_size) + off, len));
-       tdb->transaction->transaction_error = 1;
-       return -1;
-}
-
-
-/*
-  write while in a transaction - this varient never expands the transaction blocks, it only
-  updates existing blocks. This means it cannot change the recovery size
-*/
-static int transaction_write_existing(struct tdb_context *tdb, tdb_off_t off, 
-                                     const void *buf, tdb_len_t len)
-{
-       uint32_t blk;
-
-       /* break it up into block sized chunks */
-       while (len + (off % tdb->transaction->block_size) > tdb->transaction->block_size) {
-               tdb_len_t len2 = tdb->transaction->block_size - (off % tdb->transaction->block_size);
-               if (transaction_write_existing(tdb, off, buf, len2) != 0) {
-                       return -1;
-               }
-               len -= len2;
-               off += len2;
-               if (buf != NULL) {
-                       buf = (const void *)(len2 + (const char *)buf);
-               }
-       }
-
-       if (len == 0) {
-               return 0;
-       }
-
-       blk = off / tdb->transaction->block_size;
-       off = off % tdb->transaction->block_size;
-
-       if (tdb->transaction->num_blocks <= blk ||
-           tdb->transaction->blocks[blk] == NULL) {
-               return 0;
-       }
-
-       if (blk == tdb->transaction->num_blocks-1 &&
-           off + len > tdb->transaction->last_block_size) {
-               if (off >= tdb->transaction->last_block_size) {
-                       return 0;
-               }
-               len = tdb->transaction->last_block_size - off;
-       }
-
-       /* overwrite part of an existing block */
-       memcpy(tdb->transaction->blocks[blk] + off, buf, len);
-
-       return 0;
-}
-
-
-/*
-  accelerated hash chain head search, using the cached hash heads
-*/
-static void transaction_next_hash_chain(struct tdb_context *tdb, uint32_t *chain)
-{
-       uint32_t h = *chain;
-       for (;h < tdb->header.hash_size;h++) {
-               /* the +1 takes account of the freelist */
-               if (0 != tdb->transaction->hash_heads[h+1]) {
-                       break;
-               }
-       }
-       (*chain) = h;
-}
-
-/*
-  out of bounds check during a transaction
-*/
-static int transaction_oob(struct tdb_context *tdb, tdb_off_t len, int probe)
-{
-       if (len <= tdb->map_size) {
-               return 0;
-       }
-       tdb->ecode = TDB_ERR_IO;
-       return -1;
-}
-
-/*
-  transaction version of tdb_expand().
-*/
-static int transaction_expand_file(struct tdb_context *tdb, tdb_off_t size, 
-                                  tdb_off_t addition)
-{
-       /* add a write to the transaction elements, so subsequent
-          reads see the zero data */
-       if (transaction_write(tdb, size, NULL, addition) != 0) {
-               return -1;
-       }
-
-       tdb->transaction->need_repack = true;
-
-       return 0;
-}
-
-static const struct tdb_methods transaction_methods = {
-       transaction_read,
-       transaction_write,
-       transaction_next_hash_chain,
-       transaction_oob,
-       transaction_expand_file,
-};
-
-/*
-  sync to disk
-*/
-static int transaction_sync(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t length)
-{      
-       if (tdb->flags & TDB_NOSYNC) {
-               return 0;
-       }
-
-       if (fsync(tdb->fd) != 0) {
-               tdb->ecode = TDB_ERR_IO;
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: fsync failed\n"));
-               return -1;
-       }
-#ifdef MS_SYNC
-       if (tdb->map_ptr) {
-               tdb_off_t moffset = offset & ~(tdb->page_size-1);
-               if (msync(moffset + (char *)tdb->map_ptr, 
-                         length + (offset - moffset), MS_SYNC) != 0) {
-                       tdb->ecode = TDB_ERR_IO;
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: msync failed - %s\n",
-                                strerror(errno)));
-                       return -1;
-               }
-       }
-#endif
-       return 0;
-}
-
-
-static int _tdb_transaction_cancel(struct tdb_context *tdb)
-{
-       int i, ret = 0;
-
-       if (tdb->transaction == NULL) {
-               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_cancel: no transaction\n"));
-               return -1;
-       }
-
-       if (tdb->transaction->nesting != 0) {
-               tdb->transaction->transaction_error = 1;
-               tdb->transaction->nesting--;
-               return 0;
-       }               
-
-       tdb->map_size = tdb->transaction->old_map_size;
-
-       /* free all the transaction blocks */
-       for (i=0;i<tdb->transaction->num_blocks;i++) {
-               if (tdb->transaction->blocks[i] != NULL) {
-                       free(tdb->transaction->blocks[i]);
-               }
-       }
-       SAFE_FREE(tdb->transaction->blocks);
-
-       if (tdb->transaction->magic_offset) {
-               const struct tdb_methods *methods = tdb->transaction->io_methods;
-               uint32_t invalid = TDB_RECOVERY_INVALID_MAGIC;
-
-               /* remove the recovery marker */
-               if (methods->tdb_write(tdb, tdb->transaction->magic_offset, &invalid, 4) == -1 ||
-               transaction_sync(tdb, tdb->transaction->magic_offset, 4) == -1) {
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_cancel: failed to remove recovery magic\n"));
-                       ret = -1;
-               }
-       }
-
-       /* This also removes the OPEN_LOCK, if we have it. */
-       tdb_release_extra_locks(tdb);
-
-       /* restore the normal io methods */
-       tdb->methods = tdb->transaction->io_methods;
-
-       tdb_transaction_unlock(tdb, F_WRLCK);
-       SAFE_FREE(tdb->transaction->hash_heads);
-       SAFE_FREE(tdb->transaction);
-       
-       return ret;
-}
-
-/*
-  start a tdb transaction. No token is returned, as only a single
-  transaction is allowed to be pending per tdb_context
-*/
-int tdb_transaction_start(struct tdb_context *tdb)
-{
-       /* some sanity checks */
-       if (tdb->read_only || (tdb->flags & TDB_INTERNAL) || tdb->traverse_read) {
-               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: cannot start a transaction on a read-only or internal db\n"));
-               tdb->ecode = TDB_ERR_EINVAL;
-               return -1;
-       }
-
-       /* cope with nested tdb_transaction_start() calls */
-       if (tdb->transaction != NULL) {
-               if (!(tdb->flags & TDB_ALLOW_NESTING)) {
-                       tdb->ecode = TDB_ERR_NESTING;
-                       return -1;
-               }
-               tdb_trace(tdb, "tdb_transaction_start");
-               tdb->transaction->nesting++;
-               TDB_LOG((tdb, TDB_DEBUG_TRACE, "tdb_transaction_start: nesting %d\n", 
-                        tdb->transaction->nesting));
-               return 0;
-       }
-
-       if (tdb_have_extra_locks(tdb)) {
-               /* the caller must not have any locks when starting a
-                  transaction as otherwise we'll be screwed by lack
-                  of nested locks in posix */
-               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: cannot start a transaction with locks held\n"));
-               tdb->ecode = TDB_ERR_LOCK;
-               return -1;
-       }
-
-       if (tdb->travlocks.next != NULL) {
-               /* you cannot use transactions inside a traverse (although you can use
-                  traverse inside a transaction) as otherwise you can end up with
-                  deadlock */
-               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: cannot start a transaction within a traverse\n"));
-               tdb->ecode = TDB_ERR_LOCK;
-               return -1;
-       }
-
-       tdb->transaction = (struct tdb_transaction *)
-               calloc(sizeof(struct tdb_transaction), 1);
-       if (tdb->transaction == NULL) {
-               tdb->ecode = TDB_ERR_OOM;
-               return -1;
-       }
-
-       /* a page at a time seems like a reasonable compromise between compactness and efficiency */
-       tdb->transaction->block_size = tdb->page_size;
-
-       /* get the transaction write lock. This is a blocking lock. As
-          discussed with Volker, there are a number of ways we could
-          make this async, which we will probably do in the future */
-       if (tdb_transaction_lock(tdb, F_WRLCK) == -1) {
-               SAFE_FREE(tdb->transaction->blocks);
-               SAFE_FREE(tdb->transaction);
-               return -1;
-       }
-       
-       /* get a read lock from the freelist to the end of file. This
-          is upgraded to a write lock during the commit */
-       if (tdb_allrecord_lock(tdb, F_RDLCK, TDB_LOCK_WAIT, true) == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: failed to get hash locks\n"));
-               goto fail_allrecord_lock;
-       }
-
-       /* setup a copy of the hash table heads so the hash scan in
-          traverse can be fast */
-       tdb->transaction->hash_heads = (uint32_t *)
-               calloc(tdb->header.hash_size+1, sizeof(uint32_t));
-       if (tdb->transaction->hash_heads == NULL) {
-               tdb->ecode = TDB_ERR_OOM;
-               goto fail;
-       }
-       if (tdb->methods->tdb_read(tdb, FREELIST_TOP, tdb->transaction->hash_heads,
-                                  TDB_HASHTABLE_SIZE(tdb), 0) != 0) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_start: failed to read hash heads\n"));
-               tdb->ecode = TDB_ERR_IO;
-               goto fail;
-       }
-
-       /* make sure we know about any file expansions already done by
-          anyone else */
-       tdb->methods->tdb_oob(tdb, tdb->map_size + 1, 1);
-       tdb->transaction->old_map_size = tdb->map_size;
-
-       /* finally hook the io methods, replacing them with
-          transaction specific methods */
-       tdb->transaction->io_methods = tdb->methods;
-       tdb->methods = &transaction_methods;
-
-       /* Trace at the end, so we get sequence number correct. */
-       tdb_trace(tdb, "tdb_transaction_start");
-       return 0;
-       
-fail:
-       tdb_allrecord_unlock(tdb, F_RDLCK, false);
-fail_allrecord_lock:
-       tdb_transaction_unlock(tdb, F_WRLCK);
-       SAFE_FREE(tdb->transaction->blocks);
-       SAFE_FREE(tdb->transaction->hash_heads);
-       SAFE_FREE(tdb->transaction);
-       return -1;
-}
-
-
-/*
-  cancel the current transaction
-*/
-int tdb_transaction_cancel(struct tdb_context *tdb)
-{
-       tdb_trace(tdb, "tdb_transaction_cancel");
-       return _tdb_transaction_cancel(tdb);
-}
-
-/*
-  work out how much space the linearised recovery data will consume
-*/
-static tdb_len_t tdb_recovery_size(struct tdb_context *tdb)
-{
-       tdb_len_t recovery_size = 0;
-       int i;
-
-       recovery_size = sizeof(uint32_t);
-       for (i=0;i<tdb->transaction->num_blocks;i++) {
-               if (i * tdb->transaction->block_size >= tdb->transaction->old_map_size) {
-                       break;
-               }
-               if (tdb->transaction->blocks[i] == NULL) {
-                       continue;
-               }
-               recovery_size += 2*sizeof(tdb_off_t);
-               if (i == tdb->transaction->num_blocks-1) {
-                       recovery_size += tdb->transaction->last_block_size;
-               } else {
-                       recovery_size += tdb->transaction->block_size;
-               }
-       }       
-
-       return recovery_size;
-}
-
-/*
-  allocate the recovery area, or use an existing recovery area if it is
-  large enough
-*/
-static int tdb_recovery_allocate(struct tdb_context *tdb, 
-                                tdb_len_t *recovery_size,
-                                tdb_off_t *recovery_offset,
-                                tdb_len_t *recovery_max_size)
-{
-       struct tdb_record rec;
-       const struct tdb_methods *methods = tdb->transaction->io_methods;
-       tdb_off_t recovery_head, new_end;
-
-       if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to read recovery head\n"));
-               return -1;
-       }
-
-       rec.rec_len = 0;
-
-       if (recovery_head != 0) {
-               if (methods->tdb_read(tdb, recovery_head, &rec, sizeof(rec), DOCONV()) == -1) {
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to read recovery record\n"));
-                       return -1;
-               }
-               /* ignore invalid recovery regions: can happen in crash */
-               if (rec.magic != TDB_RECOVERY_MAGIC &&
-                   rec.magic != TDB_RECOVERY_INVALID_MAGIC) {
-                       recovery_head = 0;
-               }
-       }
-
-       *recovery_size = tdb_recovery_size(tdb);
-
-       /* Existing recovery area? */
-       if (recovery_head != 0 && *recovery_size <= rec.rec_len) {
-               /* it fits in the existing area */
-               *recovery_max_size = rec.rec_len;
-               *recovery_offset = recovery_head;
-               return 0;
-       }
-
-       /* If recovery area in middle of file, we need a new one. */
-       if (recovery_head == 0
-           || recovery_head + sizeof(rec) + rec.rec_len != tdb->map_size) {
-               /* we need to free up the old recovery area, then allocate a
-                  new one at the end of the file. Note that we cannot use
-                  tdb_allocate() to allocate the new one as that might return
-                  us an area that is being currently used (as of the start of
-                  the transaction) */
-               if (recovery_head) {
-                       if (tdb_free(tdb, recovery_head, &rec) == -1) {
-                               TDB_LOG((tdb, TDB_DEBUG_FATAL,
-                                        "tdb_recovery_allocate: failed to"
-                                        " free previous recovery area\n"));
-                               return -1;
-                       }
-
-                       /* the tdb_free() call might have increased
-                        * the recovery size */
-                       *recovery_size = tdb_recovery_size(tdb);
-               }
-
-               /* New head will be at end of file. */
-               recovery_head = tdb->map_size;
-       }
-
-       /* Now we know where it will be. */
-       *recovery_offset = recovery_head;
-
-       /* Expand by more than we need, so we don't do it often. */
-       *recovery_max_size = tdb_expand_adjust(tdb->map_size,
-                                              *recovery_size,
-                                              tdb->page_size)
-               - sizeof(rec);
-
-       new_end = recovery_head + sizeof(rec) + *recovery_max_size;
-
-       if (methods->tdb_expand_file(tdb, tdb->transaction->old_map_size, 
-                                    new_end - tdb->transaction->old_map_size)
-           == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to create recovery area\n"));
-               return -1;
-       }
-
-       /* remap the file (if using mmap) */
-       methods->tdb_oob(tdb, tdb->map_size + 1, 1);
-
-       /* we have to reset the old map size so that we don't try to expand the file
-          again in the transaction commit, which would destroy the recovery area */
-       tdb->transaction->old_map_size = tdb->map_size;
-
-       /* write the recovery header offset and sync - we can sync without a race here
-          as the magic ptr in the recovery record has not been set */
-       CONVERT(recovery_head);
-       if (methods->tdb_write(tdb, TDB_RECOVERY_HEAD, 
-                              &recovery_head, sizeof(tdb_off_t)) == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to write recovery head\n"));
-               return -1;
-       }
-       if (transaction_write_existing(tdb, TDB_RECOVERY_HEAD, &recovery_head, sizeof(tdb_off_t)) == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to write recovery head\n"));
-               return -1;
-       }
-
-       return 0;
-}
-
-
-/*
-  setup the recovery data that will be used on a crash during commit
-*/
-static int transaction_setup_recovery(struct tdb_context *tdb, 
-                                     tdb_off_t *magic_offset)
-{
-       tdb_len_t recovery_size;
-       unsigned char *data, *p;
-       const struct tdb_methods *methods = tdb->transaction->io_methods;
-       struct tdb_record *rec;
-       tdb_off_t recovery_offset, recovery_max_size;
-       tdb_off_t old_map_size = tdb->transaction->old_map_size;
-       uint32_t magic, tailer;
-       int i;
-
-       /*
-         check that the recovery area has enough space
-       */
-       if (tdb_recovery_allocate(tdb, &recovery_size, 
-                                 &recovery_offset, &recovery_max_size) == -1) {
-               return -1;
-       }
-
-       data = (unsigned char *)malloc(recovery_size + sizeof(*rec));
-       if (data == NULL) {
-               tdb->ecode = TDB_ERR_OOM;
-               return -1;
-       }
-
-       rec = (struct tdb_record *)data;
-       memset(rec, 0, sizeof(*rec));
-
-       rec->magic    = TDB_RECOVERY_INVALID_MAGIC;
-       rec->data_len = recovery_size;
-       rec->rec_len  = recovery_max_size;
-       rec->key_len  = old_map_size;
-       CONVERT(rec);
-
-       /* build the recovery data into a single blob to allow us to do a single
-          large write, which should be more efficient */
-       p = data + sizeof(*rec);
-       for (i=0;i<tdb->transaction->num_blocks;i++) {
-               tdb_off_t offset;
-               tdb_len_t length;
-
-               if (tdb->transaction->blocks[i] == NULL) {
-                       continue;
-               }
-
-               offset = i * tdb->transaction->block_size;
-               length = tdb->transaction->block_size;
-               if (i == tdb->transaction->num_blocks-1) {
-                       length = tdb->transaction->last_block_size;
-               }
-               
-               if (offset >= old_map_size) {
-                       continue;
-               }
-               if (offset + length > tdb->transaction->old_map_size) {
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: transaction data over new region boundary\n"));
-                       free(data);
-                       tdb->ecode = TDB_ERR_CORRUPT;
-                       return -1;
-               }
-               memcpy(p, &offset, 4);
-               memcpy(p+4, &length, 4);
-               if (DOCONV()) {
-                       tdb_convert(p, 8);
-               }
-               /* the recovery area contains the old data, not the
-                  new data, so we have to call the original tdb_read
-                  method to get it */
-               if (methods->tdb_read(tdb, offset, p + 8, length, 0) != 0) {
-                       free(data);
-                       tdb->ecode = TDB_ERR_IO;
-                       return -1;
-               }
-               p += 8 + length;
-       }
-
-       /* and the tailer */
-       tailer = sizeof(*rec) + recovery_max_size;
-       memcpy(p, &tailer, 4);
-       CONVERT(p);
-
-       /* write the recovery data to the recovery area */
-       if (methods->tdb_write(tdb, recovery_offset, data, sizeof(*rec) + recovery_size) == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: failed to write recovery data\n"));
-               free(data);
-               tdb->ecode = TDB_ERR_IO;
-               return -1;
-       }
-       if (transaction_write_existing(tdb, recovery_offset, data, sizeof(*rec) + recovery_size) == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: failed to write secondary recovery data\n"));
-               free(data);
-               tdb->ecode = TDB_ERR_IO;
-               return -1;
-       }
-
-       /* as we don't have ordered writes, we have to sync the recovery
-          data before we update the magic to indicate that the recovery
-          data is present */
-       if (transaction_sync(tdb, recovery_offset, sizeof(*rec) + recovery_size) == -1) {
-               free(data);
-               return -1;
-       }
-
-       free(data);
-
-       magic = TDB_RECOVERY_MAGIC;
-       CONVERT(magic);
-
-       *magic_offset = recovery_offset + offsetof(struct tdb_record, magic);
-
-       if (methods->tdb_write(tdb, *magic_offset, &magic, sizeof(magic)) == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: failed to write recovery magic\n"));
-               tdb->ecode = TDB_ERR_IO;
-               return -1;
-       }
-       if (transaction_write_existing(tdb, *magic_offset, &magic, sizeof(magic)) == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: failed to write secondary recovery magic\n"));
-               tdb->ecode = TDB_ERR_IO;
-               return -1;
-       }
-
-       /* ensure the recovery magic marker is on disk */
-       if (transaction_sync(tdb, *magic_offset, sizeof(magic)) == -1) {
-               return -1;
-       }
-
-       return 0;
-}
-
-static int _tdb_transaction_prepare_commit(struct tdb_context *tdb)
-{      
-       const struct tdb_methods *methods;
-
-       if (tdb->transaction == NULL) {
-               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: no transaction\n"));
-               return -1;
-       }
-
-       if (tdb->transaction->prepared) {
-               tdb->ecode = TDB_ERR_EINVAL;
-               _tdb_transaction_cancel(tdb);
-               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: transaction already prepared\n"));
-               return -1;
-       }
-
-       if (tdb->transaction->transaction_error) {
-               tdb->ecode = TDB_ERR_IO;
-               _tdb_transaction_cancel(tdb);
-               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: transaction error pending\n"));
-               return -1;
-       }
-
-
-       if (tdb->transaction->nesting != 0) {
-               tdb->transaction->nesting--;
-               return 0;
-       }               
-
-       /* check for a null transaction */
-       if (tdb->transaction->blocks == NULL) {
-               return 0;
-       }
-
-       methods = tdb->transaction->io_methods;
-       
-       /* if there are any locks pending then the caller has not
-          nested their locks properly, so fail the transaction */
-       if (tdb_have_extra_locks(tdb)) {
-               tdb->ecode = TDB_ERR_LOCK;
-               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: locks pending on commit\n"));
-               _tdb_transaction_cancel(tdb);
-               return -1;
-       }
-
-       /* upgrade the main transaction lock region to a write lock */
-       if (tdb_allrecord_upgrade(tdb) == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: failed to upgrade hash locks\n"));
-               _tdb_transaction_cancel(tdb);
-               return -1;
-       }
-
-       /* get the open lock - this prevents new users attaching to the database
-          during the commit */
-       if (tdb_nest_lock(tdb, OPEN_LOCK, F_WRLCK, TDB_LOCK_WAIT) == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: failed to get open lock\n"));
-               _tdb_transaction_cancel(tdb);
-               return -1;
-       }
-
-       if (!(tdb->flags & TDB_NOSYNC)) {
-               /* write the recovery data to the end of the file */
-               if (transaction_setup_recovery(tdb, &tdb->transaction->magic_offset) == -1) {
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_prepare_commit: failed to setup recovery data\n"));
-                       _tdb_transaction_cancel(tdb);
-                       return -1;
-               }
-       }
-
-       tdb->transaction->prepared = true;
-
-       /* expand the file to the new size if needed */
-       if (tdb->map_size != tdb->transaction->old_map_size) {
-               if (methods->tdb_expand_file(tdb, tdb->transaction->old_map_size, 
-                                            tdb->map_size - 
-                                            tdb->transaction->old_map_size) == -1) {
-                       tdb->ecode = TDB_ERR_IO;
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_prepare_commit: expansion failed\n"));
-                       _tdb_transaction_cancel(tdb);
-                       return -1;
-               }
-               tdb->map_size = tdb->transaction->old_map_size;
-               methods->tdb_oob(tdb, tdb->map_size + 1, 1);
-       }
-
-       /* Keep the open lock until the actual commit */
-
-       return 0;
-}
-
-/*
-   prepare to commit the current transaction
-*/
-int tdb_transaction_prepare_commit(struct tdb_context *tdb)
-{      
-       tdb_trace(tdb, "tdb_transaction_prepare_commit");
-       return _tdb_transaction_prepare_commit(tdb);
-}
-
-/*
-  commit the current transaction
-*/
-int tdb_transaction_commit(struct tdb_context *tdb)
-{      
-       const struct tdb_methods *methods;
-       int i;
-       bool need_repack;
-
-       if (tdb->transaction == NULL) {
-               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: no transaction\n"));
-               return -1;
-       }
-
-       tdb_trace(tdb, "tdb_transaction_commit");
-
-       if (tdb->transaction->transaction_error) {
-               tdb->ecode = TDB_ERR_IO;
-               tdb_transaction_cancel(tdb);
-               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: transaction error pending\n"));
-               return -1;
-       }
-
-
-       if (tdb->transaction->nesting != 0) {
-               tdb->transaction->nesting--;
-               return 0;
-       }
-
-       /* check for a null transaction */
-       if (tdb->transaction->blocks == NULL) {
-               _tdb_transaction_cancel(tdb);
-               return 0;
-       }
-
-       if (!tdb->transaction->prepared) {
-               int ret = _tdb_transaction_prepare_commit(tdb);
-               if (ret)
-                       return ret;
-       }
-
-       methods = tdb->transaction->io_methods;
-
-       /* perform all the writes */
-       for (i=0;i<tdb->transaction->num_blocks;i++) {
-               tdb_off_t offset;
-               tdb_len_t length;
-
-               if (tdb->transaction->blocks[i] == NULL) {
-                       continue;
-               }
-
-               offset = i * tdb->transaction->block_size;
-               length = tdb->transaction->block_size;
-               if (i == tdb->transaction->num_blocks-1) {
-                       length = tdb->transaction->last_block_size;
-               }
-
-               if (methods->tdb_write(tdb, offset, tdb->transaction->blocks[i], length) == -1) {
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: write failed during commit\n"));
-                       
-                       /* we've overwritten part of the data and
-                          possibly expanded the file, so we need to
-                          run the crash recovery code */
-                       tdb->methods = methods;
-                       tdb_transaction_recover(tdb); 
-
-                       _tdb_transaction_cancel(tdb);
-
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: write failed\n"));
-                       return -1;
-               }
-               SAFE_FREE(tdb->transaction->blocks[i]);
-       } 
-
-       SAFE_FREE(tdb->transaction->blocks);
-       tdb->transaction->num_blocks = 0;
-
-       /* ensure the new data is on disk */
-       if (transaction_sync(tdb, 0, tdb->map_size) == -1) {
-               return -1;
-       }
-
-       /*
-         TODO: maybe write to some dummy hdr field, or write to magic
-         offset without mmap, before the last sync, instead of the
-         utime() call
-       */
-
-       /* on some systems (like Linux 2.6.x) changes via mmap/msync
-          don't change the mtime of the file, this means the file may
-          not be backed up (as tdb rounding to block sizes means that
-          file size changes are quite rare too). The following forces
-          mtime changes when a transaction completes */
-#if HAVE_UTIME
-       utime(tdb->name, NULL);
-#endif
-
-       need_repack = tdb->transaction->need_repack;
-
-       /* use a transaction cancel to free memory and remove the
-          transaction locks */
-       _tdb_transaction_cancel(tdb);
-
-       if (need_repack) {
-               return tdb_repack(tdb);
-       }
-
-       return 0;
-}
-
-
-/*
-  recover from an aborted transaction. Must be called with exclusive
-  database write access already established (including the open
-  lock to prevent new processes attaching)
-*/
-int tdb_transaction_recover(struct tdb_context *tdb)
-{
-       tdb_off_t recovery_head, recovery_eof;
-       unsigned char *data, *p;
-       uint32_t zero = 0;
-       struct tdb_record rec;
-
-       /* find the recovery area */
-       if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to read recovery head\n"));
-               tdb->ecode = TDB_ERR_IO;
-               return -1;
-       }
-
-       if (recovery_head == 0) {
-               /* we have never allocated a recovery record */
-               return 0;
-       }
-
-       /* read the recovery record */
-       if (tdb->methods->tdb_read(tdb, recovery_head, &rec, 
-                                  sizeof(rec), DOCONV()) == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to read recovery record\n"));           
-               tdb->ecode = TDB_ERR_IO;
-               return -1;
-       }
-
-       if (rec.magic != TDB_RECOVERY_MAGIC) {
-               /* there is no valid recovery data */
-               return 0;
-       }
-
-       if (tdb->read_only) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: attempt to recover read only database\n"));
-               tdb->ecode = TDB_ERR_CORRUPT;
-               return -1;
-       }
-
-       recovery_eof = rec.key_len;
-
-       data = (unsigned char *)malloc(rec.data_len);
-       if (data == NULL) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to allocate recovery data\n"));         
-               tdb->ecode = TDB_ERR_OOM;
-               return -1;
-       }
-
-       /* read the full recovery data */
-       if (tdb->methods->tdb_read(tdb, recovery_head + sizeof(rec), data,
-                                  rec.data_len, 0) == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to read recovery data\n"));             
-               tdb->ecode = TDB_ERR_IO;
-               return -1;
-       }
-
-       /* recover the file data */
-       p = data;
-       while (p+8 < data + rec.data_len) {
-               uint32_t ofs, len;
-               if (DOCONV()) {
-                       tdb_convert(p, 8);
-               }
-               memcpy(&ofs, p, 4);
-               memcpy(&len, p+4, 4);
-
-               if (tdb->methods->tdb_write(tdb, ofs, p+8, len) == -1) {
-                       free(data);
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to recover %d bytes at offset %d\n", len, ofs));
-                       tdb->ecode = TDB_ERR_IO;
-                       return -1;
-               }
-               p += 8 + len;
-       }
-
-       free(data);
-
-       if (transaction_sync(tdb, 0, tdb->map_size) == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to sync recovery\n"));
-               tdb->ecode = TDB_ERR_IO;
-               return -1;
-       }
-
-       /* if the recovery area is after the recovered eof then remove it */
-       if (recovery_eof <= recovery_head) {
-               if (tdb_ofs_write(tdb, TDB_RECOVERY_HEAD, &zero) == -1) {
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to remove recovery head\n"));
-                       tdb->ecode = TDB_ERR_IO;
-                       return -1;                      
-               }
-       }
-
-       /* remove the recovery magic */
-       if (tdb_ofs_write(tdb, recovery_head + offsetof(struct tdb_record, magic),
-                         &zero) == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to remove recovery magic\n"));
-               tdb->ecode = TDB_ERR_IO;
-               return -1;                      
-       }
-       
-       if (transaction_sync(tdb, 0, recovery_eof) == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to sync2 recovery\n"));
-               tdb->ecode = TDB_ERR_IO;
-               return -1;
-       }
-
-       TDB_LOG((tdb, TDB_DEBUG_TRACE, "tdb_transaction_recover: recovered %d byte database\n", 
-                recovery_eof));
-
-       /* all done */
-       return 0;
-}
-
-/* Any I/O failures we say "needs recovery". */
-bool tdb_needs_recovery(struct tdb_context *tdb)
-{
-       tdb_off_t recovery_head;
-       struct tdb_record rec;
-
-       /* find the recovery area */
-       if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) {
-               return true;
-       }
-
-       if (recovery_head == 0) {
-               /* we have never allocated a recovery record */
-               return false;
-       }
-
-       /* read the recovery record */
-       if (tdb->methods->tdb_read(tdb, recovery_head, &rec,
-                                  sizeof(rec), DOCONV()) == -1) {
-               return true;
-       }
-
-       return (rec.magic == TDB_RECOVERY_MAGIC);
-}
diff --git a/ccan/tdb/traverse.c b/ccan/tdb/traverse.c
deleted file mode 100644 (file)
index c605c8e..0000000
+++ /dev/null
@@ -1,366 +0,0 @@
- /* 
-   Unix SMB/CIFS implementation.
-
-   trivial database library
-
-   Copyright (C) Andrew Tridgell              1999-2005
-   Copyright (C) Paul `Rusty' Russell             2000
-   Copyright (C) Jeremy Allison                           2000-2003
-   
-     ** NOTE! The following LGPL license applies to the tdb
-     ** library. This does NOT imply that all of Samba is released
-     ** under the LGPL
-   
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "tdb_private.h"
-
-#define TDB_NEXT_LOCK_ERR ((tdb_off_t)-1)
-
-/* Uses traverse lock: 0 = finish, TDB_NEXT_LOCK_ERR = error,
-   other = record offset */
-static tdb_off_t tdb_next_lock(struct tdb_context *tdb, struct tdb_traverse_lock *tlock,
-                        struct tdb_record *rec)
-{
-       int want_next = (tlock->off != 0);
-
-       /* Lock each chain from the start one. */
-       for (; tlock->hash < tdb->header.hash_size; tlock->hash++) {
-               if (!tlock->off && tlock->hash != 0) {
-                       /* this is an optimization for the common case where
-                          the hash chain is empty, which is particularly
-                          common for the use of tdb with ldb, where large
-                          hashes are used. In that case we spend most of our
-                          time in tdb_brlock(), locking empty hash chains.
-                          
-                          To avoid this, we do an unlocked pre-check to see
-                          if the hash chain is empty before starting to look
-                          inside it. If it is empty then we can avoid that
-                          hash chain. If it isn't empty then we can't believe
-                          the value we get back, as we read it without a
-                          lock, so instead we get the lock and re-fetch the
-                          value below.
-                          
-                          Notice that not doing this optimization on the
-                          first hash chain is critical. We must guarantee
-                          that we have done at least one fcntl lock at the
-                          start of a search to guarantee that memory is
-                          coherent on SMP systems. If records are added by
-                          others during the search then thats OK, and we
-                          could possibly miss those with this trick, but we
-                          could miss them anyway without this trick, so the
-                          semantics don't change.
-                          
-                          With a non-indexed ldb search this trick gains us a
-                          factor of around 80 in speed on a linux 2.6.x
-                          system (testing using ldbtest).
-                       */
-                       tdb->methods->next_hash_chain(tdb, &tlock->hash);
-                       if (tlock->hash == tdb->header.hash_size) {
-                               continue;
-                       }
-               }
-
-               if (tdb_lock(tdb, tlock->hash, tlock->lock_rw) == -1)
-                       return TDB_NEXT_LOCK_ERR;
-
-               /* No previous record?  Start at top of chain. */
-               if (!tlock->off) {
-                       if (tdb_ofs_read(tdb, TDB_HASH_TOP(tlock->hash),
-                                    &tlock->off) == -1)
-                               goto fail;
-               } else {
-                       /* Otherwise unlock the previous record. */
-                       if (tdb_unlock_record(tdb, tlock->off) != 0)
-                               goto fail;
-               }
-
-               if (want_next) {
-                       /* We have offset of old record: grab next */
-                       if (tdb_rec_read(tdb, tlock->off, rec) == -1)
-                               goto fail;
-                       tlock->off = rec->next;
-               }
-
-               /* Iterate through chain */
-               while( tlock->off) {
-                       tdb_off_t current;
-                       if (tdb_rec_read(tdb, tlock->off, rec) == -1)
-                               goto fail;
-
-                       /* Detect infinite loops. From "Shlomi Yaakobovich" <Shlomi@exanet.com>. */
-                       if (tlock->off == rec->next) {
-                               tdb->ecode = TDB_ERR_CORRUPT;
-                               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_next_lock: loop detected.\n"));
-                               goto fail;
-                       }
-
-                       if (!TDB_DEAD(rec)) {
-                               /* Woohoo: we found one! */
-                               if (tdb_lock_record(tdb, tlock->off) != 0)
-                                       goto fail;
-                               return tlock->off;
-                       }
-
-                       /* Try to clean dead ones from old traverses */
-                       current = tlock->off;
-                       tlock->off = rec->next;
-                       if (!(tdb->read_only || tdb->traverse_read) && 
-                           tdb_do_delete(tdb, current, rec) != 0)
-                               goto fail;
-               }
-               tdb_unlock(tdb, tlock->hash, tlock->lock_rw);
-               want_next = 0;
-       }
-       /* We finished iteration without finding anything */
-       tdb->ecode = TDB_SUCCESS;
-       return 0;
-
- fail:
-       tlock->off = 0;
-       if (tdb_unlock(tdb, tlock->hash, tlock->lock_rw) != 0)
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_next_lock: On error unlock failed!\n"));
-       return TDB_NEXT_LOCK_ERR;
-}
-
-/* traverse the entire database - calling fn(tdb, key, data) on each element.
-   return -1 on error or the record count traversed
-   if fn is NULL then it is not called
-   a non-zero return value from fn() indicates that the traversal should stop
-  */
-static int tdb_traverse_internal(struct tdb_context *tdb, 
-                                tdb_traverse_func fn, void *private_data,
-                                struct tdb_traverse_lock *tl)
-{
-       TDB_DATA key, dbuf;
-       struct tdb_record rec;
-       int ret = 0, count = 0;
-       tdb_off_t off;
-
-       /* This was in the initializaton, above, but the IRIX compiler
-        * did not like it.  crh
-        */
-       tl->next = tdb->travlocks.next;
-
-       /* fcntl locks don't stack: beware traverse inside traverse */
-       tdb->travlocks.next = tl;
-
-       /* tdb_next_lock places locks on the record returned, and its chain */
-       while ((off = tdb_next_lock(tdb, tl, &rec)) != 0) {
-               if (off == TDB_NEXT_LOCK_ERR) {
-                       ret = -1;
-                       goto out;
-               }
-               count++;
-               /* now read the full record */
-               key.dptr = tdb_alloc_read(tdb, tl->off + sizeof(rec), 
-                                         rec.key_len + rec.data_len);
-               if (!key.dptr) {
-                       ret = -1;
-                       if (tdb_unlock(tdb, tl->hash, tl->lock_rw) != 0)
-                               goto out;
-                       if (tdb_unlock_record(tdb, tl->off) != 0)
-                               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_traverse: key.dptr == NULL and unlock_record failed!\n"));
-                       goto out;
-               }
-               key.dsize = rec.key_len;
-               dbuf.dptr = key.dptr + rec.key_len;
-               dbuf.dsize = rec.data_len;
-
-               tdb_trace_1rec_retrec(tdb, "traverse", key, dbuf);
-
-               /* Drop chain lock, call out */
-               if (tdb_unlock(tdb, tl->hash, tl->lock_rw) != 0) {
-                       ret = -1;
-                       SAFE_FREE(key.dptr);
-                       goto out;
-               }
-               if (fn && fn(tdb, key, dbuf, private_data)) {
-                       /* They want us to terminate traversal */
-                       tdb_trace_ret(tdb, "tdb_traverse_end", count);
-                       if (tdb_unlock_record(tdb, tl->off) != 0) {
-                               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_traverse: unlock_record failed!\n"));;
-                               ret = -1;
-                       }
-                       SAFE_FREE(key.dptr);
-                       goto out;
-               }
-               SAFE_FREE(key.dptr);
-       }
-       tdb_trace(tdb, "tdb_traverse_end");
-out:
-       tdb->travlocks.next = tl->next;
-       if (ret < 0)
-               return -1;
-       else
-               return count;
-}
-
-
-/*
-  a write style traverse - temporarily marks the db read only
-*/
-int tdb_traverse_read(struct tdb_context *tdb, 
-                     tdb_traverse_func fn, void *private_data)
-{
-       struct tdb_traverse_lock tl = { NULL, 0, 0, F_RDLCK };
-       int ret;
-
-       /* we need to get a read lock on the transaction lock here to
-          cope with the lock ordering semantics of solaris10 */
-       if (tdb_transaction_lock(tdb, F_RDLCK)) {
-               return -1;
-       }
-
-       tdb->traverse_read++;
-       tdb_trace(tdb, "tdb_traverse_read_start");
-       ret = tdb_traverse_internal(tdb, fn, private_data, &tl);
-       tdb->traverse_read--;
-
-       tdb_transaction_unlock(tdb, F_RDLCK);
-
-       return ret;
-}
-
-/*
-  a write style traverse - needs to get the transaction lock to
-  prevent deadlocks
-
-  WARNING: The data buffer given to the callback fn does NOT meet the
-  alignment restrictions malloc gives you.
-*/
-int tdb_traverse(struct tdb_context *tdb, 
-                tdb_traverse_func fn, void *private_data)
-{
-       struct tdb_traverse_lock tl = { NULL, 0, 0, F_WRLCK };
-       int ret;
-
-       if (tdb->read_only || tdb->traverse_read) {
-               return tdb_traverse_read(tdb, fn, private_data);
-       }
-
-       if (tdb_transaction_lock(tdb, F_WRLCK)) {
-               return -1;
-       }
-
-       tdb->traverse_write++;
-       tdb_trace(tdb, "tdb_traverse_start");
-       ret = tdb_traverse_internal(tdb, fn, private_data, &tl);
-       tdb->traverse_write--;
-
-       tdb_transaction_unlock(tdb, F_WRLCK);
-
-       return ret;
-}
-
-
-/* find the first entry in the database and return its key */
-TDB_DATA tdb_firstkey(struct tdb_context *tdb)
-{
-       TDB_DATA key;
-       struct tdb_record rec;
-       tdb_off_t off;
-
-       /* release any old lock */
-       if (tdb_unlock_record(tdb, tdb->travlocks.off) != 0)
-               return tdb_null;
-       tdb->travlocks.off = tdb->travlocks.hash = 0;
-       tdb->travlocks.lock_rw = F_RDLCK;
-
-       /* Grab first record: locks chain and returned record. */
-       off = tdb_next_lock(tdb, &tdb->travlocks, &rec);
-       if (off == 0 || off == TDB_NEXT_LOCK_ERR) {
-               tdb_trace_retrec(tdb, "tdb_firstkey", tdb_null);
-               return tdb_null;
-       }
-       /* now read the key */
-       key.dsize = rec.key_len;
-       key.dptr =tdb_alloc_read(tdb,tdb->travlocks.off+sizeof(rec),key.dsize);
-
-       tdb_trace_retrec(tdb, "tdb_firstkey", key);
-
-       /* Unlock the hash chain of the record we just read. */
-       if (tdb_unlock(tdb, tdb->travlocks.hash, tdb->travlocks.lock_rw) != 0)
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_firstkey: error occurred while tdb_unlocking!\n"));
-       return key;
-}
-
-/* find the next entry in the database, returning its key */
-TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA oldkey)
-{
-       uint32_t oldhash;
-       TDB_DATA key = tdb_null;
-       struct tdb_record rec;
-       unsigned char *k = NULL;
-       tdb_off_t off;
-
-       /* Is locked key the old key?  If so, traverse will be reliable. */
-       if (tdb->travlocks.off) {
-               if (tdb_lock(tdb,tdb->travlocks.hash,tdb->travlocks.lock_rw))
-                       return tdb_null;
-               if (tdb_rec_read(tdb, tdb->travlocks.off, &rec) == -1
-                   || !(k = tdb_alloc_read(tdb,tdb->travlocks.off+sizeof(rec),
-                                           rec.key_len))
-                   || memcmp(k, oldkey.dptr, oldkey.dsize) != 0) {
-                       /* No, it wasn't: unlock it and start from scratch */
-                       if (tdb_unlock_record(tdb, tdb->travlocks.off) != 0) {
-                               tdb_trace_1rec_retrec(tdb, "tdb_nextkey",
-                                                     oldkey, tdb_null);
-                               SAFE_FREE(k);
-                               return tdb_null;
-                       }
-                       if (tdb_unlock(tdb, tdb->travlocks.hash, tdb->travlocks.lock_rw) != 0) {
-                               SAFE_FREE(k);
-                               return tdb_null;
-                       }
-                       tdb->travlocks.off = 0;
-               }
-
-               SAFE_FREE(k);
-       }
-
-       if (!tdb->travlocks.off) {
-               /* No previous element: do normal find, and lock record */
-               tdb->travlocks.off = tdb_find_lock_hash(tdb, oldkey, tdb->hash_fn(&oldkey), tdb->travlocks.lock_rw, &rec);
-               if (!tdb->travlocks.off) {
-                       tdb_trace_1rec_retrec(tdb, "tdb_nextkey", oldkey, tdb_null);
-                       return tdb_null;
-               }
-               tdb->travlocks.hash = BUCKET(rec.full_hash);
-               if (tdb_lock_record(tdb, tdb->travlocks.off) != 0) {
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_nextkey: lock_record failed (%s)!\n", strerror(errno)));
-                       return tdb_null;
-               }
-       }
-       oldhash = tdb->travlocks.hash;
-
-       /* Grab next record: locks chain and returned record,
-          unlocks old record */
-       off = tdb_next_lock(tdb, &tdb->travlocks, &rec);
-       if (off != TDB_NEXT_LOCK_ERR && off != 0) {
-               key.dsize = rec.key_len;
-               key.dptr = tdb_alloc_read(tdb, tdb->travlocks.off+sizeof(rec),
-                                         key.dsize);
-               /* Unlock the chain of this new record */
-               if (tdb_unlock(tdb, tdb->travlocks.hash, tdb->travlocks.lock_rw) != 0)
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_nextkey: WARNING tdb_unlock failed!\n"));
-       }
-       /* Unlock the chain of old record */
-       if (tdb_unlock(tdb, BUCKET(oldhash), tdb->travlocks.lock_rw) != 0)
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_nextkey: WARNING tdb_unlock failed!\n"));
-       tdb_trace_1rec_retrec(tdb, "tdb_nextkey", oldkey, key);
-       return key;
-}
-