Bug#1110851: trixie-pu: package python-oslo.db/17.2.1-2
Package: release.debian.org
Severity: normal
Tags: trixie
X-Debbugs-Cc: python-oslo.db@packages.debian.org
Control: affects -1 + src:python-oslo.db
User: release.debian.org@packages.debian.org
Usertags: pu
Hi,
[ Reason ]
Starting at mariadb 11.6.2, there's a new mode that is on by
default: innodb_snapshot_isolation.
With that version, one must have to set:
innodb_snapshot_isolation = OFF
in my.cnf, otherwise, all of OpenStack fails. This patch makes
it possible to not require this configuration, which is otherwise
surprising to users. This patch handles MariaDB error 1020 "Record has
changed since last read" which occurs under REPEATABLE-READ isolation
level when MariaDB detects that a row has changed since it was last read
in the current transaction.
[ Impact ]
Users of OpenStack on Trixie not knowing about this, and having
innodb_snapshot_isolation set to ON (the default) will have a non-working
setup.
[ Tests ]
Ran all in my CI, that deploys all of OpenStack, and saw no issue.
[ Risks ]
No risk because of the tests.
[ Checklist ]
[x] *all* changes are documented in the d/changelog
[x] I reviewed all changes and I approve them
[x] attach debdiff against the package in (old)stable
[x] the issue is verified as fixed in unstable
Please allow me to upload python-oslo.db_17.2.1-2+deb13u1
Cheers,
Thomas Goirand (zigo)
diff -Nru python-oslo.db-17.2.1/debian/changelog python-oslo.db-17.2.1/debian/changelog
--- python-oslo.db-17.2.1/debian/changelog 2025-03-28 10:19:31.000000000 +0100
+++ python-oslo.db-17.2.1/debian/changelog 2025-08-11 11:35:58.000000000 +0200
@@ -1,3 +1,10 @@
+python-oslo.db (17.2.1-2+deb13u1) trixie; urgency=medium
+
+ * Add patch:
+ Add_MariaDB_error_1020_handling_as_DBConsistencyError_subclass_....patch.
+
+ -- Thomas Goirand <zigo@debian.org> Mon, 11 Aug 2025 11:35:58 +0200
+
python-oslo.db (17.2.1-2) unstable; urgency=medium
* Uploading to unstable.
diff -Nru python-oslo.db-17.2.1/debian/patches/Add_MariaDB_error_1020_handling_as_DBConsistencyError_subclass_of_DBDeadlock.patch python-oslo.db-17.2.1/debian/patches/Add_MariaDB_error_1020_handling_as_DBConsistencyError_subclass_of_DBDeadlock.patch
--- python-oslo.db-17.2.1/debian/patches/Add_MariaDB_error_1020_handling_as_DBConsistencyError_subclass_of_DBDeadlock.patch 1970-01-01 01:00:00.000000000 +0100
+++ python-oslo.db-17.2.1/debian/patches/Add_MariaDB_error_1020_handling_as_DBConsistencyError_subclass_of_DBDeadlock.patch 2025-08-11 11:35:58.000000000 +0200
@@ -0,0 +1,186 @@
+Author: Hervé Beraud <hberaud@redhat.com>
+Date: Wed, 16 Jul 2025 15:02:27 +0200
+Subject: Add MariaDB error 1020 handling as DBConsistencyError subclass of DBDeadlock
+ MariaDB under REPEATABLE-READ isolation level can raise error 1020
+ "Record has changed since last read" when it detects that a row has
+ changed since it was last read in the current transaction. This is
+ part of MariaDB's transaction validation model and has been observed
+ in OpenStack services like Nova and Keystone.
+ .
+ This change adds:
+ * New DBConsistencyError exception class that inherits from DBDeadlock
+ * Updated DBDeadlock docstring to cover all concurrent access conflicts
+ * Filter in exc_filters.py to detect and handle MariaDB error 1020
+ * Unit tests to verify proper detection and wrapping
+ .
+ The inheritance model ensures that existing retry decorators and error
+ handling code that catch DBDeadlock will automatically handle this new
+ MariaDB consistency error, providing seamless backward compatibility
+ while properly categorizing the error as a transient concurrency issue.
+ .
+ This provides better error handling for applications using oslo.db
+ with MariaDB and allows existing retry mechanisms to work without
+ modification.
+ .
+ For more details about this new isolation level in InnoDB, please
+ see https://mariadb.com/resources/blog/isolation-level-violation-testing-and-debugging-in-mariadb/
+Bug: https://launchpad.net/bugs/2116186
+Change-Id: Ie7c558ee6b82c206263227260806ca55ebdb77a9
+Signed-off-by: Hervé Beraud <hberaud@redhat.com>
+Generated-By: Claude Sonnet 4
+Origin: upstream, https://review.opendev.org/c/openstack/oslo.db/+/957009
+Last-Update: 2025-08-11
+
+diff --git a/oslo_db/exception.py b/oslo_db/exception.py
+index 1205552..379fd0a 100644
+--- a/oslo_db/exception.py
++++ b/oslo_db/exception.py
+@@ -167,17 +167,32 @@
+
+ class DBDeadlock(DBError):
+
+- """Database dead lock error.
++ """Database deadlock error.
+
+- Deadlock is a situation that occurs when two or more different database
+- sessions have some data locked, and each database session requests a lock
+- on the data that another, different, session has already locked.
++ Raised when a database operation fails due to concurrent access conflicts,
++ including traditional deadlocks where two or more database sessions have
++ conflicting locks, as well as other transient concurrency issues like
++ consistency validation failures. These conditions are typically resolved
++ by retrying the transaction.
+ """
+
+ def __init__(self, inner_exception=None):
+ super().__init__(inner_exception)
+
+
++class DBConsistencyError(DBDeadlock):
++
++ """Database consistency error.
++
++ Raised when a database operation fails due to consistency requirements,
++ such as when MariaDB detects that a row has changed since it was last
++ read in the current transaction under REPEATABLE-READ isolation level.
++ This is a subclass of DBDeadlock as it represents the same kind of
++ transient concurrency issue that can be resolved by retrying the
++ transaction.
++ """
++
++
+ class DBInvalidUnicodeParameter(Exception):
+
+ """Database unicode error.
+diff --git a/oslo_db/sqlalchemy/exc_filters.py b/oslo_db/sqlalchemy/exc_filters.py
+index 0aa9772..9b7532e 100644
+--- a/oslo_db/sqlalchemy/exc_filters.py
++++ b/oslo_db/sqlalchemy/exc_filters.py
+@@ -92,6 +92,25 @@
+ raise exception.DBDeadlock(operational_error)
+
+
++@filters("mysql", sqla_exc.OperationalError,
++ r"^.*\b1020\b.*Record has changed since last read.*")
++def _mariadb_consistency_error(operational_error, match, engine_name,
++ is_disconnect):
++ """Filter for MariaDB consistency error.
++
++ MariaDB under REPEATABLE-READ isolation level can raise error 1020
++ when it detects that a row has changed since it was last read in the
++ current transaction. This is part of MariaDB's transaction validation
++ model and typically indicates a transient condition that can be resolved
++ by retrying the transaction.
++
++ Example error message:
++ (OperationalError) (pymysql.err.OperationalError) (1020,
++ "Record has changed since last read in table 'table_name'")
++ """
++ raise exception.DBConsistencyError(operational_error)
++
++
+ @filters("mysql", sqla_exc.IntegrityError,
+ r"^.*\b1062\b.*Duplicate entry '(?P<value>.*)'"
+ r" for key '(?P<columns>[^']+)'.*$")
+diff --git a/oslo_db/tests/sqlalchemy/test_exc_filters.py b/oslo_db/tests/sqlalchemy/test_exc_filters.py
+index fe00db8..21d806f 100644
+--- a/oslo_db/tests/sqlalchemy/test_exc_filters.py
++++ b/oslo_db/tests/sqlalchemy/test_exc_filters.py
+@@ -1053,6 +1053,48 @@
+ )
+
+
++class TestMariaDBConsistencyError(TestsExceptionFilter):
++ """Test MariaDB consistency error detection."""
++
++ statement = ('UPDATE users SET status = :status_1 '
++ 'WHERE users.id = :id_1')
++ params = {
++ 'status_1': 'active',
++ 'id_1': 123
++ }
++
++ def _run_consistency_error_test(
++ self, dialect_name, message,
++ orig_exception_cls=TestsExceptionFilter.OperationalError):
++ self._run_test(
++ dialect_name, self.statement,
++ orig_exception_cls(message),
++ exception.DBConsistencyError,
++ params=self.params
++ )
++
++ def test_mariadb_pymysql_consistency_error(self):
++ self._run_consistency_error_test(
++ "mysql",
++ "(1020, \"Record has changed since "
++ "last read in table 'test_table'\")"
++ )
++
++ def test_mariadb_mysqlconnector_consistency_error(self):
++ self._run_consistency_error_test(
++ "mysql",
++ "1020 (HY000): Record has changed since "
++ "last read in table 'test_table'"
++ )
++
++ def test_mariadb_consistency_error_with_details(self):
++ self._run_consistency_error_test(
++ "mysql",
++ "(1020, \"Record has changed since last read "
++ "in table 'users' (transaction id 12345)\")"
++ )
++
++
+ class TestDataError(TestsExceptionFilter):
+ def _run_bad_data_test(self, dialect_name, message, error_class):
+ self._run_test(dialect_name,
+diff --git a/releasenotes/notes/handle-mariadb-transactional-error-d84c95cdb4d3b27f.yaml b/releasenotes/notes/handle-mariadb-transactional-error-d84c95cdb4d3b27f.yaml
+new file mode 100644
+index 0000000..e8d2b38
+--- /dev/null
++++ b/releasenotes/notes/handle-mariadb-transactional-error-d84c95cdb4d3b27f.yaml
+@@ -0,0 +1,23 @@
++---
++features:
++ - |
++ Added support for detecting and handling MariaDB error 1020 "Record has
++ changed since last read" which occurs under REPEATABLE-READ isolation
++ level when MariaDB detects that a row has changed since it was last read
++ in the current transaction. This error is now wrapped in a new
++ ``DBConsistencyError`` exception class that inherits from ``DBDeadlock``,
++ ensuring that existing retry decorators and error handling code will
++ automatically handle this transient concurrency condition.
++fixes:
++ - |
++ Fixed handling of MariaDB error 1020 that was previously not properly
++ categorized by oslo.db's exception filtering system. This error, which
++ can occur in OpenStack services like Nova and Keystone when using MariaDB
++ with REPEATABLE-READ isolation level, is now properly wrapped in a
++ ``DBConsistencyError`` exception (a subclass of ``DBDeadlock``) instead
++ of being passed through as a generic ``OperationalError``. This ensures
++ that existing retry mechanisms that handle deadlock-like conditions will
++ automatically work with this MariaDB-specific consistency error.
++
++ For more details, see `bug 2116186
++ <https://bugs.launchpad.net/nova/+bug/2116186>`_.
diff -Nru python-oslo.db-17.2.1/debian/patches/series python-oslo.db-17.2.1/debian/patches/series
--- python-oslo.db-17.2.1/debian/patches/series 1970-01-01 01:00:00.000000000 +0100
+++ python-oslo.db-17.2.1/debian/patches/series 2025-08-11 11:35:58.000000000 +0200
@@ -0,0 +1 @@
+Add_MariaDB_error_1020_handling_as_DBConsistencyError_subclass_of_DBDeadlock.patch
Reply to: