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) ...@@ -13,7 +13,7 @@ Db::Db(DbEnv *env, u_int32_t flags)
is_private_env = (the_Env == 0); is_private_env = (the_Env == 0);
DB *tmp_db; 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) { if (ret!=0) {
the_Env->maybe_throw_error(ret); the_Env->maybe_throw_error(ret);
// Otherwise cannot do much // Otherwise cannot do much
......
...@@ -14,3 +14,9 @@ int Dbc::get(Dbt* key, Dbt *data, u_int32_t flags) { ...@@ -14,3 +14,9 @@ int Dbc::get(Dbt* key, Dbt *data, u_int32_t flags) {
DbEnv *env = (DbEnv*)dbenv_c->api1_internal; DbEnv *env = (DbEnv*)dbenv_c->api1_internal;
return env->maybe_throw_error(ret); return env->maybe_throw_error(ret);
} }
// Not callable, but some compilers require it to be defined anyway.
Dbc::~Dbc()
{
}
#include <assert.h> #include <assert.h>
#include <db_cxx.h> #include <db_cxx.h>
#include <errno.h> #include <errno.h>
#include <unistd.h>
#define TC(expr, expect) ({ \ #define TC(expr, expect) ({ \
try { \ try { \
...@@ -47,7 +48,63 @@ void test_env_exceptions (void) { ...@@ -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[]) { int main(int argc, char *argv[]) {
test_env_exceptions(); test_env_exceptions();
test_db_exceptions();
return 0; return 0;
} }
...@@ -100,7 +100,7 @@ class Db { ...@@ -100,7 +100,7 @@ class Db {
int cursor(DbTxn */*txnid*/, Dbc **/*cursorp*/, u_int32_t /*flags*/); int cursor(DbTxn */*txnid*/, Dbc **/*cursorp*/, u_int32_t /*flags*/);
int del(DbTxn */*txnid*/, Dbt */*key*/, 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 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 put(DbTxn *, Dbt *, Dbt *, u_int32_t);
int get_flags(u_int32_t *); int get_flags(u_int32_t *);
int set_flags(u_int32_t); int set_flags(u_int32_t);
...@@ -175,4 +175,7 @@ class Dbc : protected DBC ...@@ -175,4 +175,7 @@ class Dbc : protected DBC
public: public:
int close(void); int close(void);
int get(Dbt*, Dbt *, u_int32_t); 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 ...@@ -1561,6 +1561,11 @@ int toku_brt_open(BRT t, const char *fname, const char *fname_in_env, const char
} }
assert(t->nodesize>0); assert(t->nodesize>0);
//printf("%s:%d %d alloced\n", __FILE__, __LINE__, get_n_items_malloced()); toku_print_malloced_items(); //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) { if (is_create) {
r = toku_read_and_pin_brt_header(t->cf, &t->h); r = toku_read_and_pin_brt_header(t->cf, &t->h);
if (r==-1) { if (r==-1) {
...@@ -1569,7 +1574,8 @@ int toku_brt_open(BRT t, const char *fname, const char *fname_in_env, const char ...@@ -1569,7 +1574,8 @@ int toku_brt_open(BRT t, const char *fname, const char *fname_in_env, const char
assert(errno==ENOMEM); assert(errno==ENOMEM);
r = ENOMEM; r = ENOMEM;
if (0) { died2: toku_free(t->h); } if (0) { died2: toku_free(t->h); }
goto died1; t->h=0;
goto died_after_read_and_pin;
} }
t->h->dirty=1; t->h->dirty=1;
t->h->flags = t->flags; 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 ...@@ -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; } 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) { else if (r!=0) {
goto died1; goto died_after_read_and_pin;
} }
else { else {
int i; int i;
assert(r==0); assert(r==0);
assert(dbname); 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); assert(t->h->n_named_roots>=0);
for (i=0; i<t->h->n_named_roots; i++) { for (i=0; i<t->h->n_named_roots; i++) {
if (strcmp(t->h->names[i], dbname)==0) { if (strcmp(t->h->names[i], dbname)==0) {
if (only_create) { if (only_create) {
r = EEXIST; r = EEXIST;
goto died1; /* deallocate everything. */ goto died_after_read_and_pin;
} }
else goto found_it; 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->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 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 died_after_read_and_pin; }
t->h->n_named_roots++; 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); //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->roots[t->h->n_named_roots-1] = malloc_diskblock_header_is_in_memory(t, t->h->nodesize);
t->h->dirty = 1; 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 { } else {
if ((r = toku_read_and_pin_brt_header(t->cf, &t->h))!=0) goto died1; if ((r = toku_read_and_pin_brt_header(t->cf, &t->h))!=0) goto died1;
if (!dbname) { 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 { } else {
int i; 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); // printf("%s:%d n_roots=%d\n", __FILE__, __LINE__, t->h->n_named_roots);
for (i=0; i<t->h->n_named_roots; i++) { for (i=0; i<t->h->n_named_roots; i++) {
if (strcmp(t->h->names[i], dbname)==0) { 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 ...@@ -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 */ r=ENOENT; /* the database doesn't exist */
goto died1; goto died_after_read_and_pin;
} }
found_it: found_it:
t->nodesize = t->h->nodesize; /* inherit the pagesize from the file */ t->nodesize = t->h->nodesize; /* inherit the pagesize from the file */
if (t->flags != t->h->flags) { /* flags must match */ if (t->flags != t->h->flags) { /* flags must match */
if (load_flags) t->flags = t->h->flags; 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); 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); assert(t->h==0);
WHEN_BRTTRACE(fprintf(stderr, "BRTTRACE -> %p\n", t)); WHEN_BRTTRACE(fprintf(stderr, "BRTTRACE -> %p\n", t));
return 0; return 0;
...@@ -2914,6 +2921,8 @@ int toku_brt_cursor_get (BRT_CURSOR cursor, DBT *kbt, DBT *vbt, int flags, TOKUT ...@@ -2914,6 +2921,8 @@ int toku_brt_cursor_get (BRT_CURSOR cursor, DBT *kbt, DBT *vbt, int flags, TOKUT
if (r != 0) goto died0; if (r != 0) goto died0;
break; break;
default: default:
toku_unpin_brt_header(cursor->brt);
return EINVAL;
fprintf(stderr, "%s:%d c_get(...,%d) not ready\n", __FILE__, __LINE__, flags); fprintf(stderr, "%s:%d c_get(...,%d) not ready\n", __FILE__, __LINE__, flags);
abort(); abort();
} }
......
...@@ -124,6 +124,7 @@ NO_VGRIND = \ ...@@ -124,6 +124,7 @@ NO_VGRIND = \
db_env_open_open_close \ db_env_open_open_close \
db_open_notexist_reopen \ db_open_notexist_reopen \
db_remove_subdb \ db_remove_subdb \
log4 \
# Comment to terminate list so the previous line can end with a slash # Comment to terminate list so the previous line can end with a slash
$(patsubst %,test_%.bdbrun,$(NO_VGRIND)): VGRIND= $(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 ...@@ -1285,11 +1285,17 @@ static int toku_db_open(DB * db, DB_TXN * txn, const char *fname, const char *db
int openflags = 0; int openflags = 0;
int r; int r;
if (dbtype!=DB_BTREE && dbtype!=DB_UNKNOWN) return EINVAL; if (dbtype!=DB_BTREE && dbtype!=DB_UNKNOWN) return EINVAL;
if ((flags & DB_EXCL) && !(flags & DB_CREATE)) return EINVAL; int is_db_excl = flags & DB_EXCL; flags&=~DB_EXCL;
if (dbtype==DB_UNKNOWN && (flags & DB_EXCL)) return EINVAL; 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)) 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); r = find_db_file(db->dbenv, fname, &db->i->full_fname);
if (r != 0) goto error_cleanup; 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 ...@@ -1299,7 +1305,7 @@ static int toku_db_open(DB * db, DB_TXN * txn, const char *fname, const char *db
r = ENOMEM; r = ENOMEM;
goto error_cleanup; goto error_cleanup;
} }
if (flags & DB_RDONLY) if (is_db_rdonly)
openflags |= O_RDONLY; openflags |= O_RDONLY;
else else
openflags |= O_RDWR; openflags |= O_RDWR;
...@@ -1308,29 +1314,29 @@ static int toku_db_open(DB * db, DB_TXN * txn, const char *fname, const char *db ...@@ -1308,29 +1314,29 @@ static int toku_db_open(DB * db, DB_TXN * txn, const char *fname, const char *db
struct stat statbuf; struct stat statbuf;
if (stat(db->i->full_fname, &statbuf) == 0) { 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 the database exists at the file level, and we specified no db_name, then complain here. */
if (dbname == 0 && (flags & DB_CREATE)) { if (dbname == 0 && is_db_create) {
if (flags & DB_EXCL) { if (is_db_excl) {
r = EEXIST; r = EEXIST;
goto error_cleanup; goto error_cleanup;
} }
flags &= ~DB_CREATE; is_db_create = 0; // It's not a create after all, since the file exists.
} }
} else { } else {
if (!(flags & DB_CREATE)) { if (!is_db_create) {
r = ENOENT; r = ENOENT;
goto error_cleanup; 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_flags = flags;
db->i->open_mode = mode; db->i->open_mode = mode;
r = toku_brt_open(db->i->brt, db->i->full_fname, fname, dbname, 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, db->dbenv->i->cachetable,
txn ? txn->i->tokutxn : NULL_TXN); txn ? txn->i->tokutxn : NULL_TXN);
if (r != 0) if (r != 0)
goto error_cleanup; goto error_cleanup;
......
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