changeset 8607:04816f18bf18 HEAD

Berkeley DB fixes and cleanups. Don't leak memory/bdb resources.
author Timo Sirainen <tss@iki.fi>
date Fri, 09 Jan 2009 13:14:04 -0500
parents c1fea9e157c8
children 63ec83d811bb
files src/lib-dict/dict-db.c
diffstat 1 files changed, 92 insertions(+), 72 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-dict/dict-db.c	Fri Jan 09 11:17:20 2009 -0500
+++ b/src/lib-dict/dict-db.c	Fri Jan 09 13:14:04 2009 -0500
@@ -15,6 +15,7 @@
 	DB_ENV *db_env;
 	DB *pdb;
 	DB *sdb;
+	DB_TXN *tid;
 };
 
 struct db_dict_iterate_context {
@@ -60,103 +61,119 @@
 		(*ua < *ub ? -1 : 0);
 }
 
-static struct dict *db_dict_init(struct dict *driver, const char *uri,
-				 enum dict_data_type value_type,
-				 const char *username ATTR_UNUSED)
+static int db_dict_open(struct db_dict *dict, const char *uri,
+			const char *username)
 {
-	struct db_dict *dict;
-	const char *hdir;
-	DB_TXN *tid = NULL;
-	pool_t pool;
+	const char *dir;
 	int ret;
-	
-	pool = pool_alloconly_create("db dict", 1024);
-	dict = p_new(pool, struct db_dict, 1);
-	dict->pool = pool;
-	dict->dict = *driver;
+
+	dict->db_env->set_errfile(dict->db_env, stderr);
+	dict->db_env->set_errpfx(dict->db_env,
+		p_strdup_printf(dict->pool, "db_env(%s)", username));
 
-	/* prepare the environment */
-	ret = db_env_create(&dict->db_env, 0);
+	dir = strrchr(uri, '/');
+	if (dir != NULL)
+		dir = t_strdup_until(uri, dir);
+	else
+		dir = ".";
+
+	ret = dict->db_env->open(dict->db_env, dir, DB_CREATE |
+				 DB_INIT_MPOOL | DB_INIT_TXN, 0);
 	if (ret != 0) {
-		i_error("db_env:%s\n", db_strerror(ret));
-		pool_unref(&pool);
-		return NULL;
+		i_error("db_env.open(%s) failed: %s\n", dir, db_strerror(ret));
+		return -1;
 	}
 
-	dict->db_env->set_errfile(dict->db_env, stderr);
-	dict->db_env->set_errpfx(dict->db_env, "db_env");
-
-	hdir = strrchr(uri, '/');
-	if (hdir != NULL)
-		hdir = t_strndup(uri, hdir - uri);
-
-	ret = dict->db_env->open(dict->db_env, hdir, DB_CREATE | 
-				 DB_INIT_MPOOL | DB_INIT_TXN, 0);
+	ret = dict->db_env->txn_begin(dict->db_env, NULL, &dict->tid, 0);
 	if (ret != 0) {
-		pool_unref(&pool);
-		return NULL;
-	}
-
-	ret = dict->db_env->txn_begin(dict->db_env, NULL, &tid, 0);
-	if (ret != 0) {
-		pool_unref(&pool);
-		return NULL;
+		i_error("db_env.txn_begin() failed: %s\n", db_strerror(ret));
+		return -1;
 	}
 
 	/* create both primary and secondary databases */
 	ret = db_create(&dict->pdb, dict->db_env, 0);
 	if (ret != 0) {
-		i_error("primary db:%s\n", db_strerror(ret));
-		db_dict_deinit(&dict->dict);
-		return NULL;
+		i_error("db_create(primary) failed: %s\n", db_strerror(ret));
+		return -1;
 	}
 	dict->pdb->set_errfile(dict->pdb, stderr);
-	dict->pdb->set_errpfx(dict->pdb, "primary db");
+	dict->pdb->set_errpfx(dict->pdb,
+		p_strdup_printf(dict->pool, "db(primary, %s)", username));
 
 	ret = db_create(&dict->sdb, dict->db_env, 0);
 	if (ret != 0) {
-		i_error("secondary db:%s\n", db_strerror(ret));
-		db_dict_deinit(&dict->dict);
-		return NULL;
+		i_error("db_create(secondary) failed: %s\n", db_strerror(ret));
+		return -1;
+	}
+	dict->sdb->set_errfile(dict->sdb, stderr);
+	dict->sdb->set_errpfx(dict->sdb,
+		p_strdup_printf(dict->pool, "db(secondary, %s)", username));
+
+	if ((ret = dict->pdb->open(dict->pdb, dict->tid, uri, NULL,
+				   DB_BTREE, DB_CREATE, 0)) != 0) {
+		i_error("pdb.open() failed: %s\n", db_strerror(ret));
+		return -1;
+	}
+	if (dict->sdb->set_flags(dict->sdb, DB_DUP) != 0)
+		return -1;
+	
+	/* by default keys are compared as strings. if we store uint32_t,
+	   we need a customized compare function */
+	if (dict->value_type == DICT_DATA_TYPE_UINT32) {
+		if (dict->sdb->set_bt_compare(dict->sdb, uint32_t_compare) != 0)
+			return -1;
 	}
-	dict->pdb->set_errfile(dict->pdb, stderr);
-	dict->pdb->set_errpfx(dict->pdb, "secondary db");
+
+	if ((ret = dict->sdb->open(dict->sdb, dict->tid, NULL, NULL,
+				   DB_BTREE, DB_CREATE, 0)) != 0) {
+		i_error("sdb.open() failed: %s\n", db_strerror(ret));
+		return -1;
+	}
+	if ((ret = dict->pdb->associate(dict->pdb, dict->tid, dict->sdb,
+					associate_key, DB_CREATE)) != 0) {
+		i_error("pdb.associate() failed: %s\n", db_strerror(ret));
+		return -1;
+	}
+	return 0;
+}
 
