245 lines
5.3 KiB
C
245 lines
5.3 KiB
C
/*-
|
|
* See the file LICENSE for redistribution information.
|
|
*
|
|
* Copyright (c) 2005,2008 Oracle. All rights reserved.
|
|
*
|
|
* $Id: db.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
|
*/
|
|
|
|
#include "csv.h"
|
|
#include "csv_local.h"
|
|
#include "csv_extern.h"
|
|
|
|
static int compare_uint32(DB *, const DBT *, const DBT *);
|
|
|
|
/*
|
|
* csv_env_init --
|
|
* Initialize the database environment.
|
|
*/
|
|
int
|
|
csv_env_open(const char *home, int is_rdonly)
|
|
{
|
|
int ret;
|
|
|
|
dbenv = NULL;
|
|
db = NULL;
|
|
|
|
/* Create a database environment handle. */
|
|
if ((ret = db_env_create(&dbenv, 0)) != 0) {
|
|
fprintf(stderr,
|
|
"%s: db_env_create: %s\n", progname, db_strerror(ret));
|
|
return (1);
|
|
}
|
|
|
|
/*
|
|
* Configure Berkeley DB error reporting to stderr, with our program
|
|
* name as the prefix.
|
|
*/
|
|
dbenv->set_errfile(dbenv, stderr);
|
|
dbenv->set_errpfx(dbenv, progname);
|
|
|
|
/*
|
|
* The default Berkeley DB cache size is fairly small; configure a
|
|
* 1MB cache for now. This value will require tuning in the future.
|
|
*/
|
|
if ((ret = dbenv->set_cachesize(dbenv, 0, 1048576, 1)) != 0) {
|
|
dbenv->err(dbenv, ret, "DB_ENV->set_cachesize");
|
|
return (1);
|
|
}
|
|
|
|
/*
|
|
* We may be working with an existing environment -- try and join it.
|
|
* If that fails, create a new database environment; for now, we only
|
|
* need a cache, no logging, locking, or transactions.
|
|
*/
|
|
if ((ret = dbenv->open(dbenv, home,
|
|
DB_JOINENV | DB_USE_ENVIRON, 0)) != 0 &&
|
|
(ret = dbenv->open(dbenv, home,
|
|
DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_USE_ENVIRON, 0)) != 0) {
|
|
dbenv->err(dbenv, ret, "DB_ENV->open");
|
|
return (1);
|
|
}
|
|
|
|
/* Create the primary database handle. */
|
|
if ((ret = db_create(&db, dbenv, 0)) != 0) {
|
|
dbenv->err(dbenv, ret, "db_create");
|
|
return (1);
|
|
}
|
|
|
|
/*
|
|
* Records may be relatively large -- use a large page size.
|
|
*/
|
|
if ((ret = db->set_pagesize(db, 32 * 1024)) != 0) {
|
|
dbenv->err(dbenv, ret, "DB->set_pagesize");
|
|
return (1);
|
|
}
|
|
|
|
/*
|
|
* The primary database uses an integer as its key; on little-endian
|
|
* machines, integers sort badly using the default Berkeley DB sort
|
|
* function (which is lexicographic). Specify a comparison function
|
|
* for the database.
|
|
*/
|
|
if ((ret = db->set_bt_compare(db, compare_uint32)) != 0) {
|
|
dbenv->err(dbenv, ret, "DB->set_bt_compare");
|
|
return (1);
|
|
}
|
|
|
|
/* Open the primary database. */
|
|
if ((ret = db->open(db, NULL,
|
|
"primary", NULL, DB_BTREE, is_rdonly ? 0 : DB_CREATE, 0)) != 0) {
|
|
dbenv->err(dbenv, ret, "DB->open: primary");
|
|
return (1);
|
|
}
|
|
|
|
/* Open the secondaries. */
|
|
if ((ret = csv_secondary_open()) != 0)
|
|
return (1);
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* csv_env_close --
|
|
* Discard the database environment.
|
|
*/
|
|
int
|
|
csv_env_close()
|
|
{
|
|
int ret, t_ret;
|
|
|
|
ret = 0;
|
|
|
|
/* Close the secondaries. */
|
|
ret = csv_secondary_close();
|
|
|
|
/* Close the primary handle. */
|
|
if (db != NULL && (t_ret = db->close(db, 0)) != 0) {
|
|
dbenv->err(dbenv, ret, "DB->close");
|
|
if (ret == 0)
|
|
ret = t_ret;
|
|
}
|
|
if ((t_ret = dbenv->close(dbenv, 0)) != 0) {
|
|
fprintf(stderr,
|
|
"%s: DB_ENV->close: %s\n", progname, db_strerror(ret));
|
|
if (ret == 0)
|
|
ret = t_ret;
|
|
}
|
|
|
|
return (ret);
|
|
}
|
|
|
|
/*
|
|
* csv_secondary_open --
|
|
* Open any secondary indices.
|
|
*/
|
|
int
|
|
csv_secondary_open()
|
|
{
|
|
DB *sdb;
|
|
DbField *f;
|
|
int ret, (*fcmp)(DB *, const DBT *, const DBT *);
|
|
|
|
/*
|
|
* Create secondary database handles.
|
|
*/
|
|
for (f = fieldlist; f->name != NULL; ++f) {
|
|
if (f->indx == 0)
|
|
continue;
|
|
|
|
if ((ret = db_create(&sdb, dbenv, 0)) != 0) {
|
|
dbenv->err(dbenv, ret, "db_create");
|
|
return (1);
|
|
}
|
|
sdb->app_private = f;
|
|
|
|
/* Keys are small, use a relatively small page size. */
|
|
if ((ret = sdb->set_pagesize(sdb, 8 * 1024)) != 0) {
|
|
dbenv->err(dbenv, ret, "DB->set_pagesize");
|
|
return (1);
|
|
}
|
|
|
|
/*
|
|
* Sort the database based on the underlying type. Skip
|
|
* strings, Berkeley DB defaults to lexicographic sort.
|
|
*/
|
|
switch (f->type) {
|
|
case DOUBLE:
|
|
fcmp = compare_double;
|
|
break;
|
|
case UNSIGNED_LONG:
|
|
fcmp = compare_ulong;
|
|
break;
|
|
case NOTSET:
|
|
case STRING:
|
|
default:
|
|
fcmp = NULL;
|
|
break;
|
|
}
|
|
if (fcmp != NULL &&
|
|
(ret = sdb->set_bt_compare(sdb, fcmp)) != 0) {
|
|
dbenv->err(dbenv, ret, "DB->set_bt_compare");
|
|
return (1);
|
|
}
|
|
|
|
/* Always configure secondaries for sorted duplicates. */
|
|
if ((ret = sdb->set_flags(sdb, DB_DUPSORT)) != 0) {
|
|
dbenv->err(dbenv, ret, "DB->set_flags");
|
|
return (1);
|
|
}
|
|
if ((ret = sdb->set_dup_compare(sdb, compare_ulong)) != 0) {
|
|
dbenv->err(dbenv, ret, "DB->set_dup_compare");
|
|
return (1);
|
|
}
|
|
|
|
if ((ret = sdb->open(
|
|
sdb, NULL, f->name, NULL, DB_BTREE, DB_CREATE, 0)) != 0) {
|
|
dbenv->err(dbenv, ret, "DB->open: %s", f->name);
|
|
return (1);
|
|
}
|
|
if ((ret = sdb->associate(
|
|
db, NULL, sdb, secondary_callback, DB_CREATE)) != 0) {
|
|
dbenv->err(dbenv, ret, "DB->set_associate");
|
|
return (1);
|
|
}
|
|
f->secondary = sdb;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* csv_secondary_close --
|
|
* Close any secondary indices.
|
|
*/
|
|
int
|
|
csv_secondary_close()
|
|
{
|
|
DbField *f;
|
|
int ret, t_ret;
|
|
|
|
ret = 0;
|
|
for (f = fieldlist; f->name != NULL; ++f)
|
|
if (f->secondary != NULL && (t_ret =
|
|
f->secondary->close(f->secondary, 0)) != 0 && ret == 0)
|
|
ret = t_ret;
|
|
|
|
return (ret);
|
|
}
|
|
|
|
/*
|
|
* compare_uint32 --
|
|
* Compare two keys.
|
|
*/
|
|
static int
|
|
compare_uint32(DB *db_arg, const DBT *a_arg, const DBT *b_arg)
|
|
{
|
|
u_int32_t a, b;
|
|
|
|
db_arg = db_arg; /* Quiet compiler. */
|
|
|
|
memcpy(&a, a_arg->data, sizeof(u_int32_t));
|
|
memcpy(&b, b_arg->data, sizeof(u_int32_t));
|
|
return (a > b ? 1 : ((a < b) ? -1 : 0));
|
|
}
|