Fixing a bug in DB API method that acquires entity lock

* Before this change method acquire_lock() would override all changes
  made for an entity by a concurrent transaction when calling
  entity.update() although one line before it should have read this
  entity from DB and update only a timestamp to acquire the lock.
  The solution is just to append "FOR UPDATE" to an SQL statement
  when fetching an entity from DB. In this case we don't need to
  artificially update a timestamp at all.
* Unit test for MySQL or Postgres is currently impossible, all unit
  tests are run against sqlite
* Adding "PYTHONHASHSEED = 0" into "venv" environment in tox.ini to
  prevent sphinx from failing. It should be added to "venv" because
  docs building run with command "tox -evenv -- python setup.py build_sphinx".
* Fixed minor style issues

Change-Id: Ia749f397e18e927820ff7ae6bac7d28dc2aa2ba4
(cherry picked from commit 3e9aa8b310)
This commit is contained in:
Renat Akhmerov 2016-03-23 13:03:16 +06:00
parent e4d82cf03c
commit 1333f2a222
3 changed files with 11 additions and 13 deletions

View File

@ -21,7 +21,6 @@ from oslo_db import exception as db_exc
from oslo_db import sqlalchemy as oslo_sqlalchemy
from oslo_db.sqlalchemy import utils as db_utils
from oslo_log import log as logging
from oslo_utils import timeutils
from oslo_utils import uuidutils
import sqlalchemy as sa
@ -96,20 +95,16 @@ def acquire_lock(model, id, session=None):
# will be up-to-date from the DB and not from cache.
session.expire_all()
if b.get_driver_name() != 'sqlite':
entity = _get_one_entity(model, id)
entity.update({'updated_at': timeutils.utcnow()})
else:
if b.get_driver_name() == 'sqlite':
# In case of 'sqlite' we need to apply a manual lock.
sqlite_lock.acquire_lock(id, session)
entity = _get_one_entity(model, id)
return entity
return _lock_entity(model, id)
def _get_one_entity(model, id):
# Get entity by ID and expect exactly one object.
return _secure_query(model).filter(model.id == id).one()
def _lock_entity(model, id):
# Get entity by ID in "FOR UPDATE" mode and expect exactly one object.
return _secure_query(model).with_for_update().filter(model.id == id).one()
def _secure_query(model, *columns):

View File

@ -70,8 +70,8 @@ class WorkflowController(object):
according to this workflow type rules and identifies a list of
commands needed to continue the workflow.
:param: task_ex: Task execution to rerun.
:param: reset: If true, then purge action executions for the tasks.
:param task_ex: Task execution to rerun.
:param reset: If true, then purge action executions for the tasks.
:param env: A set of environment variables to overwrite.
:return: List of workflow commands (instances of
mistral.workflow.commands.WorkflowCommand).
@ -88,6 +88,7 @@ class WorkflowController(object):
def is_error_handled_for(self, task_ex):
"""Determines if error is handled for specific task.
:param task_ex: Task execution perform a check for.
:return: True if either there is no error at all or
error is considered handled.
"""

View File

@ -39,7 +39,9 @@ commands =
oslo-config-generator --config-file tools/config/config-generator.mistral.conf \
--output-file etc/mistral.conf.sample
#set PYTHONHASHSEED=0 to prevent wsmeext.sphinxext from randomly failing.
[testenv:venv]
setenv = PYTHONHASHSEED=0
commands = {posargs}
[testenv:docs]