Tue Jan 15 16:23:44 CET 2008  kaplan+greyfix@kim-minh.com
  * BUGFIX detect deadlocks during run_expiry.
  Closes ticket #8 <URL:http://trac.kim-minh.com/greyfix/ticket/8>
diff -rN -u old-greyfix/greyfix.c new-greyfix/greyfix.c
--- old-greyfix/greyfix.c	2008-01-15 16:30:40.000000000 +0100
+++ new-greyfix/greyfix.c	2008-01-15 16:30:40.000000000 +0100
@@ -79,6 +79,7 @@
 static DBT dbkey = { 0 };
 static DBT dbdata = { 0 };
 static struct triplet_data triplet_data;
+static int deadlock_detect = 0;
 
 static unsigned long greylist_delay = DELAY_MAIL_SECS;
 static unsigned long bloc_max_idle = AUTO_RECORD_LIFE_SECS;
@@ -161,6 +162,11 @@
 	log_db_error("db_env_create", rc);
     else {
 	dbenv->set_errcall(dbenv, db_errcall_fcn);
+	rc = dbenv->set_lk_detect(dbenv, DB_LOCK_YOUNGEST);
+	if (rc)
+	    log_db_error("dbenv->set_lk_detect DB_LOCK_YOUNGEST, expired triplets will not be deleted", rc);
+	else
+	    deadlock_detect = 1;
 	rc = dbenv->open(dbenv, db_home,
 			 DB_INIT_LOCK | DB_INIT_MPOOL | DB_CREATE, 0);
 	if (rc) {
@@ -269,7 +275,10 @@
     int rc;
     time_t now;
     unsigned int count = 0;
-    if (db == 0)
+    /* Cursor operations can hold several locks and therefore deadlock
+       so don't run expiry if deadlock detection does not work
+       http://www.oracle.com/technology/documentation/berkeley-db/db/ref/lock/notxn.html */
+    if (db == 0 || deadlock_detect == 0)
 	return;
     if (time(&now) == (time_t)-1) {
 	syslog(LOG_ERR, "time failed during run_expiry");
@@ -303,7 +312,10 @@
 		    count++;
 	    }
 	}
-	if (rc != DB_NOTFOUND)
+	if (rc == DB_LOCK_DEADLOCK)
+	    syslog(LOG_DEBUG, "skipping concurrent expiry avoids "
+		   "deadlocks and unnecessary work");
+	else if (rc != DB_NOTFOUND)
 	    log_db_error("dbcp->c_get failed", rc);
 	if (rc = dbcp->c_close(dbcp))
 	    log_db_error("dbcp->c_close failed", rc);


