1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-27 03:21:53 +03:00
samba-mirror/source3/tdb/tools/tdbtest.c
Jeremy Allison cc13e21dbe r19959: Allow tdb to be built standalone in Samba3.
Add code to check for loops in the free list.
Should help us validate tdb's against corruption.
Jeremy.
(This used to be commit f8e7386773)
2007-10-10 12:16:15 -05:00

266 lines
4.8 KiB
C

/* a test program for tdb - the trivial database */
#include "replace.h"
#include "tdb.h"
#include "system/filesys.h"
#include "system/time.h"
#include <gdbm.h>
#define DELETE_PROB 7
#define STORE_PROB 5
static struct tdb_context *db;
static GDBM_FILE gdbm;
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 fatal(const char *why)
{
perror(why);
exit(1);
}
#ifdef PRINTF_ATTRIBUTE
static void tdb_log(struct tdb_context *tdb, int level, const char *format, ...) PRINTF_ATTRIBUTE(3,4);
#endif
static void tdb_log(struct tdb_context *tdb, int level, const char *format, ...)
{
va_list ap;
va_start(ap, format);
vfprintf(stdout, format, ap);
va_end(ap);
fflush(stdout);
}
static void compare_db(void)
{
TDB_DATA d, key, nextkey;
datum gd, gkey, gnextkey;
key = tdb_firstkey(db);
while (key.dptr) {
d = tdb_fetch(db, key);
gkey.dptr = key.dptr;
gkey.dsize = key.dsize;
gd = gdbm_fetch(gdbm, gkey);
if (!gd.dptr) fatal("key not in gdbm");
if (gd.dsize != d.dsize) fatal("data sizes differ");
if (memcmp(gd.dptr, d.dptr, d.dsize)) {
fatal("data differs");
}
nextkey = tdb_nextkey(db, key);
free(key.dptr);
free(d.dptr);
free(gd.dptr);
key = nextkey;
}
gkey = gdbm_firstkey(gdbm);
while (gkey.dptr) {
gd = gdbm_fetch(gdbm, gkey);
key.dptr = gkey.dptr;
key.dsize = gkey.dsize;
d = tdb_fetch(db, key);
if (!d.dptr) fatal("key not in db");
if (d.dsize != gd.dsize) fatal("data sizes differ");
if (memcmp(d.dptr, gd.dptr, gd.dsize)) {
fatal("data differs");
}
gnextkey = gdbm_nextkey(gdbm, gkey);
free(gkey.dptr);
free(gd.dptr);
free(d.dptr);
gkey = gnextkey;
}
}
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)
{
int klen, dlen;
char *k, *d;
TDB_DATA key, data;
klen = 1 + (rand() % 4);
dlen = 1 + (rand() % 100);
k = randbuf(klen);
d = randbuf(dlen);
key.dptr = k;
key.dsize = klen+1;
data.dptr = d;
data.dsize = dlen+1;
if (rand() % DELETE_PROB == 0) {
tdb_delete(db, key);
} else if (rand() % STORE_PROB == 0) {
if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
fatal("tdb_store failed");
}
} else {
data = tdb_fetch(db, key);
if (data.dptr) free(data.dptr);
}
free(k);
free(d);
}
static void addrec_gdbm(void)
{
int klen, dlen;
char *k, *d;
datum key, data;
klen = 1 + (rand() % 4);
dlen = 1 + (rand() % 100);
k = randbuf(klen);
d = randbuf(dlen);
key.dptr = k;
key.dsize = klen+1;
data.dptr = d;
data.dsize = dlen+1;
if (rand() % DELETE_PROB == 0) {
gdbm_delete(gdbm, key);
} else if (rand() % STORE_PROB == 0) {
if (gdbm_store(gdbm, key, data, GDBM_REPLACE) != 0) {
fatal("gdbm_store failed");
}
} else {
data = gdbm_fetch(gdbm, key);
if (data.dptr) free(data.dptr);
}
free(k);
free(d);
}
static int traverse_fn(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
{
#if 0
printf("[%s] [%s]\n", key.dptr, dbuf.dptr);
#endif
tdb_delete(tdb, key);
return 0;
}
static void merge_test(void)
{
int i;
char keys[5][2];
char tdata[] = "test";
TDB_DATA key, data;
for (i = 0; i < 5; i++) {
snprintf(keys[i],2, "%d", i);
key.dptr = keys[i];
key.dsize = 2;
data.dptr = tdata;
data.dsize = 4;
if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
fatal("tdb_store failed");
}
}
key.dptr = keys[0];
tdb_delete(db, key);
key.dptr = keys[4];
tdb_delete(db, key);
key.dptr = keys[2];
tdb_delete(db, key);
key.dptr = keys[1];
tdb_delete(db, key);
key.dptr = keys[3];
tdb_delete(db, key);
}
int main(int argc, const char *argv[])
{
int i, seed=0;
int loops = 10000;
int num_entries;
char test_gdbm[] = "test.gdbm";
unlink("test.gdbm");
db = tdb_open("test.tdb", 0, TDB_CLEAR_IF_FIRST,
O_RDWR | O_CREAT | O_TRUNC, 0600);
gdbm = gdbm_open(test_gdbm, 512, GDBM_WRITER|GDBM_NEWDB|GDBM_FAST,
0600, NULL);
if (!db || !gdbm) {
fatal("db open failed");
}
#if 1
srand(seed);
_start_timer();
for (i=0;i<loops;i++) addrec_gdbm();
printf("gdbm got %.2f ops/sec\n", i/_end_timer());
#endif
merge_test();
srand(seed);
_start_timer();
for (i=0;i<loops;i++) addrec_db();
printf("tdb got %.2f ops/sec\n", i/_end_timer());
if (tdb_validate_freelist(db, &num_entries) == -1) {
printf("tdb freelist is corrupt\n");
} else {
printf("tdb freelist is good (%d entries)\n", num_entries);
}
compare_db();
printf("traversed %d records\n", tdb_traverse(db, traverse_fn, NULL));
printf("traversed %d records\n", tdb_traverse(db, traverse_fn, NULL));
tdb_close(db);
gdbm_close(gdbm);
return 0;
}