-	if (dict->pdb->open(dict->pdb, tid, uri, NULL,
-			    DB_BTREE, DB_CREATE, 0) != 0) {
-		db_dict_deinit(&dict->dict);
+static struct dict *db_dict_init(struct dict *driver, const char *uri,
+				 enum dict_data_type value_type,
+				 const char *username)
+{
+	struct db_dict *dict;
+	pool_t pool;
+	int ret, major, minor, patch;
+
+	(void)db_version(&major, &minor, &patch);
+	if (major != DB_VERSION_MAJOR || minor != DB_VERSION_MINOR) {
+		i_error("Berkeley DB version mismatch: "
+			"Compiled against %d.%d.%d headers, "
+			"run-time linked against %d.%d.%d library",
+			DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH,
+			major, minor, patch);
 		return NULL;
 	}
 
-	if (dict->sdb->set_flags(dict->sdb, DB_DUP) != 0) {
+	pool = pool_alloconly_create("db dict", 1024);
+	dict = p_new(pool, struct db_dict, 1);
+	dict->pool = pool;
+	dict->dict = *driver;
+	dict->value_type = value_type;
+
+	/* prepare the environment */
+	ret = db_env_create(&dict->db_env, 0);
+	if (ret != 0) {
+		i_error("db_env_create() failed: %s\n", db_strerror(ret));
+		pool_unref(&pool);
+		return NULL;
+	}
+
+	if (db_dict_open(dict, uri, username) < 0) {
+		i_error("db(%s) open failed", uri);
 		db_dict_deinit(&dict->dict);
 		return NULL;
 	}
-	
-	/* by default db compare keys as if they are strings.
-	   if we store uint32_t, then we need a customized
-	   compare function */
-	dict->value_type = value_type;
-	if (value_type == DICT_DATA_TYPE_UINT32) {
-		if (dict->sdb->set_bt_compare(dict->sdb,
-					      uint32_t_compare) != 0) {
-			db_dict_deinit(&dict->dict);
-			return NULL;
-		}
-	}
-
-	if (dict->sdb->open(dict->sdb, tid, NULL, NULL,
-			    DB_BTREE, DB_CREATE, 0) != 0) {
-		db_dict_deinit(&dict->dict);
-		return NULL;
-	}
-	
-	if (dict->pdb->associate(dict->pdb, tid, dict->sdb,
-				 associate_key, DB_CREATE) != 0) {
-		db_dict_deinit(&dict->dict);
-		return NULL;
-	}
-	
 	return &dict->dict;
 }
 
@@ -164,10 +181,13 @@
 {
 	struct db_dict *dict = (struct db_dict *)_dict;
 
+	if (dict->tid != NULL)
+		(void)dict->tid->commit(dict->tid, 0);
 	if (dict->pdb != NULL)
 		dict->pdb->close(dict->pdb, 0);
 	if (dict->sdb != NULL)
 		dict->sdb->close(dict->sdb, 0);
+	dict->db_env->close(dict->db_env, 0);
 	pool_unref(&dict->pool);
 }