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
This commit is contained in:
parent
dc6508aae2
commit
7b4350a4cb
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue