From 656d2e182686fed6d5b84ee711f2c771df3b14a7 Mon Sep 17 00:00:00 2001
From: Jonathan McDowell <noodles@earth.li>
Date: Mon, 31 May 2004 23:47:24 +0000
Subject: [PATCH] cscvs to tla changeset 54 Author: noodles Date: 2003/01/22
 23:31:32 Add transaction support to DB3 backend to attempt to prevent locking
 with multiple instances running at once.

---
 keydb_db3.c | 122 +++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 102 insertions(+), 20 deletions(-)

diff --git a/keydb_db3.c b/keydb_db3.c
index 6177ac7..0ccaec3 100644
--- a/keydb_db3.c
+++ b/keydb_db3.c
@@ -6,6 +6,7 @@
  * Copyright 2002 Project Purple
  */
 
+#include <assert.h>
 #include <sys/types.h>
 #include <sys/uio.h>
 #include <ctype.h>
@@ -27,6 +28,11 @@
 #include "onak-conf.h"
 #include "parsekey.h"
 
+/**
+ *	dbenv - our database environment.
+ */
+static DB_ENV *dbenv = NULL;
+
 /**
  *	dbconn - our connection to the key database.
  */
@@ -37,6 +43,11 @@ static DB *dbconn = NULL;
  */
 static DB *worddb = NULL;
 
+/**
+ *	txn - our current transaction id.
+ */
+static DB_TXN *txn = NULL;
+
 /**
  *	makewordlist - Takes a string and splits it into a set of unique words.
  *	@wordlist: The current word list.
@@ -99,38 +110,50 @@ void initdb(void)
 	char buf[1024];
 	int ret = 0;
 
-	strcpy(buf, config.db_dir);
-	strcat(buf, "/keydb.db");
-	
-	ret = db_create(&dbconn, NULL, 0);
+	ret = db_env_create(&dbenv, 0);
+	if (ret != 0) {
+		fprintf(stderr, "db_env_create: %s\n", db_strerror(ret));
+		exit(1);
+	}
+
+	ret = dbenv->open(dbenv, config.db_dir,
+			DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_LOCK |
+			DB_INIT_TXN |
+			DB_RECOVER | DB_CREATE,
+			0);
+	if (ret != 0) {
+		dbenv->err(dbenv, ret, "%s", config.db_dir);
+		exit(1);
+	}
+
+	ret = db_create(&dbconn, dbenv, 0);
 	if (ret != 0) {
 		fprintf(stderr, "db_create: %s\n", db_strerror(ret));
 		exit(1);
 	}
 
-	ret = dbconn->open(dbconn, buf, NULL, DB_HASH,
+	ret = dbconn->open(dbconn, "keydb.db", 
+			NULL,
+			DB_HASH,
 			DB_CREATE,
 			0664);
 	if (ret != 0) {
-		dbconn->err(dbconn, ret, "%s", buf);
+		dbconn->err(dbconn, ret, "keydb.db");
 		exit(1);
 	}
 
-	strcpy(buf, config.db_dir);
-	strcat(buf, "/worddb");
-	
-	ret = db_create(&worddb, NULL, 0);
+	ret = db_create(&worddb, dbenv, 0);
 	if (ret != 0) {
 		fprintf(stderr, "db_create: %s\n", db_strerror(ret));
 		exit(1);
 	}
 	ret = worddb->set_flags(worddb, DB_DUP);
 
-	ret = worddb->open(worddb, buf, NULL, DB_BTREE,
+	ret = worddb->open(worddb, "worddb", NULL, DB_BTREE,
 			DB_CREATE,
 			0664);
 	if (ret != 0) {
-		worddb->err(worddb, ret, "%s", buf);
+		worddb->err(worddb, ret, "worddb");
 		exit(1);
 	}
 	
@@ -149,6 +172,8 @@ void cleanupdb(void)
 	worddb = NULL;
 	dbconn->close(dbconn, 0);
 	dbconn = NULL;
+	dbenv->close(dbenv, 0);
+	dbenv = NULL;
 }
 
 /**
@@ -160,6 +185,19 @@ void cleanupdb(void)
  */
 bool starttrans(void)
 {
+	int ret;
+
+	assert(txn == NULL);
+
+	ret = txn_begin(dbenv,
+		NULL, /* No parent transaction */
+		&txn,
+		0);
+	if (ret != 0) {
+		dbenv->err(dbenv, ret, "starttrans():");
+		exit(1);
+	}
+
 	return true;
 }
 
