From c46edbc7d62585b0181dfe4bb72c1be0620fc937 Mon Sep 17 00:00:00 2001 From: Kevin Benton Date: Mon, 18 Jul 2016 22:39:19 -0600 Subject: [PATCH] Use db_api.retry_db_errors in quota engine The quota engine was still using oslo_db wrap_db_retry which does not automatically take into account deadlocks that occur inside of nested savepoint transactions. In one case it didn't matter because it passed in the correct exception checker but in the one that protected 'set_quota_usage' it did not use is_retriable so a deadlock inside of the savepoint would have resulted in a much more expensive retry all of the way up at the API layer. This patch just adjusts them to both use the standard neutron retry_db_errors decorator. Change-Id: I1e45eb15f14bf35881e5b1dce77733e831e9c6b1 Related-Bug: #1596075 --- doc/source/devref/quota.rst | 2 +- neutron/db/quota/driver.py | 7 +------ neutron/quota/resource.py | 8 +------- 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/doc/source/devref/quota.rst b/doc/source/devref/quota.rst index af0ff2fc920..52431c43ed8 100644 --- a/doc/source/devref/quota.rst +++ b/doc/source/devref/quota.rst @@ -217,7 +217,7 @@ In order to ensure correct operations, a row-level lock is acquired in the transaction which creates the reservation. The lock is acquired when reading usage data. In case of write-set certification failures, which can occur in active/active clusters such as MySQL galera, the decorator -oslo_db.api.wrap_db_retry will retry the transaction if a DBDeadLock +neutron.db.api.retry_db_errors will retry the transaction if a DBDeadLock exception is raised. While non-locking approaches are possible, it has been found out that, since a non-locking algorithms increases the chances of collision, the cost of diff --git a/neutron/db/quota/driver.py b/neutron/db/quota/driver.py index a063e4d8027..01532c5e95c 100644 --- a/neutron/db/quota/driver.py +++ b/neutron/db/quota/driver.py @@ -14,7 +14,6 @@ # under the License. from neutron_lib import exceptions -from oslo_db import api as oslo_db_api from oslo_log import log from neutron.common import exceptions as n_exc @@ -157,11 +156,7 @@ class DbQuotaDriver(object): quota_api.remove_expired_reservations( context, tenant_id=tenant_id) - @oslo_db_api.wrap_db_retry(max_retries=db_api.MAX_RETRIES, - retry_interval=0.1, - inc_retry_interval=True, - retry_on_request=True, - exception_checker=db_api.is_retriable) + @db_api.retry_db_errors def make_reservation(self, context, tenant_id, resources, deltas, plugin): # Lock current reservation table # NOTE(salv-orlando): This routine uses DB write locks. diff --git a/neutron/quota/resource.py b/neutron/quota/resource.py index 3a4244553ab..fbfdf775abb 100644 --- a/neutron/quota/resource.py +++ b/neutron/quota/resource.py @@ -13,8 +13,6 @@ # under the License. from oslo_config import cfg -from oslo_db import api as oslo_db_api -from oslo_db import exception as oslo_db_exception from oslo_log import log from oslo_utils import excutils from sqlalchemy import event @@ -209,11 +207,7 @@ class TrackedResource(BaseResource): # can happen is two or more workers are trying to create a resource of a # give kind for the same tenant concurrently. Retrying the operation will # ensure that an UPDATE statement is emitted rather than an INSERT one - @oslo_db_api.wrap_db_retry( - max_retries=db_api.MAX_RETRIES, - exception_checker=lambda exc: - isinstance(exc, (oslo_db_exception.DBDuplicateEntry, - oslo_db_exception.DBDeadlock))) + @db_api.retry_db_errors def _set_quota_usage(self, context, tenant_id, in_use): return quota_api.set_quota_usage( context, self.name, tenant_id, in_use=in_use)