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