@@ -170,6 +208,18 @@ bool starttrans(void)
  */
 void endtrans(void)
 {
+	int ret;
+
+	assert(txn != NULL);
+
+	ret = txn_commit(txn,
+		0);
+	if (ret != 0) {
+		dbenv->err(dbenv, ret, "endtrans():");
+		exit(1);
+	}
+	txn = NULL;
+
 	return;
 }
 
@@ -204,8 +254,12 @@ int fetch_key(uint64_t keyid, struct openpgp_publickey **publickey,
 	key.data = &keyid;
 	keyid &= 0xFFFFFFFF;
 
+	if (!intrans) {
+		starttrans();
+	}
+
 	ret = dbconn->get(dbconn,
-			NULL, /* txn id */
+			txn,
 			&key,
 			&data,
 			0); /* flags*/
@@ -224,6 +278,10 @@ int fetch_key(uint64_t keyid, struct openpgp_publickey **publickey,
 		dbconn->err(dbconn, ret, "Problem retrieving key");
 	}
 
+	if (!intrans) {
+		endtrans();
+	}
+
 	return (numkeys);
 }
 
@@ -258,9 +316,10 @@ int fetch_key_text(const char *search, struct openpgp_publickey **publickey)
 	searchtext = strdup(search);
 	wordlist = makewordlist(wordlist, searchtext);
 
+	starttrans();
 
 	ret = worddb->cursor(worddb,
-			NULL, /* txn */
+			txn,
 			&cursor,
 			0);   /* flags */
 
@@ -322,7 +381,7 @@ int fetch_key_text(const char *search, struct openpgp_publickey **publickey)
 
 			numkeys += fetch_key(keyid,
 					publickey,
-					false);
+					true);
 	}
 	llfree(keylist, free);
 	keylist = NULL;
@@ -331,6 +390,8 @@ int fetch_key_text(const char *search, struct openpgp_publickey **publickey)
 
 	ret = cursor->c_close(cursor);
 	cursor = NULL;
+
+	endtrans();
 	
 	return (numkeys);
 }
@@ -366,6 +427,10 @@ int store_key(struct openpgp_publickey *publickey, bool intrans, bool update)
 
 	keyid = get_keyid(publickey);
 
+	if (!intrans) {
+		starttrans();
+	}
+
 	/*
 	 * Delete the key if we already have it.
 	 *
@@ -404,7 +469,7 @@ int store_key(struct openpgp_publickey *publickey, bool intrans, bool update)
 	data.data = storebuf.buffer;
 
 	ret = dbconn->put(dbconn,
-			NULL, /* txn id */
+			txn,
 			&key,
 			&data,
 			0); /* flags*/
@@ -455,7 +520,7 @@ int store_key(struct openpgp_publickey *publickey, bool intrans, bool update)
 			worddb_data[10] = (keyid >>  8) & 0xFF;
 			worddb_data[11] = keyid & 0xFF; 
 			ret = worddb->put(worddb,
-				0,
+				txn,
 				&key,
 				&data,
 				0);
@@ -477,6 +542,10 @@ int store_key(struct openpgp_publickey *publickey, bool intrans, bool update)
 		uids = NULL;
 	}
 
+	if (!intrans) {
+		endtrans();
+	}
+
 	return 0;
 }
 
@@ -503,7 +572,11 @@ int delete_key(uint64_t keyid, bool intrans)
 
 	keyid &= 0xFFFFFFFF;
 
-	fetch_key(keyid, &publickey, intrans);
+	if (!intrans) {
+		starttrans();
+	}
+
+	fetch_key(keyid, &publickey, true);
 
 	/*
 	 * Walk through the uids removing the words from the worddb.
@@ -517,7 +590,7 @@ int delete_key(uint64_t keyid, bool intrans)
 		}
 				
 		ret = worddb->cursor(worddb,
-			NULL, /* txn */
+			txn,
 			&cursor,
 			0);   /* flags */
 
@@ -551,8 +624,13 @@ int delete_key(uint64_t keyid, bool intrans)
 				&key,
 				&data,
 				DB_GET_BOTH);
+
 			if (ret == 0) {
 				ret = cursor->c_del(cursor, 0);
+				if (ret != 0) {
+					worddb->err(worddb, ret,
+						"Problem deleting word.");
+				}
 			}
 
 			if (ret != 0) {
@@ -581,10 +659,14 @@ int delete_key(uint64_t keyid, bool intrans)
 	key.size = sizeof(keyid);
 
 	dbconn->del(dbconn,
-			NULL, /* txn id */
+			txn,
 			&key,
 			0); /* flags */
 
+	if (!intrans) {
+		endtrans();
+	}
+
 	return (ret == DB_NOTFOUND);
 }
 
-- 
2.39.5