/* $Id: db-tdb.c,v 1.14 2011/10/10 13:36:29 nicm Exp $ */

/*
 * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/types.h>
#include <sys/stat.h>

#include <fcntl.h>
#include <signal.h>
#include <string.h>
#ifndef _PUBLIC_
#define _PUBLIC_
#endif
#include <tdb.h>

#include "fdm.h"

int	db_print_item(TDB_CONTEXT *, TDB_DATA, TDB_DATA, void *);
int	db_expire_item(TDB_CONTEXT *, TDB_DATA, TDB_DATA, void *);
int	db_clear_item(TDB_CONTEXT *, TDB_DATA, TDB_DATA, void *);

TDB_CONTEXT *
db_open(char *path)
{
	TDB_CONTEXT	*db;

#ifndef DB_UNSAFE
	db = tdb_open(path, 0, 0, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
#else
	db = tdb_open(path, 0, TDB_NOLOCK, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
#endif
	return (db);
}

void
db_close(TDB_CONTEXT *db)
{
	tdb_close(db);
}

int
db_add(TDB_CONTEXT *db, char *k)
{
	TDB_DATA		key, value;
	struct cacheitem	v;
	uint64_t		tim;

	memset(&v, 0, sizeof v);
	tim = time(NULL);
	v.tim = htole64(tim);

	key.dptr = k;
	key.dsize = strlen(k);

	value.dptr = (char *) &v;
	value.dsize = sizeof v;

	return (tdb_store(db, key, value, TDB_REPLACE));
}

int
db_remove(TDB_CONTEXT *db, char *k)
{
	TDB_DATA		key;

	key.dptr = k;
	key.dsize = strlen(k);

	return (tdb_delete(db, key));
}

int
db_contains(TDB_CONTEXT *db, char *k)
{
	TDB_DATA	key;

	key.dptr = k;
	key.dsize = strlen(k);

	return (tdb_exists(db, key));
}

int
db_size(TDB_CONTEXT *db)
{
	return (tdb_traverse(db, NULL, NULL));
}

int
db_print_item(
    unused TDB_CONTEXT *tdb, unused TDB_DATA key, TDB_DATA value, void *ptr)
{
	void 			(*p)(const char *, ...) = ptr;
	struct cacheitem	v;
	uint64_t		tim;

 	if (value.dsize != sizeof v)
		return (-1);
	memcpy(&v, value.dptr, sizeof v);

	tim = letoh64(v.tim);
	p("%.*s %llu", key.dsize, key.dptr, (unsigned long long) tim);

	return (0);
}

int
db_print(TDB_CONTEXT *db, void (*p)(const char *, ...))
{
	if (tdb_traverse(db, db_print_item, p) == -1)
		return (-1);
	return (0);
}

int
db_expire_item(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA value, void *ptr)
{
	uint64_t	       *lim = ptr;
	struct cacheitem	v;

 	if (value.dsize != sizeof v)
		return (-1);
	memcpy(&v, value.dptr, sizeof v);

	if (letoh64(v.tim) < *lim)
		return (tdb_delete(tdb, key));
	return (0);
}

int
db_expire(TDB_CONTEXT *db, uint64_t age)
{
	uint64_t	lim;

	lim = time(NULL);
	if (lim <= age)
		return (0);
	lim -= age;

	if (tdb_traverse(db, db_expire_item, &lim) == -1)
		return (-1);
	return (0);
}

int
db_clear_item(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA value, unused void *ptr)
{
 	if (value.dsize != sizeof (struct cacheitem))
		return (-1);

	return (tdb_delete(tdb, key));
}

int
db_clear(TDB_CONTEXT *db)
{
	if (tdb_traverse(db, db_clear_item, NULL) == -1)
		return (-1);
	return (0);
}
