[packages/db5.3] - fix/hack build with current gcc and autotools, add patches from Fedora

hawk hawk at pld-linux.org
Mon May 18 01:49:56 CEST 2026


commit 22254daf7784aedef3c604b6ae874594e2461355
Author: Marcin Krol <hawk at tld-linux.org>
Date:   Mon May 18 01:49:10 2026 +0200

    - fix/hack build with current gcc and autotools, add patches from Fedora

 checkpoint-opd-deadlock.patch           |  14 +
 db-5.3.21-memp_stat-upstream-fix.patch  | 183 ++++++++
 db-5.3.21-mutex_leak.patch              | 718 ++++++++++++++++++++++++++++++
 db-5.3.28-atomic_compare_exchange.patch |  20 +
 db-5.3.28-condition_variable.patch      | 759 ++++++++++++++++++++++++++++++++
 db-5.3.28-lemon_hash.patch              |  20 +
 db-5.3.28-mmap-high-cpu-usage.patch     |  19 +
 db-5.3.28_cve-2019-2708.patch           | 694 +++++++++++++++++++++++++++++
 db5.3-atomic_compare_exchange.patch     | 151 -------
 db5.3.spec                              |  66 ++-
 db_version.patch                        |  42 ++
 libdb-5.3.21-region-size-check.patch    |  39 ++
 libdb-5.3.21-trickle_cpu.patch          | 150 +++++++
 libdb-c99.patch                         |  26 ++
 libdb-cbd-race.patch                    | 110 +++++
 libdb-configure-c99.patch               | 285 ++++++++++++
 libdb-limit-cpu.patch                   |  12 +
 libdb-sqlite-c99.patch                  |  20 +
 libdb-sqlite-tcl8.patch                 |  12 +
 tls.patch                               |  12 +
 20 files changed, 3190 insertions(+), 162 deletions(-)
---
diff --git a/db5.3.spec b/db5.3.spec
index 41d84ce..ffa33a0 100644
--- a/db5.3.spec
+++ b/db5.3.spec
@@ -15,7 +15,7 @@ Summary:	Berkeley DB database library for C
 Summary(pl.UTF-8):	Biblioteka C do obsługi baz Berkeley DB
 Name:		db5.3
 Version:	%{ver}.%{patchlevel}
-Release:	8
+Release:	9
 License:	BSD-like (see LICENSE)
 Group:		Libraries
 #Source0Download: http://www.oracle.com/technetwork/products/berkeleydb/downloads/index.html
@@ -23,9 +23,28 @@ Source0:	http://download.oracle.com/berkeley-db/db-%{ver}.tar.gz
 # Source0-md5:	b99454564d5b4479750567031d66fe24
 Patch0:		%{name}-link.patch
 Patch1:		%{name}-sql-features.patch
-Patch2:		db-5.3.28-cwd-db_config.patch
-Patch3:		%{name}-atomic_compare_exchange.patch
-Patch4:		java.patch
+Patch2:		java.patch
+Patch3:		db_version.patch
+Patch4:		tls.patch
+# Patches from Fedora
+Patch100:	db-5.3.21-memp_stat-upstream-fix.patch
+Patch101:	db-5.3.21-mutex_leak.patch
+Patch102:	db-5.3.28-lemon_hash.patch
+Patch103:	db-5.3.28-condition_variable.patch
+Patch104:	db-5.3.28-cwd-db_config.patch
+Patch105:	libdb-5.3.21-region-size-check.patch
+Patch106:	checkpoint-opd-deadlock.patch
+Patch107:	db-5.3.28-atomic_compare_exchange.patch
+Patch108:	libdb-cbd-race.patch
+Patch109:	libdb-limit-cpu.patch
+Patch110:	libdb-5.3.21-trickle_cpu.patch
+Patch111:	db-5.3.28_cve-2019-2708.patch
+Patch112:	db-5.3.28-mmap-high-cpu-usage.patch
+Patch113:	libdb-c99.patch
+Patch114:	libdb-configure-c99.patch
+Patch115:	libdb-sqlite-c99.patch
+Patch116:	libdb-sqlite-tcl8.patch
+
 URL:		http://www.oracle.com/technetwork/products/berkeleydb/downloads/index.html
 BuildRequires:	automake
 %if %{with java}
@@ -33,7 +52,7 @@ BuildRequires:	jdk
 BuildRequires:	rpm-javaprov
 %endif
 BuildRequires:	libstdc++-devel
-BuildRequires:	rpmbuild(macros) >= 1.426
+BuildRequires:	rpmbuild(macros) >= 2.043
 BuildRequires:	sed >= 4.0
 %{?with_tcl:BuildRequires:	tcl-devel >= 8.4.0}
 Requires:	uname(release) >= 2.6.0
@@ -377,6 +396,23 @@ poleceń.
 %patch -P3 -p1
 %patch -P4 -p1
 
+%patch -P100 -p1
+%patch -P101 -p1
+%patch -P102 -p1
+%patch -P103 -p1
+%patch -P105 -p1
+%patch -P106 -p1
+%patch -P107 -p1
+%patch -P108 -p1
+%patch -P109 -p1
+%patch -P110 -p1
+%patch -P111 -p1
+%patch -P112 -p1
+%patch -P113 -p1
+%patch -P114 -p1
+%patch -P115 -p1
+%patch -P116 -p1
+
 %build
 cp -f /usr/share/automake/config.sub dist
 cp -f /usr/share/automake/config.sub lang/sql/sqlite
@@ -384,19 +420,27 @@ cp -f /usr/share/automake/config.sub lang/sql/sqlite
 JAVACFLAGS="-source 1.6 -target 1.6"
 export JAVACFLAGS
 
-%if %{with static_libs}
-cp -a build_unix build_unix.static
+cd dist
+%{__aclocal}
+%{__autoconf}
+./s_config
+cd ..
 
-cd build_unix.static
+%define configuredir ../dist/
 
 CC="%{__cc}"
 CXX="%{__cxx}"
-CFLAGS="%{rpmcflags}"
+CFLAGS="%{rpmcflags} -std=gnu99"
 CXXFLAGS="%{rpmcflags} -fno-implicit-templates"
 LDFLAGS="%{rpmcflags} %{rpmldflags}"
 export CC CXX CFLAGS CXXFLAGS LDFLAGS
 
-../dist/%configure \
+%if %{with static_libs}
+cp -a build_unix build_unix.static
+
+cd build_unix.static
+
+%configure \
 	--disable-shared \
 	--enable-static \
 	--enable-compat185 \
@@ -414,7 +458,7 @@ cd ..
 
 cd build_unix
 
-../dist/%configure \
+%configure \
 	--prefix=%{_prefix} \
 	--libdir=%{_libdir} \
 	--enable-shared \
