From 6b0ae48381061ceded39bfbb6f942e58570fc819 Mon Sep 17 00:00:00 2001 From: Rodolfo Alonso Hernandez Date: Tue, 5 Jan 2021 12:29:46 +0000 Subject: [PATCH] Check the revision number only once When an OVO revision number transaction constraint is requested in the HTTP header, the OVO standard attributes revision number should be checked only once, because: - The revision number constrain refers to a single resource; only a single check is needed. - Some backends (OVN), execute more than one DB transaction. As reported in the related LP bug, the second time the OVO is checked during the second DB transaction, the revision number of the OVO has been bumped and does not match with the original number requested. Closes-Bug: #1909008 Change-Id: I25c36b1604e5855a22960f1b504a79f740c134bb --- neutron/services/revisions/revision_plugin.py | 7 ++++++- .../unit/services/revisions/test_revision_plugin.py | 12 ++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/neutron/services/revisions/revision_plugin.py b/neutron/services/revisions/revision_plugin.py index bf94fb5d6a4..93c415fe2fd 100644 --- a/neutron/services/revisions/revision_plugin.py +++ b/neutron/services/revisions/revision_plugin.py @@ -259,7 +259,12 @@ class RevisionPlugin(service_base.ServicePluginBase): to match. """ context = session.info.get('using_context') - criteria = context.get_transaction_constraint() if context else None + if context: + # NOTE(ralonsoh): use "pop_transaction_constraint" once implemented + criteria = context.get_transaction_constraint() + context.clear_transaction_constraint() + else: + criteria = None if not criteria: return None, None match = criteria.if_revision_match diff --git a/neutron/tests/unit/services/revisions/test_revision_plugin.py b/neutron/tests/unit/services/revisions/test_revision_plugin.py index 48ed29e91c8..fe035b4968b 100644 --- a/neutron/tests/unit/services/revisions/test_revision_plugin.py +++ b/neutron/tests/unit/services/revisions/test_revision_plugin.py @@ -155,8 +155,20 @@ class TestRevisionPlugin(test_plugin.Ml2PluginV2TestCase): raise db_exc.DBDeadlock() db_api.sqla_listen(se.Session, 'before_commit', concurrent_increment) + + # Despite the revision number is bumped twice during the session + # transaction, the revision number is tested only once the first + # time the revision number service is executed for this session and + # object. self._update('ports', port['port']['id'], new, headers={'If-Match': 'revision_number=%s' % rev}, + expected_code=exc.HTTPOk.code) + self._update('ports', port['port']['id'], new, + headers={'If-Match': 'revision_number=%s' % + str(int(rev) + 2)}, + expected_code=exc.HTTPOk.code) + self._update('ports', port['port']['id'], new, + headers={'If-Match': 'revision_number=1'}, expected_code=exc.HTTPPreconditionFailed.code) def test_port_ip_update_revises(self):