A new user interface for you! Read more...

File waitlock.diff of Package rpm

Fix global (DB_PRIVATE) lock code: fix recursion counter, retry
failed lock operations for up to 3 minutes.
Index: rpmdb/db3.c
===================================================================
--- rpmdb/db3.c.orig
+++ rpmdb/db3.c
@@ -769,6 +769,8 @@ assert(db != NULL);
 }
 /*@=mustmod@*/
 
+static int _lockdbfd = 0;
+
 /*@-moduncon@*/ /* FIX: annotate db3 methods */
 static int db3close(/*@only@*/ dbiIndex dbi, /*@unused@*/ unsigned int flags)
 	/*@globals rpmGlobalMacroContext, h_errno,
@@ -828,6 +830,10 @@ static int db3close(/*@only@*/ dbiIndex
 
 	rpmMessage(RPMMESS_DEBUG, _("closed   db index       %s/%s\n"),
 		dbhome, (dbfile ? dbfile : tagName(dbi->dbi_rpmtag)));
+	if (dbi->dbi_lockdbfd &&
+	    !((dbi->dbi_ecflags & DB_CLIENT) && dbi->dbi_host) &&
+	    _lockdbfd)
+	    _lockdbfd--;
 
     }
 
@@ -1148,8 +1154,6 @@ static int db3open(rpmdb rpmdb, rpmTag r
 		prDbiOpenFlags(oflags, 0), dbi->dbi_mode);
 
     if (rc == 0) {
-	static int _lockdbfd = 0;
-
 	/*@-moduncon@*/ /* FIX: annotate db3 methods */
 	rc = db_create(&db, dbenv, dbi->dbi_cflags);
 	/*@=moduncon@*/
@@ -1366,6 +1370,7 @@ static int db3open(rpmdb rpmdb, rpmTag r
 		if (!(db->fd(db, &fdno) == 0 && fdno >= 0)) {
 		    rc = 1;
 		} else {
+		    int tries;
 		    struct flock l;
 /*@-boundswrite@*/
 		    memset(&l, 0, sizeof(l));
@@ -1377,24 +1382,40 @@ static int db3open(rpmdb rpmdb, rpmTag r
 				? F_WRLCK : F_RDLCK;
 		    l.l_pid = 0;
 
-		    rc = fcntl(fdno, F_SETLK, (void *) &l);
-		    if (rc) {
-			/* Warning iff using non-private CDB locking. */
-			rc = ((dbi->dbi_use_dbenv &&
-				(dbi->dbi_eflags & DB_INIT_CDB) &&
-				!(dbi->dbi_eflags & DB_PRIVATE))
-			    ? 0 : 1);
-			rpmError( (rc ? RPMERR_FLOCK : RPMWARN_FLOCK),
-				_("cannot get %s lock on %s/%s\n"),
-				((dbi->dbi_mode & (O_RDWR|O_WRONLY))
-					? _("exclusive") : _("shared")),
-				dbhome, (dbfile ? dbfile : ""));
-		    } else if (dbfile) {
-			rpmMessage(RPMMESS_DEBUG,
-				_("locked   db index       %s/%s\n"),
-				dbhome, dbfile);
+		    for (tries = 0; ; tries++) {
+			rc = fcntl(fdno, F_SETLK, (void *) &l);
+			if (rc) {
+			    /* Warning iff using non-private CDB locking. */
+			    rc = ((dbi->dbi_use_dbenv &&
+				    (dbi->dbi_eflags & DB_INIT_CDB) &&
+				    !(dbi->dbi_eflags & DB_PRIVATE))
+				? 0 : 1);
+			    if (errno == EAGAIN && rc) {
+				struct timespec ts;
+				if (tries == 0)
+				    rpmMessage(RPMMESS_WARNING, _("waiting for %s lock on %s/%s\n"), ((dbi->dbi_mode & (O_RDWR|O_WRONLY)) ? _("exclusive") : _("shared")), dbhome, (dbfile ? dbfile : ""));
+				ts.tv_sec = (time_t)0;
+				ts.tv_nsec = 100000000;
+				if (tries < 10*60*3) {
+				    nanosleep(&ts, (struct timespec *)0);
+				    continue;
+				}
+			    }
+			    rpmError( (rc ? RPMERR_FLOCK : RPMWARN_FLOCK),
+				    _("cannot get %s lock on %s/%s\n"),
+				    ((dbi->dbi_mode & (O_RDWR|O_WRONLY))
+					    ? _("exclusive") : _("shared")),
+				    dbhome, (dbfile ? dbfile : ""));
+			} else if (dbfile) {
+			    rpmMessage(RPMMESS_DEBUG,
+				    _("locked   db index       %s/%s\n"),
+				    dbhome, dbfile);
+			}
+			break;
 		    }
 		}
+		if (rc && dbi->dbi_use_dbenv)
+		    _lockdbfd--;
 	    }
 	}
     }