Add support for database parking

Resolves: RHEL-126405
This commit is contained in:
Michal Domonkos 2026-06-18 09:39:57 +02:00
parent 6755696e77
commit 2310f53fa8
2 changed files with 430 additions and 0 deletions

428
rpm-4.19.x-add-parkdb.patch Normal file
View File

@ -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

View File

@ -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)