Fix global (DB_PRIVATE) lock code
authorAnas Nashif <anas.nashif@intel.com>
Thu, 11 Oct 2012 19:37:11 +0000 (12:37 -0700)
committerAnas Nashif <anas.nashif@intel.com>
Sun, 3 Feb 2013 00:44:15 +0000 (16:44 -0800)
Fix global (DB_PRIVATE) lock code: fix recursion counter, retry
failed lock operations for up to 3 minutes.

lib/backend/db3.c

index 656486b63143558440c9feb727637702e05be9e9..a47d08b78e2bd60e4009ce22eaf0d993c87f58d6 100644 (file)
@@ -426,6 +426,8 @@ int dbiVerify(dbiIndex dbi, unsigned int flags)
     return rc;
 }
 
+static int _lockdbfd = 0;
+
 int dbiClose(dbiIndex dbi, unsigned int flags)
 {
     rpmdb rdb = dbi->dbi_rpmdb;
@@ -443,6 +445,8 @@ int dbiClose(dbiIndex dbi, unsigned int flags)
 
        rpmlog(RPMLOG_DEBUG, "closed   db index       %s/%s\n",
                dbhome, dbi->dbi_file);
+       if (dbi->dbi_lockdbfd && _lockdbfd)
+           _lockdbfd--;
     }
 
     db_fini(rdb, dbhome ? dbhome : "");
@@ -482,6 +486,7 @@ static int dbiFlock(dbiIndex dbi, int mode)
        rc = 1;
     } else {
        const char *dbhome = rpmdbHome(dbi->dbi_rpmdb);
+       int tries;
        struct flock l;
        memset(&l, 0, sizeof(l));
        l.l_whence = 0;
@@ -491,20 +496,38 @@ static int dbiFlock(dbiIndex dbi, int mode)
                    ? F_RDLCK : F_WRLCK;
        l.l_pid = 0;
 
-       rc = fcntl(fdno, F_SETLK, (void *) &l);
-       if (rc) {
-           uint32_t eflags = db_envflags(db);
-           /* Warning iff using non-private CDB locking. */
-           rc = (((eflags & DB_INIT_CDB) && !(eflags & DB_PRIVATE)) ? 0 : 1);
-           rpmlog( (rc ? RPMLOG_ERR : RPMLOG_WARNING),
-                   _("cannot get %s lock on %s/%s\n"),
-                   ((mode & O_ACCMODE) == O_RDONLY)
-                           ? _("shared") : _("exclusive"),
-                   dbhome, dbi->dbi_file);
-       } else {
-           rpmlog(RPMLOG_DEBUG,
-                   "locked   db index       %s/%s\n",
-                   dbhome, dbi->dbi_file);
+       for (tries = 0; ; tries++) {
+           rc = fcntl(fdno, F_SETLK, (void *) &l);
+           if (rc) {
+               uint32_t eflags = db_envflags(db);
+               /* Warning iff using non-private CDB locking. */
+               rc = (((eflags & DB_INIT_CDB) && !(eflags & DB_PRIVATE)) ? 0 : 1);
+               if (errno == EAGAIN && rc) {
+                   struct timespec ts;
+                   if (tries == 0)
+                       rpmlog(RPMLOG_WARNING,
+                               _("waiting for %s lock on %s/%s\n"),
+                               ((mode & O_ACCMODE) == O_RDONLY)
+                                       ? _("shared") : _("exclusive"),
+                               dbhome, dbi->dbi_file);
+                   ts.tv_sec = (time_t)0;
+                   ts.tv_nsec = 100000000;     /* .1 seconds */
+                   if (tries < 10*60*3) {      /* 3 minutes */
+                       nanosleep(&ts, (struct timespec *)0);
+                       continue;
+                   }
+               }
+               rpmlog( (rc ? RPMLOG_ERR : RPMLOG_WARNING),
+                       _("cannot get %s lock on %s/%s\n"),
+                       ((mode & O_ACCMODE) == O_RDONLY)
+                               ? _("shared") : _("exclusive"),
+                       dbhome, dbi->dbi_file);
+           } else {
+               rpmlog(RPMLOG_DEBUG,
+                       "locked   db index       %s/%s\n",
+                       dbhome, dbi->dbi_file);
+           }
+           break;
        }
     }
     return rc;
@@ -521,7 +544,6 @@ int dbiOpen(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags)
     DB * db = NULL;
     DBTYPE dbtype = DB_UNKNOWN;
     uint32_t oflags;
-    static int _lockdbfd = 0;
 
     if (dbip)
        *dbip = NULL;
@@ -595,7 +617,10 @@ int dbiOpen(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags)
     dbi->dbi_db = db;
     dbi->dbi_oflags = oflags;
 
-    if (!verifyonly && rc == 0 && dbi->dbi_lockdbfd && _lockdbfd++ == 0) {
+    if (verifyonly)
+       dbi->dbi_lockdbfd = 0;  /* disable locking in verify mode */
+
+    if (rc == 0 && dbi->dbi_lockdbfd && _lockdbfd++ == 0) {
        rc = dbiFlock(dbi, rdb->db_mode);
     }