diff options
author | Kevin Benton <kevin@benton.pub> | 2016-09-07 17:11:06 -0700 |
---|---|---|
committer | Kevin Benton <kevin@benton.pub> | 2016-09-08 13:00:07 +0000 |
commit | 7b4350a4cb6da34b92deb578a0af837bcf14e023 (patch) | |
tree | 779b7a0ef7cfbe1268e2ef8a7b403797b8c183c5 /neutron/db/provisioning_blocks.py | |
parent | dc6508aae2819f2b718785b4da2c11f30bdc3ffd (diff) | |
download | neutron-7b4350a4cb6da34b92deb578a0af837bcf14e023.tar.gz |
Don't use nested transaction in provisioning blocks
Relying on duplicate entries for existing provisioning
block detection led to lots of log noise whenever we
would encounter a deadlock because the savepoint would
go missing. Additionally, since this would happen inside
of another transaction, we couldn't be guaranteed until
the final commit that this was unique anyway so the whole
transaction could throw a duplicate exception.
Since the outer transaction has to handle duplicate exceptions
anyway, this patch just adjusts the logic to check for the
existing of a record first with a regular query. If there
is a race the outer transaction will still fail with a duplicate
as before, but we at least won't have a bunch of missing savepoint
exception noise.
Closes-Bug: #1613759
Change-Id: I02d30427505591e24d7bdc1ba654d3757ab9a33d
Diffstat (limited to 'neutron/db/provisioning_blocks.py')
-rw-r--r-- | neutron/db/provisioning_blocks.py | 17 |
1 files changed, 8 insertions, 9 deletions
diff --git a/neutron/db/provisioning_blocks.py b/neutron/db/provisioning_blocks.py index 4c57bc7b17..1cc02f30b2 100644 --- a/neutron/db/provisioning_blocks.py +++ b/neutron/db/provisioning_blocks.py @@ -14,14 +14,12 @@ # from neutron_lib.db import model_base -from oslo_db import exception as db_exc from oslo_log import log as logging import sqlalchemy as sa from neutron._i18n import _LE from neutron.callbacks import registry from neutron.callbacks import resources -from neutron.db import api as db_api from neutron.db import models_v2 from neutron.db import standard_attr @@ -56,7 +54,7 @@ def add_provisioning_component(context, object_id, object_type, entity): of the entity that is doing the provisioning. While an object has these provisioning blocks present, this module will not emit any callback events indicating that provisioning has completed. Any logic that depends on - multiple disjoint components use these blocks and subscribe to the + multiple disjoint components may use these blocks and subscribe to the PROVISIONING_COMPLETE event to know when all components have completed. :param context: neutron api request context @@ -69,17 +67,18 @@ def add_provisioning_component(context, object_id, object_type, entity): standard_attr_id = _get_standard_attr_id(context, object_id, object_type) if not standard_attr_id: return - try: - with db_api.autonested_transaction(context.session): - record = ProvisioningBlock(standard_attr_id=standard_attr_id, - entity=entity) - context.session.add(record) - except db_exc.DBDuplicateEntry: + record = context.session.query(ProvisioningBlock).filter_by( + standard_attr_id=standard_attr_id, entity=entity).first() + if record: # an entry could be leftover from a previous transition that hasn't # yet been provisioned. (e.g. multiple updates in a short period) LOG.debug("Ignored duplicate provisioning block setup for %(otype)s " "%(oid)s by entity %(entity)s.", log_dict) return + with context.session.begin(subtransactions=True): + record = ProvisioningBlock(standard_attr_id=standard_attr_id, + entity=entity) + context.session.add(record) LOG.debug("Transition to ACTIVE for %(otype)s object %(oid)s " "will not be triggered until provisioned by entity %(entity)s.", log_dict) |