]> arthur.barton.de Git - netatalk.git/commitdiff
MFH: Fix CNID DB deadlock problem.
authorjmarcus <jmarcus>
Mon, 3 Dec 2001 15:53:39 +0000 (15:53 +0000)
committerjmarcus <jmarcus>
Mon, 3 Dec 2001 15:53:39 +0000 (15:53 +0000)
libatalk/cnid/cnid_add.c
libatalk/cnid/cnid_close.c
libatalk/cnid/cnid_delete.c
libatalk/cnid/cnid_get.c
libatalk/cnid/cnid_lookup.c
libatalk/cnid/cnid_nextid.c
libatalk/cnid/cnid_open.c
libatalk/cnid/cnid_private.h
libatalk/cnid/cnid_resolve.c
libatalk/cnid/cnid_update.c

index f966ac2eb73cbf42d312d42a31261bb33c0d0e03..a8236258e2d140811009671614db507a09862f0b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: cnid_add.c,v 1.14.2.1 2001-12-03 05:05:45 jmarcus Exp $
+ * $Id: cnid_add.c,v 1.14.2.2 2001-12-03 15:53:39 jmarcus Exp $
  *
  * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
  * All Rights Reserved. See COPYRIGHT.
@@ -26,6 +26,9 @@
 #endif /* HAVE_FCNTL_H */
 #include <errno.h>
 #include <syslog.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif /* HAVE_SYS_TIME_H */
 
 #include <db.h>
 #include <netatalk/endian.h>
@@ -36,6 +39,8 @@
 
 #include "cnid_private.h"
 
