Suspend exclusive database lock when scriptlets get called
authorAnas Nashif <anas.nashif@intel.com>
Thu, 11 Oct 2012 19:38:04 +0000 (12:38 -0700)
committerAnas Nashif <anas.nashif@intel.com>
Sun, 3 Feb 2013 00:44:15 +0000 (16:44 -0800)
Suspend exclusive database lock when scriptlets get called, allowing
read access in scriptlets. Only needed for DB_PRIVATE (aka global)
locking.

lib/backend/db3.c
lib/backend/dbi.h
lib/psm.c
lib/rpmdb.c
lib/rpmts.c
lib/rpmts.h

index a47d08b..a55a608 100644 (file)
@@ -632,3 +632,59 @@ int dbiOpen(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags)
 
     return rc;
 }
+
+int dbiSuspendDBLock(dbiIndex dbi, unsigned int flags)
+{
+    struct flock l;
+    int rc = 0;
+    int fdno = -1;
+
+    if (!dbi->dbi_lockdbfd)
+       return 0;
+    if (!(dbi->dbi_rpmdb->db_mode & (O_RDWR|O_WRONLY)))
+       return 0;
+    if (_lockdbfd == 0)
+       return 0;
+    if (!(dbi->dbi_db->fd(dbi->dbi_db, &fdno) == 0 && fdno >= 0))
+       return 1;
+    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"));
+    return rc;
+}
+
+int dbiResumeDBLock(dbiIndex dbi, unsigned int flags)
+{
+    struct flock l;
+    int rc = 0;
+    int tries;
+    int fdno = -1;
+
+    if (!dbi->dbi_lockdbfd)
+       return 0;
+    if (!(dbi->dbi_rpmdb->db_mode & (O_RDWR|O_WRONLY)))
+       return 0;
+    if (_lockdbfd == 0)
+       return 0;
+    if (!(dbi->dbi_db->fd(dbi->dbi_db, &fdno) == 0 && fdno >= 0))
+       return 1;
+    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;
+}
+
index 49fa1f1..3d848a8 100644 (file)
@@ -81,6 +81,24 @@ struct dbiIndex_s {
 extern "C" {
 #endif
 
+/** \ingroup dbi
+ * Suspend the exclusive lock on the dbi
+ * @param dbi          index database handle
+ * @param flags                (unused)
+ * @return             0 on success
+ */
+RPM_GNUC_INTERNAL
+int dbiSuspendDBLock(dbiIndex dbi, unsigned int flags);
+
+/** \ingroup dbi
+ * Reacquire an exclusive lock on the dbi
+ * @param dbi          index database handle
+ * @param flags                (unused)
+ * @return             0 on success
+ */
+RPM_GNUC_INTERNAL
+int dbiResumeDBLock(dbiIndex dbi, unsigned int flags);
+
 
 RPM_GNUC_INTERNAL
 /* Globally enable/disable fsync in the backend */
index c786f1e..aad047f 100644 (file)
--- a/lib/psm.c
+++ b/lib/psm.c
@@ -419,10 +419,12 @@ static rpmRC runScript(rpmpsm psm, ARGV_const_t prefixes,
     if (sfd == NULL)
        sfd = rpmtsScriptFd(psm->ts);
 
+    rpmtsSuspendResumeDBLock(psm->ts, 0);
     rpmswEnter(rpmtsOp(psm->ts, RPMTS_OP_SCRIPTLETS), 0);
     rc = rpmScriptRun(script, arg1, arg2, sfd,
                      prefixes, warn_only, selinux);
     rpmswExit(rpmtsOp(psm->ts, RPMTS_OP_SCRIPTLETS), 0);
+    rpmtsSuspendResumeDBLock(psm->ts, 1);
 
     /* Map warn-only errors to "notfound" for script stop callback */
     stoprc = (rc != RPMRC_OK && warn_only) ? RPMRC_NOTFOUND : rc;
index 1a2fda5..c17dcbf 100644 (file)
@@ -781,6 +781,12 @@ int rpmdbSync(rpmdb db)
     return dbiForeach(db->_dbi, dbiSync, 0);
 }
 
+int rpmdbSuspendResumeDBLock(rpmdb db, int mode)
+{
+    if (db == NULL) return 0;
+    return dbiForeach(db->_dbi, mode ? dbiResumeDBLock : dbiSuspendDBLock, 0);
+}
+
 static rpmdb newRpmdb(const char * root, const char * home,
                      int mode, int perms, int flags)
 {
index 9642734..d3b893a 100644 (file)
@@ -95,6 +95,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)
 {
     rpmlock lock = rpmtsAcquireLock(ts);
index 0b8d970..059f46d 100644 (file)
@@ -423,6 +423,8 @@ 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);
+
 /** \ingroup rpmts
  * Return number of (ordered) transaction set elements.
  * @param ts           transaction set