Commit 8e73bbb1 authored by Bradley C. Kuszmaul's avatar Bradley C. Kuszmaul

c++ interface is implemented (up to a point) and every method that can raise...

c++ interface is implemented (up to a point) and every method that can raise an exception is tested in exceptions.cpp.  Fixes #197, #215.

git-svn-id: file:///svn/tokudb@1334 c7de825b-a66e-492c-adef-691d508d4ae1
parent 22a90082
......@@ -13,7 +13,7 @@ Db::Db(DbEnv *env, u_int32_t flags)
is_private_env = (the_Env == 0);
DB *tmp_db;
int ret = db_create(&tmp_db, the_Env->get_DB_ENV(), flags & !(DB_CXX_NO_EXCEPTIONS));
int ret = db_create(&tmp_db, the_Env->get_DB_ENV(), flags & ~(DB_CXX_NO_EXCEPTIONS));
if (ret!=0) {
the_Env->maybe_throw_error(ret);
// Otherwise cannot do much
......
......@@ -14,3 +14,9 @@ int Dbc::get(Dbt* key, Dbt *data, u_int32_t flags) {
DbEnv *env = (DbEnv*)dbenv_c->api1_internal;
return env->maybe_throw_error(ret);
}
// Not callable, but some compilers require it to be defined anyway.
Dbc::~Dbc()
{
}
#include <assert.h>
#include <db_cxx.h>
#include <errno.h>
#include <unistd.h>
#define TC(expr, expect) ({ \
try { \
......@@ -47,7 +48,63 @@ void test_env_exceptions (void) {
}
void test_db_exceptions (void) {
DbEnv env(0);
TC(env.open(".", DB_INIT_MPOOL | DB_CREATE | DB_PRIVATE , 0777), 0);
TC( ({ Db db(&env, -1); assert(0); }), EINVAL); // Create with flags=-1 should do an EINVAL
Db db(&env, 0);
DB *dbdb=db.get_DB();
assert(dbdb!=0);
assert(dbdb==db.get_const_DB());
assert(&db==Db::get_const_Db(dbdb));
unlink("foo.db");
TC(db.open(0, "foo.db", 0, DB_BTREE, DB_CREATE, 0777), 0);
TC(db.open(0, "foo.db", 0, DB_BTREE, DB_CREATE, 0777), EINVAL); // it was already open
{
Db db2(&env, 0);
TC(db2.open(0, "foo2.db", 0, DB_BTREE, 0, 0777), ENOENT); // it doesn't exist
}
{
Db db2(&env, 0);
TC(db2.open(0, "foo.db", 0, DB_BTREE, 0, 0777), 0); // it does exist
}
{
Db db2(&env, 0);
TC(db2.open(0, "foo.db", 0, DB_BTREE, -1, 0777), EINVAL); // bad flags
}
{
Db db2(&env, 0);
TC(db2.open(0, "foo.db", 0, (DBTYPE)-1, 0, 0777), EINVAL); // bad type
}
{
Db db2(&env, 0);
TC(db2.open(0, "foo.db", "sub.db", DB_BTREE, DB_CREATE, 0777), EINVAL); // sub DB cannot exist
}
{
Db db2(&env, 0);
TC(db2.open(0, "foo.db", "sub.db", DB_BTREE, 0, 0777), EINVAL); // sub DB cannot exist withou DB_CREATE
}
{
Dbc *curs;
TC(db.cursor(0, &curs, -1), EINVAL);
}
{
Dbc *curs;
TC(db.cursor(0, &curs, 0), 0);
Dbt key,val;
TC(curs->get(&key, &val, DB_FIRST), DB_NOTFOUND);
TC(curs->get(&key, &val, -1), EINVAL); // bad flags
curs->close(); // no deleting cursors.
}
Dbt key,val;
//TC(db.del(0, &key, -1), EINVAL);
//TC(db.get(0, &key, &val, -1), EINVAL);
TC(db.put(0, &key, &val, -1), EINVAL);
}
int main(int argc, char *argv[]) {
test_env_exceptions();
test_db_exceptions();
return 0;
}
......@@ -100,7 +100,7 @@ class Db {
int cursor(DbTxn */*txnid*/, Dbc **/*cursorp*/, u_int32_t /*flags*/);
int del(DbTxn */*txnid*/, Dbt */*key*/, u_int32_t /*flags*/);
int get(DbTxn */*txnid*/, Dbt */*key*/, Dbt */*data*/, u_int32_t /*flags*/);
int open(DbTxn */*txnid*/, const char */*name*/, const char */*subname*/, DBTYPE, u_int32_t, int);
int open(DbTxn */*txnid*/, const char */*name*/, const char */*subname*/, DBTYPE, u_int32_t/*flags*/, int/*mode*/);
int put(DbTxn *, Dbt *, Dbt *, u_int32_t);
int get_flags(u_int32_t *);
int set_flags(u_int32_t);
......@@ -175,4 +175,7 @@ class Dbc : protected DBC
public:
int close(void);
int get(Dbt*, Dbt *, u_int32_t);
private:
Dbc(); // User may not call it.
~Dbc(); // User may not delete it.
};
......@@ -1561,6 +1561,11 @@ int toku_brt_open(BRT t, const char *fname, const char *fname_in_env, const char
}
assert(t->nodesize>0);
//printf("%s:%d %d alloced\n", __FILE__, __LINE__, get_n_items_malloced()); toku_print_malloced_items();
if (0) {
died_after_read_and_pin:
toku_cachetable_unpin(t->cf, 0, 0, 0); // unpin the header
goto died1;
}
if (is_create) {
r = toku_read_and_pin_brt_header(t->cf, &t->h);
if (r==-1) {
......@@ -1569,7 +1574,8 @@ int toku_brt_open(BRT t, const char *fname, const char *fname_in_env, const char
assert(errno==ENOMEM);
r = ENOMEM;
if (0) { died2: toku_free(t->h); }
goto died1;
t->h=0;
goto died_after_read_and_pin;
}
t->h->dirty=1;
t->h->flags = t->flags;
......@@ -1594,38 +1600,39 @@ int toku_brt_open(BRT t, const char *fname, const char *fname_in_env, const char
if ((r=toku_cachetable_put(t->cf, 0, t->h, 0, toku_brtheader_flush_callback, toku_brtheader_fetch_callback, 0))) { goto died6; }
}
else if (r!=0) {
goto died1;
goto died_after_read_and_pin;
}
else {
int i;
assert(r==0);
assert(dbname);
assert(t->h->unnamed_root==-1);
if (t->h->unnamed_root!=-1) { r=EINVAL; goto died_after_read_and_pin; } // Cannot create a subdb in a file that is not enabled for subdbs
assert(t->h->n_named_roots>=0);
for (i=0; i<t->h->n_named_roots; i++) {
if (strcmp(t->h->names[i], dbname)==0) {
if (only_create) {
r = EEXIST;
goto died1; /* deallocate everything. */
goto died_after_read_and_pin;
}
else goto found_it;
}
}
if ((t->h->names = toku_realloc(t->h->names, (1+t->h->n_named_roots)*sizeof(*t->h->names))) == 0) { assert(errno==ENOMEM); r=ENOMEM; goto died1; }
if ((t->h->roots = toku_realloc(t->h->roots, (1+t->h->n_named_roots)*sizeof(*t->h->roots))) == 0) { assert(errno==ENOMEM); r=ENOMEM; goto died1; }
if ((t->h->names = toku_realloc(t->h->names, (1+t->h->n_named_roots)*sizeof(*t->h->names))) == 0) { assert(errno==ENOMEM); r=ENOMEM; goto died_after_read_and_pin; }
if ((t->h->roots = toku_realloc(t->h->roots, (1+t->h->n_named_roots)*sizeof(*t->h->roots))) == 0) { assert(errno==ENOMEM); r=ENOMEM; goto died_after_read_and_pin; }
t->h->n_named_roots++;
if ((t->h->names[t->h->n_named_roots-1] = toku_strdup(dbname)) == 0) { assert(errno==ENOMEM); r=ENOMEM; goto died1; }
if ((t->h->names[t->h->n_named_roots-1] = toku_strdup(dbname)) == 0) { assert(errno==ENOMEM); r=ENOMEM; goto died_after_read_and_pin; }
//printf("%s:%d t=%p\n", __FILE__, __LINE__, t);
t->h->roots[t->h->n_named_roots-1] = malloc_diskblock_header_is_in_memory(t, t->h->nodesize);
t->h->dirty = 1;
if ((r=setup_brt_root_node(t, t->h->roots[t->h->n_named_roots-1], txn))!=0) goto died1;
if ((r=setup_brt_root_node(t, t->h->roots[t->h->n_named_roots-1], txn))!=0) goto died_after_read_and_pin;
}
} else {
if ((r = toku_read_and_pin_brt_header(t->cf, &t->h))!=0) goto died1;
if (!dbname) {
if (t->h->n_named_roots!=-1) { r = -2; /* invalid args??? */; goto died1; }
if (t->h->n_named_roots!=-1) { r = EINVAL; goto died_after_read_and_pin; } // requires a subdb
} else {
int i;
if (t->h->n_named_roots==-1) { r=EINVAL; goto died_after_read_and_pin; } // no suddbs in the db
// printf("%s:%d n_roots=%d\n", __FILE__, __LINE__, t->h->n_named_roots);
for (i=0; i<t->h->n_named_roots; i++) {
if (strcmp(t->h->names[i], dbname)==0) {
......@@ -1634,17 +1641,17 @@ int toku_brt_open(BRT t, const char *fname, const char *fname_in_env, const char
}
r=ENOENT; /* the database doesn't exist */
goto died1;
goto died_after_read_and_pin;
}
found_it:
t->nodesize = t->h->nodesize; /* inherit the pagesize from the file */
if (t->flags != t->h->flags) { /* flags must match */
if (load_flags) t->flags = t->h->flags;
else {r = EINVAL; goto died1;}
else {r = EINVAL; goto died_after_read_and_pin;}
}
}
assert(t->h);
if ((r = toku_unpin_brt_header(t)) !=0) goto died1;
if ((r = toku_unpin_brt_header(t)) !=0) goto died1; // it's unpinned
assert(t->h==0);
WHEN_BRTTRACE(fprintf(stderr, "BRTTRACE -> %p\n", t));
return 0;
......@@ -2914,6 +2921,8 @@ int toku_brt_cursor_get (BRT_CURSOR cursor, DBT *kbt, DBT *vbt, int flags, TOKUT
if (r != 0) goto died0;
break;
default:
toku_unpin_brt_header(cursor->brt);
return EINVAL;
fprintf(stderr, "%s:%d c_get(...,%d) not ready\n", __FILE__, __LINE__, flags);
abort();
}
......
......@@ -124,6 +124,7 @@ NO_VGRIND = \
db_env_open_open_close \
db_open_notexist_reopen \
db_remove_subdb \
log4 \
# Comment to terminate list so the previous line can end with a slash
$(patsubst %,test_%.bdbrun,$(NO_VGRIND)): VGRIND=
......
......@@ -1285,11 +1285,17 @@ static int toku_db_open(DB * db, DB_TXN * txn, const char *fname, const char *db
int openflags = 0;
int r;
if (dbtype!=DB_BTREE && dbtype!=DB_UNKNOWN) return EINVAL;
if ((flags & DB_EXCL) && !(flags & DB_CREATE)) return EINVAL;
if (dbtype==DB_UNKNOWN && (flags & DB_EXCL)) return EINVAL;
int is_db_excl = flags & DB_EXCL; flags&=~DB_EXCL;
int is_db_create = flags & DB_CREATE; flags&=~DB_CREATE;
int is_db_rdonly = flags & DB_RDONLY; flags&=~DB_RDONLY;
int is_db_unknown = flags & DB_UNKNOWN; flags&=~DB_UNKNOWN;
if (flags) return EINVAL; // unknown flags
if (is_db_excl && !is_db_create) return EINVAL;
if (dbtype==DB_UNKNOWN && is_db_excl) return EINVAL;
if (db_opened(db))
return -1; /* It was already open. */
return EINVAL; /* It was already open. */
r = find_db_file(db->dbenv, fname, &db->i->full_fname);
if (r != 0) goto error_cleanup;
......@@ -1299,7 +1305,7 @@ static int toku_db_open(DB * db, DB_TXN * txn, const char *fname, const char *db
r = ENOMEM;
goto error_cleanup;
}
if (flags & DB_RDONLY)
if (is_db_rdonly)
openflags |= O_RDONLY;
else
openflags |= O_RDWR;
......@@ -1308,27 +1314,27 @@ static int toku_db_open(DB * db, DB_TXN * txn, const char *fname, const char *db
struct stat statbuf;
if (stat(db->i->full_fname, &statbuf) == 0) {
/* If the database exists at the file level, and we specified no db_name, then complain here. */
if (dbname == 0 && (flags & DB_CREATE)) {
if (flags & DB_EXCL) {
if (dbname == 0 && is_db_create) {
if (is_db_excl) {
r = EEXIST;
goto error_cleanup;
}
flags &= ~DB_CREATE;
is_db_create = 0; // It's not a create after all, since the file exists.
}
} else {
if (!(flags & DB_CREATE)) {
if (!is_db_create) {
r = ENOENT;
goto error_cleanup;
}
}
}
if (flags & DB_CREATE) openflags |= O_CREAT;
if (is_db_create) openflags |= O_CREAT;
db->i->open_flags = flags;
db->i->open_mode = mode;
r = toku_brt_open(db->i->brt, db->i->full_fname, fname, dbname,
flags & DB_CREATE, flags & DB_EXCL, dbtype==DB_UNKNOWN,
is_db_create, is_db_excl, is_db_unknown,
db->dbenv->i->cachetable,
txn ? txn->i->tokutxn : NULL_TXN);
if (r != 0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment