public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
From: Michal Domonkos <mdomonko@redhat.com>
To: git-commits@fedoraproject.org
Subject: [rpms/python3-rpm] epel10: Add support for database parking
Date: Thu, 25 Jun 2026 07:43:28 GMT	[thread overview]
Message-ID: <178237340834.1.10091319780186252788.rpms-python3-rpm-2310f53fa8e5@fedoraproject.org> (raw)

            A new commit has been pushed.

            Repo   : rpms/python3-rpm
            Branch : epel10
            Commit : 2310f53fa8e5bb5c7b4dc0ff28f64a661916514c
            Author : Michal Domonkos <mdomonko@redhat.com>
            Date   : 2026-06-18T09:49:29+02:00
            Stats  : +430/-0 in 2 file(s)
            URL    : https://src.fedoraproject.org/rpms/python3-rpm/c/2310f53fa8e5bb5c7b4dc0ff28f64a661916514c?branch=epel10

            Log:
            Add support for database parking

Resolves: RHEL-126405

---
diff --git a/rpm-4.19.x-add-parkdb.patch b/rpm-4.19.x-add-parkdb.patch
new file mode 100644
index 0000000..ae88c3f
--- /dev/null
+++ b/rpm-4.19.x-add-parkdb.patch
@@ -0,0 +1,428 @@
+From 17a703eb3dfa7e2da4f441bd200d2548aef64025 Mon Sep 17 00:00:00 2001
+From: Michal Domonkos <mdomonko@redhat.com>
+Date: Tue, 2 Jun 2026 10:02:53 +0200
+Subject: [PATCH 1/2] Extract common database rebuild logic
+
+No functional change, just prepares the ground for the next commit.
+
+(backported from commit 1dcddf95b7d956f5d024f63a531ea58bc485efe5)
+---
+ lib/rpmts.c | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+diff --git a/lib/rpmts.c b/lib/rpmts.c
+index 2f293e751..bc52a2f28 100644
+--- a/lib/rpmts.c
++++ b/lib/rpmts.c
+@@ -137,12 +137,10 @@ int rpmtsSetDBMode(rpmts ts, int dbmode)
+     return rc;
+ }
+ 
+-
+-int rpmtsRebuildDB(rpmts ts)
++static int rebuildDB(rpmts ts, int rebuildflags)
+ {
+     int rc = -1;
+     rpmtxn txn = NULL;
+-    int rebuildflags = 0;
+ 
+     /* Cannot do this on a populated transaction set */
+     if (rpmtsNElements(ts) > 0)
+@@ -162,6 +160,11 @@ int rpmtsRebuildDB(rpmts ts)
+     return rc;
+ }
+ 
++int rpmtsRebuildDB(rpmts ts)
++{
++    return rebuildDB(ts, 0);
++}
++
+ int rpmtsVerifyDB(rpmts ts)
+ {
+     int rc = -1;
+-- 
+2.54.0
+
+
+From 845be24a9128d73d6307cec8692c5783a7671a61 Mon Sep 17 00:00:00 2001
+From: Michal Domonkos <mdomonko@redhat.com>
+Date: Wed, 3 Jun 2026 14:19:41 +0200
+Subject: [PATCH 2/2] Add support for database parking
+
+Prior to including the RPM database on read-only media (such as a base
+image in rpm-ostree), it should undergo some housekeeping and cleanup.
+Add a new "parking" operation to rpmdb(8) and the corresponding API to
+do just that.
+
+This operation consists of a database rebuild coupled with an optional,
+backend specific action triggered by passing a new flag RPMDB_FLAG_PARK
+on database open. Since the action may take place on database close, let
+the backend report a failure to park that way by handling the result in
+rpmdbRebuild().
+
+Implement such an action in the sqlite backend where it actually makes a
+difference: Commit a8588f8e3970223f0b2fcc5d679dcb176f2e317b enabled WAL
+mode but sqlite recommends that the database be converted to the default
+DELETE journal mode prior to "burning" it onto read-only media [*]. Make
+sure to do the conversion on database close since we may write to the
+database during the rebuild, and that should always happen in WAL mode.
+
+As a nice side effect with the sqlite backend, parking the database will
+automatically remove the *-wal and *-shm files from %_dbpath, making it
+usable in reproducible images. Hint at that in the man page but make it
+clear that this is not a guarantee (but rather an implementation detail
+of sqlite). Make use of this property in the test, though.
+
+By parking, the database does not become read-only, and the parked state
+does not stick when opening the database for writing (as we re-establish
+WAL mode in such a case). This allows for the database to be immediately
+writable inside a container running on top of a base image that includes
+the database, without the user having to unpark it first.
+
+[*] https://sqlite.org/wal.html#read_only_databases
+
+Fixes: #2219
+(backported from commit 1825517392c1a04b1f3bc6a89d308fdda2927edd)
+---
+ docs/man/rpmdb.8.md  | 13 +++++++++++--
+ include/rpm/rpmts.h  |  7 +++++++
+ lib/backend/dbi.h    |  1 +
+ lib/backend/sqlite.c | 17 +++++++++++++++--
+ lib/rpmdb.c          |  7 +++++--
+ lib/rpmdb_internal.h |  1 +
+ lib/rpmts.c          |  5 +++++
+ python/rpmts-py.c    | 15 +++++++++++++++
+ tools/rpmdb.c        |  6 ++++++
+ 9 files changed, 66 insertions(+), 6 deletions(-)
+
+diff --git a/docs/man/rpmdb.8.md b/docs/man/rpmdb.8.md
+index 8ad1ce3bb..7d308ca98 100644
+--- a/docs/man/rpmdb.8.md
++++ b/docs/man/rpmdb.8.md
+@@ -12,7 +12,7 @@ rpmdb - RPM Database Tool
+ SYNOPSIS
+ ========
+ 
+-**rpmdb** {**\--initdb\|\--rebuilddb**}
++**rpmdb** {**\--initdb\|\--rebuilddb\|\--parkdb**}
+ 
+ **rpmdb** {**\--verifydb**}
+ 
+@@ -23,7 +23,7 @@ DESCRIPTION
+ 
+ The general form of an rpmdb command is
+ 
+-**rpm** {**\--initdb\|\--rebuilddb**} \[**-v**\] \[**\--dbpath
++**rpm** {**\--initdb\|\--rebuilddb\|\--parkdb**} \[**-v**\] \[**\--dbpath
+ ***DIRECTORY*\] \[**\--root ***DIRECTORY*\]
+ 
+ Use **\--initdb** to create a new database if one doesn\'t already exist
+@@ -38,6 +38,15 @@ for transfporting to another host or database type.
+ **\--importdb** imports a database from a header-list format as created
+ by **\--exportdb**.
+ 
++**\--parkdb** parks the database. This prepares and optimizes the database for
++inclusion on read-only media, such as immutable OS images. Write operations,
++such as RPM transactions, will unpark the database and continue normally,
++leaving the database unparked when finished. Thus, to unpark manually, use
++**\--rebuilddb**. Depending on the backend used, this operation may include the
++removal of auxiliary, backend-specific files from disk, such as the write-ahead
++log or shared memory index, and thus facilitate bit-for-bit reproducible OS
++images.
++
+ SEE ALSO
+ ========
+ 
+diff --git a/include/rpm/rpmts.h b/include/rpm/rpmts.h
+index 5c168820f..d390f2ac4 100644
+--- a/include/rpm/rpmts.h
++++ b/include/rpm/rpmts.h
+@@ -308,6 +308,13 @@ int rpmtsSetDBMode(rpmts ts, int dbmode);
+  */
+ int rpmtsRebuildDB(rpmts ts);
+ 
++/** \ingroup rpmts
++ * Park the database used by the transaction.
++ * @param ts		transaction set
++ * @return		0 on success
++ */
++int rpmtsParkDB(rpmts ts);
++
+ /** \ingroup rpmts
+  * Verify the database used by the transaction.
+  * @param ts		transaction set
+diff --git a/lib/backend/dbi.h b/lib/backend/dbi.h
+index 00ada038e..6e6226ff7 100644
+--- a/lib/backend/dbi.h
++++ b/lib/backend/dbi.h
+@@ -13,6 +13,7 @@ enum rpmdbFlags {
+     RPMDB_FLAG_REBUILD		= (1 << 1),
+     RPMDB_FLAG_VERIFYONLY	= (1 << 2),
+     RPMDB_FLAG_SALVAGE		= (1 << 3),
++    RPMDB_FLAG_PARK		= (1 << 4),
+ };
+ 
+ typedef enum dbCtrlOp_e {
+diff --git a/lib/backend/sqlite.c b/lib/backend/sqlite.c
+index 76e9cae72..6cedcce16 100644
+--- a/lib/backend/sqlite.c
++++ b/lib/backend/sqlite.c
+@@ -197,10 +197,23 @@ static int sqlite_fini(rpmdb rdb)
+ 	    if (sqlite3_db_readonly(sdb, NULL) == 0) {
+ 		sqlexec(sdb, "PRAGMA optimize");
+ 		sqlexec(sdb, "PRAGMA wal_checkpoint = TRUNCATE");
++
++		/* Park the database if requested */
++		if ((rdb->db_flags & RPMDB_FLAG_PARK) != 0) {
++		    int zero = 0;
++		    /* Make sure any WAL and SHM files are cleaned up */
++		    sqlite3_file_control(sdb, NULL, SQLITE_FCNTL_PERSIST_WAL,
++					 &zero);
++		    rc = sqlexec(sdb, "PRAGMA journal_mode = DELETE");
++		    if (rc == 0)
++			rpmlog(RPMLOG_DEBUG, _("rpmdb sqlite parking done\n"));
++		    else
++			rpmlog(RPMLOG_ERR, _("rpmdb sqlite parking failed\n"));
++		}
+ 	    }
+ 	    rdb->db_dbenv = NULL;
+ 	    int xx = sqlite3_close(sdb);
+-	    rc = (xx != SQLITE_OK);
++	    rc += (xx != SQLITE_OK);
+ 	}
+     }
+ 
+@@ -329,7 +342,7 @@ static int sqlite_Close(dbiIndex dbi, unsigned int flags)
+     int rc = 0;
+     if (rdb->db_flags & RPMDB_FLAG_REBUILD)
+ 	rc = init_index(dbi, rpmTagGetValue(dbi->dbi_file));
+-    sqlite_fini(dbi->dbi_rpmdb);
++    rc += sqlite_fini(dbi->dbi_rpmdb);
+     dbiFree(dbi);
+     return rc;
+ }
+diff --git a/lib/rpmdb.c b/lib/rpmdb.c
+index 117df46e1..39b2e723e 100644
+--- a/lib/rpmdb.c
++++ b/lib/rpmdb.c
+@@ -2450,7 +2450,9 @@ int rpmdbRebuild(const char * prefix, rpmts ts,
+ 	goto exit;
+     }
+     if (openDatabase(prefix, newdbpath, &newdb,
+-		     (O_RDWR | O_CREAT), 0644, RPMDB_FLAG_REBUILD)) {
++		     (O_RDWR | O_CREAT), 0644, RPMDB_FLAG_REBUILD |
++		     (rebuildflags & RPMDB_REBUILD_FLAG_PARK ?
++		         RPMDB_FLAG_PARK : 0))) {
+ 	rc = 1;
+ 	goto exit;
+     }
+@@ -2498,7 +2500,8 @@ int rpmdbRebuild(const char * prefix, rpmts ts,
+ 
+     rpmdbClose(olddb);
+     dbCtrl(newdb, DB_CTRL_INDEXSYNC);
+-    rpmdbClose(newdb);
++    if (rpmdbClose(newdb))
++	failed = 1;
+ 
+     if (failed) {
+ 	rpmlog(RPMLOG_WARNING, 
+diff --git a/lib/rpmdb_internal.h b/lib/rpmdb_internal.h
+index 0590013db..36e18b71a 100644
+--- a/lib/rpmdb_internal.h
++++ b/lib/rpmdb_internal.h
+@@ -22,6 +22,7 @@ extern "C" {
+ 
+ enum rpmdbRebuildFlags_e {
+     RPMDB_REBUILD_FLAG_SALVAGE	= (1 << 0),
++    RPMDB_REBUILD_FLAG_PARK	= (1 << 1),
+ };
+ 
+ /** \ingroup rpmdb
+diff --git a/lib/rpmts.c b/lib/rpmts.c
+index bc52a2f28..96dd31b0a 100644
+--- a/lib/rpmts.c
++++ b/lib/rpmts.c
+@@ -165,6 +165,11 @@ int rpmtsRebuildDB(rpmts ts)
+     return rebuildDB(ts, 0);
+ }
+ 
++int rpmtsParkDB(rpmts ts)
++{
++    return rebuildDB(ts, RPMDB_REBUILD_FLAG_PARK);
++}
++
+ int rpmtsVerifyDB(rpmts ts)
+ {
+     int rc = -1;
+diff --git a/python/rpmts-py.c b/python/rpmts-py.c
+index ae2eeea28..dc81d3489 100644
+--- a/python/rpmts-py.c
++++ b/python/rpmts-py.c
+@@ -375,6 +375,18 @@ rpmts_RebuildDB(rpmtsObject * s)
+     return Py_BuildValue("i", rc);
+ }
+ 
++static PyObject *
++rpmts_ParkDB(rpmtsObject * s)
++{
++    int rc;
++
++    Py_BEGIN_ALLOW_THREADS
++    rc = rpmtsParkDB(s->ts);
++    Py_END_ALLOW_THREADS
++
++    return Py_BuildValue("i", rc);
++}
++
+ static PyObject *
+ rpmts_VerifyDB(rpmtsObject * s)
+ {
+@@ -799,6 +811,9 @@ Remove all elements from the transaction set\n" },
+  {"rebuildDB",	(PyCFunction) rpmts_RebuildDB,	METH_NOARGS,
+ "ts.rebuildDB() -> None\n\
+ - Rebuild the default transaction rpmdb.\n" },
++ {"parkDB",	(PyCFunction) rpmts_ParkDB,	METH_NOARGS,
++"ts.parkDB() -> None\n\
++- Park the default transaction rpmdb.\n" },
+  {"verifyDB",	(PyCFunction) rpmts_VerifyDB,	METH_NOARGS,
+ "ts.verifyDB() -> None\n\
+ - Verify the default transaction rpmdb.\n" },
+diff --git a/tools/rpmdb.c b/tools/rpmdb.c
+index 36efff8af..3de81be26 100644
+--- a/tools/rpmdb.c
++++ b/tools/rpmdb.c
+@@ -13,6 +13,7 @@ enum modes {
+     MODE_EXPORTDB	= (1 << 3),
+     MODE_IMPORTDB	= (1 << 4),
+     MODE_SALVAGEDB	= (1 << 5),
++    MODE_PARKDB		= (1 << 6),
+ };
+ 
+ static int mode = 0;
+@@ -23,6 +24,8 @@ static struct poptOption dbOptsTable[] = {
+     { "rebuilddb", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_REBUILDDB,
+ 	N_("rebuild database inverted lists from installed package headers"),
+ 	NULL},
++    { "parkdb", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR),
++	&mode, MODE_PARKDB, N_("park database"), NULL},
+     { "verifydb", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR),
+ 	&mode, MODE_VERIFYDB, N_("verify database"), NULL},
+     { "salvagedb", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR|POPT_ARGFLAG_DOC_HIDDEN),
+@@ -117,6 +120,9 @@ int main(int argc, char *argv[])
+ 	ec = rpmtsRebuildDB(ts);
+ 	rpmtsSetVSFlags(ts, ovsflags);
+     }	break;
++    case MODE_PARKDB:
++	ec = rpmtsParkDB(ts);
++	break;
+     case MODE_VERIFYDB:
+ 	ec = rpmtsVerifyDB(ts);
+ 	break;
+-- 
+2.54.0
+
+diff -up rpm-4.19.1.1/docs/man/rpmdb.8.orig rpm-4.19.1.1/docs/man/rpmdb.8
+--- rpm-4.19.1.1/docs/man/rpmdb.8.orig	2026-06-18 09:27:25.469107665 +0200
++++ rpm-4.19.1.1/docs/man/rpmdb.8	2026-06-18 09:27:53.907945350 +0200
+@@ -1,70 +1,60 @@
+-.\" Automatically generated by Pandoc 3.1.3
++.\" Automatically generated by Pandoc 3.1.11.1
+ .\"
+-.\" Define V font for inline verbatim, using C font in formats
+-.\" that render this, and otherwise B font.
+-.ie "\f[CB]x\f[]"x" \{\
+-. ftr V B
+-. ftr VI BI
+-. ftr VB B
+-. ftr VBI BI
+-.\}
+-.el \{\
+-. ftr V CR
+-. ftr VI CI
+-. ftr VB CB
+-. ftr VBI CBI
+-.\}
+ .TH "RPMDB" "8" "29 June 2010" "" ""
+-.hy
+ .SH NAME
+-.PP
+-rpmdb - RPM Database Tool
++rpmdb \- RPM Database Tool
+ .SH SYNOPSIS
++\f[B]rpmdb\f[R] {\f[B]\-\-initdb|\-\-rebuilddb|\-\-parkdb\f[R]}
+ .PP
+-\f[B]rpmdb\f[R] {\f[B]--initdb|--rebuilddb\f[R]}
+-.PP
+-\f[B]rpmdb\f[R] {\f[B]--verifydb\f[R]}
++\f[B]rpmdb\f[R] {\f[B]\-\-verifydb\f[R]}
+ .PP
+-\f[B]rpmdb\f[R] {\f[B]--exportdb|--importdb\f[R]}
++\f[B]rpmdb\f[R] {\f[B]\-\-exportdb|\-\-importdb\f[R]}
+ .SH DESCRIPTION
+-.PP
+ The general form of an rpmdb command is
+ .PP
+-\f[B]rpm\f[R] {\f[B]--initdb|--rebuilddb\f[R]} [\f[B]-v\f[R]]
+-[\f[B]--dbpath \f[R]\f[I]DIRECTORY\f[R]] [\f[B]--root
+-\f[R]\f[I]DIRECTORY\f[R]]
++\f[B]rpm\f[R] {\f[B]\-\-initdb|\-\-rebuilddb|\-\-parkdb\f[R]}
++[\f[B]\-v\f[R]] [\f[B]\-\-dbpath \f[R]\f[I]DIRECTORY\f[R]]
++[\f[B]\-\-root \f[R]\f[I]DIRECTORY\f[R]]
+ .PP
+-Use \f[B]--initdb\f[R] to create a new database if one doesn\[aq]t
++Use \f[B]\-\-initdb\f[R] to create a new database if one doesn\[aq]t
+ already exist (existing database is not overwritten), use
+-\f[B]--rebuilddb\f[R] to rebuild the database indices from the installed
+-package headers.
++\f[B]\-\-rebuilddb\f[R] to rebuild the database indices from the
++installed package headers.
+ .PP
+-\f[B]--verifydb\f[R] performs a low-level integrity check on the
++\f[B]\-\-verifydb\f[R] performs a low\-level integrity check on the
+ database.
+ .PP
+-\f[B]--exportdb\f[R] exports the database in header-list format,
++\f[B]\-\-exportdb\f[R] exports the database in header\-list format,
+ suitable for transfporting to another host or database type.
+ .PP
+-\f[B]--importdb\f[R] imports a database from a header-list format as
+-created by \f[B]--exportdb\f[R].
+-.SH SEE ALSO
++\f[B]\-\-importdb\f[R] imports a database from a header\-list format as
++created by \f[B]\-\-exportdb\f[R].
+ .PP
++\f[B]\-\-parkdb\f[R] parks the database.
++This prepares and optimizes the database for inclusion on read\-only
++media, such as immutable OS images.
++Write operations, such as RPM transactions, will unpark the database and
++continue normally, leaving the database unparked when finished.
++Thus, to unpark manually, use \f[B]\-\-rebuilddb\f[R].
++Depending on the backend used, this operation may include the removal of
++auxiliary, backend\-specific files from disk, such as the write\-ahead
++log or shared memory index, and thus facilitate bit\-for\-bit
++reproducible OS images.
++.SH SEE ALSO
+ \f[B]popt\f[R](3), \f[B]rpm\f[R](8), \f[B]rpmkeys\f[R](8),
+ \f[B]rpmsign\f[R](8), \f[B]rpm2cpio\f[R](8), \f[B]rpmbuild\f[R](8),
+ \f[B]rpmspec\f[R](8)
+ .PP
+-\f[B]rpm --help\f[R] - as rpm supports customizing the options via popt
+-aliases it\[aq]s impossible to guarantee that what\[aq]s described in
+-the manual matches what\[aq]s available.
++\f[B]rpm \-\-help\f[R] \- as rpm supports customizing the options via
++popt aliases it\[aq]s impossible to guarantee that what\[aq]s described
++in the manual matches what\[aq]s available.
+ .PP
+ \f[B]http://www.rpm.org/ <URL:http://www.rpm.org/>\f[R]
+ .SH AUTHORS
+ .IP
+-.nf
+-\f[C]
++.EX
+ Marc Ewing <marc\[at]redhat.com>
+ Jeff Johnson <jbj\[at]redhat.com>
+ Erik Troan <ewt\[at]redhat.com>
+ Panu Matilainen <pmatilai\[at]redhat.com>
+-\f[R]
+-.fi
++.EE

diff --git a/rpm.spec b/rpm.spec
index b49dafd..1c3a235 100644
--- a/rpm.spec
+++ b/rpm.spec
@@ -176,6 +176,7 @@ rpm-4.19.x-nsswitch-enable.patch
 0001-Fix-empty-password-field-in-passwd-group-causing-ent.patch
 
 rpm-4.19.x-add-autosetup-C.patch
+rpm-4.19.x-add-parkdb.patch
 
 # These are not yet upstream
 rpm-4.7.1-geode-i686.patch
@@ -668,6 +669,7 @@ fi
 %changelog
 * Thu Jun 18 2026 Michal Domonkos <mdomonko@redhat.com> - 4.19.1.1-24
 - Add support for %%autosetup -C (RHEL-141269)
+- Add support for database parking (RHEL-126405)
 
 * Thu Feb 05 2026 Michal Domonkos <mdomonko@redhat.com> - 4.19.1.1-23
 - Fix key import API to return NOTTRUSTED for disabled algorithms (RHEL-112394)

                 reply	other threads:[~2026-06-25  7:43 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=178237340834.1.10091319780186252788.rpms-python3-rpm-2310f53fa8e5@fedoraproject.org \
    --to=mdomonko@redhat.com \
    --cc=git-commits@fedoraproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox