File suspendlock.diff of Package rpm

Suspend exclusive database lock when scriptlets get called, allowing
read access in scriptlets. Only needed for DB_PRIVATE (aka global)
locking.

I hijacked the dbiSync function for this because I did not want
to change the ABI.

--- ./lib/backend/db3.c.orig	2010-03-25 14:35:39.000000000 +0000
+++ ./lib/backend/db3.c	2010-03-25 14:44:42.000000000 +0000
@@ -208,11 +208,17 @@ errxit:
     return rc;
 }
 
+static int db3SuspendResumeLock(dbiIndex dbi, int mode);
+
 static int db3sync(dbiIndex dbi, unsigned int flags)
 {
     DB * db = dbi->dbi_db;
     int rc = 0;
 
+    if (flags == (unsigned int)-1)
+	return db3SuspendResumeLock(dbi, 0);
+    if (flags == (unsigned int)-2)
+	return db3SuspendResumeLock(dbi, 1);
     if (db != NULL) {
 	rc = db->sync(db, flags);
 	rc = cvtdberr(dbi, "db->sync", rc, _debug);
@@ -848,6 +854,48 @@ static int db3open(rpmdb rpmdb, rpmTag r
     return rc;
 }
 
+static int
+db3SuspendResumeLock(dbiIndex dbi, int mode)
+{
+    struct flock l;
+    int rc = 0;
+    int tries;
+    int fdno = -1;
+
+    if (!dbi->dbi_lockdbfd)
+	return 0;
+    if (!(dbi->dbi_mode & (O_RDWR|O_WRONLY)))
+	return 0;
+    if (dbi->dbi_use_dbenv && _lockdbfd == 0)
+	return 0;
+    if (!(dbi->dbi_db->fd(dbi->dbi_db, &fdno) == 0 && fdno >= 0))
+	return 1;
+    if (mode == 0) {
+	memset(&l, 0, sizeof(l));
+	l.l_whence = 0;
+	l.l_start = 0;
+	l.l_len = 0;
+	l.l_type = F_RDLCK;
+	rc = fcntl(fdno, F_SETLK, (void *) &l);
+	if (rc)
+	    rpmlog(RPMLOG_WARNING, _("could not suspend database lock\n"));
+    } else {
+	for (tries = 0; tries < 2; tries++) {
+	    memset(&l, 0, sizeof(l));
+	    l.l_whence = 0;
+	    l.l_start = 0;
+	    l.l_len = 0;
+	    l.l_type = F_WRLCK;
+	    rc = fcntl(fdno, tries ? F_SETLKW : F_SETLK, (void *) &l);
+	    if (!rc)
+		break;
+	    if (tries == 0)
+		rpmlog(RPMLOG_WARNING, _("waiting to reestablish exclusive database lock\n"));
+	}
+    }
+    return rc;
+}
+
 /** \ingroup db3
  */
 RPM_GNUC_INTERNAL
--- ./lib/psm.c.orig	2010-03-25 14:43:29.000000000 +0000
+++ ./lib/psm.c	2010-03-25 14:43:41.000000000 +0000
@@ -754,6 +754,8 @@ static rpmRC runScript(rpmpsm psm, Heade
 	goto exit;
     }
 
+    rpmtsSuspendResumeDBLock(psm->ts, 0);
+
     xx = rpmsqFork(&psm->sq);
     if (psm->sq.child == 0) {
 	rpmlog(RPMLOG_DEBUG, "%s: %s\texecv(%s) pid %d\n",
@@ -768,6 +770,8 @@ static rpmRC runScript(rpmpsm psm, Heade
 
     (void) psmWait(psm);
 
+    rpmtsSuspendResumeDBLock(psm->ts, 1);
+
     if (psm->sq.reaped < 0) {
 	rpmlog(RPMLOG_ERR, _("%s scriptlet failed, waitpid(%d) rc %d: %s\n"),
 		 sname, psm->sq.child, psm->sq.reaped, strerror(errno));
--- ./lib/rpmdb.c.orig	2010-03-25 14:36:57.000000000 +0000
+++ ./lib/rpmdb.c	2010-03-25 14:43:41.000000000 +0000
@@ -903,6 +903,21 @@ int rpmdbSync(rpmdb db)
     return rc;
 }
 
+int rpmdbSuspendResumeDBLock(rpmdb db, int mode)
+{
+    int dbix;
+    int rc = 0;
+    if (db == NULL) return 0;
+    for (dbix = 0; dbix < db->db_ndbi; dbix++) {
+	int xx;
+	if (db->_dbi[dbix] == NULL)
+	    continue;
+	xx = dbiSync(db->_dbi[dbix], mode ? -2 : -1);
+	if (xx && rc == 0) rc = xx;
+    }
+    return rc;
+}
+
 /* FIX: dbTemplate structure assignment */
 static
 rpmdb newRpmdb(const char * root,
--- ./lib/rpmts.c.orig	2009-12-17 09:05:37.000000000 +0000
+++ ./lib/rpmts.c	2010-03-25 14:43:41.000000000 +0000
@@ -89,6 +89,11 @@ int rpmtsOpenDB(rpmts ts, int dbmode)
     return rc;
 }
 
+int rpmtsSuspendResumeDBLock(rpmts ts, int mode)
+{
+    return rpmdbSuspendResumeDBLock(ts->rdb, mode);
+}
+
 int rpmtsInitDB(rpmts ts, int dbmode)
 {
     void *lock = rpmtsAcquireLock(ts);
--- ./lib/rpmts.h.orig	2009-12-17 09:05:37.000000000 +0000
+++ ./lib/rpmts.h	2010-03-25 14:43:41.000000000 +0000
@@ -469,6 +469,10 @@ rpmdb rpmtsGetRdb(rpmts ts);
 void * rpmtsNotify(rpmts ts, rpmte te,
                 rpmCallbackType what, rpm_loff_t amount, rpm_loff_t total);
 
+int rpmtsSuspendResumeDBLock(rpmts ts, int mode)
+	/*@globals fileSystem @*/
+	/*@modifies fileSystem @*/;
+
 /** \ingroup rpmts
  * Return number of (ordered) transaction set elements.
  * @param ts		transaction set
openSUSE Build Service is sponsored by