+#define MAX_ABORTS 255
+
 /* add an entry to the CNID databases. we do this as a transaction
  * to prevent messiness. */
 static int add_cnid(CNID_private *db, DB_TXN *ptid, DBT *key, DBT *data) {
@@ -44,28 +49,32 @@ static int add_cnid(CNID_private *db, DB_TXN *ptid, DBT *key, DBT *data) {
     /* We create rc here because using errno is bad.  Why?  Well, if you
      * use errno once, then call another function which resets it, you're
      * screwed. */
-    int rc;
+    int rc, ret, aborts = 0;
 
     memset(&altkey, 0, sizeof(altkey));
     memset(&altdata, 0, sizeof(altdata));
 
+    if (0) {
 retry:
+        if ((rc = txn_abort(tid)) != 0) {
+            return rc;
+        }
+        if (++aborts > MAX_ABORTS) {
+            return DB_LOCK_DEADLOCK;
+        }
+    }
+
     if ((rc = txn_begin(db->dbenv, ptid, &tid, 0)) != 0) {
         return rc;
     }
 
-
     /* main database */
     if ((rc = db->db_cnid->put(db->db_cnid, tid, key, data, DB_NOOVERWRITE))) {
-        int ret;
-        if ((ret = txn_abort(tid)) != 0) {
-            return ret;
-        }
         if (rc == DB_LOCK_DEADLOCK) {
             goto retry;
         }
 
-        return rc;
+        goto abort;
     }
 
 
@@ -75,15 +84,11 @@ retry:
     altdata.data = key->data;
     altdata.size = key->size;
     if ((rc = db->db_devino->put(db->db_devino, tid, &altkey, &altdata, 0))) {
-        int ret;
-        if ((ret = txn_abort(tid)) != 0) {
-            return ret;
-        }
         if (rc == DB_LOCK_DEADLOCK) {
             goto retry;
         }
 
-        return rc;
+        goto abort;
     }
 
 
@@ -91,15 +96,11 @@ retry:
     altkey.data = (char *) data->data + CNID_DEVINO_LEN;
     altkey.size = data->size - CNID_DEVINO_LEN;
     if ((rc = db->db_didname->put(db->db_didname, tid, &altkey, &altdata, 0))) {
-        int ret;
-        if ((ret = txn_abort(tid)) != 0) {
-            return ret;
-        }
         if (rc == DB_LOCK_DEADLOCK) {
             goto retry;
         }
 
-        return rc;
+        goto abort;
     }
 
     if ((rc = txn_commit(tid, 0)) != 0) {
@@ -108,6 +109,13 @@ retry:
         return rc;
     }
     return 0;
+
+abort:
+    if ((ret = txn_abort(tid)) != 0) {
+        return ret;
+    }
+    return rc;
+
 }
 
 cnid_t cnid_add(void *CNID, const struct stat *st,
@@ -117,6 +125,7 @@ cnid_t cnid_add(void *CNID, const struct stat *st,
     CNID_private *db;
     DBT key, data, rootinfo_key, rootinfo_data;
     DB_TXN *tid;
+    struct timeval t;
     cnid_t id, save;
     int rc;
 
@@ -172,26 +181,25 @@ cnid_t cnid_add(void *CNID, const struct stat *st,
         }
     }
 
+    /* We need to create a random sleep interval to prevent deadlocks. */
+    (void)srand(getpid() ^ time(NULL));
+    t.tv_sec = 0;
+
     memset(&rootinfo_key, 0, sizeof(rootinfo_key));
     memset(&rootinfo_data, 0, sizeof(rootinfo_data));
     rootinfo_key.data = ROOTINFO_KEY;
     rootinfo_key.size = ROOTINFO_KEYLEN;
-retry:
-    if ((rc = txn_begin(db->dbenv, NULL, &tid, 0)) != 0) {
-        syslog(LOG_ERR, "cnid_add: Failed to begin transaction: %s",
-               db_strerror(rc));
-        goto cleanup_err;
-    }
 
     /* Get the key. */
-    switch (rc = db->db_didname->get(db->db_didname, tid, &rootinfo_key,
-                                     &rootinfo_data, DB_RMW)) {
+retry_get:
+    switch (rc = db->db_didname->get(db->db_didname, NULL, &rootinfo_key,
+                                     &rootinfo_data, 0)) {
     case DB_LOCK_DEADLOCK:
         if ((rc = txn_abort(tid)) != 0) {
             syslog(LOG_ERR, "cnid_add: txn_abort: %s", db_strerror(rc));
             goto cleanup_err;
         }
-        goto retry;
+        goto retry_get;
     case 0:
         memcpy(&hint, rootinfo_data.data, sizeof(hint));
 #ifdef DEBUG
@@ -208,7 +216,20 @@ retry:
     default:
         syslog(LOG_ERR, "cnid_add: Unable to lookup rootinfo: %s",
                db_strerror(rc));
-        goto cleanup_abort;
+        goto cleanup_err;
+    }
+
+
+retry:
+    t.tv_usec = rand() % 1000000;
+#ifdef DEBUG
+    syslog(LOG_INFO, "cnid_add: Hitting MAX_ABORTS, sleeping");
+#endif
+    (void)select(0, NULL, NULL, NULL, &t);
+    if ((rc = txn_begin(db->dbenv, NULL, &tid, 0)) != 0) {
+        syslog(LOG_ERR, "cnid_add: Failed to begin transaction: %s",
+               db_strerror(rc));
+        goto cleanup_err;
     }
 
     /* Search for a new id.  We keep the first id around to check for
@@ -220,6 +241,13 @@ retry:
         if (++id < CNID_START) {
             id = CNID_START;
         }
+        if (rc == DB_LOCK_DEADLOCK) {
+            if ((rc = txn_abort(tid)) != 0) {
+                syslog(LOG_ERR, "cnid_add: txn_abort: %s", db_strerror(rc));
+                goto cleanup_err;
+            }
+            goto retry;
+        }
 
         if ((rc != DB_KEYEXIST) || (save == id)) {
             syslog(LOG_ERR, "cnid_add: Unable to add CNID %u: %s",
index 772ffef2de2f7a20ee5a9e91199e5e249d352684..dde16a7ee53235e356404e87d7b536077eaee6c7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: cnid_close.c,v 1.12.2.1 2001-12-03 05:05:46 jmarcus Exp $
+ * $Id: cnid_close.c,v 1.12.2.2 2001-12-03 15:53:39 jmarcus Exp $
  */
 
 #ifdef HAVE_CONFIG_H
index 1028ecf84e1acfc436e1d5818eb871f427920276..a4b0f3477c41ff462062f62784c57c5ee8c7f13e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: cnid_delete.c,v 1.9.2.1 2001-12-03 05:05:47 jmarcus Exp $
+ * $Id: cnid_delete.c,v 1.9.2.2 2001-12-03 15:53:39 jmarcus Exp $
  *
  * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
  * All Rights Reserved. See COPYRIGHT.
@@ -47,7 +47,7 @@ retry:
     /* Get from ain CNID database. */
     key.data = (cnid_t *)&id;
     key.size = sizeof(id);
-    if ((rc = db->db_cnid->get(db->db_cnid, tid, &key, &data, DB_RMW))) {
+    if ((rc = db->db_cnid->get(db->db_cnid, tid, &key, &data, 0))) {
         int ret;
         if ((ret = txn_abort(tid)) != 0) {
             syslog(LOG_ERR, "cnid_delete: txn_abort: %s", db_strerror(ret));
index b5c534bb959acc9f306a435952311dc556d5b7cc..c10faf72b09895c7757e4904d26461bde5a8e63f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: cnid_get.c,v 1.9.2.1 2001-12-03 05:05:47 jmarcus Exp $
+ * $Id: cnid_get.c,v 1.9.2.2 2001-12-03 15:53:39 jmarcus Exp $
  */
 
 #ifdef HAVE_CONFIG_H
index c772d00c0ae745a627f3a8862f1c3fff2a68ef82..7e1d9c6c620817af854150093a7d4df4db1cd270 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: cnid_lookup.c,v 1.9.2.1 2001-12-03 05:05:48 jmarcus Exp $
+ * $Id: cnid_lookup.c,v 1.9.2.2 2001-12-03 15:53:39 jmarcus Exp $
  */
 
 #ifdef HAVE_CONFIG_H
index f8627262a3a514ac3ccf858110398d308660f22e..9d0491416d4333aa8bd7b488d4c9f0d488380153 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: cnid_nextid.c,v 1.6.2.1 2001-12-03 05:05:48 jmarcus Exp $
+ * $Id: cnid_nextid.c,v 1.6.2.2 2001-12-03 15:53:39 jmarcus Exp $
  */
 #ifdef unused
 
index 35dec1122d78de4f8a105025ded583e5cec83b25..bdf86bbffa2eb24d7e73740fa9e26303a1a71244 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: cnid_open.c,v 1.19.2.1 2001-12-03 05:05:48 jmarcus Exp $
+ * $Id: cnid_open.c,v 1.19.2.2 2001-12-03 15:53:39 jmarcus Exp $
  *
  * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
  * All Rights Reserved. See COPYRIGHT.
@@ -285,7 +285,7 @@ void *cnid_open(const char *dir) {
 
         /* We can't get a full transactional environment, so multi-access
          * is out of the question.  Let's assume a read-only environment,
-         * and trry to at least get a shared memory pool. */
+         * and try to at least get a shared memory pool. */
         if ((rc = db->dbenv->open(db->dbenv, path, DB_INIT_MPOOL, 0666)) != 0) {
             /* Nope, not a MPOOL, either.  Last-ditch effort: we'll try to
              * open the environment with no flags. */
index c8497cd8d5c34c81c4051ad3753d1efbb4516582..8c19c9ca7cea903ed7d179c0923cc85625bfa727 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: cnid_private.h,v 1.3.2.1 2001-12-03 05:05:50 jmarcus Exp $
+ * $Id: cnid_private.h,v 1.3.2.2 2001-12-03 15:53:39 jmarcus Exp $
  */
 
 #ifndef LIBATALK_CNID_PRIVATE_H
index ffb3f8cd6602de5c5f33563d0a2fc4b352558862..41a7dbee2a823b1ab3db490030d938327abc36bf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: cnid_resolve.c,v 1.8.2.1 2001-12-03 05:05:51 jmarcus Exp $
+ * $Id: cnid_resolve.c,v 1.8.2.2 2001-12-03 15:53:39 jmarcus Exp $
  */
 
 #ifdef HAVE_CONFIG_H
index de1d7872509f300e75a9f4229e3f92fc0aef5bd0..d83753b0e83e41e0e1ca8ec7652190e6cc213fa4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: cnid_update.c,v 1.12.2.1 2001-12-03 05:05:51 jmarcus Exp $
+ * $Id: cnid_update.c,v 1.12.2.2 2001-12-03 15:53:39 jmarcus Exp $
  */
 
 #ifdef HAVE_CONFIG_H
@@ -97,6 +97,19 @@ retry:
     data.data = make_cnid_data(st, did, name, len);
     data.size = CNID_HEADER_LEN + len + 1;
 
+    /* Update the old CNID with the new info. */
+    key.data = (cnid_t *) &id;
+    key.size = sizeof(id);
+    if ((rc = db->db_cnid->put(db->db_cnid, tid, &key, &data, 0))) {
+        txn_abort(tid);
+        switch (rc) {
+        case DB_LOCK_DEADLOCK:
+            goto retry;
+        default:
+            goto update_err;
+        }
+    }
+
     /* Put in a new dev/ino mapping. */
     key.data = data.data;
     key.size = CNID_DEVINO_LEN;
@@ -125,18 +138,6 @@ retry:
         }
     }
 
-    /* Update the old CNID with the new info. */
-    key.data = (cnid_t *) &id;
-    key.size = sizeof(id);
-    if ((rc = db->db_cnid->put(db->db_cnid, tid, &key, &data, 0))) {
-        txn_abort(tid);
-        switch (rc) {
-        case DB_LOCK_DEADLOCK:
-            goto retry;
-        default:
-            goto update_err;
-        }
-    }
 
     return txn_commit(tid, 0);