Berkeley DB fixes and cleanups. Don't leak memory/bdb resources.
1.1 --- a/src/lib-dict/dict-db.c Thu Jan 08 14:47:20 2009 -0500
1.2 +++ b/src/lib-dict/dict-db.c Fri Jan 09 13:14:04 2009 -0500
1.3 @@ -15,6 +15,7 @@
1.4 DB_ENV *db_env;
1.5 DB *pdb;
1.6 DB *sdb;
1.7 + DB_TXN *tid;
1.8 };
1.9
1.10 struct db_dict_iterate_context {
1.11 @@ -60,103 +61,119 @@
1.12 (*ua < *ub ? -1 : 0);
1.13 }
1.14
1.15 -static struct dict *db_dict_init(struct dict *driver, const char *uri,
1.16 - enum dict_data_type value_type,
1.17 - const char *username ATTR_UNUSED)
1.18 +static int db_dict_open(struct db_dict *dict, const char *uri,
1.19 + const char *username)
1.20 {
1.21 - struct db_dict *dict;
1.22 - const char *hdir;
1.23 - DB_TXN *tid = NULL;
1.24 - pool_t pool;
1.25 + const char *dir;
1.26 int ret;
1.27 -
1.28 - pool = pool_alloconly_create("db dict", 1024);
1.29 - dict = p_new(pool, struct db_dict, 1);
1.30 - dict->pool = pool;
1.31 - dict->dict = *driver;
1.32
1.33 - /* prepare the environment */
1.34 - ret = db_env_create(&dict->db_env, 0);
1.35 + dict->db_env->set_errfile(dict->db_env, stderr);
1.36 + dict->db_env->set_errpfx(dict->db_env,
1.37 + p_strdup_printf(dict->pool, "db_env(%s)", username));
1.38 +
1.39 + dir = strrchr(uri, '/');
1.40 + if (dir != NULL)
1.41 + dir = t_strdup_until(uri, dir);
1.42 + else
1.43 + dir = ".";
1.44 +
1.45 + ret = dict->db_env->open(dict->db_env, dir, DB_CREATE |
1.46 + DB_INIT_MPOOL | DB_INIT_TXN, 0);
1.47 if (ret != 0) {
1.48 - i_error("db_env:%s\n", db_strerror(ret));
1.49 - pool_unref(&pool);
1.50 - return NULL;
1.51 + i_error("db_env.open(%s) failed: %s\n", dir, db_strerror(ret));
1.52 + return -1;
1.53 }
1.54
1.55 - dict->db_env->set_errfile(dict->db_env, stderr);
1.56 - dict->db_env->set_errpfx(dict->db_env, "db_env");
1.57 -
1.58 - hdir = strrchr(uri, '/');
1.59 - if (hdir != NULL)
1.60 - hdir = t_strndup(uri, hdir - uri);
1.61 -
1.62 - ret = dict->db_env->open(dict->db_env, hdir, DB_CREATE |
1.63 - DB_INIT_MPOOL | DB_INIT_TXN, 0);
1.64 + ret = dict->db_env->txn_begin(dict->db_env, NULL, &dict->tid, 0);
1.65 if (ret != 0) {
1.66 - pool_unref(&pool);
1.67 - return NULL;
1.68 - }
1.69 -
1.70 - ret = dict->db_env->txn_begin(dict->db_env, NULL, &tid, 0);
1.71 - if (ret != 0) {
1.72 - pool_unref(&pool);
1.73 - return NULL;
1.74 + i_error("db_env.txn_begin() failed: %s\n", db_strerror(ret));
1.75 + return -1;
1.76 }
1.77
1.78 /* create both primary and secondary databases */
1.79 ret = db_create(&dict->pdb, dict->db_env, 0);
1.80 if (ret != 0) {
1.81 - i_error("primary db:%s\n", db_strerror(ret));
1.82 + i_error("db_create(primary) failed: %s\n", db_strerror(ret));
1.83 + return -1;
1.84 + }
1.85 + dict->pdb->set_errfile(dict->pdb, stderr);
1.86 + dict->pdb->set_errpfx(dict->pdb,
1.87 + p_strdup_printf(dict->pool, "db(primary, %s)", username));
1.88 +
1.89 + ret = db_create(&dict->sdb, dict->db_env, 0);
1.90 + if (ret != 0) {
1.91 + i_error("db_create(secondary) failed: %s\n", db_strerror(ret));
1.92 + return -1;
1.93 + }
1.94 + dict->sdb->set_errfile(dict->sdb, stderr);
1.95 + dict->sdb->set_errpfx(dict->sdb,
1.96 + p_strdup_printf(dict->pool, "db(secondary, %s)", username));
1.97 +
1.98 + if ((ret = dict->pdb->open(dict->pdb, dict->tid, uri, NULL,
1.99 + DB_BTREE, DB_CREATE, 0)) != 0) {
1.100 + i_error("pdb.open() failed: %s\n", db_strerror(ret));
1.101 + return -1;
1.102 + }
1.103 + if (dict->sdb->set_flags(dict->sdb, DB_DUP) != 0)
1.104 + return -1;
1.105 +
1.106 + /* by default keys are compared as strings. if we store uint32_t,
1.107 + we need a customized compare function */
1.108 + if (dict->value_type == DICT_DATA_TYPE_UINT32) {
1.109 + if (dict->sdb->set_bt_compare(dict->sdb, uint32_t_compare) != 0)
1.110 + return -1;
1.111 + }
1.112 +
1.113 + if ((ret = dict->sdb->open(dict->sdb, dict->tid, NULL, NULL,
1.114 + DB_BTREE, DB_CREATE, 0)) != 0) {
1.115 + i_error("sdb.open() failed: %s\n", db_strerror(ret));
1.116 + return -1;
1.117 + }
1.118 + if ((ret = dict->pdb->associate(dict->pdb, dict->tid, dict->sdb,
1.119 + associate_key, DB_CREATE)) != 0) {
1.120 + i_error("pdb.associate() failed: %s\n", db_strerror(ret));
1.121 + return -1;
1.122 + }
1.123 + return 0;
1.124 +}
1.125 +
1.126 +static struct dict *db_dict_init(struct dict *driver, const char *uri,
1.127 + enum dict_data_type value_type,
1.128 + const char *username)
1.129 +{
1.130 + struct db_dict *dict;
1.131 + pool_t pool;
1.132 + int ret, major, minor, patch;
1.133 +
1.134 + (void)db_version(&major, &minor, &patch);
1.135 + if (major != DB_VERSION_MAJOR || minor != DB_VERSION_MINOR) {
1.136 + i_error("Berkeley DB version mismatch: "
1.137 + "Compiled against %d.%d.%d headers, "
1.138 + "run-time linked against %d.%d.%d library",
1.139 + DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH,
1.140 + major, minor, patch);
1.141 + return NULL;
1.142 + }
1.143 +
1.144 + pool = pool_alloconly_create("db dict", 1024);
1.145 + dict = p_new(pool, struct db_dict, 1);
1.146 + dict->pool = pool;
1.147 + dict->dict = *driver;
1.148 + dict->value_type = value_type;
1.149 +
1.150 + /* prepare the environment */
1.151 + ret = db_env_create(&dict->db_env, 0);
1.152 + if (ret != 0) {
1.153 + i_error("db_env_create() failed: %s\n", db_strerror(ret));
1.154 + pool_unref(&pool);
1.155 + return NULL;
1.156 + }
1.157 +
1.158 + if (db_dict_open(dict, uri, username) < 0) {
1.159 + i_error("db(%s) open failed", uri);
1.160 db_dict_deinit(&dict->dict);
1.161 return NULL;
1.162 }
1.163 - dict->pdb->set_errfile(dict->pdb, stderr);
1.164 - dict->pdb->set_errpfx(dict->pdb, "primary db");
1.165 -
1.166 - ret = db_create(&dict->sdb, dict->db_env, 0);
1.167 - if (ret != 0) {
1.168 - i_error("secondary db:%s\n", db_strerror(ret));
1.169 - db_dict_deinit(&dict->dict);
1.170 - return NULL;
1.171 - }
1.172 - dict->pdb->set_errfile(dict->pdb, stderr);
1.173 - dict->pdb->set_errpfx(dict->pdb, "secondary db");
1.174 -
1.175 - if (dict->pdb->open(dict->pdb, tid, uri, NULL,
1.176 - DB_BTREE, DB_CREATE, 0) != 0) {
1.177 - db_dict_deinit(&dict->dict);
1.178 - return NULL;
1.179 - }
1.180 -
1.181 - if (dict->sdb->set_flags(dict->sdb, DB_DUP) != 0) {
1.182 - db_dict_deinit(&dict->dict);
1.183 - return NULL;
1.184 - }
1.185 -
1.186 - /* by default db compare keys as if they are strings.
1.187 - if we store uint32_t, then we need a customized
1.188 - compare function */
1.189 - dict->value_type = value_type;
1.190 - if (value_type == DICT_DATA_TYPE_UINT32) {
1.191 - if (dict->sdb->set_bt_compare(dict->sdb,
1.192 - uint32_t_compare) != 0) {
1.193 - db_dict_deinit(&dict->dict);
1.194 - return NULL;
1.195 - }
1.196 - }
1.197 -
1.198 - if (dict->sdb->open(dict->sdb, tid, NULL, NULL,
1.199 - DB_BTREE, DB_CREATE, 0) != 0) {
1.200 - db_dict_deinit(&dict->dict);
1.201 - return NULL;
1.202 - }
1.203 -
1.204 - if (dict->pdb->associate(dict->pdb, tid, dict->sdb,
1.205 - associate_key, DB_CREATE) != 0) {
1.206 - db_dict_deinit(&dict->dict);
1.207 - return NULL;
1.208 - }
1.209 -
1.210 return &dict->dict;
1.211 }
1.212
1.213 @@ -164,10 +181,13 @@
1.214 {
1.215 struct db_dict *dict = (struct db_dict *)_dict;
1.216
1.217 + if (dict->tid != NULL)
1.218 + (void)dict->tid->commit(dict->tid, 0);
1.219 if (dict->pdb != NULL)
1.220 dict->pdb->close(dict->pdb, 0);
1.221 if (dict->sdb != NULL)
1.222 dict->sdb->close(dict->sdb, 0);
1.223 + dict->db_env->close(dict->db_env, 0);
1.224 pool_unref(&dict->pool);
1.225 }
1.226