Don't try resource-level locks when stack locked
The actions SUSPEND, RESUME, SNAPSHOT, CHECK, and also DELETE when
abandoning rather than deleting a stack, have not (yet) been converted
to the convergence workflow and still do a legacy-style in-memory
traversal with the Stack lock held, even on stacks with convergence
enabled. Since a7376f7494
we have been
attempting to get a lock on the Resource to do these operations, even
though there is no engine ID set (which caused a WARNING-level log). For
these operations, respect existing Resource locks when convergence is
enabled, but don't try to acquire the lock.
Change-Id: I6f232380398a7caf9664717debfe39e3422e70d8
Related-Bug: #1727142
Related-Bug: #1662585
This commit is contained in:
parent
86fcc11b80
commit
1d24d47e7e
|
@ -796,6 +796,22 @@ class Resource(status.ResourceStatus):
|
||||||
else:
|
else:
|
||||||
self._atomic_key = last_key + 1
|
self._atomic_key = last_key + 1
|
||||||
|
|
||||||
|
def _should_lock_on_action(self, action):
|
||||||
|
"""Return whether we should take a resource-level lock for an action.
|
||||||
|
|
||||||
|
In the legacy path, we always took a lock at the Stack level and never
|
||||||
|
at the Resource level. In convergence, we lock at the Resource level
|
||||||
|
for most operations. However, there are currently some exceptions:
|
||||||
|
the SUSPEND, RESUME, SNAPSHOT, and CHECK actions, and stack abandon.
|
||||||
|
"""
|
||||||
|
return (self.stack.convergence and
|
||||||
|
not self.abandon_in_progress and
|
||||||
|
action in {self.ADOPT,
|
||||||
|
self.CREATE,
|
||||||
|
self.UPDATE,
|
||||||
|
self.ROLLBACK,
|
||||||
|
self.DELETE})
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def _action_recorder(self, action, expected_exceptions=tuple()):
|
def _action_recorder(self, action, expected_exceptions=tuple()):
|
||||||
"""Return a context manager to record the progress of an action.
|
"""Return a context manager to record the progress of an action.
|
||||||
|
@ -811,8 +827,12 @@ class Resource(status.ResourceStatus):
|
||||||
attempts = 1
|
attempts = 1
|
||||||
first_iter = [True] # work around no nonlocal in py27
|
first_iter = [True] # work around no nonlocal in py27
|
||||||
if self.stack.convergence:
|
if self.stack.convergence:
|
||||||
lock_acquire = self.LOCK_ACQUIRE
|
if self._should_lock_on_action(action):
|
||||||
lock_release = self.LOCK_RELEASE
|
lock_acquire = self.LOCK_ACQUIRE
|
||||||
|
lock_release = self.LOCK_RELEASE
|
||||||
|
else:
|
||||||
|
lock_acquire = lock_release = self.LOCK_RESPECT
|
||||||
|
|
||||||
if action != self.CREATE:
|
if action != self.CREATE:
|
||||||
attempts += max(cfg.CONF.client_retry_limit, 0)
|
attempts += max(cfg.CONF.client_retry_limit, 0)
|
||||||
else:
|
else:
|
||||||
|
@ -2000,11 +2020,14 @@ class Resource(status.ResourceStatus):
|
||||||
self._rsrc_metadata = metadata
|
self._rsrc_metadata = metadata
|
||||||
|
|
||||||
if self.id is not None:
|
if self.id is not None:
|
||||||
if (lock == self.LOCK_NONE or self._calling_engine_id is None):
|
if (lock == self.LOCK_NONE or
|
||||||
|
(lock in {self.LOCK_ACQUIRE, self.LOCK_RELEASE} and
|
||||||
|
self._calling_engine_id is None)):
|
||||||
resource_objects.Resource.update_by_id(
|
resource_objects.Resource.update_by_id(
|
||||||
self.context, self.id, rs)
|
self.context, self.id, rs)
|
||||||
if lock != self.LOCK_NONE:
|
if lock != self.LOCK_NONE:
|
||||||
LOG.warning("no calling_engine_id in store %s", str(rs))
|
LOG.error('No calling_engine_id in store() %s',
|
||||||
|
six.text_type(rs))
|
||||||
else:
|
else:
|
||||||
self._store_with_lock(rs, lock)
|
self._store_with_lock(rs, lock)
|
||||||
else:
|
else:
|
||||||
|
|
Loading…
Reference in New Issue