diff --git a/checkpoint-opd-deadlock.patch b/checkpoint-opd-deadlock.patch
new file mode 100644
index 0000000..7aab6e1
--- /dev/null
+++ b/checkpoint-opd-deadlock.patch
@@ -0,0 +1,14 @@
+--- db-5.3.21/src/db/db_cam.c.opd_deadlock	2017-10-31 12:20:54.118979690 +0100
++++ db-5.3.21/src/db/db_cam.c	2017-10-31 12:21:06.828739341 +0100
+@@ -868,6 +868,11 @@
+ 	    flags == DB_PREV || flags == DB_PREV_DUP)) {
+ 		if (tmp_rmw && (ret = dbc->am_writelock(dbc)) != 0)
+ 			goto err;
++        /* Latch the primary tree page here in order to not deadlock later. */
++		if (cp->page == NULL &&
++		    (ret = __memp_fget(mpf, &cp->pgno,
++			 dbc->thread_info, dbc->txn, 0, &cp->page)) != 0)
++			goto err;
+ 		if (F_ISSET(dbc, DBC_TRANSIENT))
+ 			opd = cp->opd;
+ 		else if ((ret = __dbc_idup(cp->opd, &opd, DB_POSITION)) != 0)
diff --git a/db-5.3.21-memp_stat-upstream-fix.patch b/db-5.3.21-memp_stat-upstream-fix.patch
new file mode 100644
index 0000000..9e3d52b
--- /dev/null
+++ b/db-5.3.21-memp_stat-upstream-fix.patch
@@ -0,0 +1,183 @@
+diff -r -u db-5.3.21_orig/src/mp/mp_stat.c db-5.3.21/src/mp/mp_stat.c
+--- db-5.3.21_orig/src/mp/mp_stat.c	2012-05-12 01:57:53.000000000 +0800
++++ db-5.3.21/src/mp/mp_stat.c	2015-05-19 15:07:09.000000000 +0800
+@@ -87,6 +87,13 @@
+ 	u_int32_t i;
+ 	uintmax_t tmp_wait, tmp_nowait;
+ 
++	/*
++	 * The array holding the lengths related to the buffer allocated for *fspp.
++	 * The first element of the array holds the number of entries allocated.
++	 * The second element of the array holds the total number of bytes allocated.
++	 */
++	u_int32_t fsp_len[2];
++
+ 	dbmp = env->mp_handle;
+ 	mp = dbmp->reginfo[0].primary;
+ 
+@@ -193,32 +200,53 @@
+ 	if (fspp != NULL) {
+ 		*fspp = NULL;
+ 
+-		/* Count the MPOOLFILE structures. */
+-		i = 0;
+-		len = 0;
+-		if ((ret = __memp_walk_files(env,
+-		     mp, __memp_count_files, &len, &i, flags)) != 0)
+-			return (ret);
++		while (*fspp == NULL) {
++			/* Count the MPOOLFILE structures. */
++			i = 0;
++			/*
++			 * Allow space for the first __memp_get_files() to align the
++			 * structure array to uintmax_t, DB_MPOOL_STAT's most
++			 * restrictive field.  [#23150]
++			 */
++			len = sizeof(uintmax_t);
++			if ((ret = __memp_walk_files(env,
++			     mp, __memp_count_files, &len, &i, flags)) != 0)
++				return (ret);
++
++			if (i == 0)
++				return (0);
++
++			/* 
++			 * Copy the number of DB_MPOOL_FSTAT entries and the number of
++			 * bytes allocated for them into fsp_len. Do not count the space
++			 * reserved for allignment.
++			 */
++			fsp_len[0] = i;
++			fsp_len[1] = len - sizeof(uintmax_t);
+ 
+-		if (i == 0)
+-			return (0);
+-		len += sizeof(DB_MPOOL_FSTAT *);	/* Trailing NULL */
++			len += sizeof(DB_MPOOL_FSTAT *);	/* Trailing NULL */
+ 
+-		/* Allocate space */
+-		if ((ret = __os_umalloc(env, len, fspp)) != 0)
+-			return (ret);
++			/* Allocate space */
++			if ((ret = __os_umalloc(env, len, fspp)) != 0)
++				return (ret);
+ 
+-		tfsp = *fspp;
+-		*tfsp = NULL;
+-
+-		/*
+-		 * Files may have been opened since we counted, don't walk
+-		 * off the end of the allocated space.
+-		 */
+-		if ((ret = __memp_walk_files(env,
+-		    mp, __memp_get_files, &tfsp, &i, flags)) != 0)
+-			return (ret);
++			tfsp = *fspp;
++			*tfsp = NULL;
+ 
++			/*
++			 * Files may have been opened since we counted, if we walk off
++			 * the end of the allocated space specified in fsp_len, retry.
++			 */
++			if ((ret = __memp_walk_files(env,
++			    mp, __memp_get_files, &tfsp, fsp_len, flags)) != 0) {
++				if (ret == DB_BUFFER_SMALL) {
++					__os_ufree(env, *fspp);
++					*fspp = NULL;
++					tfsp = NULL;
++				} else
++					return (ret);
++			}
++		}
+ 		*++tfsp = NULL;
+ 	}
+ 
+@@ -286,28 +314,35 @@
+  * for the text file names.
+  */
+ static int
+-__memp_get_files(env, mfp, argp, countp, flags)
++__memp_get_files(env, mfp, argp, fsp_len, flags)
+ 	ENV *env;
+ 	MPOOLFILE *mfp;
+ 	void *argp;
+-	u_int32_t *countp;
++	u_int32_t fsp_len[];
+ 	u_int32_t flags;
+ {
+ 	DB_MPOOL *dbmp;
+ 	DB_MPOOL_FSTAT **tfsp, *tstruct;
+ 	char *name, *tname;
+-	size_t nlen;
++	size_t nlen, tlen;
+ 
+-	if (*countp == 0)
+-		return (0);
++	/* We walked through more files than argp was allocated for. */
++	if (fsp_len[0] == 0)
++		return DB_BUFFER_SMALL;
+ 
+ 	dbmp = env->mp_handle;
+ 	tfsp = *(DB_MPOOL_FSTAT ***)argp;
+ 
+ 	if (*tfsp == NULL) {
+-		/* Add 1 to count because we need to skip over the NULL. */
+-		tstruct = (DB_MPOOL_FSTAT *)(tfsp + *countp + 1);
+-		tname = (char *)(tstruct + *countp);
++		/*
++		 * Add 1 to count because to skip over the NULL end marker.
++		 * Align it further for DB_MPOOL_STAT's most restrictive field
++		 * because uintmax_t might require stricter alignment than
++		 * pointers; e.g., IP32 LL64 SPARC. [#23150]
++		 */
++		tstruct = (DB_MPOOL_FSTAT *)&tfsp[fsp_len[0] + 1];
++		tstruct = ALIGNP_INC(tstruct, sizeof(uintmax_t));
++		tname = (char *)&tstruct[fsp_len[0]];
+ 		*tfsp = tstruct;
+ 	} else {
+ 		tstruct = *tfsp + 1;
+@@ -317,6 +352,15 @@
+ 
+ 	name = __memp_fns(dbmp, mfp);
+ 	nlen = strlen(name) + 1;
++
++	/* The space required for file names is larger than argp was allocated for. */
++	tlen = sizeof(DB_MPOOL_FSTAT *) + sizeof(DB_MPOOL_FSTAT) + nlen;
++	if (fsp_len[1] < tlen)
++		return DB_BUFFER_SMALL;
++	else
++		/* Count down the number of bytes left in argp. */
++		fsp_len[1] -= tlen;
++
+ 	memcpy(tname, name, nlen);
+ 	memcpy(tstruct, &mfp->stat, sizeof(mfp->stat));
+ 	tstruct->file_name = tname;
+@@ -325,7 +369,9 @@
+ 	tstruct->st_pagesize = mfp->pagesize;
+ 
+ 	*(DB_MPOOL_FSTAT ***)argp = tfsp;
+-	(*countp)--;
++
++	/* Count down the number of entries left in argp. */
++	fsp_len[0]--;
+ 
+ 	if (LF_ISSET(DB_STAT_CLEAR))
+ 		memset(&mfp->stat, 0, sizeof(mfp->stat));
+diff -r -u db-5.3.21_orig/src/mp/mp_sync.c db-5.3.21/src/mp/mp_sync.c
+--- db-5.3.21_orig/src/mp/mp_sync.c	2012-05-12 01:57:53.000000000 +0800
++++ db-5.3.21/src/mp/mp_sync.c	2015-05-19 15:08:05.000000000 +0800
+@@ -57,11 +57,13 @@
+ 			if ((t_ret = func(env,
+ 			    mfp, arg, countp, flags)) != 0 && ret == 0)
+ 				ret = t_ret;
+-			if (ret != 0 && !LF_ISSET(DB_STAT_MEMP_NOERROR))
++			if (ret != 0 &&
++			    (!LF_ISSET(DB_STAT_MEMP_NOERROR) || ret == DB_BUFFER_SMALL))
+ 				break;
+ 		}
+ 		MUTEX_UNLOCK(env, hp->mtx_hash);
+-		if (ret != 0 && !LF_ISSET(DB_STAT_MEMP_NOERROR))
++		if (ret != 0 &&
++		    (!LF_ISSET(DB_STAT_MEMP_NOERROR) || ret == DB_BUFFER_SMALL))
+ 			break;
+ 	}
+ 	return (ret);
diff --git a/db-5.3.21-mutex_leak.patch b/db-5.3.21-mutex_leak.patch
new file mode 100644
index 0000000..0738dab
--- /dev/null
+++ b/db-5.3.21-mutex_leak.patch
@@ -0,0 +1,718 @@
+diff -U 5 -r db-5.3.21.old/src/dbinc_auto/int_def.in db-5.3.21/src/dbinc_auto/int_def.in
+--- db-5.3.21.old/src/dbinc_auto/int_def.in	2012-05-12 01:57:53.000000000 +0800
++++ db-5.3.21/src/dbinc_auto/int_def.in	2016-10-25 22:40:58.000000000 +0800
+@@ -1371,10 +1371,11 @@
+ #define	__memp_failchk __memp_failchk at DB_VERSION_UNIQUE_NAME@
+ #define	__memp_bhwrite __memp_bhwrite at DB_VERSION_UNIQUE_NAME@
+ #define	__memp_pgread __memp_pgread at DB_VERSION_UNIQUE_NAME@
+ #define	__memp_pg __memp_pg at DB_VERSION_UNIQUE_NAME@
+ #define	__memp_bhfree __memp_bhfree at DB_VERSION_UNIQUE_NAME@
++#define	__memp_bh_clear_dirty __memp_bh_clear_dirty at DB_VERSION_UNIQUE_NAME@
+ #define	__memp_fget_pp __memp_fget_pp at DB_VERSION_UNIQUE_NAME@
+ #define	__memp_fget __memp_fget at DB_VERSION_UNIQUE_NAME@
+ #define	__memp_fcreate_pp __memp_fcreate_pp at DB_VERSION_UNIQUE_NAME@
+ #define	__memp_fcreate __memp_fcreate at DB_VERSION_UNIQUE_NAME@
+ #define	__memp_set_clear_len __memp_set_clear_len at DB_VERSION_UNIQUE_NAME@
+@@ -1395,10 +1396,11 @@
+ #define	__memp_fopen __memp_fopen at DB_VERSION_UNIQUE_NAME@
+ #define	__memp_fclose_pp __memp_fclose_pp at DB_VERSION_UNIQUE_NAME@
+ #define	__memp_fclose __memp_fclose at DB_VERSION_UNIQUE_NAME@
+ #define	__memp_mf_discard __memp_mf_discard at DB_VERSION_UNIQUE_NAME@
+ #define	__memp_inmemlist __memp_inmemlist at DB_VERSION_UNIQUE_NAME@
++#define	__memp_mf_mark_dead __memp_mf_mark_dead at DB_VERSION_UNIQUE_NAME@
+ #define	__memp_fput_pp __memp_fput_pp at DB_VERSION_UNIQUE_NAME@
+ #define	__memp_fput __memp_fput at DB_VERSION_UNIQUE_NAME@
+ #define	__memp_unpin_buffers __memp_unpin_buffers at DB_VERSION_UNIQUE_NAME@
+ #define	__memp_dirty __memp_dirty at DB_VERSION_UNIQUE_NAME@
+ #define	__memp_shared __memp_shared at DB_VERSION_UNIQUE_NAME@
+@@ -1453,10 +1455,11 @@
+ #define	__memp_fsync_pp __memp_fsync_pp at DB_VERSION_UNIQUE_NAME@
+ #define	__memp_fsync __memp_fsync at DB_VERSION_UNIQUE_NAME@
+ #define	__mp_xxx_fh __mp_xxx_fh at DB_VERSION_UNIQUE_NAME@
+ #define	__memp_sync_int __memp_sync_int at DB_VERSION_UNIQUE_NAME@
+ #define	__memp_mf_sync __memp_mf_sync at DB_VERSION_UNIQUE_NAME@
++#define	__memp_purge_dead_files __memp_purge_dead_files at DB_VERSION_UNIQUE_NAME@
+ #define	__memp_trickle_pp __memp_trickle_pp at DB_VERSION_UNIQUE_NAME@
+ #define	__mutex_alloc __mutex_alloc at DB_VERSION_UNIQUE_NAME@
+ #define	__mutex_alloc_int __mutex_alloc_int at DB_VERSION_UNIQUE_NAME@
+ #define	__mutex_free __mutex_free at DB_VERSION_UNIQUE_NAME@
+ #define	__mutex_free_int __mutex_free_int at DB_VERSION_UNIQUE_NAME@
+diff -U 5 -r db-5.3.21.old/src/dbinc_auto/mp_ext.h db-5.3.21/src/dbinc_auto/mp_ext.h
+--- db-5.3.21.old/src/dbinc_auto/mp_ext.h	2012-05-12 01:57:53.000000000 +0800
++++ db-5.3.21/src/dbinc_auto/mp_ext.h	2016-10-25 22:40:58.000000000 +0800
+@@ -14,10 +14,11 @@
+ int __memp_failchk __P((ENV *));
+ int __memp_bhwrite __P((DB_MPOOL *, DB_MPOOL_HASH *, MPOOLFILE *, BH *, int));
+ int __memp_pgread __P((DB_MPOOLFILE *, BH *, int));
+ int __memp_pg __P((DB_MPOOLFILE *, db_pgno_t, void *, int));
+ int __memp_bhfree __P((DB_MPOOL *, REGINFO *, MPOOLFILE *, DB_MPOOL_HASH *, BH *, u_int32_t));
++void __memp_bh_clear_dirty __P((ENV*, DB_MPOOL_HASH *, BH *));
+ int __memp_fget_pp __P((DB_MPOOLFILE *, db_pgno_t *, DB_TXN *, u_int32_t, void *));
+ int __memp_fget __P((DB_MPOOLFILE *, db_pgno_t *, DB_THREAD_INFO *, DB_TXN *, u_int32_t, void *));
+ int __memp_fcreate_pp __P((DB_ENV *, DB_MPOOLFILE **, u_int32_t));
+ int __memp_fcreate __P((ENV *, DB_MPOOLFILE **));
+ int __memp_set_clear_len __P((DB_MPOOLFILE *, u_int32_t));
+@@ -38,10 +39,11 @@
+ int __memp_fopen __P((DB_MPOOLFILE *, MPOOLFILE *, const char *, const char **, u_int32_t, int, size_t));
+ int __memp_fclose_pp __P((DB_MPOOLFILE *, u_int32_t));
+ int __memp_fclose __P((DB_MPOOLFILE *, u_int32_t));
+ int __memp_mf_discard __P((DB_MPOOL *, MPOOLFILE *, int));
+ int __memp_inmemlist __P((ENV *, char ***, int *));
++void __memp_mf_mark_dead __P((DB_MPOOL *, MPOOLFILE *, int*));
+ int __memp_fput_pp __P((DB_MPOOLFILE *, void *, DB_CACHE_PRIORITY, u_int32_t));
+ int __memp_fput __P((DB_MPOOLFILE *, DB_THREAD_INFO *, void *, DB_CACHE_PRIORITY));
+ int __memp_unpin_buffers __P((ENV *, DB_THREAD_INFO *));
+ int __memp_dirty __P((DB_MPOOLFILE *, void *, DB_THREAD_INFO *, DB_TXN *, DB_CACHE_PRIORITY, u_int32_t));
+ int __memp_shared __P((DB_MPOOLFILE *, void *));
+@@ -96,10 +98,11 @@
+ int __memp_fsync_pp __P((DB_MPOOLFILE *));
+ int __memp_fsync __P((DB_MPOOLFILE *));
+ int __mp_xxx_fh __P((DB_MPOOLFILE *, DB_FH **));
+ int __memp_sync_int __P((ENV *, DB_MPOOLFILE *, u_int32_t, u_int32_t, u_int32_t *, int *));
+ int __memp_mf_sync __P((DB_MPOOL *, MPOOLFILE *, int));
++int __memp_purge_dead_files __P((ENV *));
+ int __memp_trickle_pp __P((DB_ENV *, int, int *));
+ 
+ #if defined(__cplusplus)
+ }
+ #endif
+diff -U 5 -r db-5.3.21.old/src/mp/mp_bh.c db-5.3.21/src/mp/mp_bh.c
+--- db-5.3.21.old/src/mp/mp_bh.c	2012-05-12 01:57:53.000000000 +0800
++++ db-5.3.21/src/mp/mp_bh.c	2016-10-25 17:09:35.000000000 +0800
+@@ -472,15 +472,12 @@
+ 	 * a shared latch.
+ 	 */
+ 	if (F_ISSET(bhp, BH_DIRTY | BH_TRASH)) {
+ 		MUTEX_LOCK(env, hp->mtx_hash);
+ 		DB_ASSERT(env, !SH_CHAIN_HASNEXT(bhp, vc));
+-		if (ret == 0 && F_ISSET(bhp, BH_DIRTY)) {
+-			F_CLR(bhp, BH_DIRTY | BH_DIRTY_CREATE);
+-			DB_ASSERT(env, atomic_read(&hp->hash_page_dirty) > 0);
+-			atomic_dec(env, &hp->hash_page_dirty);
+-		}
++		if (ret == 0)
++			__memp_bh_clear_dirty(env, hp, bhp);
+ 
+ 		/* put the page back if necessary. */
+ 		if ((ret != 0 || BH_REFCOUNT(bhp) > 1) &&
+ 		    F_ISSET(bhp, BH_TRASH)) {
+ 			ret = __memp_pg(dbmfp, bhp->pgno, bhp->buf, 1);
+@@ -686,5 +683,31 @@
+ 	} else
+ 		MUTEX_UNLOCK(env, mfp->mutex);
+ 
+ 	return (ret);
+ }
++
++/*
++ * __memp_bh_clear_dirty --
++ *	Clear the dirty flag of of a buffer. Calls on the same buffer must be
++ *	serialized to get the accounting correct. This can be achieved by
++ *	acquiring an exclusive lock on the buffer, a shared lock on the
++ *	buffer plus an exclusive lock on the hash bucket, or some other
++ *	mechanism that guarantees single-thread access to the entire region
++ *	(e.g. during __memp_region_bhfree()).
++ *
++ * PUBLIC: void __memp_bh_clear_dirty __P((ENV*, DB_MPOOL_HASH *, BH *));
++ */
++void
++__memp_bh_clear_dirty(env, hp, bhp)
++	ENV *env;
++	DB_MPOOL_HASH *hp;
++	BH *bhp;
++{
++	COMPQUIET(env, env);
++	if (F_ISSET(bhp, BH_DIRTY)) {
++		F_CLR(bhp, BH_DIRTY | BH_DIRTY_CREATE);
++		DB_ASSERT(env, atomic_read(&hp->hash_page_dirty) > 0);
++		(void)atomic_dec(env, &hp->hash_page_dirty);
++	}
++}
++
+diff -U 5 -r db-5.3.21.old/src/mp/mp_fget.c db-5.3.21/src/mp/mp_fget.c
+--- db-5.3.21.old/src/mp/mp_fget.c	2012-05-12 01:57:53.000000000 +0800
++++ db-5.3.21/src/mp/mp_fget.c	2016-10-25 17:11:08.000000000 +0800
+@@ -437,16 +437,11 @@
+ 		 * complain and get out.
+ 		 */
+ 		if (flags == DB_MPOOL_FREE) {
+ freebuf:		MUTEX_LOCK(env, hp->mtx_hash);
+ 			h_locked = 1;
+-			if (F_ISSET(bhp, BH_DIRTY)) {
+-				F_CLR(bhp, BH_DIRTY | BH_DIRTY_CREATE);
+-				DB_ASSERT(env,
+-				   atomic_read(&hp->hash_page_dirty) > 0);
+-				atomic_dec(env, &hp->hash_page_dirty);
+-			}
++			__memp_bh_clear_dirty(env, hp, bhp);
+ 
+ 			/*
+ 			 * If the buffer we found is already freed, we're done.
+ 			 * If the ref count is not 1 then someone may be
+ 			 * peeking at the buffer.  We cannot free it until they
+diff -U 5 -r db-5.3.21.old/src/mp/mp_fopen.c db-5.3.21/src/mp/mp_fopen.c
+--- db-5.3.21.old/src/mp/mp_fopen.c	2012-05-12 01:57:53.000000000 +0800
++++ db-5.3.21/src/mp/mp_fopen.c	2016-10-25 22:31:05.000000000 +0800
+@@ -12,10 +12,11 @@
+ #include "dbinc/log.h"
+ #include "dbinc/mp.h"
+ #include "dbinc/db_page.h"
+ #include "dbinc/hash.h"
+ 
++static int __memp_count_dead_mutex __P((DB_MPOOL *, u_int32_t *));
+ static int __memp_mpf_alloc __P((DB_MPOOL *,
+     DB_MPOOLFILE *, const char *, u_int32_t, u_int32_t, MPOOLFILE **));
+ static int __memp_mpf_find __P((ENV *,
+     DB_MPOOLFILE *, DB_MPOOL_HASH *, const char *, u_int32_t, MPOOLFILE **));
+ 
+@@ -709,11 +710,15 @@
+ 		 * We should be able to set mfp to NULL and break out of the
+ 		 * loop, but I like the idea of checking all the entries.
+ 		 */
+ 		if (LF_ISSET(DB_TRUNCATE)) {
+ 			MUTEX_LOCK(env, mfp->mutex);
+-			mfp->deadfile = 1;
++			/*
++			 * We cannot purge dead files here, because the caller
++			 * is holding the mutex of the hash bucket of mfp.
++			 */
++			__memp_mf_mark_dead(dbmp, mfp, NULL);
+ 			MUTEX_UNLOCK(env, mfp->mutex);
+ 			continue;
+ 		}
+ 
+ 		/*
+@@ -907,14 +912,15 @@
+ 	DB_MPOOL *dbmp;
+ 	ENV *env;
+ 	MPOOLFILE *mfp;
+ 	char *rpath;
+ 	u_int32_t ref;
+-	int deleted, ret, t_ret;
++	int deleted, purge_dead, ret, t_ret;
+ 
+ 	env = dbmfp->env;
+ 	dbmp = env->mp_handle;
++	purge_dead = 0;
+ 	ret = 0;
+ 
+ 	/*
+ 	 * Remove the DB_MPOOLFILE from the process' list.
+ 	 *
+@@ -1004,11 +1010,11 @@
+ 	}
+ 	DB_ASSERT(env, mfp->neutral_cnt < mfp->mpf_cnt);
+ 	if (--mfp->mpf_cnt == 0 || LF_ISSET(DB_MPOOL_DISCARD)) {
+ 		if (LF_ISSET(DB_MPOOL_DISCARD) ||
+ 		    F_ISSET(mfp, MP_TEMP) || mfp->unlink_on_close) {
+-			mfp->deadfile = 1;
++			__memp_mf_mark_dead(dbmp, mfp, &purge_dead);
+ 		}
+ 		if (mfp->unlink_on_close) {
+ 			if ((t_ret = __db_appname(dbmp->env, DB_APP_DATA,
+ 			    R_ADDR(dbmp->reginfo, mfp->path_off), NULL,
+ 			    &rpath)) != 0 && ret == 0)
+@@ -1037,10 +1043,12 @@
+ 			deleted = 1;
+ 		}
+ 	}
+ 	if (!deleted && !LF_ISSET(DB_MPOOL_NOLOCK))
+ 		MUTEX_UNLOCK(env, mfp->mutex);
++	if (purge_dead)
++		(void)__memp_purge_dead_files(env);
+ 
+ done:	/* Discard the DB_MPOOLFILE structure. */
+ 	if (dbmfp->pgcookie != NULL) {
+ 		__os_free(env, dbmfp->pgcookie->data);
+ 		__os_free(env, dbmfp->pgcookie);
+@@ -1091,11 +1099,11 @@
+ 	/*
+ 	 * We have to release the MPOOLFILE mutex before acquiring the region
+ 	 * mutex so we don't deadlock.  Make sure nobody ever looks at this
+ 	 * structure again.
+ 	 */
+-	mfp->deadfile = 1;
++	__memp_mf_mark_dead(dbmp, mfp, NULL);
+ 
+ 	/* Discard the mutex we're holding and return it too the pool. */
+ 	MUTEX_UNLOCK(env, mfp->mutex);
+ 	if ((t_ret = __mutex_free(env, &mfp->mutex)) != 0 && ret == 0)
+ 		ret = t_ret;
+@@ -1216,5 +1224,106 @@
+ 	/* Make sure we don't return any garbage. */
+ 	*cntp = 0;
+ 	*namesp = NULL;
+ 	return (ret);
+ }
++
++/*
++ * __memp_mf_mark_dead --
++ *	Mark an MPOOLFILE as dead because its contents are no longer necessary.
++ *	This happens when removing, truncation, or closing an unnamed in-memory
++ *	database. Return, in the purgep parameter, whether the caller should
++ *	call __memp_purge_dead_files() after the lock on mfp is released. The
++ *	caller must hold an exclusive lock on the mfp handle.
++ *
++ * PUBLIC: void __memp_mf_mark_dead __P((DB_MPOOL *, MPOOLFILE *, int*));
++ */
++void
++__memp_mf_mark_dead(dbmp, mfp, purgep)
++	DB_MPOOL *dbmp;	
++	MPOOLFILE *mfp;
++	int *purgep;
++{
++	ENV *env;
++#ifdef HAVE_MUTEX_SUPPORT
++	REGINFO *infop;
++	DB_MUTEXREGION *mtxregion;
++	u_int32_t mutex_max, mutex_inuse, dead_mutex;
++#endif
++
++	if (purgep != NULL)
++		*purgep = 0;
++
++	env = dbmp->env;
++
++#ifdef HAVE_MUTEX_SUPPORT
++	MUTEX_REQUIRED(env, mfp->mutex);
++
++	if (MUTEX_ON(env) && mfp->deadfile == 0) {
++		infop = &env->mutex_handle->reginfo;
++		mtxregion = infop->primary;
++
++		mutex_inuse = mtxregion->stat.st_mutex_inuse;
++		if ((mutex_max = env->dbenv->mutex_max) == 0)
++			mutex_max = infop->rp->max / mtxregion->mutex_size;
++
++		/*
++		 * Purging dead pages requires a full scan of the entire cache
++		 * buffer, so it is a slow operation. We only want to do it
++		 * when it is necessary and provides enough benefits. Below is
++		 * a simple heuristic that determines when to purge all dead
++		 * pages.
++		 */
++		if (purgep != NULL && mutex_inuse > mutex_max - 200) {
++			/*
++			 * If the mutex region is almost full and there are
++			 * many mutexes held by dead files, purge dead files.
++			 */
++			(void)__memp_count_dead_mutex(dbmp, &dead_mutex);
++			dead_mutex += mfp->block_cnt + 1;
++
++			if (dead_mutex > mutex_inuse / 20)
++				*purgep = 1;
++		}
++	}
++#endif
++
++	mfp->deadfile = 1;
++}
++
++/*
++ * __memp_count_dead_mutex --
++ *	Estimate the number of mutexes held by dead files.
++ */
++static int
++__memp_count_dead_mutex(dbmp, dead_mutex)
++	DB_MPOOL *dbmp;
++	u_int32_t *dead_mutex;
++{
++	ENV *env;
++	DB_MPOOL_HASH *hp;
++	MPOOL *mp;
++	MPOOLFILE *mfp;
++	u_int32_t mutex_per_file;
++	int busy, i;
++
++	env = dbmp->env;
++	*dead_mutex = 0;
++	mutex_per_file = 1;
++#ifndef HAVE_ATOMICFILEREAD
++	mutex_per_file = 2;
++#endif
++	mp = dbmp->reginfo[0].primary;
++	hp = R_ADDR(dbmp->reginfo, mp->ftab);
++	for (i = 0; i < MPOOL_FILE_BUCKETS; i++, hp++) {
++		busy = MUTEX_TRYLOCK(env, hp->mtx_hash);
++		if (busy)
++			continue;
++		SH_TAILQ_FOREACH(mfp, &hp->hash_bucket, q, __mpoolfile) {
++			if (mfp->deadfile)
++				*dead_mutex += mfp->block_cnt + mutex_per_file;
++		}
++		MUTEX_UNLOCK(env, hp->mtx_hash);
++	}
++
++	return (0);
++}
+diff -U 5 -r db-5.3.21.old/src/mp/mp_method.c db-5.3.21/src/mp/mp_method.c
+--- db-5.3.21.old/src/mp/mp_method.c	2012-05-12 01:57:53.000000000 +0800
++++ db-5.3.21/src/mp/mp_method.c	2016-10-25 17:22:23.000000000 +0800
+@@ -638,11 +638,11 @@
+ 	DB_MPOOL_HASH *hp, *nhp;
+ 	MPOOL *mp;
+ 	MPOOLFILE *mfp;
+ 	roff_t newname_off;
+ 	u_int32_t bucket;
+-	int locked, ret;
++	int locked, purge_dead, ret;
+ 	size_t nlen;
+ 	void *p;
+ 
+ #undef	op_is_remove
+ #define	op_is_remove	(newname == NULL)
+@@ -655,10 +655,11 @@
+ 	dbmp = NULL;
+ 	mfp = NULL;
+ 	nhp = NULL;
+ 	p = NULL;
+ 	locked = ret = 0;
++	purge_dead = 0;
+ 
+ 	if (!MPOOL_ON(env))
+ 		goto fsop;
+ 
+ 	dbmp = env->mp_handle;
+@@ -747,11 +748,11 @@
+ 		 * they do not get reclaimed as long as they exist.  Since we
+ 		 * are now deleting the database, we need to dec that count.
+ 		 */
+ 		if (mfp->no_backing_file)
+ 			mfp->mpf_cnt--;
+-		mfp->deadfile = 1;
++		__memp_mf_mark_dead(dbmp, mfp, &purge_dead);
+ 		MUTEX_UNLOCK(env, mfp->mutex);
+ 	} else {
+ 		/*
+ 		 * Else, it's a rename.  We've allocated memory for the new
+ 		 * name.  Swap it with the old one.  If it's in memory we
+@@ -806,10 +807,16 @@
+ 	if (locked == 1) {
+ 		MUTEX_UNLOCK(env, hp->mtx_hash);
+ 		if (nhp != NULL && nhp != hp)
+ 			MUTEX_UNLOCK(env, nhp->mtx_hash);
+ 	}
++	/* 
++	 * __memp_purge_dead_files() must be called when the hash bucket is
++	 * unlocked.
++	 */
++	if (purge_dead)
++		(void)__memp_purge_dead_files(env);
+ 	return (ret);
+ }
+ 
+ /*
+  * __memp_ftruncate __
+diff -U 5 -r db-5.3.21.old/src/mp/mp_sync.c db-5.3.21/src/mp/mp_sync.c
+--- db-5.3.21.old/src/mp/mp_sync.c	2012-05-12 01:57:53.000000000 +0800
++++ db-5.3.21/src/mp/mp_sync.c	2016-10-25 17:26:58.000000000 +0800
+@@ -24,10 +24,11 @@
+ static int __bhcmp __P((const void *, const void *));
+ static int __memp_close_flush_files __P((ENV *, int));
+ static int __memp_sync_files __P((ENV *));
+ static int __memp_sync_file __P((ENV *,
+ 		MPOOLFILE *, void *, u_int32_t *, u_int32_t));
++static inline void __update_err_ret(int, int*);
+ 
+ /*
+  * __memp_walk_files --
+  * PUBLIC: int __memp_walk_files __P((ENV *, MPOOL *,
+  * PUBLIC:	int (*) __P((ENV *, MPOOLFILE *, void *,
+@@ -961,5 +962,125 @@
+ 		return (-1);
+ 	if (bhp1->track_pgno > bhp2->track_pgno)
+ 		return (1);
+ 	return (0);
+ }
++
++/*
++ * __memp_purge_dead_files --
++ *	Remove all dead files and their buffers from the mpool. The caller
++ *	cannot hold any lock on the dead MPOOLFILE handles, their buffers
++ *	or their hash buckets.
++ *
++ * PUBLIC: int __memp_purge_dead_files __P((ENV *));
++ */
++int
++__memp_purge_dead_files(env)
++	ENV *env;
++{
++	BH *bhp;
++	DB_MPOOL *dbmp;
++	DB_MPOOL_HASH *hp, *hp_end;
++	REGINFO *infop;
++	MPOOL *c_mp, *mp;
++	MPOOLFILE *mfp;
++	u_int32_t i_cache;
++	int ret, t_ret, h_lock;
++
++	if (!MPOOL_ON(env))
++		return (0);
++
++	dbmp = env->mp_handle;
++	mp = dbmp->reginfo[0].primary;
++	ret = t_ret = h_lock = 0;
++
++	/*
++	 * Walk each cache's list of buffers and free all buffers whose
++	 * MPOOLFILE is marked as dead.
++	 */
++	for (i_cache = 0; i_cache < mp->nreg; i_cache++) {
++		infop = &dbmp->reginfo[i_cache]; 
++		c_mp = infop->primary;
++
++		hp = R_ADDR(infop, c_mp->htab);
++		hp_end = &hp[c_mp->htab_buckets];
++		for (; hp < hp_end; hp++) {
++			/* Skip empty buckets. */
++			if (SH_TAILQ_FIRST(&hp->hash_bucket, __bh) == NULL)
++				continue;
++
++			/* 
++			 * Search for a dead buffer. Other places that call
++			 * __memp_bhfree() acquire the buffer lock before the
++			 * hash bucket lock. Even though we acquire the two
++			 * locks in reverse order, we cannot deadlock here
++			 * because we don't block waiting for the locks.
++			 */
++			t_ret = MUTEX_TRYLOCK(env, hp->mtx_hash);
++			if (t_ret != 0) {
++				__update_err_ret(t_ret, &ret);
++				continue;
++			}
++			h_lock = 1;
++			SH_TAILQ_FOREACH(bhp, &hp->hash_bucket, hq, __bh) {
++				/* Skip buffers that are being used. */
++				if (BH_REFCOUNT(bhp) > 0)
++					continue;
++
++				mfp = R_ADDR(dbmp->reginfo, bhp->mf_offset);
++				if (!mfp->deadfile)
++					continue;
++
++				/* Found a dead buffer. Prepare to free it. */
++				t_ret = MUTEX_TRYLOCK(env, bhp->mtx_buf);
++				if (t_ret != 0) {
++					__update_err_ret(t_ret, &ret);
++					continue;
++				}
++
++				DB_ASSERT(env, (!F_ISSET(bhp, BH_EXCLUSIVE) &&
++				    BH_REFCOUNT(bhp) == 0));
++				F_SET(bhp, BH_EXCLUSIVE);
++				(void)atomic_inc(env, &bhp->ref);
++
++				__memp_bh_clear_dirty(env, hp, bhp);
++
++				/*
++				 * Free the buffer. The buffer and hash bucket
++				 * are unlocked by __memp_bhfree.
++				 */
++				if ((t_ret = __memp_bhfree(dbmp, infop, mfp,
++				    hp, bhp, BH_FREE_FREEMEM)) == 0)
++					/*
++					 * Decrement hp, so the next turn will
++					 * search the same bucket again.
++					 */
++					hp--;
++				else
++					__update_err_ret(t_ret, &ret);
++
++				/*
++				 * The hash bucket is unlocked, we need to
++				 * start over again.
++				 */
++				h_lock = 0;
++				break;
++			}
++
++			if (h_lock) {
++				MUTEX_UNLOCK(env, hp->mtx_hash);
++				h_lock = 0;
++			}
++		}
++	}
++
++	return (ret);
++}
++
++static inline void
++__update_err_ret(t_ret, retp)
++	int t_ret;
++	int *retp;
++{
++	if (t_ret != 0 && t_ret != DB_LOCK_NOTGRANTED && *retp == 0)
++		*retp = t_ret;
++}
+diff -U 5 -r db-5.3.21.old/src/mp/mp_trickle.c db-5.3.21/src/mp/mp_trickle.c
+--- db-5.3.21.old/src/mp/mp_trickle.c	2012-05-12 01:57:53.000000000 +0800
++++ db-5.3.21/src/mp/mp_trickle.c	2016-10-25 17:27:57.000000000 +0800
+@@ -65,10 +65,14 @@
+ 	    "DB_ENV->memp_trickle: %d: percent must be between 1 and 100",
+ 		    "%d"), pct);
+ 		return (EINVAL);
+ 	}
+ 
++	/* First we purge all dead files and their buffers. */
++	if ((ret = __memp_purge_dead_files(env)) != 0)
++		return (ret);
++
+ 	/*
+ 	 * Loop through the caches counting total/dirty buffers.
+ 	 *
+ 	 * XXX
+ 	 * Using hash_page_dirty is our only choice at the moment, but it's not
+diff -U 5 -r db-5.3.21.old/src/mutex/mut_region.c db-5.3.21/src/mutex/mut_region.c
+--- db-5.3.21.old/src/mutex/mut_region.c	2012-05-12 01:57:54.000000000 +0800
++++ db-5.3.21/src/mutex/mut_region.c	2016-10-25 17:34:22.000000000 +0800
+@@ -15,11 +15,11 @@
+ #include "dbinc/txn.h"
+ 
+ static db_size_t __mutex_align_size __P((ENV *));
+ static int __mutex_region_init __P((ENV *, DB_MUTEXMGR *));
+ static size_t __mutex_region_size __P((ENV *));
+-static size_t __mutex_region_max __P((ENV *));
++static size_t __mutex_region_max __P((ENV *, u_int32_t));
+ 
+ /*
+  * __mutex_open --
+  *	Open a mutex region.
+  *
+@@ -32,11 +32,11 @@
+ {
+ 	DB_ENV *dbenv;
+ 	DB_MUTEXMGR *mtxmgr;
+ 	DB_MUTEXREGION *mtxregion;
+ 	size_t size;
+-	u_int32_t cpu_count;
++	u_int32_t cpu_count, mutex_needed;
+ 	int ret;
+ #ifndef HAVE_ATOMIC_SUPPORT
+ 	u_int i;
+ #endif
+ 
+@@ -59,23 +59,24 @@
+ 		    cpu_count : cpu_count * MUTEX_SPINS_PER_PROCESSOR)) != 0)
+ 			return (ret);
+ 	}
+ 
+ 	/*
+-	 * If the user didn't set an absolute value on the number of mutexes
+-	 * we'll need, figure it out.  We're conservative in our allocation,
+-	 * we need mutexes for DB handles, group-commit queues and other things
+-	 * applications allocate at run-time.  The application may have kicked
+-	 * up our count to allocate its own mutexes, add that in.
++	 * Figure out the number of mutexes we'll need.  We're conservative in
++	 * our allocation, we need mutexes for DB handles, group-commit queues
++	 * and other things applications allocate at run-time.  The application
++	 * may have kicked up our count to allocate its own mutexes, add that
++	 * in.
+ 	 */
++	mutex_needed =
++	    __lock_region_mutex_count(env) +
++	    __log_region_mutex_count(env) +
++	    __memp_region_mutex_count(env) +
++	    __txn_region_mutex_count(env);
+ 	if (dbenv->mutex_cnt == 0 &&
+ 	    F_ISSET(env, ENV_PRIVATE | ENV_THREAD) != ENV_PRIVATE)
+-		dbenv->mutex_cnt =
+-		    __lock_region_mutex_count(env) +
+-		    __log_region_mutex_count(env) +
+-		    __memp_region_mutex_count(env) +
+-		    __txn_region_mutex_count(env);
++		dbenv->mutex_cnt = mutex_needed;
+ 
+ 	if (dbenv->mutex_max != 0 && dbenv->mutex_cnt > dbenv->mutex_max)
+ 		dbenv->mutex_cnt = dbenv->mutex_max;
+ 
+ 	/* Create/initialize the mutex manager structure. */
+@@ -88,12 +89,12 @@
+ 	mtxmgr->reginfo.id = INVALID_REGION_ID;
+ 	mtxmgr->reginfo.flags = REGION_JOIN_OK;
+ 	size = __mutex_region_size(env);
+ 	if (create_ok)
+ 		F_SET(&mtxmgr->reginfo, REGION_CREATE_OK);
+-	if ((ret = __env_region_attach(env,
+-	    &mtxmgr->reginfo, size, size + __mutex_region_max(env))) != 0)
++	if ((ret = __env_region_attach(env, &mtxmgr->reginfo,
++	    size, size + __mutex_region_max(env, mutex_needed))) != 0)
+ 		goto err;
+ 
+ 	/* If we created the region, initialize it. */
+ 	if (F_ISSET(&mtxmgr->reginfo, REGION_CREATE))
+ 		if ((ret = __mutex_region_init(env, mtxmgr)) != 0)
+@@ -350,44 +351,62 @@
+ 
+ 	dbenv = env->dbenv;
+ 
+ 	s = sizeof(DB_MUTEXMGR) + 1024;
+ 
+-	/* We discard one mutex for the OOB slot. */
++	/* 
++	 * We discard one mutex for the OOB slot. Make sure mutex_cnt doesn't
++	 * overflow.
++	 */
+ 	s += __env_alloc_size(
+-	    (dbenv->mutex_cnt + 1) *__mutex_align_size(env));
++	    (dbenv->mutex_cnt + (dbenv->mutex_cnt == UINT32_MAX ? 0 : 1)) *
++	    __mutex_align_size(env));
+ 
+ 	return (s);
+ }
+ 
+ /*
+  * __mutex_region_max --
+  *	 Return the amount of space needed to reach the maximum size.
+  */
+ static size_t
+-__mutex_region_max(env)
++__mutex_region_max(env, mutex_needed)
+ 	ENV *env;
++	u_int32_t mutex_needed;
+ {
+ 	DB_ENV *dbenv;
+-	u_int32_t max;
++	u_int32_t max, mutex_cnt;
+ 
+ 	dbenv = env->dbenv;
++	mutex_cnt = dbenv->mutex_cnt;
+ 
+-	if ((max = dbenv->mutex_max) == 0) {
++	/*
++	 * We want to limit the region size to accommodate at most UINT32_MAX
++	 * mutexes. If mutex_cnt is UINT32_MAX, no more space is allowed.
++	 */
++	if ((max = dbenv->mutex_max) == 0 && mutex_cnt != UINT32_MAX)
+ 		if (F_ISSET(env, ENV_PRIVATE | ENV_THREAD) == ENV_PRIVATE)
+-			max = dbenv->mutex_inc + 1;
+-		else
++			if (dbenv->mutex_inc + 1 < UINT32_MAX - mutex_cnt)
++				max = dbenv->mutex_inc + 1 + mutex_cnt;
++			else
++				max = UINT32_MAX;
++		else {
+ 			max = __lock_region_mutex_max(env) +
+ 			    __txn_region_mutex_max(env) +
+ 			    __log_region_mutex_max(env) +
+ 			    dbenv->mutex_inc + 100;
+-	} else if (max <= dbenv->mutex_cnt)
++			if (max < UINT32_MAX - mutex_needed)
++				max += mutex_needed;
++			else
++				max = UINT32_MAX;
++		}
++
++	if (max <= mutex_cnt)
+ 		return (0);
+ 	else
+-		max -= dbenv->mutex_cnt;
+-
+-	return ( __env_alloc_size(max * __mutex_align_size(env)));
++		return (__env_alloc_size(
++		    (max - mutex_cnt) * __mutex_align_size(env)));
+ }
+ 
+ #ifdef	HAVE_MUTEX_SYSTEM_RESOURCES
+ /*
+  * __mutex_resource_return
+
diff --git a/db-5.3.28-atomic_compare_exchange.patch b/db-5.3.28-atomic_compare_exchange.patch
new file mode 100644
index 0000000..4eab02c
--- /dev/null
+++ b/db-5.3.28-atomic_compare_exchange.patch
@@ -0,0 +1,20 @@
+--- db-5.3.28/src/dbinc/atomic.h.old	2018-05-23 09:20:04.216914922 +0200
++++ db-5.3.28/src/dbinc/atomic.h	2018-05-23 09:20:49.510057897 +0200
+@@ -144,7 +144,7 @@
+ #define	atomic_inc(env, p)	__atomic_inc(p)
+ #define	atomic_dec(env, p)	__atomic_dec(p)
+ #define	atomic_compare_exchange(env, p, o, n)	\
+-	__atomic_compare_exchange((p), (o), (n))
++	__db_atomic_compare_exchange((p), (o), (n))
+ static inline int __atomic_inc(db_atomic_t *p)
+ {
+ 	int	temp;
+@@ -176,7 +176,7 @@
+  * http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html
+  * which configure could be changed to use.
+  */
+-static inline int __atomic_compare_exchange(
++static inline int __db_atomic_compare_exchange(
+ 	db_atomic_t *p, atomic_value_t oldval, atomic_value_t newval)
+ {
+ 	atomic_value_t was;
diff --git a/db-5.3.28-condition_variable.patch b/db-5.3.28-condition_variable.patch
new file mode 100644
index 0000000..ca947e6
--- /dev/null
+++ b/db-5.3.28-condition_variable.patch
@@ -0,0 +1,759 @@
+diff -up db-5.3.28/dist/android/android_config.in.pthreads db-5.3.28/dist/android/android_config.in
+--- db-5.3.28/dist/android/android_config.in.pthreads	2013-09-09 17:35:02.000000000 +0200
++++ db-5.3.28/dist/android/android_config.in	2017-06-13 11:15:15.323215161 +0200
+@@ -123,6 +123,9 @@
+ /* Define to 1 if allocated filesystem blocks are not zeroed. */
+ /* #undef HAVE_FILESYSTEM_NOTZERO */
+ 
++/* Define to 1 if you have the `flock' function. */
++#undef HAVE_FLOCK
++
+ /* Define to 1 if you have the `fopen' function. */
+ #define HAVE_FOPEN 1
+ 
+diff -up db-5.3.28/dist/config.hin.pthreads db-5.3.28/dist/config.hin
+--- db-5.3.28/dist/config.hin.pthreads	2013-09-09 17:35:02.000000000 +0200
++++ db-5.3.28/dist/config.hin	2017-06-13 11:15:15.000000000 +0200
+@@ -92,6 +92,9 @@
+ /* Define to 1 if you have the <dlfcn.h> header file. */
+ #undef HAVE_DLFCN_H
+ 
++/* Define to 1 if you have the `dl_iterate_phdr' function. */
++#undef HAVE_DL_ITERATE_PHDR
++
+ /* Define to 1 to use dtrace for performance monitoring. */
+ #undef HAVE_DTRACE
+ 
+@@ -125,6 +128,9 @@
+ /* Define to 1 if allocated filesystem blocks are not zeroed. */
+ #undef HAVE_FILESYSTEM_NOTZERO
+ 
++/* Define to 1 if you have the `flock' function. */
++#undef HAVE_FLOCK
++
+ /* Define to 1 if you have the `fopen' function. */
+ #undef HAVE_FOPEN
+ 
+@@ -360,6 +366,9 @@
+ /* Define to 1 if you have the `pstat_getdynamic' function. */
+ #undef HAVE_PSTAT_GETDYNAMIC
+ 
++/* Define to 1 if you have dl_iterate_phdr and use pthread-based mutexes. */
++#undef HAVE_PTHREADS_TIMESTAMP
++
+ /* Define to 1 if it is OK to initialize an already initialized
+    pthread_cond_t. */
+ #undef HAVE_PTHREAD_COND_REINIT_OKAY
+@@ -620,6 +629,11 @@
+ /* Define to 1 to mask harmless uninitialized memory read/writes. */
+ #undef UMRW
+ 
++/* Enable large inode numbers on Mac OS X 10.5.  */
++#ifndef _DARWIN_USE_64_BIT_INODE
++# define _DARWIN_USE_64_BIT_INODE 1
++#endif
++
+ /* Number of bits in a file offset, on hosts where this is settable. */
+ #undef _FILE_OFFSET_BITS
+ 
+diff -up db-5.3.28/dist/configure.ac.pthreads db-5.3.28/dist/configure.ac
+--- db-5.3.28/dist/configure.ac.pthreads	2017-06-13 11:15:15.309215434 +0200
++++ db-5.3.28/dist/configure.ac	2017-06-13 11:15:15.323215161 +0200
+@@ -698,7 +698,7 @@ AC_REPLACE_FUNCS(\
+ # Check for system functions we optionally use.
+ AC_CHECK_FUNCS(\
+ 	_fstati64 backtrace backtrace_symbols directio fchmod fclose\
+-	fcntl fdatasync fgetc fgets fopen fwrite getgid\
++	fcntl fdatasync fgetc fgets flock fopen fwrite getgid\
+ 	getrusage getuid hstrerror mprotect pstat_getdynamic\
+ 	pthread_self pthread_yield random sched_yield select setgid setuid\
+ 	sigaction snprintf stat sysconf vsnprintf yield)
+@@ -1042,6 +1042,34 @@ if test "$db_cv_localization" = "yes"; t
+ [Define to 1 if you have localization function to support globalization.])
+ fi
+ 
++# Check for dl_iterate_phdr; do the test explicitly instead of using
++# AC_CHECK_FUNCS because <netdb.h> isn't a standard include file.
++AC_CACHE_CHECK([for dl_iterate_phdr], db_cv_dl_iterate_phdr, [
++AC_TRY_LINK([
++#include <sys/types.h>
++#include <netdb.h>], [
++	dl_iterate_phdr(0, 0);
++], [db_cv_dl_iterate_phdr=yes], [db_cv_dl_iterate_phdr=no])])
++if test "$db_cv_dl_iterate_phdr" = "yes"; then
++	AC_DEFINE(HAVE_DL_ITERATE_PHDR)
++	AH_TEMPLATE(HAVE_DL_ITERATE_PHDR,
++	    [Define to 1 if you have the `dl_iterate_phdr' function.])
++fi
++ 
++# If we are using pthread mutex or condition variables, and dl_iterate_phdr() is 
++# available, then we try to detect when libpthread is updated -- which can
++# render existing environment invalid.   DB_ENV->open() tries to rebuild such
++# environments when they are idle.
++case "$db_cv_mutex" in
++    *pthreads*)
++    if test "$db_cv_dl_iterate_phdr" = "yes" ; then
++	AC_DEFINE(HAVE_PTHREADS_TIMESTAMP)
++	AH_TEMPLATE(HAVE_PTHREADS_TIMESTAMP,
++     [Define to 1 if you have dl_iterate_phdr and use pthread-based mutexes.])
++    fi
++    ;;
++esac
++
+ # We need to add the additional object files into the Makefile with the correct
+ # suffix.  We can't use $LTLIBOBJS itself, because that variable has $U encoded
+ # in it for automake, and that's not what we want.  See SR #7227 for additional
+diff -up db-5.3.28/src/db/db_meta.c.pthreads db-5.3.28/src/db/db_meta.c
+--- db-5.3.28/src/db/db_meta.c.pthreads	2013-09-09 17:35:07.000000000 +0200
++++ db-5.3.28/src/db/db_meta.c	2017-06-13 11:15:15.323215161 +0200
+@@ -1330,8 +1330,9 @@ __db_haslock(env, locker, dbmfp, pgno, m
+ }
+ /*
+  * __db_has_pagelock --
+- *	Determine if this locker holds a particular page lock.
+- *	Returns 0 if lock is held, non-zero otherwise.
++ *	Determine if this locker holds a particular page lock, and return an
++ *	error if it is missing a page lock that it should have.
++ *	Otherwise (TDS with the page locked, or DS or CDS) return 0.
+  *
+  * PUBLIC: #ifdef DIAGNOSTIC
+  * PUBLIC: int __db_has_pagelock __P((ENV *, DB_LOCKER *,
+@@ -1348,6 +1349,9 @@ __db_has_pagelock(env, locker, dbmfp, pa
+ {
+ 	int ret;
+ 
++	if (!FLD_ISSET(env->open_flags, DB_INIT_TXN))
++		return (0);
++
+ 	switch (pagep->type) {
+ 	case P_OVERFLOW:
+ 	case P_INVALID:
+diff -up db-5.3.28/src/dbinc_auto/int_def.in.pthreads db-5.3.28/src/dbinc_auto/int_def.in
+--- db-5.3.28/src/dbinc_auto/int_def.in.pthreads	2017-06-13 11:15:15.317215278 +0200
++++ db-5.3.28/src/dbinc_auto/int_def.in	2017-06-13 11:15:15.324215141 +0200
+@@ -1545,6 +1545,7 @@
+ #if defined(HAVE_REPLICATION_THREADS)
+ #define	__os_freeaddrinfo __os_freeaddrinfo at DB_VERSION_UNIQUE_NAME@
+ #endif
++#define	__os_pthreads_timestamp __os_pthreads_timestamp at DB_VERSION_UNIQUE_NAME@
+ #define	__os_umalloc __os_umalloc at DB_VERSION_UNIQUE_NAME@
+ #define	__os_urealloc __os_urealloc at DB_VERSION_UNIQUE_NAME@
+ #define	__os_ufree __os_ufree at DB_VERSION_UNIQUE_NAME@
+diff -up db-5.3.28/src/dbinc_auto/os_ext.h.pthreads db-5.3.28/src/dbinc_auto/os_ext.h
+--- db-5.3.28/src/dbinc_auto/os_ext.h.pthreads	2013-09-09 17:35:08.000000000 +0200
++++ db-5.3.28/src/dbinc_auto/os_ext.h	2017-06-13 11:15:15.324215141 +0200
+@@ -14,6 +14,7 @@ int __os_getaddrinfo __P((ENV *, const c
+ #if defined(HAVE_REPLICATION_THREADS)
+ void __os_freeaddrinfo __P((ENV *, ADDRINFO *));
+ #endif
++time_t __os_pthreads_timestamp __P((ENV *));
+ int __os_umalloc __P((ENV *, size_t, void *));
+ int __os_urealloc __P((ENV *, size_t, void *));
+ void __os_ufree __P((ENV *, void *));
+@@ -40,7 +41,7 @@ void __os_set_errno __P((int));
+ char *__os_strerror __P((int, char *, size_t));
+ int __os_posix_err __P((int));
+ int __os_fileid __P((ENV *, const char *, int, u_int8_t *));
+-int __os_fdlock __P((ENV *, DB_FH *, off_t, int, int));
++int __os_fdlock __P((ENV *, DB_FH *, off_t, db_lockmode_t, int));
+ int __os_fsync __P((ENV *, DB_FH *));
+ int __os_getenv __P((ENV *, const char *, char **, size_t));
+ int __os_openhandle __P((ENV *, const char *, int, int, DB_FH **));
+diff -up db-5.3.28/src/dbinc/region.h.pthreads db-5.3.28/src/dbinc/region.h
+--- db-5.3.28/src/dbinc/region.h.pthreads	2013-09-09 17:35:08.000000000 +0200
++++ db-5.3.28/src/dbinc/region.h	2017-06-13 11:15:15.324215141 +0200
+@@ -178,6 +178,16 @@ typedef struct __db_reg_env { /* SHARED
+ 	u_int32_t envid;		/* Unique environment ID. */
+ 
+ 	u_int32_t signature;		/* Structure signatures. */
++#if defined(HAVE_PTHREADS_TIMESTAMP) && defined(HAVE_MUTEX_PTHREADS)
++	/*
++	 * Updates to glibc/libpthread can change its pthreads implementation
++	 * and invalidate on-disk environments, even without changing the
++	 * version number.  If using POSIX mutexes and a change in this
++	 * timestamp is detecting when opening an environment with DB_CREATE,
++	 *  __env_attach recreates any existing on-disk environment.
++	 */
++	time_t pthreads_timestamp;
++#endif
+ 
+ 	time_t	  timestamp;		/* Creation time. */
+ 
+diff -up db-5.3.28/src/env/env_open.c.pthreads db-5.3.28/src/env/env_open.c
+--- db-5.3.28/src/env/env_open.c.pthreads	2013-09-09 17:35:08.000000000 +0200
++++ db-5.3.28/src/env/env_open.c	2017-06-13 11:15:15.324215141 +0200
+@@ -1031,11 +1031,11 @@ __env_attach_regions(dbenv, flags, orig_
+ 		goto err;
+ 
+ 	/*
+-	 * __env_attach will return the saved init_flags field, which contains
++	 * __env_attach has returned the saved init_flags field, which contains
+ 	 * the DB_INIT_* flags used when the environment was created.
+ 	 *
+-	 * We may be joining an environment -- reset our flags to match the
+-	 * ones in the environment.
++	 * We may be joining an existing environment -- reset our flags to match
++	 * the ones in the environment.
+ 	 */
+ 	if (FLD_ISSET(init_flags, DB_INITENV_CDB))
+ 		LF_SET(DB_INIT_CDB);
+diff -up db-5.3.28/src/env/env_region.c.pthreads db-5.3.28/src/env/env_region.c
+--- db-5.3.28/src/env/env_region.c.pthreads	2013-09-09 17:35:08.000000000 +0200
++++ db-5.3.28/src/env/env_region.c	2017-06-13 11:16:02.159299222 +0200
+@@ -18,13 +18,49 @@ static int  __env_des_get __P((ENV *, RE
+ static int  __env_faultmem __P((ENV *, void *, size_t, int));
+ static int  __env_sys_attach __P((ENV *, REGINFO *, REGION *));
+ static int  __env_sys_detach __P((ENV *, REGINFO *, int));
++static int  __env_check_recreate __P((ENV *, REGENV *, u_int32_t));
+ static void __env_des_destroy __P((ENV *, REGION *));
+ static void __env_remove_file __P((ENV *));
+ 
++
++/*
++ * If the system supports flock()-like file locking, then the primary region
++ * file __db.001 is exclusively locked during creation, and is read-locked while
++ * the environment is open. Most Unix-like systems have flock(), with the
++ * notable exception of Solaris.
++ * Note: fcntl cannot be used for this locking because of the unfortunate
++ * definition of its interaction with close(2). A process's fcntl locks are
++ * released whenever it closes any file descriptor for that file. So, if an
++ * environment is opened more than once, closing one of the DB_ENV handles would
++ * release the read lock that protects the other handle.
++ */
++#ifdef HAVE_FLOCK
++#define ENV_PRIMARY_LOCK(env, lockmode, async)	\
++	((env)->lockfhp == NULL ? 0 :	\
++	__os_fdlock((env), (env)->lockfhp, -1, lockmode, async))
++#define ENV_PRIMARY_UNLOCK(env)			\
++	((env)->lockfhp == NULL ? 0 :	\
++	__os_fdlock((env), (env)->lockfhp, -1, DB_LOCK_NG, 0))
++#else
++#define ENV_PRIMARY_LOCK(env, lockmode, async)	(0)
++#define ENV_PRIMARY_UNLOCK(env)			(0)
++#endif
++
+ /*
+  * __env_attach
+  *	Join/create the environment
+  *
++ * Safely detecting and managing multiple processes' environment handles:
++ *	BDB uses a shared or exclusive fcntl()-style lock on the first byte
++ *	of the primary region file (__db.001) to detect whether other processes
++ *	have the environment open, and to single-thread attempts to create the
++ *	environment.  If the open includes DB_CREATE, an exclusive lock is
++ *	obtained during the open call.  After the creation is finished, and
++ *	anytime during a non-DB_CREATE env open, the process holds a shared
++ *	lock. 
++ *	- single-thread creation of the environment
++ *	- detect whether any other processes are currently attached to it.
++ *
+  * PUBLIC: int __env_attach __P((ENV *, u_int32_t *, int, int));
+  */
+ int
+@@ -122,7 +158,11 @@ loop:	renv = NULL;
+ 	if ((ret = __os_open(
+ 	    env, infop->name, 0, DB_OSO_REGION, 0, &env->lockfhp)) != 0)
+ 		goto err;
+-
++	/* Wait to get shared access to the primary region. */
++	if ((ret = ENV_PRIMARY_LOCK(env, DB_LOCK_READ, 0)) != 0) {
++		__db_err(env, ret, "__env_attach: existing: shared lock error");
++		goto err;
++	}
+ 	/*
+ 	 * !!!
+ 	 * The region may be in system memory not backed by the filesystem
+@@ -218,11 +258,10 @@ loop:	renv = NULL;
+ 		segid = ref.segid;
+ 	}
+ 
+-#ifndef HAVE_MUTEX_FCNTL
++#if !defined(HAVE_FCNTL) && !defined(HAVE_PTHREADS_TIMESTAMP)
+ 	/*
+-	 * If we're not doing fcntl locking, we can close the file handle.  We
+-	 * no longer need it and the less contact between the buffer cache and
+-	 * the VM, the better.
++	 * Without fcntl-like support, we no longer need the file handle.  Close
++	 * it to limit the interaction between the buffer cache and the VM.
+ 	 */
+ 	(void)__os_closehandle(env, env->lockfhp);
+ 	 env->lockfhp = NULL;
+@@ -233,6 +272,8 @@ loop:	renv = NULL;
+ 	tregion.size = (roff_t)size;
+ 	tregion.max = (roff_t)max;
+ 	tregion.segid = segid;
++	/* Attach to the existing primary region. */
++	/* The leaking db.001 gets open inside of here, in __os_attach(). */
+ 	if ((ret = __env_sys_attach(env, infop, &tregion)) != 0)
+ 		goto err;
+ 
+@@ -245,21 +286,48 @@ user_map_functions:
+ 	infop->primary = infop->addr;
+ 	infop->head = (u_int8_t *)infop->addr + sizeof(REGENV);
+ 	renv = infop->primary;
++    ret = __env_check_recreate(env, renv, signature);
++
++	if (create_ok &&
++	    ret == DB_OLD_VERSION &&
++	    ENV_PRIMARY_LOCK(env, DB_LOCK_WRITE, 1) == 0) {
++		if (FLD_ISSET(dbenv->verbose, DB_VERB_RECOVERY))
++			__db_msg(env, "Recreating idle environment");
++		F_SET(infop, REGION_CREATE_OK);
++
++		/*
++		 * Detach from the environment region; we need to unmap it (and
++		 * close any file handle) so that we don't leak memory or files.
++		 */
++		DB_ASSERT(env, infop->rp == NULL);
++		infop->rp = &tregion;
++		(void)__env_sys_detach(env, infop, 0);
++		goto creation;
++	}
++
++    /* We have an old environment but cannot rebuild it safely. */
++    if (ret == DB_OLD_VERSION) {
++ 		__db_errx(env, DB_STR("1539",
++		    "Build signature doesn't match environment"));
++		ret = DB_VERSION_MISMATCH;
++        goto err;
++    }
+ 
+-	/*
+-	 * Make sure the region matches our build.  Special case a region
+-	 * that's all nul bytes, just treat it like any other corruption.
+-	 */
+ 	if (renv->majver != DB_VERSION_MAJOR ||
+ 	    renv->minver != DB_VERSION_MINOR) {
+-		if (renv->majver != 0 || renv->minver != 0) {
++		/*
++		 * Special case a region that's all nul bytes, just treat it
++		 * like any other corruption.
++		 */
++		if (renv->majver == 0 && renv->minver == 0)
++			ret = EINVAL;
++		else {
+ 			__db_errx(env, DB_STR_A("1538",
+-	    "Program version %d.%d doesn't match environment version %d.%d",
++	"Program version %d.%d doesn't match in-use environment version %d.%d",
+ 			    "%d %d %d %d"), DB_VERSION_MAJOR, DB_VERSION_MINOR,
+ 			    renv->majver, renv->minver);
+ 			ret = DB_VERSION_MISMATCH;
+-		} else
+-			ret = EINVAL;
++		}
+ 		goto err;
+ 	}
+ 	if (renv->signature != signature) {
+@@ -289,6 +357,18 @@ user_map_functions:
+ 	}
+ 	if (renv->magic != DB_REGION_MAGIC)
+ 		goto retry;
++	    /*
++	     * A bad magic number means that the env is new and not yet available:
++	     * wait a while and try again.  If the magic number says recovery is in
++	     * process, remember the env creation time to record that recovery was
++	     * the reason that the open failed.
++	     */
++	    if (renv->magic != DB_REGION_MAGIC) {
++		    __db_msg(env, "attach sees bad region magic 0x%lx",
++			(u_long)renv->magic);
++		    goto retry;
++	    }
++
+ 
+ 	/*
+ 	 * Get a reference to the underlying REGION information for this
+@@ -346,6 +426,12 @@ user_map_functions:
+ 	return (0);
+ 
+ creation:
++	/* Should this wait for the lock (passing 0 instead of 1)? */
++	if ((ret = ENV_PRIMARY_LOCK(env, DB_LOCK_WRITE, 1)) != 0) {
++		__db_err(env, ret, "__env_attach: creation could not lock %s",
++		    env->lockfhp->name);
++		goto err;
++	}
+ 	/* Create the environment region. */
+ 	F_SET(infop, REGION_CREATE);
+ 
+@@ -437,7 +523,14 @@ creation:
+ 	renv->minver = (u_int32_t)minver;
+ 	renv->patchver = (u_int32_t)patchver;
+ 	renv->signature = signature;
+-
++#ifdef HAVE_PTHREADS_TIMESTAMP
++	renv->pthreads_timestamp = __os_pthreads_timestamp(env);
++	{
++		char *s = getenv("TS_ADJUST");
++		if (s != NULL)
++			renv->pthreads_timestamp -= atoi(s);
++	}
++#endif
+ 	(void)time(&renv->timestamp);
+ 	__os_unique_id(env, &renv->envid);
+ 
+@@ -513,16 +606,24 @@ find_err:	__db_errx(env, DB_STR_A("1544"
+ 		}
+ 	}
+ 
+-#ifndef HAVE_MUTEX_FCNTL
+-	/*
+-	 * If we're not doing fcntl locking, we can close the file handle.  We
+-	 * no longer need it and the less contact between the buffer cache and
+-	 * the VM, the better.
+-	 */
++#ifdef HAVE_FCNTL
++	if ((ret = ENV_PRIMARY_UNLOCK(env)) != 0) {
++		__db_err(env, ret, "__env_attach: release exclusive lock");
++		goto err;
++	}
++	if ((ret = ENV_PRIMARY_LOCK(env, DB_LOCK_READ, 0)) != 0) {
++		__db_err(env, ret, "__env_attach: new: acquire shared lock");
++		goto err;
++	}
++#else
++ 	/*
++	 * We no longer need the primary region file's handle and the less
++	 * contact between the buffer cache and the VM, the better.
++ 	 */
+ 	if (env->lockfhp != NULL) {
+ 		 (void)__os_closehandle(env, env->lockfhp);
+ 		 env->lockfhp = NULL;
+-	}
++ 	}
+ #endif
+ 
+ 	/* Everything looks good, we're done. */
+@@ -562,9 +663,9 @@ retry:	/* Close any open file handle. */
+ 	/* If we had a temporary error, wait awhile and try again. */
+ 	if (ret == 0) {
+ 		if (!retry_ok || ++retry_cnt > 3) {
++			ret = EAGAIN;
+ 			__db_errx(env, DB_STR("1546",
+ 			    "unable to join the environment"));
+-			ret = EAGAIN;
+ 		} else {
+ 			__os_yield(env, retry_cnt * 3, 0);
+ 			goto loop;
+@@ -575,6 +676,59 @@ retry:	/* Close any open file handle. */
+ }
+ 
+ /*
++ * __env_check_recreate --
++ *	Determine whether an existing on-disk environment should be recreated
++ *	because it is not compatible with this compiled BDB library.
++ *
++ *	Returns:
++ *	    0 -
++ *		The env was generated by this library. No recreation needed.
++ *	    DB_OLD_VERSION -
++ *		It was created by an earlier BDB version, or by an earlier
++ *		version of libpthreads (on certain Linux systems).  The caller
++ *		will try to recreate it with the currently configured settings.
++ *	    DB_VERSION_MISMATCH -
++ *		It was created by a newer version of BDB.  Do not attempt to
++ *		fix it, something is probably wrong with the application setup.
++ */
++static int
++__env_check_recreate(env, renv, signature)
++	ENV	*env;
++	REGENV	*renv;
++	u_int32_t signature;
++{
++#ifdef HAVE_PTHREADS_TIMESTAMP
++	time_t pthreads_time;
++	char envtime[CTIME_BUFLEN], libtime[CTIME_BUFLEN];
++#endif
++
++	/* First, bail out if the env is too new for this code to handle. */
++	if (renv->majver > DB_VERSION_MAJOR ||
++	    (renv->majver == DB_VERSION_MAJOR &&
++	    renv->minver > DB_VERSION_MINOR))
++	    	return (DB_VERSION_MISMATCH);
++
++#ifdef HAVE_PTHREADS_TIMESTAMP
++	pthreads_time = __os_pthreads_timestamp(env);
++	if (pthreads_time != renv->pthreads_timestamp) {
++		if (FLD_ISSET(env->dbenv->verbose, DB_VERB_RECOVERY))
++			__db_msg(env,
++			"Pthreads timestamp changed: env %.24s current %.24s",
++			    __os_ctime(&renv->pthreads_timestamp, envtime),
++			    __os_ctime(&pthreads_time, libtime));
++		return (DB_OLD_VERSION);
++	}
++#endif
++	if (renv->signature != signature || renv->majver != DB_VERSION_MAJOR ||
++	    renv->minver != DB_VERSION_MINOR) {
++		if (FLD_ISSET(env->dbenv->verbose, DB_VERB_RECOVERY))
++			__db_msg(env, "Signature or version changed");
++		return (DB_OLD_VERSION);
++	}
++    	return (0);
++}
++
++/*
+  * __env_turn_on --
+  *	Turn on the created environment.
+  *
+diff -up db-5.3.28/src/env/env_register.c.pthreads db-5.3.28/src/env/env_register.c
+--- db-5.3.28/src/env/env_register.c.pthreads	2013-09-09 17:35:08.000000000 +0200
++++ db-5.3.28/src/env/env_register.c	2017-06-13 11:15:15.325215121 +0200
+@@ -19,9 +19,9 @@
+ #define	PID_LEN		(25)				/* PID entry length */
+ 
+ #define	REGISTRY_LOCK(env, pos, nowait)					\
+-	__os_fdlock(env, (env)->dbenv->registry, (off_t)(pos), 1, nowait)
++	__os_fdlock(env, (env)->dbenv->registry, (off_t)(pos), DB_LOCK_WRITE, nowait)
+ #define	REGISTRY_UNLOCK(env, pos)					\
+-	__os_fdlock(env, (env)->dbenv->registry, (off_t)(pos), 0, 0)
++	__os_fdlock(env, (env)->dbenv->registry, (off_t)(pos), DB_LOCK_NG, 0)
+ #define	REGISTRY_EXCL_LOCK(env, nowait)					\
+ 	REGISTRY_LOCK(env, 1, nowait)
+ #define	REGISTRY_EXCL_UNLOCK(env)					\
+diff -up db-5.3.28/src/env/env_stat.c.pthreads db-5.3.28/src/env/env_stat.c
+--- db-5.3.28/src/env/env_stat.c.pthreads	2013-09-09 17:35:08.000000000 +0200
++++ db-5.3.28/src/env/env_stat.c	2017-06-13 11:15:15.325215121 +0200
+@@ -177,6 +177,10 @@ __env_print_stats(env, flags)
+ 	STAT_LONG("Txn version", DB_TXNVERSION);
+ 	__db_msg(env,
+ 	    "%.24s\tCreation time", __os_ctime(&renv->timestamp, time_buf));
++#if defined(HAVE_PTHREADS_TIMESTAMP) && defined(HAVE_MUTEX_PTHREADS)
++	__db_msg(env,
++	    "%.24s\tlibpthread timestamp", __os_ctime(&renv->pthreads_timestamp, time_buf));
++#endif
+ 	STAT_HEX("Environment ID", renv->envid);
+ 	__mutex_print_debug_single(env,
+ 	    "Primary region allocation and reference count mutex",
+diff -up db-5.3.28/src/os/os_addrinfo.c.pthreads db-5.3.28/src/os/os_addrinfo.c
+--- db-5.3.28/src/os/os_addrinfo.c.pthreads	2013-09-09 17:35:09.000000000 +0200
++++ db-5.3.28/src/os/os_addrinfo.c	2017-06-13 11:15:15.325215121 +0200
+@@ -10,6 +10,10 @@
+ 
+ #include "db_int.h"
+ 
++#ifdef HAVE_PTHREADS_TIMESTAMP
++#include <link.h>
++#endif
++
+ /*
+  * __os_getaddrinfo and __os_freeaddrinfo wrap the getaddrinfo and freeaddrinfo
+  * calls, as well as the associated platform dependent error handling, mapping
+@@ -177,3 +181,48 @@ __os_freeaddrinfo(env, ai)
+ 	}
+ #endif
+ }
++
++#ifdef HAVE_PTHREADS_TIMESTAMP
++/*
++ *  callback_find_pthreads --
++ *  	dl_iterate_phdr() calls this once for each loaded library.
++ *
++ * Returns:
++ *	0 - the library does not appear to be libpthreads.
++ *	1 - the library *does* seem to be libpthreads. Its modification time is
++ *	    stored into into the last argument's location.
++ */
++static int
++callback_find_pthreads(struct dl_phdr_info *info, size_t size, void *data)
++{
++	struct stat stbuf;
++
++	/* Stop (return non-zero) when libc is found. */
++	if (strstr(info->dlpi_name, "libpthread") != NULL &&
++	    stat(info->dlpi_name, &stbuf) == 0) {
++		*(time_t *)data = stbuf.st_mtime;
++		return (1);
++	}
++	COMPQUIET(size, 0);
++	COMPQUIET(data, NULL);
++	return (0);
++}
++
++/*
++ * __os_pthreads_timestamp --
++ *
++ * PUBLIC: time_t __os_pthreads_timestamp __P((ENV *));
++ */
++time_t
++__os_pthreads_timestamp(env)
++	ENV *env;
++{
++	time_t	timestamp;
++
++	timestamp = 0;
++	dl_iterate_phdr(callback_find_pthreads, &timestamp);
++
++	COMPQUIET(env, 0);
++	return (timestamp);
++}
++#endif
+diff -up db-5.3.28/src/os/os_flock.c.pthreads db-5.3.28/src/os/os_flock.c
+--- db-5.3.28/src/os/os_flock.c.pthreads	2013-09-09 17:35:09.000000000 +0200
++++ db-5.3.28/src/os/os_flock.c	2017-06-13 11:15:15.325215121 +0200
+@@ -10,41 +10,98 @@
+ 
+ #include "db_int.h"
+ 
++#if !defined(HAVE_FCNTL) || !defined(HAVE_FLOCK)
++static int __os_filelocking_notsup __P((ENV *));
++#endif
++
+ /*
+  * __os_fdlock --
+  *	Acquire/release a lock on a byte in a file.
+  *
+- * PUBLIC: int __os_fdlock __P((ENV *, DB_FH *, off_t, int, int));
++ *	The lock modes supported here are:
++ *	DB_LOCK_NG	- release the lock
++ *	DB_LOCK_READ	- get shared access
++ *	DB_LOCK_WRITE	- get exclusive access
++ *
++ *	Use fcntl()-like semantics most of the time (DB_REGISTER support). Fcntl
++ *	supports range locking, but has the additional broken semantics that
++ *	closing any of the file's descriptors releases any locks, even if its
++ *	other file descriptors remain open. Thanks SYSV & POSIX.
++ *	However, if the offset is negative (which is allowed, because POSIX
++ *	off_t a signed integer) then use flock() instead.  It has only whole-
++ *	file locks, but they persist until explicitly unlocked or the process
++ *	exits.
++ * PUBLIC: int __os_fdlock __P((ENV *, DB_FH *, off_t, db_lockmode_t, int));
+  */
+ int
+-__os_fdlock(env, fhp, offset, acquire, nowait)
++__os_fdlock(env, fhp, offset, lockmode, nowait)
+ 	ENV *env;
+ 	DB_FH *fhp;
+-	int acquire, nowait;
+ 	off_t offset;
++	db_lockmode_t lockmode;
++	int nowait;
+ {
+ #ifdef HAVE_FCNTL
+ 	DB_ENV *dbenv;
+ 	struct flock fl;
+ 	int ret, t_ret;
++	static char *mode_string[DB_LOCK_WRITE + 1] = {
++		"unlock",
++		"read",
++		"write"
++	};
++	short mode_fcntl[DB_LOCK_WRITE + 1] = {
++		F_UNLCK,
++		F_RDLCK,
++		F_WRLCK
++	};
++#ifdef HAVE_FLOCK
++	short mode_flock[DB_LOCK_WRITE + 1] = {
++		LOCK_UN,
++		LOCK_SH,
++		LOCK_EX
++	};
++#endif
+ 
+ 	dbenv = env == NULL ? NULL : env->dbenv;
+ 
+ 	DB_ASSERT(env, F_ISSET(fhp, DB_FH_OPENED) && fhp->fd != -1);
++	DB_ASSERT(env, lockmode <= DB_LOCK_WRITE);
+ 
+-	if (dbenv != NULL && FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS_ALL))
+-		__db_msg(env, DB_STR_A("0138",
+-		    "fileops: flock %s %s offset %lu", "%s %s %lu"), fhp->name,
+-		    acquire ? DB_STR_P("acquire"): DB_STR_P("release"),
+-		    (u_long)offset);
+-
+-	fl.l_start = offset;
+-	fl.l_len = 1;
+-	fl.l_type = acquire ? F_WRLCK : F_UNLCK;
+-	fl.l_whence = SEEK_SET;
+-
+-	RETRY_CHK_EINTR_ONLY(
+-	    (fcntl(fhp->fd, nowait ? F_SETLK : F_SETLKW, &fl)), ret);
++	if (dbenv != NULL && FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS_ALL)) {
++		if (offset < 0)
++		      __db_msg(env, DB_STR_A("####",
++			  "fileops: flock %s %s %s", "%s %s %s"),
++			  fhp->name, mode_string[lockmode],
++			  nowait ? "nowait" : "");
++	      else
++		      __db_msg(env, DB_STR_A("0020",
++			  "fileops: fcntls %s %s offset %lu", "%s %s %lu"),
++			  fhp->name, mode_string[lockmode], (u_long)offset);
++	}
++
++	if (offset < 0) {
++#ifdef HAVE_FLOCK
++	        RETRY_CHK_EINTR_ONLY(flock(fhp->fd,
++	            mode_flock[lockmode] | (nowait ? LOCK_NB : 0)), ret);
++#else
++		ret = __os_filelocking_notsup(env);
++#endif
++	} else {
++	        fl.l_start = offset;
++	        fl.l_len = 1;
++	        fl.l_whence = SEEK_SET;
++	        fl.l_type = mode_fcntl[lockmode];
++	           RETRY_CHK_EINTR_ONLY(
++	            fcntl(fhp->fd, nowait ? F_SETLK : F_SETLKW, &fl), ret);
++	}
++
++	if (offset < 0 && dbenv != NULL &&
++	    FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS_ALL))
++		__db_msg(env, DB_STR_A("####",
++		    "fileops: flock %s %s %s returns %s", "%s %s %s"),
++		    fhp->name, mode_string[lockmode],
++		    nowait ? "nowait" : "", db_strerror(ret));
+ 
+ 	if (ret == 0)
+ 		return (0);
+@@ -53,12 +110,29 @@ __os_fdlock(env, fhp, offset, acquire, n
+ 		__db_syserr(env, ret, DB_STR("0139", "fcntl"));
+ 	return (t_ret);
+ #else
++	ret = __os_filelocking_notsup(env);
+ 	COMPQUIET(fhp, NULL);
+-	COMPQUIET(acquire, 0);
++	COMPQUIET(lockmode, 0);
+ 	COMPQUIET(nowait, 0);
+ 	COMPQUIET(offset, 0);
++	return (ret)
++#endif
++}
++
++
++#if !defined(HAVE_FCNTL) || !defined(HAVE_FLOCK)
++/*
++ * __os_filelocking_notsup --
++ *	Generate an error message if fcntl() or flock() is requested on a
++ *	platform that does not support it.
++ *
++ */
++static int
++__os_filelocking_notsup(env)
++ 	ENV *env;
++{
+ 	__db_syserr(env, DB_OPNOTSUP, DB_STR("0140",
+ 	    "advisory file locking unavailable"));
+ 	return (DB_OPNOTSUP);
+-#endif
+ }
++#endif
+diff -up db-5.3.28/src/os/os_map.c.pthreads db-5.3.28/src/os/os_map.c
+--- db-5.3.28/src/os/os_map.c.pthreads	2013-09-09 17:35:09.000000000 +0200
++++ db-5.3.28/src/os/os_map.c	2017-06-13 11:15:15.325215121 +0200
+@@ -32,7 +32,7 @@ static int __no_system_mem __P((ENV *));
+ 
+ /*
+  * __os_attach --
+- *	Create/join a shared memory region.
++ *	Create/join a 'shared' region of Berkeley DB memory.
+  *
+  * PUBLIC: int __os_attach __P((ENV *, REGINFO *, REGION *));
+  */
+@@ -50,6 +50,7 @@ __os_attach(env, infop, rp)
+ 	 * so there must be a valid handle.
+ 	 */
+ 	DB_ASSERT(env, env != NULL && env->dbenv != NULL);
++	DB_ASSERT(env, infop->fhp == NULL);
+ 	dbenv = env->dbenv;
+ 
+ 	if (DB_GLOBAL(j_region_map) != NULL) {
diff --git a/db-5.3.28-lemon_hash.patch b/db-5.3.28-lemon_hash.patch
new file mode 100644
index 0000000..1556d5d
--- /dev/null
+++ b/db-5.3.28-lemon_hash.patch
@@ -0,0 +1,20 @@
+--- db-5.3.28/lang/sql/sqlite/tool/lemon.c.lemon_hash	2013-09-09 17:35:07.000000000 +0200
++++ db-5.3.28/lang/sql/sqlite/tool/lemon.c	2017-02-22 13:12:08.564106051 +0100
+@@ -3428,7 +3428,7 @@
+   int maxdtlength;          /* Maximum length of any ".datatype" field. */
+   char *stddt;              /* Standardized name for a datatype */
+   int i,j;                  /* Loop counters */
+-  int hash;                 /* For hashing the name of a type */
++  unsigned hash;            /* For hashing the name of a type */
+   const char *name;         /* Name of the parser */
+ 
+   /* Allocate and initialize types[] and allocate stddt[] */
+@@ -3491,7 +3491,7 @@
+         break;
+       }
+       hash++;
+-      if( hash>=arraysize ) hash = 0;
++      if( hash>=(unsigned)arraysize ) hash = 0;
+     }
+     if( types[hash]==0 ){
+       sp->dtnum = hash + 1;
diff --git a/db-5.3.28-mmap-high-cpu-usage.patch b/db-5.3.28-mmap-high-cpu-usage.patch
new file mode 100644
index 0000000..b11ce08
--- /dev/null
+++ b/db-5.3.28-mmap-high-cpu-usage.patch
@@ -0,0 +1,19 @@
+Author: Filip Januš <fjanus at redhat.com>
+Date: 6 Sep 2021
+Related: https://bugzilla.redhat.com/show_bug.cgi?id=1992402
+Patch was created based on the discussion in the previous link
+diff -ur db-5.3.28/src/os/os_map.c db_patch/src/os/os_map.c
+--- db-5.3.28/src/os/os_map.c	2013-09-09 17:35:09.000000000 +0200
++++ db_patch/src/os/os_map.c	2021-09-09 07:33:12.027328265 +0200
+@@ -213,7 +213,10 @@
+ 	if (rp->max < rp->size)
+ 		rp->max = rp->size;
+ 	if (ret == 0 && F_ISSET(infop, REGION_CREATE)) {
+-		if (F_ISSET(dbenv, DB_ENV_REGION_INIT))
++
++		rp->size = rp->max;
++
++        if (F_ISSET(dbenv, DB_ENV_REGION_INIT))
+ 			ret = __db_file_write(env, infop->fhp,
+ 			    rp->size / MEGABYTE, rp->size % MEGABYTE, 0x00);
+ 		else
diff --git a/db-5.3.28_cve-2019-2708.patch b/db-5.3.28_cve-2019-2708.patch
new file mode 100644
index 0000000..341cb4b
--- /dev/null
+++ b/db-5.3.28_cve-2019-2708.patch
@@ -0,0 +1,694 @@
+--- db-18.1.32/src/btree/bt_cursor.c	2019-02-20 03:21:20.000000000 +0530
++++ db-18.1.40/src/btree/bt_cursor.c	2020-05-29 23:28:22.000000000 +0530
+@@ -282,6 +282,8 @@
+ 	 *
+ 	 * Recno uses the btree bt_ovflsize value -- it's close enough.
+ 	 */
++	if (t->bt_minkey == 0)
++		return (DB_RECOVER);
+ 	cp->ovflsize = B_MINKEY_TO_OVFLSIZE(
+ 	    dbp,  F_ISSET(dbc, DBC_OPD) ? 2 : t->bt_minkey, dbp->pgsize);
+ 
+--- db-18.1.32/src/btree/bt_verify.c	2019-02-20 03:21:20.000000000 +0530
++++ db-18.1.40/src/btree/bt_verify.c	2020-05-29 23:28:22.000000000 +0530
+@@ -700,7 +700,11 @@
+ 			isbad = 1;
+ 			goto err;
+ 		default:
++			if (ret == 0) {
++				isbad = 1;
++				ret = DB_VERIFY_FATAL;
++				goto err;
++			}
+-			DB_ASSERT(env, ret != 0);
+ 			break;
+ 		}
+ 
+@@ -1074,7 +1078,7 @@
+ 	DBT dbta, dbtb, dup_1, dup_2, *p1, *p2, *tmp;
+ 	ENV *env;
+ 	PAGE *child;
++	db_pgno_t cpgno, grandparent;
+-	db_pgno_t cpgno;
+ 	VRFY_PAGEINFO *pip;
+ 	db_indx_t i, *inp;
+ 	int adj, cmp, freedup_1, freedup_2, isbad, ret, t_ret;
+@@ -1106,7 +1110,8 @@
+ 
+ 	buf1 = buf2 = NULL;
+ 
++	if (LF_ISSET(DB_NOORDERCHK))
++		return (EINVAL);
+-	DB_ASSERT(env, !LF_ISSET(DB_NOORDERCHK));
+ 
+ 	dupfunc = (dbp->dup_compare == NULL) ? __bam_defcmp : dbp->dup_compare;
+ 	if (TYPE(h) == P_LDUP)
+@@ -1115,6 +1120,7 @@
+ 		func = __bam_defcmp;
+ 		if (dbp->bt_internal != NULL) {
+ 			bt = (BTREE *)dbp->bt_internal;
++			grandparent = bt->bt_root;
+ 			if (TYPE(h) == P_IBTREE && (bt->bt_compare != NULL ||
+ 			    dupfunc != __bam_defcmp)) {
+ 				/*
+@@ -974,8 +980,24 @@
+ 				 */
+ 				mpf = dbp->mpf;
+ 				child = h;
++				cpgno = pgno;
+ 				while (TYPE(child) == P_IBTREE) {
++					if (NUM_ENT(child) == 0) {
++						EPRINT((env, DB_STR_A("1088",
++		    "Page %lu: internal page is empty and should not be",
++					    "%lu"), (u_long)cpgno));
++						ret = DB_VERIFY_BAD;
++						goto err;
++					}
+ 					bi = GET_BINTERNAL(dbp, child, 0);
++					if (grandparent == bi->pgno) {
++						EPRINT((env, DB_STR_A("5552",
++					      "Page %lu: found twice in the btree",
++				          "%lu"), (u_long)grandparent));
++						ret = DB_VERIFY_FATAL;
++						goto err;
++					} else
++						grandparent = cpgno;
+ 					cpgno = bi->pgno;
+ 					if (child != h &&
+ 					    (ret = __memp_fput(mpf,
+@@ -1402,7 +1416,10 @@
+ 					 */
+ 					if (dup_1.data == NULL ||
+ 					    dup_2.data == NULL) {
++						if (ovflok) {
++							isbad = 1;
++							goto err;
++						}
+-						DB_ASSERT(env, !ovflok);
+ 						if (pip != NULL)
+ 							F_SET(pip,
+ 							    VRFY_INCOMPLETE);
+@@ -1747,9 +1764,10 @@
+ 			    (ret = __db_vrfy_ovfl_structure(dbp, vdp,
+ 			    child->pgno, child->tlen,
+ 			    flags | DB_ST_OVFL_LEAF)) != 0) {
++				if (ret == DB_VERIFY_BAD) {
+-				if (ret == DB_VERIFY_BAD)
+ 					isbad = 1;
++					break;
++				} else
+-				else
+ 					goto done;
+ 			}
+ 
+@@ -1823,9 +1841,10 @@
+ 						    stflags | DB_ST_TOPLEVEL,
+ 						    NULL, NULL, NULL)) != 0) {
+ 							if (ret ==
++							    DB_VERIFY_BAD) {
+-							    DB_VERIFY_BAD)
+ 								isbad = 1;
++								break;
++							} else
+-							else
+ 								goto err;
+ 						}
+ 					}
+@@ -1969,7 +1988,10 @@
+ 			 */
+ 
+ 			/* Otherwise, __db_vrfy_childput would be broken. */
++			if (child->refcnt < 1) {
++				isbad = 1;
++				goto err;
++			}
+-			DB_ASSERT(env, child->refcnt >= 1);
+ 
+ 			/*
+ 			 * An overflow referenced more than twice here
+@@ -1986,9 +2008,10 @@
+ 					if ((ret = __db_vrfy_ovfl_structure(dbp,
+ 					    vdp, child->pgno, child->tlen,
+ 					    flags)) != 0) {
++						if (ret == DB_VERIFY_BAD) {
+-						if (ret == DB_VERIFY_BAD)
+ 							isbad = 1;
++							break;
++						} else
+-						else
+ 							goto done;
+ 					}
+ 		}
+@@ -2026,9 +2049,10 @@
+ 		if ((ret = __bam_vrfy_subtree(dbp, vdp, li->pgno,
+ 		    i == 0 ? NULL : li, ri, flags, &child_level,
+ 		    &child_nrecs, NULL)) != 0) {
++			if (ret == DB_VERIFY_BAD) {
+-			if (ret == DB_VERIFY_BAD)
+ 				isbad = 1;
++				break;
++			} else
+-			else
+ 				goto done;
+ 		}
+ 
+@@ -2929,7 +2953,11 @@
+ 	db_pgno_t current, p;
+ 	int err_ret, ret;
+ 
++	if (pgset == NULL) {
++		EPRINT((dbp->env, DB_STR("5542",
++			"Error, database contains no visible pages.")));
++		return (DB_RUNRECOVERY);
++	}
+-	DB_ASSERT(dbp->env, pgset != NULL);
+ 
+ 	mpf = dbp->mpf;
+ 	h = NULL;
+--- db-18.1.32/src/db/db_conv.c	2019-02-20 03:21:20.000000000 +0530
++++ db-18.1.40/src/db/db_conv.c	2020-05-29 23:28:22.000000000 +0530
+@@ -493,8 +493,11 @@
+ 	db_indx_t i, *inp, len, tmp;
+ 	u_int8_t *end, *p, *pgend;
+ 
+-	if (pagesize == 0)
+-		return (0);
++	/* This function is also used to byteswap logs, so
++	 * the pagesize might not be an actual page size.
++	 */
++	if (!(pagesize >= 24 && pagesize <= DB_MAX_PGSIZE))
++		return (EINVAL);
+ 
+ 	if (pgin) {
+ 		M_32_SWAP(h->lsn.file);
+@@ -513,26 +516,41 @@
+ 	pgend = (u_int8_t *)h + pagesize;
+ 
+ 	inp = P_INP(dbp, h);
+-	if ((u_int8_t *)inp >= pgend)
+-		goto out;
++	if ((u_int8_t *)inp > pgend)
++		return (__db_pgfmt(env, pg));
+ 
+ 	switch (TYPE(h)) {
+ 	case P_HASH_UNSORTED:
+ 	case P_HASH:
+ 		for (i = 0; i < NUM_ENT(h); i++) {
++			if ((u_int8_t*)(inp + i) >= pgend)
++				return (__db_pgfmt(env, pg));
++			if (inp[i] == 0)
++				continue;
+ 			if (pgin)
+ 				M_16_SWAP(inp[i]);
++			if (inp[i] >= pagesize)
++				return (__db_pgfmt(env, pg));
+ 
+-			if (P_ENTRY(dbp, h, i) >= pgend)
+-				continue;
++	   		if (P_ENTRY(dbp, h, i) >= pgend)
++				return (__db_pgfmt(env, pg));
+ 
+ 			switch (HPAGE_TYPE(dbp, h, i)) {
+ 			case H_KEYDATA:
+ 				break;
+ 			case H_DUPLICATE:
++				if (LEN_HITEM(dbp, h, pagesize, i) < 
++				    HKEYDATA_SIZE(0))
++					return (__db_pgfmt(env, pg));
++
+ 				len = LEN_HKEYDATA(dbp, h, pagesize, i);
+ 				p = HKEYDATA_DATA(P_ENTRY(dbp, h, i));
+-				for (end = p + len; p < end;) {
++
++				end = p + len;
++				if (end > pgend)
++					return (__db_pgfmt(env, pg));
++
++				while (p < end) {
+ 					if (pgin) {
+ 						P_16_SWAP(p);
+ 						memcpy(&tmp,
+@@ -544,14 +562,20 @@
+ 						SWAP16(p);
+ 					}
+ 					p += tmp;
++					if (p >= end)
++						return (__db_pgfmt(env, pg));
+ 					SWAP16(p);
+ 				}
+ 				break;
+ 			case H_OFFDUP:
++				if ((inp[i] + HOFFDUP_SIZE) > pagesize)
++					return (__db_pgfmt(env, pg));
+ 				p = HOFFPAGE_PGNO(P_ENTRY(dbp, h, i));
+ 				SWAP32(p);			/* pgno */
+ 				break;
+ 			case H_OFFPAGE:
++				if ((inp[i] + HOFFPAGE_SIZE) > pagesize)
++					return (__db_pgfmt(env, pg));
+ 				p = HOFFPAGE_PGNO(P_ENTRY(dbp, h, i));
+ 				SWAP32(p);			/* pgno */
+ 				SWAP32(p);			/* tlen */
+@@ -559,7 +583,6 @@
+ 			default:
+ 				return (__db_pgfmt(env, pg));
+ 			}
+-
+ 		}
+ 
+ 		/*
+@@ -576,8 +599,12 @@
+ 	case P_LDUP:
+ 	case P_LRECNO:
+ 		for (i = 0; i < NUM_ENT(h); i++) {
++			if ((u_int8_t *)(inp + i) >= pgend)
++				return (__db_pgfmt(env, pg));
+ 			if (pgin)
+ 				M_16_SWAP(inp[i]);
++			if (inp[i] >= pagesize)
++				return (__db_pgfmt(env, pg));
+ 
+ 			/*
+ 			 * In the case of on-page duplicates, key information
+@@ -597,7 +624,7 @@
+ 
+ 			bk = GET_BKEYDATA(dbp, h, i);
+ 			if ((u_int8_t *)bk >= pgend)
+-				continue;
++				return (__db_pgfmt(env, pg));
+ 			switch (B_TYPE(bk->type)) {
+ 			case B_KEYDATA:
+ 				M_16_SWAP(bk->len);
+@@ -605,6 +632,8 @@
+ 			case B_DUPLICATE:
+ 			case B_OVERFLOW:
+ 				bo = (BOVERFLOW *)bk;
++				if (((u_int8_t *)bo + BOVERFLOW_SIZE) > pgend)
++					return (__db_pgfmt(env, pg));
+ 				M_32_SWAP(bo->pgno);
+ 				M_32_SWAP(bo->tlen);
+ 				break;
+@@ -618,12 +647,17 @@
+ 		break;
+ 	case P_IBTREE:
+ 		for (i = 0; i < NUM_ENT(h); i++) {
++			if ((u_int8_t *)(inp + i) > pgend)
++				return (__db_pgfmt(env, pg));
+ 			if (pgin)
+ 				M_16_SWAP(inp[i]);
++			if ((u_int16_t)(inp[i] + 
++			    BINTERNAL_SIZE(0) - 1) > pagesize)
++				break;
+ 
+ 			bi = GET_BINTERNAL(dbp, h, i);
+-			if ((u_int8_t *)bi >= pgend)
+-				continue;
++			if (((u_int8_t *)bi + BINTERNAL_SIZE(0)) > pgend)
++				return (__db_pgfmt(env, pg));
+ 
+ 			M_16_SWAP(bi->len);
+ 			M_32_SWAP(bi->pgno);
+@@ -634,6 +668,10 @@
+ 				break;
+ 			case B_DUPLICATE:
+ 			case B_OVERFLOW:
++				if ((u_int16_t)(inp[i] + 
++				    BINTERNAL_SIZE(BOVERFLOW_SIZE) - 1) >
++				    pagesize)
++					goto out;
+ 				bo = (BOVERFLOW *)bi->data;
+ 				M_32_SWAP(bo->pgno);
+ 				M_32_SWAP(bo->tlen);
+@@ -648,12 +686,16 @@
+ 		break;
+ 	case P_IRECNO:
+ 		for (i = 0; i < NUM_ENT(h); i++) {
++			if ((u_int8_t *)(inp + i) >= pgend)
++				return (__db_pgfmt(env, pg));
+ 			if (pgin)
+ 				M_16_SWAP(inp[i]);
++			if (inp[i] >= pagesize)
++				return (__db_pgfmt(env, pg));
+ 
+ 			ri = GET_RINTERNAL(dbp, h, i);
+-			if ((u_int8_t *)ri >= pgend)
+-				continue;
++			if ((((u_int8_t *)ri) + RINTERNAL_SIZE) > pgend)
++				return (__db_pgfmt(env, pg));
+ 
+ 			M_32_SWAP(ri->pgno);
+ 			M_32_SWAP(ri->nrecs);
+--- db-18.1.32/src/db/db_vrfy.c	2019-02-20 03:21:20.000000000 +0530
++++ db-18.1.40/src/db/db_vrfy.c	2020-05-29 23:28:22.000000000 +0530
+@@ -381,8 +381,10 @@
+ 		    vdp, name, 0, lp, rp, flags)) != 0) {
+ 			if (t_ret == DB_VERIFY_BAD)
+ 				isbad = 1;
++			else {
++			    ret = t_ret;
++			    goto err;
++			}
+-			else
+-				goto err;
+ 		}
+ 
+ 	/*
+@@ -771,9 +773,10 @@
+ 		 */
+ 		if ((t_ret = __memp_fget(mpf, &i,
+ 		    vdp->thread_info, NULL, 0, &h)) != 0) {
++			if ((dbp->type == DB_HASH ||
+-			if (dbp->type == DB_HASH ||
+ 			    (dbp->type == DB_QUEUE &&
++			    F_ISSET(dbp, DB_AM_INMEM))) &&
++			    t_ret != DB_RUNRECOVERY) {
+-			    F_ISSET(dbp, DB_AM_INMEM))) {
+ 				if ((t_ret =
+ 				    __db_vrfy_getpageinfo(vdp, i, &pip)) != 0)
+ 					goto err1;
+@@ -945,6 +948,8 @@
+ 			return (ret == 0 ? t_ret : ret);
+ 	}
+ 
++	if (ret == DB_PAGE_NOTFOUND && isbad == 1)
++		ret = 0;
+ 	return ((isbad == 1 && ret == 0) ? DB_VERIFY_BAD : ret);
+ }
+ 
+@@ -1581,7 +1586,7 @@
+ 	if (pgno == PGNO_BASE_MD &&
+ 	    dbtype != DB_QUEUE && meta->last_pgno != vdp->last_pgno) {
+ #ifdef HAVE_FTRUNCATE
++		ret = DB_VERIFY_FATAL;
+-		isbad = 1;
+ 		EPRINT((env, DB_STR_A("0552",
+ 		    "Page %lu: last_pgno is not correct: %lu != %lu",
+ 		    "%lu %lu %lu"), (u_long)pgno,
+@@ -1622,7 +1627,11 @@
+ 
+ 	env = dbp->env;
+ 	pgset = vdp->pgset;
++	if (pgset == NULL) {
++		EPRINT((env, DB_STR("5543",
++			"Error, database contains no visible pages.")));
++		return (DB_RUNRECOVERY);
++	}
+-	DB_ASSERT(env, pgset != NULL);
+ 
+ 	if ((ret = __db_vrfy_getpageinfo(vdp, meta, &pip)) != 0)
+ 		return (ret);
+@@ -2014,7 +2023,8 @@
+ 	int keyflag, ret, t_ret;
+ 
+ 	env = dbp->env;
++	if (!LF_ISSET(DB_SALVAGE))
++		return (EINVAL);
+-	DB_ASSERT(env, LF_ISSET(DB_SALVAGE));
+ 
+ 	/*
+ 	 * !!!
+@@ -2126,10 +2136,8 @@
+ 	int (*callback) __P((void *, const void *));
+ 	u_int32_t flags;
+ {
+-	ENV *env;
+-
+-	env = dbp->env;
+-	DB_ASSERT(env, LF_ISSET(DB_SALVAGE));
++	if (!LF_ISSET(DB_SALVAGE))
++		return (EINVAL);
+ 
+ 	/* If we got this page in the subdb pass, we can safely skip it. */
+ 	if (__db_salvage_isdone(vdp, pgno))
+@@ -2242,8 +2253,8 @@
+ 				ret = t_ret;
+ 			break;
+ 		case SALVAGE_OVERFLOW:
++			EPRINT((env, DB_STR("5544", "Invalid page type to salvage.")));
++			return (EINVAL);
+-			DB_ASSERT(env, 0);	/* Shouldn't ever happen. */
+-			break;
+ 		case SALVAGE_HASH:
+ 			if ((t_ret = __ham_salvage(dbp, vdp,
+ 			    pgno, h, handle, callback, flags)) != 0 && ret == 0)
+@@ -2256,8 +2267,8 @@
+ 			 * Shouldn't happen, but if it does, just do what the
+ 			 * nice man says.
+ 			 */
++			EPRINT((env, DB_STR("5545", "Invalid page type to salvage.")));
++			return (EINVAL);
+-			DB_ASSERT(env, 0);
+-			break;
+ 		}
+ 		if ((t_ret = __memp_fput(mpf,
+ 		    vdp->thread_info, h, dbp->priority)) != 0 && ret == 0)
+@@ -2303,8 +2314,8 @@
+ 					ret = t_ret;
+ 			break;
+ 		default:
++			EPRINT((env, DB_STR("5546", "Invalid page type to salvage.")));
++			return (EINVAL);
+-			DB_ASSERT(env, 0);	/* Shouldn't ever happen. */
+-			break;
+ 		}
+ 		if ((t_ret = __memp_fput(mpf,
+ 		    vdp->thread_info, h, dbp->priority)) != 0 && ret == 0)
+@@ -2361,7 +2372,10 @@
+ 
+ 	env = dbp->env;
+ 
++	if (himarkp == NULL) {
++		__db_msg(env, "Page %lu index has no end.", (u_long)pgno);
++		return (DB_VERIFY_FATAL);
++	}
+-	DB_ASSERT(env, himarkp != NULL);
+ 	inp = P_INP(dbp, h);
+ 
+ 	/*
+@@ -2783,7 +2797,11 @@
+ 					goto err;
+ 				ovfl_bufsz = bkkey->len + 1;
+ 			}
++			if (subdbname == NULL) {
++				EPRINT((env, DB_STR("5547", "Subdatabase cannot be null.")));
++				ret = EINVAL;
++				goto err;
++			}
+-			DB_ASSERT(env, subdbname != NULL);
+ 			memcpy(subdbname, bkkey->data, bkkey->len);
+ 			subdbname[bkkey->len] = '\0';
+ 		}
+--- db-18.1.32/src/db/db_vrfyutil.c	2019-02-20 03:21:20.000000000 +0530
++++ db-18.1.40/src/db/db_vrfyutil.c	2020-05-29 23:28:22.000000000 +0530
+@@ -214,7 +214,8 @@
+ 	if ((ret = __db_get(pgdbp,
+ 	    vdp->thread_info, vdp->txn, &key, &data, 0)) == 0) {
+ 		/* Found it. */
++		if (data.size != sizeof(VRFY_PAGEINFO))
++			return (DB_VERIFY_FATAL);
+-		DB_ASSERT(env, data.size == sizeof(VRFY_PAGEINFO));
+ 		pip = data.data;
+ 		LIST_INSERT_HEAD(&vdp->activepips, pip, links);
+ 		goto found;
+@@ -342,7 +343,8 @@
+ 	F_SET(&data, DB_DBT_USERMEM);
+ 
+ 	if ((ret = __db_get(dbp, ip, txn, &key, &data, 0)) == 0) {
++		if (data.size != sizeof(int))
++			return (EINVAL);
+-		DB_ASSERT(dbp->env, data.size == sizeof(int));
+ 	} else if (ret == DB_NOTFOUND)
+ 		val = 0;
+ 	else
+@@ -382,7 +384,8 @@
+ 	F_SET(&data, DB_DBT_USERMEM);
+ 
+ 	if ((ret = __db_get(dbp, ip, txn, &key, &data, 0)) == 0) {
++		if (data.size != sizeof(int))
++			return (DB_VERIFY_FATAL);
+-		DB_ASSERT(dbp->env, data.size == sizeof(int));
+ 	} else if (ret != DB_NOTFOUND)
+ 		return (ret);
+ 
+@@ -419,7 +422,8 @@
+ 	if ((ret = __dbc_get(dbc, &key, &data, DB_NEXT)) != 0)
+ 		return (ret);
+ 
++	if (key.size != sizeof(db_pgno_t))
++		return (DB_VERIFY_FATAL);
+-	DB_ASSERT(dbc->env, key.size == sizeof(db_pgno_t));
+ 	*pgnop = pgno;
+ 
+ 	return (0);
+@@ -566,7 +570,8 @@
+ 	if ((ret = __dbc_get(dbc, &key, &data, DB_SET)) != 0)
+ 		return (ret);
+ 
++	if (data.size != sizeof(VRFY_CHILDINFO))
++		return (DB_VERIFY_FATAL);
+-	DB_ASSERT(dbc->env, data.size == sizeof(VRFY_CHILDINFO));
+ 	*cipp = (VRFY_CHILDINFO *)data.data;
+ 
+ 	return (0);
+@@ -594,7 +599,8 @@
+ 	if ((ret = __dbc_get(dbc, &key, &data, DB_NEXT_DUP)) != 0)
+ 		return (ret);
+ 
++	if (data.size != sizeof(VRFY_CHILDINFO))
++		return (DB_VERIFY_FATAL);
+-	DB_ASSERT(dbc->env, data.size == sizeof(VRFY_CHILDINFO));
+ 	*cipp = (VRFY_CHILDINFO *)data.data;
+ 
+ 	return (0);
+@@ -721,7 +727,8 @@
+ 		return (ret);
+ 
+ 	while ((ret = __dbc_get(*dbcp, &key, &data, DB_NEXT)) == 0) {
++		if (data.size != sizeof(u_int32_t))
++			return (DB_VERIFY_FATAL);
+-		DB_ASSERT(dbp->env, data.size == sizeof(u_int32_t));
+ 		memcpy(&pgtype, data.data, sizeof(pgtype));
+ 
+ 		if (skip_overflow && pgtype == SALVAGE_OVERFLOW)
+@@ -730,8 +737,9 @@
+ 		if ((ret = __dbc_del(*dbcp, 0)) != 0)
+ 			return (ret);
+ 		if (pgtype != SALVAGE_IGNORE) {
++			if (key.size != sizeof(db_pgno_t)
++				|| data.size != sizeof(u_int32_t))
++				return (DB_VERIFY_FATAL);
+-			DB_ASSERT(dbp->env, key.size == sizeof(db_pgno_t));
+-			DB_ASSERT(dbp->env, data.size == sizeof(u_int32_t));
+ 
+ 			*pgnop = *(db_pgno_t *)key.data;
+ 			*pgtypep = *(u_int32_t *)data.data;
+--- db-18.1.32/src/db/partition.c	2019-02-20 03:21:20.000000000 +0530
++++ db-18.1.40/src/db/partition.c	2020-05-29 23:28:22.000000000 +0530
+@@ -461,9 +461,19 @@
+ 		} else
+ 			part->nparts = meta->nparts;
+ 	} else if (meta->nparts != 0 && part->nparts != meta->nparts) {
++		ret = EINVAL;
+ 		__db_errx(env, DB_STR("0656",
+ 		    "Number of partitions does not match."));
+-		ret = EINVAL;
++		goto err;
++	}
++	/*
++	 * There is no limit on the number of partitions, but I cannot imagine a real
++	 * database having more than 10000.
++	 */
++	if (meta->nparts > 10000) {
++		ret = EINVAL;
++		__db_errx(env, DB_STR_A("5553",
++			"Too many partitions %lu", "%lu"), (u_long)(meta->nparts));
+ 		goto err;
+ 	}
+ 
+@@ -2106,10 +2116,13 @@
+ 			memcpy(rp->data, key->data, key->size);
+ 			B_TSET(rp->type, B_KEYDATA);
+ 		}
++vrfy:   if ((t_ret = __db_verify(*pdbp, ip, (*pdbp)->fname,
++	      NULL, handle, callback,
++	      lp, rp, flags | DB_VERIFY_PARTITION)) != 0 && ret == 0) {
++	        ret = t_ret;
++            if (ret == ENOENT)
++                break;
++	    }
+-vrfy:		if ((t_ret = __db_verify(*pdbp, ip, (*pdbp)->fname,
+-		    NULL, handle, callback,
+-		    lp, rp, flags | DB_VERIFY_PARTITION)) != 0 && ret == 0)
+-			ret = t_ret;
+ 	}
+ 
+ err:	if (lp != NULL)
+--- db-18.1.32/src/hash/hash_page.c	2019-02-20 03:21:20.000000000 +0530
++++ db-18.1.40/src/hash/hash_page.c	2020-05-29 23:28:22.000000000 +0530
+@@ -869,7 +869,11 @@
+ 	/* Validate that next, prev pointers are OK */
+ 	n = NUM_ENT(p);
+ 	dbp = dbc->dbp;
++	if (n % 2 != 0) {
++		__db_errx(dbp->env, DB_STR_A("5549",
++		  "Odd number of entries on page: %lu", "%lu"), (u_long)(p->pgno));
++		return (DB_VERIFY_FATAL);
++	}
+-	DB_ASSERT(dbp->env, n%2 == 0 );
+ 
+ 	env = dbp->env;
+ 	t = dbp->h_internal;
+@@ -940,7 +944,12 @@
+ 			if ((ret = __db_prpage(dbp, p, DB_PR_PAGE)) != 0)
+ 				return (ret);
+ #endif
++			if (res >= 0) {
++				__db_errx(env, DB_STR_A("5550",
++					"Odd number of entries on page: %lu", "%lu"),
++					(u_long)p->pgno);
++				return (DB_VERIFY_FATAL);
++			}
+-			DB_ASSERT(dbp->env, res < 0);
+ 		}
+ 
+ 		prev = curr;
+--- db-18.1.32/src/hash/hash_verify.c	2019-02-20 03:21:20.000000000 +0530
++++ db-18.1.40/src/hash/hash_verify.c	2020-05-29 23:28:22.000000000 +0530
+@@ -615,7 +615,7 @@
+ 				isbad = 1;
+ 			else
+ 				goto err;
++		}
+-		    }
+ 
+ 	/*
+ 	 * There may be unused hash pages corresponding to buckets
+@@ -746,7 +746,7 @@
+ 		    "Page %lu: impossible first page in bucket %lu", "%lu %lu"),
+ 		    (u_long)pgno, (u_long)bucket));
+ 		/* Unsafe to continue. */
++		ret = DB_VERIFY_FATAL;
+-		isbad = 1;
+ 		goto err;
+ 	}
+ 
+@@ -776,7 +776,7 @@
+ 			EPRINT((env, DB_STR_A("1116",
+ 			    "Page %lu: hash page referenced twice", "%lu"),
+ 			    (u_long)pgno));
++			ret = DB_VERIFY_FATAL;
+-			isbad = 1;
+ 			/* Unsafe to continue. */
+ 			goto err;
+ 		} else if ((ret = __db_vrfy_pgset_inc(vdp->pgset,
+@@ -1307,7 +1307,11 @@
+ 	COMPQUIET(flags, 0);
+ 	ip = vdp->thread_info;
+ 
++	if (pgset == NULL) {
++		EPRINT((dbp->env, DB_STR("5548",
++			"Error, database contains no visible pages.")));
++		return (DB_VERIFY_FATAL);
++	}
+-	DB_ASSERT(dbp->env, pgset != NULL);
+ 
+ 	mpf = dbp->mpf;
+ 	totpgs = 0;
+--- db-18.1.32/src/qam/qam_verify.c	2019-02-20 03:21:20.000000000 +0530
++++ db-18.1.40/src/qam/qam_verify.c	2020-05-29 23:28:22.000000000 +0530
+@@ -465,7 +465,14 @@
+ 	/* Verify/salvage each page. */
+ 	if ((ret = __db_cursor(dbp, vdp->thread_info, NULL, &dbc, 0)) != 0)
+ 		return (ret);
+-begin:	for (; i <= stop; i++) {
++begin:	if ((stop - i) > 100000) {
++		EPRINT((env, DB_STR_A("5551",
++"Warning, many possible extends files (%lu), will take a long time to verify",
++          "%lu"), (u_long)(stop - i)));
++	}
++	for (; i <= stop; i++) {
++		if (i == UINT32_MAX)
++			break;
+ 		/*
+ 		 * If DB_SALVAGE is set, we inspect our database of completed
+ 		 * pages, and skip any we've already printed in the subdb pass.
diff --git a/db5.3-atomic_compare_exchange.patch b/db5.3-atomic_compare_exchange.patch
deleted file mode 100644
index 6bbc582..0000000
--- a/db5.3-atomic_compare_exchange.patch
+++ /dev/null
@@ -1,151 +0,0 @@
-diff -ur db-5.3.28.orig/src/dbinc/atomic.h db-5.3.28/src/dbinc/atomic.h
---- db-5.3.28.orig/src/dbinc/atomic.h	2013-09-09 17:35:08.000000000 +0200
-+++ db-5.3.28/src/dbinc/atomic.h	2020-10-29 19:09:22.546238669 +0100
-@@ -25,7 +25,7 @@
-  *	 atomic_dec(env, valueptr)
-  *	    Subtracts 1 from the db_atomic_t value, returning the new value.
-  *
-- *	 atomic_compare_exchange(env, valueptr, oldval, newval)
-+ *	 atomic_compare_exchange_db(env, valueptr, oldval, newval)
-  *	    If the db_atomic_t's value is still oldval, set it to newval.
-  *	    It returns 1 for success or 0 for failure.
-  *
-@@ -115,12 +115,12 @@
- 	(WINCE_ATOMIC_MAGIC(p),						\
- 	InterlockedDecrement((interlocked_val)(&(p)->value)))
- #if defined(_MSC_VER) && _MSC_VER < 1300
--#define	atomic_compare_exchange(env, p, oldval, newval)			\
-+#define	atomic_compare_exchange_db(env, p, oldval, newval)			\
- 	(WINCE_ATOMIC_MAGIC(p),						\
- 	(InterlockedCompareExchange((PVOID *)(&(p)->value),		\
- 	(PVOID)(newval), (PVOID)(oldval)) == (PVOID)(oldval)))
- #else
--#define	atomic_compare_exchange(env, p, oldval, newval)			\
-+#define	atomic_compare_exchange_db(env, p, oldval, newval)			\
- 	(WINCE_ATOMIC_MAGIC(p),						\
- 	(InterlockedCompareExchange((interlocked_val)(&(p)->value),	\
- 	(newval), (oldval)) == (oldval)))
-@@ -134,7 +134,7 @@
- 	atomic_inc_uint_nv((volatile unsigned int *) &(p)->value)
- #define	atomic_dec(env, p)	\
- 	atomic_dec_uint_nv((volatile unsigned int *) &(p)->value)
--#define	atomic_compare_exchange(env, p, oval, nval)		\
-+#define	atomic_compare_exchange_db(env, p, oval, nval)		\
- 	(atomic_cas_32((volatile unsigned int *) &(p)->value,	\
- 	    (oval), (nval)) == (oval))
- #endif
-@@ -143,8 +143,8 @@
- /* x86/x86_64 gcc  */
- #define	atomic_inc(env, p)	__atomic_inc(p)
- #define	atomic_dec(env, p)	__atomic_dec(p)
--#define	atomic_compare_exchange(env, p, o, n)	\
--	__atomic_compare_exchange((p), (o), (n))
-+#define	atomic_compare_exchange_db(env, p, o, n)	\
-+	__atomic_compare_exchange_db((p), (o), (n))
- static inline int __atomic_inc(db_atomic_t *p)
- {
- 	int	temp;
-@@ -176,7 +176,7 @@
-  * http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html
-  * which configure could be changed to use.
-  */
--static inline int __atomic_compare_exchange(
-+static inline int __atomic_compare_exchange_db(
- 	db_atomic_t *p, atomic_value_t oldval, atomic_value_t newval)
- {
- 	atomic_value_t was;
-@@ -204,7 +204,7 @@
-  */
- #define	atomic_inc(env, p)	(++(p)->value)
- #define	atomic_dec(env, p)	(--(p)->value)
--#define	atomic_compare_exchange(env, p, oldval, newval)		\
-+#define	atomic_compare_exchange_db(env, p, oldval, newval)		\
- 	(DB_ASSERT(env, atomic_read(p) == (oldval)),		\
- 	atomic_init(p, (newval)), 1)
- #else
-diff -ur db-5.3.28.orig/src/dbinc/mutex_int.h db-5.3.28/src/dbinc/mutex_int.h
---- db-5.3.28.orig/src/dbinc/mutex_int.h	2013-09-09 17:35:08.000000000 +0200
-+++ db-5.3.28/src/dbinc/mutex_int.h	2020-10-29 19:09:29.846238669 +0100
-@@ -1050,7 +1050,7 @@
-  */
- #define	MUTEXP_ACQUIRE(mutexp)	\
- 	(F_ISSET(mutexp, DB_MUTEX_SHARED) ?			\
--	atomic_compare_exchange(env,				\
-+	atomic_compare_exchange_db(env,				\
- 	    &(mutexp)->sharecount, 0, MUTEX_SHARE_ISEXCLUSIVE) :	\
- 	MUTEX_SET(&(mutexp)->tas))
- #else
-diff -ur db-5.3.28.orig/src/dbinc_auto/int_def.in db-5.3.28/src/dbinc_auto/int_def.in
---- db-5.3.28.orig/src/dbinc_auto/int_def.in	2013-09-09 17:35:08.000000000 +0200
-+++ db-5.3.28/src/dbinc_auto/int_def.in	2020-10-29 19:09:56.642238669 +0100
-@@ -1488,7 +1488,7 @@
- #define	__atomic_dec __atomic_dec at DB_VERSION_UNIQUE_NAME@
- #endif
- #if !defined(HAVE_ATOMIC_SUPPORT) && defined(HAVE_MUTEX_SUPPORT)
--#define	atomic_compare_exchange atomic_compare_exchange at DB_VERSION_UNIQUE_NAME@
-+#define	atomic_compare_exchange_db atomic_compare_exchange_db at DB_VERSION_UNIQUE_NAME@
- #endif
- #define	__db_pthread_mutex_init __db_pthread_mutex_init at DB_VERSION_UNIQUE_NAME@
- #ifndef HAVE_MUTEX_HYBRID
-diff -ur db-5.3.28.orig/src/dbinc_auto/mutex_ext.h db-5.3.28/src/dbinc_auto/mutex_ext.h
---- db-5.3.28.orig/src/dbinc_auto/mutex_ext.h	2013-09-09 17:35:08.000000000 +0200
-+++ db-5.3.28/src/dbinc_auto/mutex_ext.h	2020-10-29 19:10:00.649238669 +0100
-@@ -38,7 +38,7 @@
- atomic_value_t __atomic_dec __P((ENV *, db_atomic_t *));
- #endif
- #if !defined(HAVE_ATOMIC_SUPPORT) && defined(HAVE_MUTEX_SUPPORT)
--int atomic_compare_exchange __P((ENV *, db_atomic_t *, atomic_value_t, atomic_value_t));
-+int atomic_compare_exchange_db __P((ENV *, db_atomic_t *, atomic_value_t, atomic_value_t));
- #endif
- int __db_pthread_mutex_init __P((ENV *, db_mutex_t, u_int32_t));
- #ifndef HAVE_MUTEX_HYBRID
-diff -ur db-5.3.28.orig/src/mutex/mut_method.c db-5.3.28/src/mutex/mut_method.c
---- db-5.3.28.orig/src/mutex/mut_method.c	2013-09-09 17:35:09.000000000 +0200
-+++ db-5.3.28/src/mutex/mut_method.c	2020-10-29 19:09:45.172238669 +0100
-@@ -445,11 +445,11 @@
- }
- 
- /*
-- * atomic_compare_exchange
-+ * atomic_compare_exchange_db
-  *	Use a mutex to provide an atomic decrement function
-  *
-  * PUBLIC: #if !defined(HAVE_ATOMIC_SUPPORT) && defined(HAVE_MUTEX_SUPPORT)
-- * PUBLIC: int atomic_compare_exchange
-+ * PUBLIC: int atomic_compare_exchange_db
-  * PUBLIC:     __P((ENV *, db_atomic_t *, atomic_value_t, atomic_value_t));
-  * PUBLIC: #endif
-  *	Returns 1 if the *v was equal to oldval, else 0
-@@ -458,7 +458,7 @@
-  *		Sets the value to newval if and only if returning 1
-  */
- int
--atomic_compare_exchange(env, v, oldval, newval)
-+atomic_compare_exchange_db(env, v, oldval, newval)
- 	ENV *env;
- 	db_atomic_t *v;
- 	atomic_value_t oldval;
-diff -ur db-5.3.28.orig/src/mutex/mut_tas.c db-5.3.28/src/mutex/mut_tas.c
---- db-5.3.28.orig/src/mutex/mut_tas.c	2013-09-09 17:35:09.000000000 +0200
-+++ db-5.3.28/src/mutex/mut_tas.c	2020-10-29 19:09:40.046238669 +0100
-@@ -366,7 +366,7 @@
- 	    mtxregion->stat.st_mutex_tas_spins; nspins > 0; --nspins) {
- 		lock = atomic_read(&mutexp->sharecount);
- 		if (lock == MUTEX_SHARE_ISEXCLUSIVE ||
--		    !atomic_compare_exchange(env,
-+		    !atomic_compare_exchange_db(env,
- 			&mutexp->sharecount, lock, lock + 1)) {
- 			/*
- 			 * Some systems (notably those with newer Intel CPUs)
-diff -ur db-5.3.28.orig/src/mutex/mut_win32.c db-5.3.28/src/mutex/mut_win32.c
---- db-5.3.28.orig/src/mutex/mut_win32.c	2013-09-09 17:35:09.000000000 +0200
-+++ db-5.3.28/src/mutex/mut_win32.c	2020-10-29 19:09:51.148238669 +0100
-@@ -361,7 +361,7 @@
- 				return (DB_LOCK_NOTGRANTED);
- 
- 			continue;
--		} else if (!atomic_compare_exchange(env, &mutexp->sharecount,
-+		} else if (!atomic_compare_exchange_db(env, &mutexp->sharecount,
- 		    mtx_val, mtx_val + 1)) {
- 			/*
- 			 * Some systems (notably those with newer Intel CPUs)
diff --git a/db_version.patch b/db_version.patch
new file mode 100644
index 0000000..68f17c8
--- /dev/null
+++ b/db_version.patch
@@ -0,0 +1,42 @@
+--- db-5.3.28/dist/s_config	2013-09-09 17:35:02.000000000 +0200
++++ db-5.3.28/dist/s_config	2026-05-18 01:32:49.384443145 +0200
+@@ -1,26 +1,9 @@
+ #!/bin/sh -
+-#	$Id$
+-#
+-# Build the autoconfiguration files.
+-
+-trap 'rm -f aclocal.m4 ; exit 0' 0 1 2 3 13 15
+ 
+ . ./RELEASE
+ 
+-echo "autoconf: building aclocal.m4..."
+-cat aclocal/*.m4 aclocal_java/*.m4 > aclocal.m4
+-
+-echo "autoconf: running autoheader to build config.hin..."
+-rm -f config.hin
+-autoheader
+-chmod 644 config.hin
+-
+-echo "autoconf: running autoconf to build configure"
+-rm -f configure
+-autoconf
+-
+ # Edit version information we couldn't pre-compute.
+-sed -e "s/__EDIT_DB_VERSION_FAMILY__/$DB_VERSION_FAMILY/g" \
++sed -i -e "s/__EDIT_DB_VERSION_FAMILY__/$DB_VERSION_FAMILY/g" \
+     -e "s/__EDIT_DB_VERSION_RELEASE__/$DB_VERSION_RELEASE/g" \
+     -e "s/__EDIT_DB_VERSION_MAJOR__/$DB_VERSION_MAJOR/g" \
+     -e "s/__EDIT_DB_VERSION_MINOR__/$DB_VERSION_MINOR/g" \
+@@ -28,10 +11,5 @@
+     -e "s/__EDIT_DB_VERSION_STRING__/$DB_VERSION_STRING/g" \
+     -e "s/__EDIT_DB_VERSION_FULL_STRING__/$DB_VERSION_FULL_STRING/g" \
+     -e "s/__EDIT_DB_VERSION_UNIQUE_NAME__/$DB_VERSION_UNIQUE_NAME/g" \
+-    -e "s/__EDIT_DB_VERSION__/$DB_VERSION/g" configure > configure.version
+-mv configure.version configure
+-
+-rm -rf autom4te.cache
+-chmod 755 configure
++    -e "s/__EDIT_DB_VERSION__/$DB_VERSION/g" configure
+ 
+-chmod 755 config.guess config.sub install-sh
diff --git a/libdb-5.3.21-region-size-check.patch b/libdb-5.3.21-region-size-check.patch
new file mode 100644
index 0000000..77be25e
--- /dev/null
+++ b/libdb-5.3.21-region-size-check.patch
@@ -0,0 +1,39 @@
+diff -up db-5.3.21/src/env/env_region.c.zero-region db-5.3.21/src/env/env_region.c
+--- db-5.3.21/src/env/env_region.c.zero-region	2012-05-11 19:57:53.000000000 +0200
++++ db-5.3.21/src/env/env_region.c	2017-09-06 08:50:45.310276385 +0200
+@@ -1060,6 +1060,7 @@ __env_region_attach(env, infop, init, ma
+ 	REGION *rp;
+ 	int ret;
+ 	char buf[sizeof(DB_REGION_FMT) + 20];
++	struct stat st;
+ 
+ 	/*
+ 	 * Find or create a REGION structure for this region.  If we create
+@@ -1090,6 +1091,14 @@ __env_region_attach(env, infop, init, ma
+ 	if ((ret = __env_sys_attach(env, infop, rp)) != 0)
+ 		goto err;
+ 
++        /* Check the size of the underlying file */
++        if (infop->fhp != NULL && F_ISSET(infop->fhp, DB_FH_OPENED) &&
++            infop->fhp->fd != -1 && fstat(infop->fhp->fd, &st) != -1 &&
++            st.st_size == 0) {
++            ret = DB_RUNRECOVERY;
++            goto err;
++        }
++
+ 	/*
+ 	 * Fault the pages into memory.  Note, do this BEFORE we initialize
+ 	 * anything because we're writing pages in created regions, not just
+diff -up db-5.3.21/src/os/os_map.c.zero-region db-5.3.21/src/os/os_map.c
+--- db-5.3.21/src/os/os_map.c.zero-region	2012-05-11 19:57:54.000000000 +0200
++++ db-5.3.21/src/os/os_map.c	2017-09-06 08:49:39.144546552 +0200
+@@ -265,6 +265,9 @@ __os_detach(env, infop, destroy)
+ 	dbenv = env->dbenv;
+ 
+ 	rp = infop->rp;
++	/* Do not touch the region information if it no longer exists */
++	if (rp == NULL)
++	    return EINVAL;
+ 
+ 	/* If the user replaced the unmap call, call through their interface. */
+ 	if (DB_GLOBAL(j_region_unmap) != NULL)
diff --git a/libdb-5.3.21-trickle_cpu.patch b/libdb-5.3.21-trickle_cpu.patch
new file mode 100644
index 0000000..20b0e88
--- /dev/null
+++ b/libdb-5.3.21-trickle_cpu.patch
@@ -0,0 +1,150 @@
+diff -up db-5.3.21/src/dbinc_auto/int_def.in.trickle db-5.3.21/src/dbinc_auto/int_def.in
+--- db-5.3.21/src/dbinc_auto/int_def.in.trickle	2018-08-21 10:54:06.066757392 +0200
++++ db-5.3.21/src/dbinc_auto/int_def.in	2018-08-21 10:54:06.111756561 +0200
+@@ -1458,6 +1458,7 @@
+ #define	__memp_sync_int __memp_sync_int at DB_VERSION_UNIQUE_NAME@
+ #define	__memp_mf_sync __memp_mf_sync at DB_VERSION_UNIQUE_NAME@
+ #define	__memp_purge_dead_files __memp_purge_dead_files at DB_VERSION_UNIQUE_NAME@
++#define	__memp_purge_dead_and_count __memp_purge_dead_and_count at DB_VERSION_UNIQUE_NAME@
+ #define	__memp_trickle_pp __memp_trickle_pp at DB_VERSION_UNIQUE_NAME@
+ #define	__mutex_alloc __mutex_alloc at DB_VERSION_UNIQUE_NAME@
+ #define	__mutex_alloc_int __mutex_alloc_int at DB_VERSION_UNIQUE_NAME@
+diff -up db-5.3.21/src/dbinc_auto/mp_ext.h.trickle db-5.3.21/src/dbinc_auto/mp_ext.h
+--- db-5.3.21/src/dbinc_auto/mp_ext.h.trickle	2018-08-21 10:54:06.103756709 +0200
++++ db-5.3.21/src/dbinc_auto/mp_ext.h	2018-08-21 10:54:06.112756543 +0200
+@@ -101,6 +101,7 @@ int __mp_xxx_fh __P((DB_MPOOLFILE *, DB_
+ int __memp_sync_int __P((ENV *, DB_MPOOLFILE *, u_int32_t, u_int32_t, u_int32_t *, int *));
+ int __memp_mf_sync __P((DB_MPOOL *, MPOOLFILE *, int));
+ int __memp_purge_dead_files __P((ENV *));
++int __memp_purge_dead_and_count __P((ENV *, u_int32_t *, u_int32_t *));
+ int __memp_trickle_pp __P((DB_ENV *, int, int *));
+ 
+ #if defined(__cplusplus)
+diff -up db-5.3.21/src/mp/mp_sync.c.trickle db-5.3.21/src/mp/mp_sync.c
+--- db-5.3.21/src/mp/mp_sync.c.trickle	2018-08-21 10:54:06.105756672 +0200
++++ db-5.3.21/src/mp/mp_sync.c	2018-09-04 09:43:57.502992291 +0200
+@@ -965,17 +965,34 @@ __bhcmp(p1, p2)
+ 	return (0);
+ }
+ 
++
+ /*
+  * __memp_purge_dead_files --
++ *  Thin wrapper over __memp_purge_dead_and_count. Does not return any
++ *  information about the number of total/dirty buffers.
++ *
++ * PUBLIC: int __memp_purge_dead_files __P((ENV *));
++ */
++int
++__memp_purge_dead_files(env)
++    ENV *env;
++{
++    return __memp_purge_dead_and_count(env, NULL, NULL);
++}
++
++/*
++ * __memp_purge_dead_and_count --
+  *	Remove all dead files and their buffers from the mpool. The caller
+  *	cannot hold any lock on the dead MPOOLFILE handles, their buffers
+  *	or their hash buckets.
+  *
+- * PUBLIC: int __memp_purge_dead_files __P((ENV *));
++ * PUBLIC: int __memp_purge_dead_and_count __P((ENV *, u_int32_t *, u_int32_t *));
+  */
+ int
+-__memp_purge_dead_files(env)
++__memp_purge_dead_and_count(env, totalp, dirtyp)
+ 	ENV *env;
++    u_int32_t *totalp;
++    u_int32_t *dirtyp;
+ {
+ 	BH *bhp;
+ 	DB_MPOOL *dbmp;
+@@ -983,7 +1000,7 @@ __memp_purge_dead_files(env)
+ 	REGINFO *infop;
+ 	MPOOL *c_mp, *mp;
+ 	MPOOLFILE *mfp;
+-	u_int32_t i_cache;
++	u_int32_t i_cache, dirty, total;
+ 	int ret, t_ret, h_lock;
+ 
+ 	if (!MPOOL_ON(env))
+@@ -992,6 +1009,7 @@ __memp_purge_dead_files(env)
+ 	dbmp = env->mp_handle;
+ 	mp = dbmp->reginfo[0].primary;
+ 	ret = t_ret = h_lock = 0;
++    dirty = total = 0;
+ 
+ 	/*
+ 	 * Walk each cache's list of buffers and free all buffers whose
+@@ -1000,6 +1018,7 @@ __memp_purge_dead_files(env)
+ 	for (i_cache = 0; i_cache < mp->nreg; i_cache++) {
+ 		infop = &dbmp->reginfo[i_cache]; 
+ 		c_mp = infop->primary;
++        total += c_mp->pages;
+ 
+ 		hp = R_ADDR(infop, c_mp->htab);
+ 		hp_end = &hp[c_mp->htab_buckets];
+@@ -1008,6 +1027,9 @@ __memp_purge_dead_files(env)
+ 			if (SH_TAILQ_FIRST(&hp->hash_bucket, __bh) == NULL)
+ 				continue;
+ 
++            /* Count dirty pages first as we do not wait on mutex locks */
++            dirty += (u_int32_t)atomic_read(&hp->hash_page_dirty);
++
+ 			/* 
+ 			 * Search for a dead buffer. Other places that call
+ 			 * __memp_bhfree() acquire the buffer lock before the
+@@ -1073,6 +1095,11 @@ __memp_purge_dead_files(env)
+ 		}
+ 	}
+ 
++    if (dirtyp != NULL)
++		*dirtyp = dirty;
++    if (totalp != NULL)
++		*totalp = total;
++
+ 	return (ret);
+ }
+ 
+diff -up db-5.3.21/src/mp/mp_trickle.c.trickle db-5.3.21/src/mp/mp_trickle.c
+--- db-5.3.21/src/mp/mp_trickle.c.trickle	2018-08-21 10:54:06.105756672 +0200
++++ db-5.3.21/src/mp/mp_trickle.c	2018-08-21 10:54:06.112756543 +0200
+@@ -56,6 +56,7 @@ __memp_trickle(env, pct, nwrotep)
+ 
+ 	dbmp = env->mp_handle;
+ 	mp = dbmp->reginfo[0].primary;
++    dirty = total = 0;
+ 
+ 	if (nwrotep != NULL)
+ 		*nwrotep = 0;
+@@ -67,12 +68,8 @@ __memp_trickle(env, pct, nwrotep)
+ 		return (EINVAL);
+ 	}
+ 
+-	/* First we purge all dead files and their buffers. */
+-	if ((ret = __memp_purge_dead_files(env)) != 0)
+-		return (ret);
+-
+-	/*
+-	 * Loop through the caches counting total/dirty buffers.
++	/* First we purge all dead files and their buffers and
++	 * loop through the caches counting total/dirty buffers.
+ 	 *
+ 	 * XXX
+ 	 * Using hash_page_dirty is our only choice at the moment, but it's not
+@@ -80,12 +77,8 @@ __memp_trickle(env, pct, nwrotep)
+ 	 * than one page size, as a free 512B buffer may not be equivalent to
+ 	 * having a free 8KB buffer.
+ 	 */
+-	for (ret = 0, i = dirty = total = 0; i < mp->nreg; ++i) {
+-		c_mp = dbmp->reginfo[i].primary;
+-		total += c_mp->pages;
+-		__memp_stat_hash(&dbmp->reginfo[i], c_mp, &dtmp);
+-		dirty += dtmp;
+-	}
++	if ((ret = __memp_purge_dead_and_count(env, &total, &dirty)) != 0)
++		return (ret);
+ 
+ 	/*
+ 	 * If there are sufficient clean buffers, no buffers or no dirty
diff --git a/libdb-c99.patch b/libdb-c99.patch
new file mode 100644
index 0000000..4217ee6
--- /dev/null
+++ b/libdb-c99.patch
@@ -0,0 +1,26 @@
+Add additional header files to avoid implicit declaration of the flock
+and usleep functions.  Improves C99 compatibility.
+
+diff -ur db-5.3.28.orig/src/os/os_flock.c db-5.3.28/src/os/os_flock.c
+--- db-5.3.28.orig/src/os/os_flock.c	2022-12-10 12:29:48.614322281 +0100
++++ db-5.3.28/src/os/os_flock.c	2022-12-10 14:33:21.785814691 +0100
+@@ -10,6 +10,8 @@
+ 
+ #include "db_int.h"
+ 
++#include <sys/file.h>
++
+ #if !defined(HAVE_FCNTL) || !defined(HAVE_FLOCK)
+ static int __os_filelocking_notsup __P((ENV *));
+ #endif
+diff -ur db-5.3.28.orig/util/db_dump185.c db-5.3.28/util/db_dump185.c
+--- db-5.3.28.orig/util/db_dump185.c	2013-09-09 17:35:12.000000000 +0200
++++ db-5.3.28/util/db_dump185.c	2022-12-10 12:35:08.415288426 +0100
+@@ -19,6 +19,7 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
++#include <unistd.h>
+ 
+ #ifdef HAVE_DB_185_H
+ #include <db_185.h>
diff --git a/libdb-cbd-race.patch b/libdb-cbd-race.patch
new file mode 100644
index 0000000..ad56d06
--- /dev/null
+++ b/libdb-cbd-race.patch
@@ -0,0 +1,110 @@
+From 4ae2eb88fadc256ddf9862b2e72ed216ddbb919d Mon Sep 17 00:00:00 2001
+From: michael brey <michael.brey at oracle.com>
+Date: Tue, 20 May 2014 14:49:44 +0200
+Subject: [PATCH] Fix a CDB race
+
+Report and reproducer here:
+https://community.oracle.com/thread/3514381
+
+From: michael brey <michael.brey at oracle.com>
+To: Lubomir Rintel <lkundrak at v3.sk>
+Subject: Re: BDB crash
+Date: Tue, 13 May 2014 09:07:45 -0600 (05/13/2014 05:07:45 PM)
+Message-id: <53723541.7040203 at oracle.com>
+
+  attached are patches for each release.  the 5.3.28 patch will apply on
+top of 5.3.21.
+
+thanks
+mike
+
+RHBZ: #1099509
+---
+ src/env/env_failchk.c | 24 ++++++++++++++++++++++++
+ src/mutex/mut_tas.c   | 18 +++++++++++++++++-
+ 2 files changed, 41 insertions(+), 1 deletion(-)
+
+diff --git a/src/env/env_failchk.c b/src/env/env_failchk.c
+index 05752f0..b09df96 100644
+--- a/src/env/env_failchk.c
++++ b/src/env/env_failchk.c
+@@ -312,6 +312,7 @@ __env_in_api(env)
+ 	REGINFO *infop;
+ 	THREAD_INFO *thread;
+ 	u_int32_t i;
++	pid_t pid;
+ 	int unpin, ret;
+ 
+ 	if ((htab = env->thr_hashtab) == NULL)
+@@ -325,6 +326,7 @@ __env_in_api(env)
+ 
+ 	for (i = 0; i < env->thr_nbucket; i++)
+ 		SH_TAILQ_FOREACH(ip, &htab[i], dbth_links, __db_thread_info) {
++			pid = ip->dbth_pid;
+ 			if (ip->dbth_state == THREAD_SLOT_NOT_IN_USE ||
+ 			    (ip->dbth_state == THREAD_OUT &&
+ 			    thread->thr_count <  thread->thr_max))
+@@ -341,6 +343,28 @@ __env_in_api(env)
+ 				ip->dbth_state = THREAD_SLOT_NOT_IN_USE;
+ 				continue;
+ 			}
++			/*
++			 * The above tests are not atomic, so it is possible that
++			 * the process pointed by ip has changed during the tests.
++			 * In particular, if the process pointed by ip when is_alive
++			 * was executed terminated normally, a new process may reuse
++			 * the same ip structure and change its dbth_state before the
++			 * next two tests were performed. Therefore, we need to test
++			 * here that all four tests above are done on the same process.
++			 * If the process pointed by ip changed, all tests are invalid
++			 * and can be ignored.
++			 * Similarly, it's also possible for two processes racing to
++			 * change the dbth_state of the same ip structure. For example,
++			 * both process A and B reach the above test for the same
++			 * terminated process C where C's dbth_state is THREAD_OUT.
++			 * If A goes into the 'if' block and changes C's dbth_state to
++			 * THREAD_SLOT_NOT_IN_USE before B checks the condition, B
++			 * would incorrectly fail the test and run into this line.
++			 * Therefore, we need to check C's dbth_state again and fail
++			 * the db only if C's dbth_state is indeed THREAD_ACTIVE.
++			 */
++			if (ip->dbth_state != THREAD_ACTIVE || ip->dbth_pid != pid)
++				continue;
+ 			return (__db_failed(env, DB_STR("1507",
+ 			    "Thread died in Berkeley DB library"),
+ 			    ip->dbth_pid, ip->dbth_tid));
+diff --git a/src/mutex/mut_tas.c b/src/mutex/mut_tas.c
+index 0899d23..db95030 100644
+--- a/src/mutex/mut_tas.c
++++ b/src/mutex/mut_tas.c
+@@ -151,10 +151,26 @@ loop:	/* Attempt to acquire the resource for N spins. */
+ 			if (F_ISSET(dbenv, DB_ENV_FAILCHK) &&
+ 			    ip == NULL && dbenv->is_alive(dbenv,
+ 			    mutexp->pid, mutexp->tid, 0) == 0) {
++				/*
++				 * The process owing the mutex is "dead" now, but it may
++				 * have already released the mutex. We need to check again
++				 * by going back to the top of the loop
++				 * if the mutex is still held by the "dead" process. We
++				 * yield 10 us to increase the likelyhood of mutexp fields
++				 * being up-to-date. Set spin so we spin one more time
++				 * because no need to spin more if dead process owns mutex.
++				 */                               
++				if (nspins > 1) {
++					nspins = 2;
++					__os_yield(env, 0, 10);
++					continue;
++				}
+ 				ret = __env_set_state(env, &ip, THREAD_VERIFY);
+ 				if (ret != 0 ||
+-				    ip->dbth_state == THREAD_FAILCHK)
++				    ip->dbth_state == THREAD_FAILCHK) {
++					printf("mut_tas:172, pid: %d, flag: %d\n", mutexp->pid, mutexp->flags);
+ 					return (DB_RUNRECOVERY);
++				}
+ 			}
+ 			if (nowait)
+ 				return (DB_LOCK_NOTGRANTED);
+-- 
+1.8.3.1
+
diff --git a/libdb-configure-c99.patch b/libdb-configure-c99.patch
new file mode 100644
index 0000000..ff9c79d
--- /dev/null
+++ b/libdb-configure-c99.patch
@@ -0,0 +1,285 @@
+Port the configure script to C99.  Add missing header files, avoid
+calling the undeclared exit function, and add missing return types
+main.  This improves compatibility with compilers which do not accept
+language features that were removed from C99.
+
+diff -ur db-5.3.28.orig/dist/aclocal/clock.m4 db-5.3.28/dist/aclocal/clock.m4
+--- db-5.3.28.orig/dist/aclocal/clock.m4	2013-09-09 17:35:02.000000000 +0200
++++ db-5.3.28/dist/aclocal/clock.m4	2022-12-10 12:35:08.415288426 +0100
+@@ -21,12 +21,14 @@
+ AC_CACHE_CHECK([for clock_gettime monotonic clock], db_cv_clock_monotonic, [
+ AC_TRY_RUN([
+ #include <sys/time.h>
+-main() {
++#include <time.h>
++int main() {
+ 	struct timespec t;
+ 	return (clock_gettime(CLOCK_MONOTONIC, &t) != 0);
+ }], db_cv_clock_monotonic=yes, db_cv_clock_monotonic=no,
+ AC_TRY_LINK([
+-#include <sys/time.h>], [
++#include <sys/time.h>
++#include <time.h>], [
+ struct timespec t;
+ clock_gettime(CLOCK_MONOTONIC, &t);
+ ], db_cv_clock_monotonic=yes, db_cv_clock_monotonic=no))
+diff -u db-5.3.28/dist/aclocal/mmap.m4 db-5.3.28/dist/aclocal/mmap.m4
+--- db-5.3.28/dist/aclocal/mmap.m4	2024-01-05 16:07:07.340002918 +0100
++++ db-5.3.28/dist/aclocal/mmap.m4	2024-01-05 16:45:12.128407358 +0100
+@@ -42,13 +42,11 @@
+     #define MAP_FAILED (-1)
+     #endif
+ 
+-    int catch_sig(sig)
+-	    int sig;
++    void catch_sig(int sig)
+     {
+-	    exit(1);
+     }
+ 
+-    main() {
++    int main() {
+ 	    const char *underlying;
+ 	    unsigned gapsize;
+ 	    char *base;
+diff -ur db-5.3.28.orig/dist/aclocal/mutex.m4 db-5.3.28/dist/aclocal/mutex.m4
+--- db-5.3.28.orig/dist/aclocal/mutex.m4	2013-09-09 17:35:02.000000000 +0200
++++ db-5.3.28/dist/aclocal/mutex.m4	2022-12-10 12:35:08.415288426 +0100
+@@ -5,7 +5,7 @@
+ AC_TRY_RUN([
+ #include <stdlib.h>
+ #include <pthread.h>
+-main() {
++int main() {
+ 	pthread_cond_t cond;
+ 	pthread_mutex_t mutex;
+ 	pthread_condattr_t condattr;
+@@ -49,7 +49,7 @@
+ AC_TRY_RUN([
+ #include <stdlib.h>
+ #include <pthread.h>
+-main() {
++int main() {
+ 	pthread_cond_t cond;
+ 	pthread_mutex_t mutex;
+ 	pthread_condattr_t condattr;
+@@ -89,7 +89,7 @@
+ AC_TRY_RUN([
+ #include <stdlib.h>
+ #include <pthread.h>
+-main() {
++int main() {
+ 	pthread_cond_t cond;
+ 	pthread_condattr_t condattr;
+ 	exit(pthread_condattr_init(&condattr) ||
+@@ -110,7 +110,7 @@
+ AC_TRY_RUN([
+ #include <stdlib.h>
+ #include <pthread.h>
+-main() {
++int main() {
+ 	pthread_rwlock_t rwlock;
+ 	pthread_rwlockattr_t rwlockattr;
+ 	exit(pthread_rwlockattr_init(&rwlockattr) ||
+@@ -282,7 +282,7 @@
+ 	# x86/gcc: FreeBSD, NetBSD, BSD/OS, Linux
+ 	AC_TRY_COMPILE(,[
+ 	#if (defined(i386) || defined(__i386__)) && defined(__GNUC__)
+-		exit(0);
++		return 0;
+ 	#else
+ 		FAIL TO COMPILE/LINK
+ 	#endif
+@@ -291,7 +291,7 @@
+ 	# x86_64/gcc: FreeBSD, NetBSD, BSD/OS, Linux
+ 	AC_TRY_COMPILE(,[
+ 	#if (defined(x86_64) || defined(__x86_64__)) && defined(__GNUC__)
+-		exit(0);
++		return 0;
+ 	#else
+ 		FAIL TO COMPILE/LINK
+ 	#endif
+@@ -314,7 +314,7 @@
+ 	AC_TRY_COMPILE(,[
+ 	#if defined(__sparc__) && defined(__GNUC__)
+ 		asm volatile ("membar #StoreStore|#StoreLoad|#LoadStore");
+-		exit(0);
++		return 0;
+ 	#else
+ 		FAIL TO COMPILE/LINK
+ 	#endif
+@@ -356,7 +356,7 @@
+ 	msem_init(&x, 0);
+ 	msem_lock(&x, 0);
+ 	msem_unlock(&x, 0);
+-	exit(0);
++	return 0;
+ #else
+ 	FAIL TO COMPILE/LINK
+ #endif
+@@ -373,7 +373,7 @@
+ 	msem_init(&x, 0);
+ 	msem_lock(&x, 0);
+ 	msem_unlock(&x, 0);
+-	exit(0);
++	return 0;
+ ], [db_cv_mutex=UNIX/msem_init])
+ fi
+ 
+@@ -395,7 +395,7 @@
+ if test "$db_cv_mutex" = no; then
+ AC_TRY_COMPILE(,[
+ #if defined(__USLC__)
+-	exit(0);
++	return 0;
+ #else
+ 	FAIL TO COMPILE/LINK
+ #endif
+@@ -452,7 +452,7 @@
+ if test "$db_cv_mutex" = no; then
+ AC_TRY_COMPILE(,[
+ #if defined(__alpha) && defined(__DECC)
+-	exit(0);
++	return 0;
+ #else
+ 	FAIL TO COMPILE/LINK
+ #endif
+@@ -463,7 +463,7 @@
+ if test "$db_cv_mutex" = no; then
+ AC_TRY_COMPILE(,[
+ #if defined(__alpha) && defined(__GNUC__)
+-	exit(0);
++	return 0;
+ #else
+ 	FAIL TO COMPILE/LINK
+ #endif
+@@ -474,7 +474,7 @@
+ if test "$db_cv_mutex" = no; then
+ AC_TRY_COMPILE(,[
+ #if defined(__arm__) && defined(__GNUC__)
+-	exit(0);
++	return 0;
+ #else
+ 	FAIL TO COMPILE/LINK
+ #endif
+@@ -485,7 +485,7 @@
+ if test "$db_cv_mutex" = no; then
+ AC_TRY_COMPILE(,[
+ #if (defined(__mips) || defined(__mips__)) && defined(__GNUC__)
+-	exit(0);
++	return 0;
+ #else
+ 	FAIL TO COMPILE/LINK
+ #endif
+@@ -496,7 +496,7 @@
+ if test "$db_cv_mutex" = no; then
+ AC_TRY_COMPILE(,[
+ #if (defined(__hppa) || defined(__hppa__)) && defined(__GNUC__)
+-	exit(0);
++	return 0;
+ #else
+ 	FAIL TO COMPILE/LINK
+ #endif
+@@ -507,7 +507,7 @@
+ if test "$db_cv_mutex" = no; then
+ AC_TRY_COMPILE(,[
+ #if (defined(__powerpc__) || defined(__ppc__)) && defined(__GNUC__)
+-	exit(0);
++	return 0;
+ #else
+ 	FAIL TO COMPILE/LINK
+ #endif
+@@ -518,7 +518,7 @@
+ if test "$db_cv_mutex" = no; then
+ AC_TRY_COMPILE(,[
+ #if (defined(mc68020) || defined(sun3)) && defined(__GNUC__)
+-	exit(0);
++	return 0;
+ #else
+ 	FAIL TO COMPILE/LINK
+ #endif
+@@ -529,7 +529,7 @@
+ if test "$db_cv_mutex" = no; then
+ AC_TRY_COMPILE(,[
+ #if defined(__MVS__) && defined(__IBMC__)
+-	exit(0);
++	return 0;
+ #else
+ 	FAIL TO COMPILE/LINK
+ #endif
+@@ -540,7 +540,7 @@
+ if test "$db_cv_mutex" = no; then
+ AC_TRY_COMPILE(,[
+ #if defined(__s390__) && defined(__GNUC__)
+-	exit(0);
++	return 0;
+ #else
+ 	FAIL TO COMPILE/LINK
+ #endif
+@@ -551,7 +551,7 @@
+ if test "$db_cv_mutex" = no; then
+ AC_TRY_COMPILE(,[
+ #if defined(__ia64) && defined(__GNUC__)
+-	exit(0);
++	return 0;
+ #else
+ 	FAIL TO COMPILE/LINK
+ #endif
+@@ -562,7 +562,7 @@
+ if test "$db_cv_mutex" = no; then
+ AC_TRY_COMPILE(,[
+ #if defined(_UTS)
+-	exit(0);
++	return 0;
+ #else
+ 	FAIL TO COMPILE/LINK
+ #endif
+@@ -910,9 +910,9 @@
+ if test "$db_cv_atomic" = no; then
+ 	AC_TRY_COMPILE(,[
+ 	#if ((defined(i386) || defined(__i386__)) && defined(__GNUC__))
+-		exit(0);
++		return 0;
+ 	#elif ((defined(x86_64) || defined(__x86_64__)) && defined(__GNUC__))
+-		exit(0);
++		return 0;
+ 	#else
+ 		FAIL TO COMPILE/LINK
+ 	#endif
+diff -ur db-5.3.28.orig/dist/aclocal/sequence.m4 db-5.3.28/dist/aclocal/sequence.m4
+--- db-5.3.28.orig/dist/aclocal/sequence.m4	2022-12-10 12:29:48.598322433 +0100
++++ db-5.3.28/dist/aclocal/sequence.m4	2022-12-10 12:35:08.415288426 +0100
+@@ -43,7 +43,9 @@
+ 	# test, which won't test for the appropriate printf format strings.
+ 	if test "$db_cv_build_sequence" = "yes"; then
+ 		AC_TRY_RUN([
+-		main() {
++		#include <stdio.h>
++		#include <string.h>
++		int main() {
+ 			$db_cv_seq_type l;
+ 			unsigned $db_cv_seq_type u;
+ 			char buf@<:@100@:>@;
+@@ -59,7 +61,10 @@
+ 				return (1);
+ 			return (0);
+ 		}],, [db_cv_build_sequence="no"],
+-		AC_TRY_LINK(,[
++		AC_TRY_LINK([
++		#include <stdio.h>
++		#include <string.h>
++		],[
+ 			$db_cv_seq_type l;
+ 			unsigned $db_cv_seq_type u;
+ 			char buf@<:@100@:>@;
+diff -ur db-5.3.28.orig/dist/configure.ac db-5.3.28/dist/configure.ac
+--- db-5.3.28.orig/dist/configure.ac	2022-12-10 12:29:48.610322320 +0100
++++ db-5.3.28/dist/configure.ac	2022-12-10 12:43:38.840398043 +0100
+@@ -1047,6 +1047,7 @@
+ AC_CACHE_CHECK([for dl_iterate_phdr], db_cv_dl_iterate_phdr, [
+ AC_TRY_LINK([
+ #include <sys/types.h>
++#include <link.h>
+ #include <netdb.h>], [
+ 	dl_iterate_phdr(0, 0);
+ ], [db_cv_dl_iterate_phdr=yes], [db_cv_dl_iterate_phdr=no])])
diff --git a/libdb-limit-cpu.patch b/libdb-limit-cpu.patch
new file mode 100644
index 0000000..475aa50
--- /dev/null
+++ b/libdb-limit-cpu.patch
@@ -0,0 +1,12 @@
+diff -Naurp db_old/src/os/os_cpu.c db_new/src/os/os_cpu.c
+--- db_old/src/os/os_cpu.c	2012-05-11 12:57:54.000000000 -0500
++++ db_new/src/os/os_cpu.c	2015-08-12 14:00:37.232498880 -0500
+@@ -40,6 +40,8 @@ __os_cpu_count()
+ 	long nproc;
+ 
+ 	nproc = sysconf(_SC_NPROCESSORS_ONLN);
++	if (nproc > 1024)
++		nproc = 1024;
+ 	return ((u_int32_t)(nproc > 1 ? nproc : 1));
+ #else
+ 	return (1);
diff --git a/libdb-sqlite-c99.patch b/libdb-sqlite-c99.patch
new file mode 100644
index 0000000..c9bcf5d
--- /dev/null
+++ b/libdb-sqlite-c99.patch
@@ -0,0 +1,20 @@
+Avoid implicit function declarations due to missing prototypes for
+internal functions.
+
+diff -ur db-5.3.28.orig/lang/sql/sqlite/src/test_stat.c db-5.3.28/lang/sql/sqlite/src/test_stat.c
+--- db-5.3.28.orig/lang/sql/sqlite/src/test_stat.c	2013-09-09 17:35:06.000000000 +0200
++++ db-5.3.28/lang/sql/sqlite/src/test_stat.c	2022-12-10 14:40:10.362683745 +0100
+@@ -136,6 +136,13 @@
+ #endif
+ 
+ /*
++** Internal functions used by this test.
++*/
++int sqlite3PagerGet(Pager *pPager, Pgno pgno, DbPage **ppPage);
++void *sqlite3PagerGetData(DbPage *pPg);
++void sqlite3PagerUnref(DbPage *pPg);
++
++/*
+ ** Connect to or create a statvfs virtual table.
+ */
+ static int statConnect(
diff --git a/libdb-sqlite-tcl8.patch b/libdb-sqlite-tcl8.patch
new file mode 100644
index 0000000..4396020
--- /dev/null
+++ b/libdb-sqlite-tcl8.patch
@@ -0,0 +1,12 @@
+diff -up ./lang/sql/sqlite/Makefile.in.orig ./lang/sql/sqlite/Makefile.in
+--- ./lang/sql/sqlite/Makefile.in.orig	2013-09-09 11:35:05.000000000 -0400
++++ ./lang/sql/sqlite/Makefile.in	2025-03-05 07:40:54.156535196 -0500
+@@ -803,7 +803,7 @@ parse.c:	$(TOP)/src/parse.y lemon$(BEXE)
+ 	$(NAWK) -f $(TOP)/addopcodes.awk parse.h.temp >parse.h
+ 
+ sqlite3.h:	$(TOP)/src/sqlite.h.in $(TOP)/manifest.uuid $(TOP)/VERSION
+-	tclsh $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.h
++	$(TCLSH_CMD) $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.h
+ 
+ keywordhash.h:	$(TOP)/tool/mkkeywordhash.c
+ 	$(BCC) -o mkkeywordhash$(BEXE) $(OPT_FEATURE_FLAGS) $(OPTS) $(TOP)/tool/mkkeywordhash.c
diff --git a/tls.patch b/tls.patch
new file mode 100644
index 0000000..b7ad202
--- /dev/null
+++ b/tls.patch
@@ -0,0 +1,12 @@
+--- db-5.3.28/dist/aclocal/tls.m4	2013-09-09 17:35:02.000000000 +0200
++++ db-5.3.28/dist/aclocal/tls.m4	2026-05-18 01:30:13.963857395 +0200
+@@ -15,7 +15,8 @@
+       for ax_tls_defn_keyword in $ax_tls_keywords ""; do
+           test -z "$ax_tls_decl_keyword" &&
+               test -z "$ax_tls_defn_keyword" && continue
+-          AC_TRY_COMPILE([template <typename T>class TLSClass {
++          AC_TRY_COMPILE([#include <cstddef>
++              template <typename T>class TLSClass {
+               public: static ] $ax_tls_decl_keyword [ T *tlsvar;
+               };
+               class TLSClass2 {
================================================================

---- gitweb:

http://git.pld-linux.org/gitweb.cgi/packages/db5.3.git/commitdiff/22254daf7784aedef3c604b6ae874594e2461355



More information about the pld-cvs-commit mailing list