+ snprintf(buf, sizeof(buf) - 1, "%s/num_keydb", config.db_dir);
+ numdb = fopen(buf, "r");
+ if (numdb != NULL) {
+ if (fgets(buf, sizeof(buf), numdb) != NULL) {
+ privctx->numdbs = atoi(buf);
+ }
+ fclose(numdb);
+ } else if (!readonly) {
+ logthing(LOGTHING_ERROR, "Couldn't open num_keydb: %s",
+ strerror(errno));
+ numdb = fopen(buf, "w");
+ if (numdb != NULL) {
+ fprintf(numdb, "%d", privctx->numdbs);
+ fclose(numdb);
+ } else {
+ logthing(LOGTHING_ERROR,
+ "Couldn't write num_keydb: %s",
+ strerror(errno));
+ }
+ }
+
+ privctx->dbconns = calloc(privctx->numdbs, sizeof (DB *));
+ if (privctx->dbconns == NULL) {
+ logthing(LOGTHING_CRITICAL,
+ "Couldn't allocate memory for dbconns");
+ ret = 1;
+ }
+
+ if (ret == 0) {
+ ret = db_env_create(&privctx->dbenv, 0);
+ if (ret != 0) {
+ logthing(LOGTHING_CRITICAL,
+ "db_env_create: %s", db_strerror(ret));
+ }
+ }
+
+ /*
+ * Up the number of locks we're allowed at once. We base this on
+ * the maximum number of keys we're going to return.
+ */
+ maxlocks = config.maxkeys * 16;
+ if (maxlocks < 1000) {
+ maxlocks = 1000;
+ }
+ privctx->dbenv->set_lk_max_locks(privctx->dbenv, maxlocks);
+ privctx->dbenv->set_lk_max_objects(privctx->dbenv, maxlocks);
+
+ /*
+ * Enable deadlock detection so that we don't block indefinitely on
+ * anything. What we really want is simple 2 state locks, but I'm not
+ * sure how to make the standard DB functions do that yet.
+ */
+ if (ret == 0) {
+ privctx->dbenv->set_errcall(privctx->dbenv, &db4_errfunc);
+ ret = privctx->dbenv->set_lk_detect(privctx->dbenv, DB_LOCK_DEFAULT);
+ if (ret != 0) {
+ logthing(LOGTHING_CRITICAL,
+ "db_env_create: %s", db_strerror(ret));
+ }
+ }
+
+ if (ret == 0) {
+ ret = privctx->dbenv->open(privctx->dbenv, config.db_dir,
+ DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_LOCK |
+ DB_INIT_TXN |
+ DB_CREATE,
+ 0);
+#ifdef DB_VERSION_MISMATCH
+ if (ret == DB_VERSION_MISMATCH) {
+ privctx->dbenv->close(privctx->dbenv, 0);
+ privctx->dbenv = NULL;
+ ret = db4_upgradedb(privctx);
+ if (ret == 0) {
+ ret = db_env_create(&privctx->dbenv, 0);
+ }
+ if (ret == 0) {
+ privctx->dbenv->set_errcall(privctx->dbenv,
+ &db4_errfunc);
+ privctx->dbenv->set_lk_detect(privctx->dbenv,
+ DB_LOCK_DEFAULT);
+ ret = privctx->dbenv->open(privctx->dbenv,
+ config.db_dir,
+ DB_INIT_LOG | DB_INIT_MPOOL |
+ DB_INIT_LOCK | DB_INIT_TXN |
+ DB_CREATE | DB_RECOVER,
+ 0);
+
+ if (ret == 0) {
+ privctx->dbenv->txn_checkpoint(
+ privctx->dbenv,
+ 0,
+ 0,
+ DB_FORCE);
+ }
+ }
+ }
+#endif
+ if (ret != 0) {
+ logthing(LOGTHING_CRITICAL,
+ "Error opening db environment: %s (%s)",
+ config.db_dir,
+ db_strerror(ret));
+ if (privctx->dbenv != NULL) {
+ privctx->dbenv->close(privctx->dbenv, 0);
+ privctx->dbenv = NULL;