static ex_t dbe_env_purgelogs(DB_ENV *dbe)
{
    char **i, **list;
    ex_t e;

    /* figure redundant log files and nuke them */
    e = BF_LOG_ARCHIVE(dbe, &list, DB_ARCH_ABS);
    if (e != 0) {
	print_error(__FILE__, __LINE__,
		"DB_ENV->log_archive failed: %s",
		db_strerror(e));
	exit(EX_ERROR);
    }

    if (list != NULL) {
	if (DEBUG_DATABASE(0))
	    fprintf(dbgout, "removing inactive logfiles\n");

	for (i = list; *i != NULL; i++) {
	    if (DEBUG_DATABASE(1))
		fprintf(dbgout, " removing logfile %s\n", *i);
	    if (unlink(*i)) {
		if (errno != ENOENT)
		    print_error(__FILE__, __LINE__,
			    "cannot unlink \"%s\": %s", *i, strerror(errno));
		/* proceed anyways */
	    }
	}
	xfree(list);
    }
    return EX_OK;
}
/* dummy infrastructure, to be expanded by environment
 * or transactional initialization/shutdown */
static dbe_t *dbe_xinit(dbe_t *env, bfpath *bfp, u_int32_t flags)
{
    int ret;

    env->magic = MAGIC_DBE;	    /* poor man's type checking */

    ret = bf_dbenv_create(&env->dbe);

    if (db_cachesize != 0 &&
	    (ret = env->dbe->set_cachesize(env->dbe, db_cachesize/1024, (db_cachesize % 1024) * 1024*1024, 1)) != 0) {
	print_error(__FILE__, __LINE__, "DB_ENV->set_cachesize(%u), err: %d, %s",
		db_cachesize, ret, db_strerror(ret));
	exit(EX_ERROR);
    }

    if (DEBUG_DATABASE(1))
	fprintf(dbgout, "DB_ENV->set_cachesize(%u)\n", db_cachesize);

    dbe_config(env);

    flags |= DB_CREATE | dbenv_defflags;

    ret = env->dbe->open(env->dbe, bfp->dirname, flags, DS_MODE);
    if (ret != 0) {
	env->dbe->close(env->dbe, 0);
	print_error(__FILE__, __LINE__, "DB_ENV->open, err: %d, %s", ret, db_strerror(ret));
	switch (ret) {
	    case DB_RUNRECOVERY:
		diag_dbeopen(flags, bfp);
		break;
	    case EINVAL:
		fprintf(stderr, "\n"
			"If you have just got a message that only private environments are supported,\n"
			"your Berkeley DB %d.%d was not configured properly.\n"
			"Bogofilter requires shared environments to support Berkeley DB transactions.\n",
			DB_VERSION_MAJOR, DB_VERSION_MINOR);
		fprintf(stderr,
			"Reconfigure and recompile Berkeley DB with the right mutex interface,\n"
			"see the docs/ref/build_unix/conf.html file that comes with your db source code.\n"
			"This can happen when the DB library was compiled with POSIX threads\n"
			"but your system does not support NPTL.\n");
		break;
	}

	exit(EX_ERROR);
    }

    if (DEBUG_DATABASE(1))
	fprintf(dbgout, "DB_ENV->open(home=%s)\n", bfp->dirname);

    return env;
}
static int dbx_abort(void *vhandle)
{
    int ret;
    dbh_t *dbh = vhandle;
    DB_TXN *t;

    assert(dbh);
    assert(dbh->magic == MAGIC_DBH);

    t = dbh->txn;

    assert(t);

    ret = BF_TXN_ABORT(t);
    if (ret)
	print_error(__FILE__, __LINE__, "DB_TXN->abort(%lx) error: %s",
		(unsigned long)BF_TXN_ID(t), db_strerror(ret));
    else
	if (DEBUG_DATABASE(2))
	    fprintf(dbgout, "DB_TXN->abort(%lx)\n",
		    (unsigned long)BF_TXN_ID(t));

    dbh->txn = NULL;

    switch (ret) {
	case 0:
	    return DST_OK;
	case DB_LOCK_DEADLOCK:
	    return DST_TEMPFAIL;
	default:
	    return DST_FAILURE;
    }
}
static int dbx_begin(void *vhandle)
{
    DB_TXN *t;
    int ret;

    dbh_t *dbh = vhandle;
    dbe_t *env = dbh->dbenv;

    assert(dbh);
    assert(dbh->magic == MAGIC_DBH);
    assert(dbh->txn == 0);

    assert(env);
    assert(env->dbe);

    ret = BF_TXN_BEGIN(env->dbe, NULL, &t, 0);
    if (ret) {
	print_error(__FILE__, __LINE__, "DB_ENV->txn_begin(%p), err: %d, %s",
		(void *)env->dbe, ret, db_strerror(ret));
	return ret;
    }
    dbh->txn = t;

    if (DEBUG_DATABASE(2))
	fprintf(dbgout, "DB_ENV->dbx_begin(%p), tid: %lx\n",
		(void *)env->dbe, (unsigned long)BF_TXN_ID(t));

    return 0;
}
/* close the environment, but do not release locks */
static void dbx_cleanup_lite(dbe_t *env)
{
    if (env) {
	if (env->dbe) {
	    int ret;

	    /* checkpoint if more than 64 kB of logs have been written
	     * or 120 min have passed since the previous checkpoint */
	    /*                                kB  min flags */
	    ret = BF_TXN_CHECKPOINT(env->dbe, 64, 120, 0);
	    ret = dbx_sync(env->dbe, ret);
	    if (ret)
		print_error(__FILE__, __LINE__, "DBE->dbx_checkpoint err: %d, %s", ret, db_strerror(ret));

	    if (db_log_autoremove)
		dbe_env_purgelogs(env->dbe);

	    ret = env->dbe->close(env->dbe, 0);
	    if (DEBUG_DATABASE(1) || ret)
		fprintf(dbgout, "DB_ENV->close(%p): %s\n", (void *)env->dbe,
			db_strerror(ret));
	    clear_lock();
	    if (lockfd >= 0)
		close(lockfd); /* release locks */
	}

	xfree(env->directory);
	xfree(env);
    }
}
ex_t dbx_recover(bfpath *bfp, bool catastrophic, bool force)
{
    dbe_t *env = xcalloc(1, sizeof(dbe_t));

    /* set exclusive/write lock for recovery */
    while ((force || needs_recovery())
	    && (db_try_glock(bfp, F_WRLCK, F_SETLKW) <= 0))
	rand_sleep(10000,1000000);

    /* ok, when we have the lock, a concurrent process may have
     * proceeded with recovery */
    if (!(force || needs_recovery()))
	return EX_OK;

    if (DEBUG_DATABASE(0))
        fprintf(dbgout, "running %s data base recovery\n",
	    catastrophic ? "catastrophic" : "regular");
    env = dbe_xinit(env, bfp,
		    catastrophic ? DB_RECOVER_FATAL : DB_RECOVER);
    if (env == NULL) {
	exit(EX_ERROR);
    }

    clear_lockfile();
    dbx_cleanup_lite(env);

    return EX_OK;
}
void dbx_log_flush(DB_ENV *dbe)
{
    int ret;

    ret = BF_LOG_FLUSH(dbe, NULL);

    if (DEBUG_DATABASE(1))
	fprintf(dbgout, "DB_ENV->log_flush(%p): %s\n", (void *)dbe,
		db_strerror(ret));
}
/** Create environment or exit with EX_ERROR */
static int bf_dbenv_create(DB_ENV **env)
{
    int ret = db_env_create(env, 0);
    if (ret != 0) {
	print_error(__FILE__, __LINE__, "db_env_create, err: %d, %s",
		ret, db_strerror(ret));
	exit(EX_ERROR);
    }
    if (DEBUG_DATABASE(1))
	fprintf(dbgout, "db_env_create: %p\n", (void *)env);
    (*env)->set_errfile(*env, stderr);

    return ret;
}
/** run recovery, open environment and keep the exclusive lock */
static DB_ENV *dbe_recover_open(bfpath *bfp, u_int32_t flags)
{
    const u_int32_t local_flags = flags | DB_CREATE;
    DB_ENV *dbe;
    int e;

    if (DEBUG_DATABASE(0))
        fprintf(dbgout, "trying to lock database directory\n");
    db_try_glock(bfp, F_WRLCK, F_SETLKW); /* wait for exclusive lock */

    /* run recovery */
    bf_dbenv_create(&dbe);

    if (DEBUG_DATABASE(0))
        fprintf(dbgout, "running regular data base recovery%s\n",
	       flags & DB_PRIVATE ? " and removing environment" : "");

    /* quirk: DB_RECOVER requires DB_CREATE and cannot work with DB_JOINENV */

    /*
     * Hint from Keith Bostic, SleepyCat support, 2004-11-29,
     * we can use the DB_PRIVATE flag, that rebuilds the database
     * environment in heap memory, so we don't need to remove it.
     */

    e = dbe->open(dbe, bfp->dirname,
		  dbenv_defflags | local_flags | DB_RECOVER, DS_MODE);
    if (e != 0) {
	print_error(__FILE__, __LINE__, "Cannot recover environment \"%s\": %s",
		bfp->dirname, db_strerror(e));
	if (e == DB_RUNRECOVERY)
	    diag_dbeopen(flags, bfp);
	exit(EX_ERROR);
    }

    return dbe;
}
/** checkpoint the open environment \a dbe once and unconditionally */
static ex_t dbe_env_checkpoint(DB_ENV *dbe) {
    int e;

    if (DEBUG_DATABASE(0))
	fprintf(dbgout, "checkpoint database\n");

    /* checkpoint the transactional system */
    e = BF_TXN_CHECKPOINT(dbe, 0, 0, 0);
    e = dbx_sync(dbe, e);
    if (e != 0) {
	print_error(__FILE__, __LINE__, "DB_ENV->txn_checkpoint failed: %s",
		db_strerror(e));
	exit(EX_ERROR);
    }

    return EX_OK;
}
static void dbe_config(void *vhandle)
{
    dbe_t *env = vhandle;
    int ret = 0;
    u_int32_t logsize = 1048576;    /* 1 MByte (default in BDB 10 MByte) */

    /* configure log file size */
    ret = env->dbe->set_lg_max(env->dbe, logsize);
    if (ret) {
	print_error(__FILE__, __LINE__, "DB_ENV->set_lg_max(%lu) err: %d, %s",
		(unsigned long)logsize, ret, db_strerror(ret));
	exit(EX_ERROR);
    }

    if (DEBUG_DATABASE(1))
	fprintf(dbgout, "DB_ENV->set_lg_max(%lu)\n", (unsigned long)logsize);
}
Пример #12
0
/*
  Initialize database.
  Returns: pointer to database handle on success, NULL otherwise.
*/
void *db_open(void * dummy, bfpath *bfp, dbmode_t open_mode)
{
    dbh_t *handle;

    bool res;
    int open_flags;
    TCBDB *dbp;

    UNUSED(dummy);

    if (open_mode & DS_WRITE)
	open_flags = BDBOWRITER;
    else
	open_flags = BDBOREADER;

    handle = dbh_init(bfp);

    if (handle == NULL) return NULL;

    dbp = handle->dbp = tcbdbnew();
    res = tcbdbopen(dbp, handle->name, open_flags);
    if (!res && (open_mode & DS_WRITE)) {
        res = tcbdbopen(dbp, handle->name, open_flags | BDBOCREAT);
        handle->created |= res;
    }

    if (!res)
	goto open_err;

    if (DEBUG_DATABASE(1))
	fprintf(dbgout, "(tc) tcbdbopen( %s, %d )\n", handle->name, open_mode);

    return handle;

 open_err:
    print_error(__FILE__, __LINE__, "(tc) tcbdbopen(%s, %d), err: %d, %s",
		handle->name, open_flags, 
		tcbdbecode(dbp), tcbdberrmsg(tcbdbecode(dbp)));
    dbh_free(handle);

    return NULL;
}
Пример #13
0
/*
  Initialize database.
  Returns: pointer to database handle on success, NULL otherwise.
*/
void *db_open(void * dummy, bfpath *bfp, dbmode_t open_mode)
{
    dbh_t *handle;

    int open_flags;
    VILLA *dbp;

    UNUSED(dummy);

    if (open_mode & DS_WRITE)
	open_flags = VL_OWRITER;
    else
	open_flags = VL_OREADER;

    handle = dbh_init(bfp);

    if (handle == NULL) return NULL;

    dbp = handle->dbp = vlopen(handle->name, open_flags, cmpkey);

    if ((dbp == NULL) && (open_mode & DS_WRITE)) {
	dbp = handle->dbp = vlopen(handle->name, open_flags|VL_OCREAT, cmpkey);
	if (dbp != NULL)
	    handle->created = true;
    }

    if (dbp == NULL)
	goto open_err;

    if (DEBUG_DATABASE(1))
	fprintf(dbgout, "(qdbm) vlopen( %s, %d )\n", handle->name, open_mode);

    return handle;

 open_err:
    print_error(__FILE__, __LINE__, "(qdbm) vlopen(%s, %d), err: %d, %s",
		handle->name, open_flags, 
		dpecode, dperrmsg(dpecode));
    dbh_free(handle);

    return NULL;
}
static ex_t dbx_common_close(DB_ENV *dbe, bfpath *bfp)
{
    int e;

    if (db_log_autoremove)
	dbe_env_purgelogs(dbe);

    if (DEBUG_DATABASE(0))
	fprintf(dbgout, "closing environment\n");

    e = dbe->close(dbe, 0);
    if (e != 0) {
	print_error(__FILE__, __LINE__, "Error closing environment \"%s\": %s",
		    bfp->dirname, db_strerror(e));
	exit(EX_ERROR);
    }

    clear_lock();
    db_try_glock(bfp, F_UNLCK, F_SETLKW); /* release lock */
    return EX_OK;
}
static int dbx_commit(void *vhandle)
{
    int ret;
    dbh_t *dbh = vhandle;
    DB_TXN *t;
    u_int32_t id;

    assert(dbh);
    assert(dbh->magic == MAGIC_DBH);

    t = dbh->txn;

    assert(t);

    id = BF_TXN_ID(t);
    ret = BF_TXN_COMMIT(t, 0);
    if (ret)
	print_error(__FILE__, __LINE__, "DB_TXN->commit(%lx) error: %s",
		(unsigned long)id, db_strerror(ret));
    else
	if (DEBUG_DATABASE(2))
	    fprintf(dbgout, "DB_TXN->commit(%lx, 0)\n",
		    (unsigned long)id);

    dbh->txn = NULL;

    switch (ret) {
	case 0:
	    /* push out buffer pages so that >=15% are clean - we
	     * can ignore errors here, as the log has all the data */
	    BF_MEMP_TRICKLE(dbh->dbenv->dbe, 15, NULL);

	    return DST_OK;
	case DB_LOCK_DEADLOCK:
	    return DST_TEMPFAIL;
	default:
	    return DST_FAILURE;
    }
}
Пример #16
0
/*
   Close files and clean up.
*/
void db_close(void *vhandle)
{
    dbh_t *handle = vhandle;
    VILLA *dbp;

    if (handle == NULL) return;

    if (DEBUG_DATABASE(1))
	fprintf(dbgout, "(qdbm) vlclose(%s)\n", handle->name);

    dbp = handle->dbp;

    db_optimize(dbp, handle->name);

    if (!vlclose(dbp))
	print_error(__FILE__, __LINE__, "(qdbm) vlclose for %s err: %d, %s",
		    handle->name, 
		    dpecode, dperrmsg(dpecode));

    handle->dbp = NULL;

    dbh_free(handle);
}
Пример #17
0
/*
   Close files and clean up.
*/
void db_close(void *vhandle)
{
    dbh_t *handle = vhandle;
    TCBDB *dbp;

    if (handle == NULL) return;

    if (DEBUG_DATABASE(1))
	fprintf(dbgout, "(tc) tcbdbclose(%s)\n", handle->name);

    dbp = handle->dbp;

    db_optimize(dbp, handle->name);

    if (!tcbdbclose(dbp))
	print_error(__FILE__, __LINE__, "(tc) tcbdbclose for %s err: %d, %s",
		    handle->name, 
		    tcbdbecode(dbp), tcbdberrmsg(tcbdbecode(dbp)));

    tcbdbdel(dbp);
    handle->dbp = NULL;

    dbh_free(handle);
}