/* $Id: dbexp.c,v 1.5 2005/09/20 19:13:03 dm Exp $ */
/*
*
* Copyright (C) 2004 David Mazieres (dm@uun.org)
*
* 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 2, 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
*/
#include "avutil.h"
#include "dbexp.h"
#define RECOVLK "recov.lock"
static int
_dbenv_init_lockfd (dbenv *dbe, const char *path)
{
struct stat sb;
char *pb;
mode_t m;
if (!stat (path, &sb)) {
if (!S_ISDIR (sb.st_mode)) {
fprintf (stderr, "%s: not a directory\n", path);
return ENOTDIR;
}
}
else if (errno != ENOENT) {
perror (path);
return errno;
}
else if (mkdir (path, 0700)) {
perror (path);
return errno;
}
pb = xmalloc (strlen (path) + sizeof (RECOVLK) + 1);
sprintf (pb, "%s/%s", path, RECOVLK);
m = umask (0);
umask (m);
if (m & 02)
m |= 04;
if (m & 020)
m |= 040;
dbe->lockfd = open (pb, O_CREAT|O_RDWR, 0666 & ~m);
if (dbe->lockfd < 0) {
perror (pb);
free (pb);
return errno;
}
free (pb);
return 0;
}
dbenv *
dbenv_alloc (const char *path)
{
int err;
int recover = DB_RECOVER;
dbenv *dbe = xmalloc (sizeof (*dbe));
bzero (dbe, sizeof (*dbe));
err = db_env_create (&dbe->e, 0);
if (err) {
fprintf (stderr, "db_env_create: %s\n", db_strerror (err));
return NULL;
}
if (!path) {
err = dbe->e->open (dbe->e, NULL,
DB_PRIVATE|DB_CREATE|DB_INIT_MPOOL, 0666);
if (!err)
return dbe;
fprintf (stderr, "dbenv_open: %s\n", db_strerror (err));
dbe->e->close (dbe->e, 0);
free (dbe);
return NULL;
}
if (_dbenv_init_lockfd (dbe, path)) {
dbe->e->close (dbe->e, 0);
free (dbe);
return NULL;
}
if (flock (dbe->lockfd, LOCK_EX|LOCK_NB)) {
recover = 0;
if (flock (dbe->lockfd, LOCK_SH)) {
fprintf (stderr, "%s/%s: %s\n", path, RECOVLK, strerror (errno));
close (dbe->lockfd);
dbe->e->close (dbe->e, 0);
free (dbe);
return NULL;
}
}
#if 0
/* For debugging: */
err = dbe->e->set_lg_bsize (dbe->e, 25 * 1024);
if (err)
fprintf (stderr, "set_lg_bsize: %s\n", db_strerror (err));
dbe->e->set_lg_max (dbe->e, 100 * 1024);
if (err)
fprintf (stderr, "set_lg_size: %s\n", db_strerror (err));
#endif
err = dbe->e->open (dbe->e, path,
(DB_INIT_MPOOL|DB_INIT_LOG|DB_INIT_LOCK|DB_INIT_TXN
|recover|DB_CREATE), 0666);
if (err) {
fprintf (stderr, "%s: %s\n", path, db_strerror (err));
close (dbe->lockfd);
dbe->e->close (dbe->e, 0);
free (dbe);
return NULL;
}
if (recover)
flock (dbe->lockfd, LOCK_SH);
dbe->txnflag = DB_AUTO_COMMIT;
dbe->home = xmalloc (strlen (path) + 1);
strcpy (dbe->home, path);
return dbe;
}
void
dbenv_free (dbenv *dbe)
{
dbe->e->close (dbe->e, 0);
close (dbe->lockfd);
free (dbe);
}
int
dbenv_txn (DB_TXN **tid, dbenv *dbe)
{
if (dbe->txnflag)
return dbe->e->txn_begin (dbe->e, NULL, tid, 0);
*tid = NULL;
return 0;
}
int
dbenv_commit (DB_TXN *tid)
{
if (tid)
return tid->commit (tid, 0);
return 0;
}
int
dbexp_clean (dbexp *dbx)
{
u_int32_t now = time (NULL);
DB_TXN *tid;
int i;
int err = 0;
DBC *c;
DBT k, v;
while (!err) {
if ((err = dbenv_txn (&tid, dbx->dbe))) {
fprintf (stderr, "%s: %s\n", dbx->path, db_strerror (err));
return err;
}
if ((err = dbx->exp->cursor (dbx->exp, tid, &c, 0))) {
fprintf (stderr, "%s: %s\n", dbx->path, db_strerror (err));
dbenv_commit (tid);
return err;
}
bzero (&k, sizeof (k));
bzero (&v, sizeof (v));
err = c->c_get (c, &k, &v, DB_FIRST);
for (i = 0; !err && i < 20; i++) {
if (k.size >= 4) {
if (getint (k.data) > now)
err = DB_NOTFOUND;
else
err = c->c_del (c, 0);
}
if (!err)
err = c->c_get (c, &k, &v, DB_NEXT);
}
if (err && err != DB_NOTFOUND)
fprintf (stderr, "%s: %s\n", dbx->path, db_strerror (err));
c->c_close (c);
if (!err)
err = dbenv_commit (tid);
else
dbenv_commit (tid);
}
if (dbx->dbe->home) {
#ifdef DB_ARCH_REMOVE
dbx->dbe->e->log_archive (dbx->dbe->e, NULL, DB_ARCH_REMOVE);
#else /* !DB_ARCH_REMOVE */
int i;
char **paths = NULL;
int err = dbx->dbe->e->log_archive (dbx->dbe->e, &paths, DB_ARCH_ABS);
if (err)
fprintf (stderr, "%s: log_archive: %s\n", dbx->path, db_strerror (err));
else if (paths) {
for (i = 0; paths[i]; i++)
unlink (paths[i]);
free (paths);
}
#endif /* !DB_ARCH_REMOVE */
}
if (err == DB_NOTFOUND)
return 0;
return err;
}
int
dbexp_free (dbexp *dbx, int sync)
{
int ret = 0;
int err;
if (dbx->exp) {
err = dbx->exp->close (dbx->exp, 0);
if (err) {
fprintf (stderr, "%s: %s\n", dbx->path, db_strerror (err));
ret = err;
}
}
if (dbx->db) {
if (sync && !ret && !dbx->dbe->txnflag) {
err = dbx->db->sync (dbx->db, 0);
if (!ret && err) {
fprintf (stderr, "%s; %s\n", dbx->path, db_strerror (err));
ret = err;
}
}
err = dbx->db->close (dbx->db, 0);
if (!ret && err) {
fprintf (stderr, "%s: %s\n", dbx->path, db_strerror (err));
ret = err;
}
}
free (dbx->path);
free (dbx);
return ret;
}
static int
_dbexp_getexp (DB *exp, const DBT *pkey, const DBT *pdata, DBT *skey)
{
if (pdata->size < 4)
return EINVAL;
skey->data = pdata->data;
skey->size = 4;
return 0;
}
dbexp *
dbexp_alloc (dbenv *dbe, const char *path, int rdonly)
{
int err;
int fd;
dbexp *dbx = malloc (sizeof (*dbx));
bzero (dbx, sizeof (*dbx));
dbx->dbe = dbe;
dbx->path = xmalloc (strlen (path) + 1);
strcpy (dbx->path, path);
err = db_create (&dbx->db, dbx->dbe->e, 0);
if (!err)
err = dbx->db->set_flags(dbx->db, DB_CHKSUM);
if (!rdonly) {
if (!err)
err = db_create (&dbx->exp, dbx->dbe->e, 0);
if (!err)
err = dbx->exp->set_flags(dbx->exp, DB_DUPSORT);
}
if (err) {
fprintf (stderr, "db_create: %s\n", db_strerror (err));
dbexp_free (dbx, 0);
return NULL;
}
err = dbx->db->open (dbx->db, NULL, dbx->path, "db", DB_BTREE,
rdonly ? DB_RDONLY : dbx->dbe->txnflag|DB_CREATE,
0666);
if (!err)
err = dbx->db->fd (dbx->db, &fd);
if (err) {
fprintf (stderr, "%s: %s\n", dbx->path, db_strerror (err));
dbexp_free (dbx, 0);
return NULL;
}
if (flock (fd, rdonly ? LOCK_SH : LOCK_EX) < 0) {
fprintf (stderr, "flock (%s): %s\n", dbx->path, strerror (errno));
dbexp_free (dbx, 0);
return NULL;
}
if (!rdonly) {
err = dbx->exp->open (dbx->exp, NULL, dbx->path, "exp", DB_BTREE,
dbx->dbe->txnflag|DB_CREATE, 0666);
if (!err)
err = dbx->db->associate (dbx->db, NULL, dbx->exp,
_dbexp_getexp, dbx->dbe->txnflag);
if (err) {
fprintf (stderr, "%s: %s\n", dbx->path, db_strerror (err));
dbexp_free (dbx, 0);
return NULL;
}
}
return dbx;
}
syntax highlighted by Code2HTML, v. 0.9.1