Commit e5d4bd7c authored by Bradley C. Kuszmaul's avatar Bradley C. Kuszmaul

Clean up the valgrind memory leaks (caused by lots of subtle c++ bugs. Addresse #215

git-svn-id: file:///svn/tokudb@1320 c7de825b-a66e-492c-adef-691d508d4ae1
parent 824b7137
...@@ -15,3 +15,7 @@ test1: test1.o dbt.o db.o dbenv.o ../lib/libdb.a ...@@ -15,3 +15,7 @@ test1: test1.o dbt.o db.o dbenv.o ../lib/libdb.a
$(LIBNAME).a: $(OBJS) $(LIBNAME).a: $(OBJS)
$(AR) rv $@ $(OBJS) $(AR) rv $@ $(OBJS)
clean:
rm -f $(OBJS) $(LIBNAME).a $(LIBNAME).so
...@@ -27,11 +27,13 @@ Db::Db(DbEnv *env, u_int32_t flags) ...@@ -27,11 +27,13 @@ Db::Db(DbEnv *env, u_int32_t flags)
} }
Db::~Db() { Db::~Db() {
if (is_private_env) { if (is_private_env && the_Env) {
delete the_Env; // The destructor closes the env. the_Env->close(0);
delete the_Env;
} }
if (!the_db) { if (the_db) {
close(0); // the user should have called close, but we do it here if not done. close(0); // the user should have called close, but we do it here if not done.
assert(the_db==0);
} }
} }
...@@ -41,13 +43,25 @@ int Db::close (u_int32_t flags) { ...@@ -41,13 +43,25 @@ int Db::close (u_int32_t flags) {
} }
the_db->api_internal = 0; the_db->api_internal = 0;
int ret = the_db->close(the_db, flags); int ret = the_db->close(the_db, flags);
the_db = 0; the_db = 0;
int no_exceptions = the_Env->do_no_exceptions; // Get this out before possibly deleting the env
if (is_private_env) {
// The env was closed by the_db->close, we have to tell the DbEnv that the DB_ENV is gone, and delete it.
the_Env->the_env = 0;
delete the_Env;
the_Env=0;
}
// Do we need to clean up "private environments"? // Do we need to clean up "private environments"?
// What about cursors? They should be cleaned up already, but who did it? // What about cursors? They should be cleaned up already, but who did it?
return the_Env->maybe_throw_error(ret); // This maybe_throw must be the static one because the env is gone.
return DbEnv::maybe_throw_error(ret, NULL, no_exceptions);
} }
int Db::open(DbTxn *txn, const char *filename, const char *subname, DBTYPE typ, u_int32_t flags, int mode) { int Db::open(DbTxn *txn, const char *filename, const char *subname, DBTYPE typ, u_int32_t flags, int mode) {
...@@ -72,6 +86,7 @@ int Db::set_pagesize(u_int32_t size) { ...@@ -72,6 +86,7 @@ int Db::set_pagesize(u_int32_t size) {
int Db::remove(const char *file, const char *database, u_int32_t flags) { int Db::remove(const char *file, const char *database, u_int32_t flags) {
int ret = the_db->remove(the_db, file, database, flags); int ret = the_db->remove(the_db, file, database, flags);
the_db = 0;
return the_Env->maybe_throw_error(ret); return the_Env->maybe_throw_error(ret);
} }
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
int Dbc::close (void) { int Dbc::close (void) {
DBC *dbc = this; DBC *dbc = this;
DbEnv *env = (DbEnv*)dbc->dbp->api_internal; // Must grab the env before closing the cursor.
int ret = dbc->c_close(dbc); int ret = dbc->c_close(dbc);
DbEnv *env = (DbEnv*)dbc->dbp->api_internal;
return env->maybe_throw_error(ret); return env->maybe_throw_error(ret);
} }
......
...@@ -23,9 +23,18 @@ DbEnv::DbEnv(DB_ENV *env, u_int32_t flags) ...@@ -23,9 +23,18 @@ DbEnv::DbEnv(DB_ENV *env, u_int32_t flags)
the_env->api1_internal = this; the_env->api1_internal = this;
} }
// If still open, close it. In most cases, the caller should call close explicitly so that they can catch the exceptions.
DbEnv::~DbEnv(void)
{
if (the_env!=NULL) {
(void)the_env->close(the_env, 0);
the_env = 0;
}
}
int DbEnv::close(u_int32_t flags) { int DbEnv::close(u_int32_t flags) {
int ret = the_env->close(the_env, flags); int ret = the_env->close(the_env, flags);
the_env = 0; /* get rid of the env ref, so we don't touch it (even if we failed.) */ the_env = 0; /* get rid of the env ref, so we don't touch it (even if we failed, or when the destructor is called) */
return maybe_throw_error(ret); return maybe_throw_error(ret);
} }
...@@ -64,19 +73,23 @@ void DbEnv::set_errpfx(const char *errpfx) { ...@@ -64,19 +73,23 @@ void DbEnv::set_errpfx(const char *errpfx) {
the_env->set_errpfx(the_env, errpfx); the_env->set_errpfx(the_env, errpfx);
} }
int DbEnv::maybe_throw_error(int err) throw (DbException) { int DbEnv::maybe_throw_error(int err, DbEnv *env, int no_exceptions) throw (DbException) {
if (err==0) return 0; if (err==0) return 0;
if (do_no_exceptions) return err; if (no_exceptions) return err;
if (err==DB_LOCK_DEADLOCK) { if (err==DB_LOCK_DEADLOCK) {
DbDeadlockException e(this); DbDeadlockException e(env);
throw e; throw e;
} else { } else {
DbException e(err); DbException e(err);
e.set_env(this); e.set_env(env);
throw e; throw e;
} }
} }
int DbEnv::maybe_throw_error(int err) throw (DbException) {
return maybe_throw_error(err, this, do_no_exceptions);
}
extern "C" { extern "C" {
void toku_db_env_err_vararg(const DB_ENV * env, int error, const char *fmt, va_list ap); void toku_db_env_err_vararg(const DB_ENV * env, int error, const char *fmt, va_list ap);
}; };
......
...@@ -5,6 +5,12 @@ CPPFLAGS = -I../ -I../../include ...@@ -5,6 +5,12 @@ CPPFLAGS = -I../ -I../../include
CXXFLAGS = -Wall -g CXXFLAGS = -Wall -g
LDLIBS = ../../lib/libtdb_cxx.a ../../lib/libdb.a -lz LDLIBS = ../../lib/libtdb_cxx.a ../../lib/libdb.a -lz
ifeq ($(OSX),OSX)
VGRIND=
else
VGRIND=valgrind --quiet --error-exitcode=1 --leak-check=yes
endif
all: $(TARGETS) all: $(TARGETS)
$(TARGETS): $(DBCXX) $(TARGETS): $(DBCXX)
...@@ -15,5 +21,9 @@ clean: ...@@ -15,5 +21,9 @@ clean:
rm -rf $(TARGETS) rm -rf $(TARGETS)
check: $(TARGETS) check: $(TARGETS)
./test1 $(VGRIND) ./test1
./test1e $(VGRIND) ./test1e
$(VGRIND) ./db_create foo.db a b c d
$(VGRIND) ./db_dump foo.db > foo.out
(echo " 61";echo " 62";echo " 63";echo " 64")>foo.expectout
diff foo.out foo.expectout
...@@ -36,6 +36,8 @@ void test_db(void) { ...@@ -36,6 +36,8 @@ void test_db(void) {
r = db.set_bt_compare(cmp); assert(r == 0); r = db.set_bt_compare(cmp); assert(r == 0);
r = db.remove("DoesNotExist.db", NULL, 0); assert(r == ENOENT); r = db.remove("DoesNotExist.db", NULL, 0); assert(r == ENOENT);
// The db is closed
r = env.close(0); assert(r== 0);
} }
void test_db_env(void) { void test_db_env(void) {
...@@ -55,6 +57,5 @@ int main() ...@@ -55,6 +57,5 @@ int main()
test_dbt(); test_dbt();
test_db(); test_db();
test_db_env(); test_db_env();
cout << "Hello World!" << endl; cout << "Welcome to C++ Programming" << endl;
return 0; return 0;
} }
...@@ -68,6 +68,5 @@ int main() ...@@ -68,6 +68,5 @@ int main()
test_dbt(); test_dbt();
test_db(); test_db();
test_db_env(); test_db_env();
cout << "Hello World!" << endl; cout << "Welcome to C++ Programming" << endl;
return 0; return 0;
} }
...@@ -9,5 +9,6 @@ DbTxn::DbTxn(DB_TXN *txn) ...@@ -9,5 +9,6 @@ DbTxn::DbTxn(DB_TXN *txn)
int DbTxn::commit (u_int32_t flags) { int DbTxn::commit (u_int32_t flags) {
DB_TXN *txn = get_DB_TXN(); DB_TXN *txn = get_DB_TXN();
int ret = txn->commit(txn, flags); int ret = txn->commit(txn, flags);
return ret; DbEnv *env = (DbEnv*)txn->mgrp->api1_internal;
return env->maybe_throw_error(ret);
} }
...@@ -211,8 +211,9 @@ struct __toku_db_txn_active { ...@@ -211,8 +211,9 @@ struct __toku_db_txn_active {
char __toku_dummy2[184]; /* Padding at the end */ char __toku_dummy2[184]; /* Padding at the end */
}; };
struct __toku_db_txn { struct __toku_db_txn {
DB_ENV *mgrp /*In TokuDB, mgrp is a DB_ENV not a DB_TXNMGR*/; /* 32-bit offset=0 size=4, 64=bit offset=0 size=8 */
struct __toku_db_txn_internal *i; struct __toku_db_txn_internal *i;
void* __toku_dummy0[18]; void* __toku_dummy0[17];
char __toku_dummy1[8]; char __toku_dummy1[8];
void *api_internal; /* 32-bit offset=84 size=4, 64=bit offset=160 size=8 */ void *api_internal; /* 32-bit offset=84 size=4, 64=bit offset=160 size=8 */
void* __toku_dummy2[2]; void* __toku_dummy2[2];
......
...@@ -117,8 +117,10 @@ class Db { ...@@ -117,8 +117,10 @@ class Db {
class DbEnv { class DbEnv {
friend class Db; friend class Db;
friend class Dbc; friend class Dbc;
friend class DbTxn;
public: public:
DbEnv(u_int32_t flags); DbEnv(u_int32_t flags);
~DbEnv(void);
DB_ENV *get_DB_ENV(void) { DB_ENV *get_DB_ENV(void) {
if (this==0) return 0; if (this==0) return 0;
...@@ -145,6 +147,7 @@ class DbEnv { ...@@ -145,6 +147,7 @@ class DbEnv {
DbEnv(DB_ENV *, u_int32_t /*flags*/); DbEnv(DB_ENV *, u_int32_t /*flags*/);
int maybe_throw_error(int /*err*/) throw (DbException); int maybe_throw_error(int /*err*/) throw (DbException);
static int maybe_throw_error(int, DbEnv*, int /*no_exceptions*/) throw (DbException);
}; };
...@@ -161,6 +164,7 @@ class DbTxn { ...@@ -161,6 +164,7 @@ class DbTxn {
DbTxn(DB_TXN*); DbTxn(DB_TXN*);
private: private:
DB_TXN *the_txn; DB_TXN *the_txn;
}; };
class Dbc : protected DBC class Dbc : protected DBC
......
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