diff options
-rw-r--r-- | nova/db/sqlalchemy/api.py | 36 | ||||
-rw-r--r-- | nova/db/sqlalchemy/migrate_repo/versions/155_add_task_log_uc.py | 40 | ||||
-rw-r--r-- | nova/tests/test_db_api.py | 7 |
3 files changed, 62 insertions, 21 deletions
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index eb9181fce..375a3884b 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -4756,27 +4756,21 @@ def task_log_get_all(context, task_name, period_beginning, period_ending, @require_admin_context def task_log_begin_task(context, task_name, period_beginning, period_ending, host, task_items=None, message=None): - # NOTE(boris-42): This method has a race condition and will be rewritten - # after bp/db-unique-keys implementation. - session = get_session() - with session.begin(): - task_ref = _task_log_get_query(context, task_name, period_beginning, - period_ending, host, session=session).\ - first() - if task_ref: - #It's already run(ning)! - raise exception.TaskAlreadyRunning(task_name=task_name, host=host) - task = models.TaskLog() - task.task_name = task_name - task.period_beginning = period_beginning - task.period_ending = period_ending - task.host = host - task.state = "RUNNING" - if message: - task.message = message - if task_items: - task.task_items = task_items - task.save(session=session) + + task = models.TaskLog() + task.task_name = task_name + task.period_beginning = period_beginning + task.period_ending = period_ending + task.host = host + task.state = "RUNNING" + if message: + task.message = message + if task_items: + task.task_items = task_items + try: + task.save() + except db_session.DBDuplicateEntry: + raise exception.TaskAlreadyRunning(task_name=task_name, host=host) @require_admin_context diff --git a/nova/db/sqlalchemy/migrate_repo/versions/155_add_task_log_uc.py b/nova/db/sqlalchemy/migrate_repo/versions/155_add_task_log_uc.py new file mode 100644 index 000000000..04e033544 --- /dev/null +++ b/nova/db/sqlalchemy/migrate_repo/versions/155_add_task_log_uc.py @@ -0,0 +1,40 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright (c) 2013 Boris Pavlovic (boris@pavlovic.me). +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from migrate.changeset import UniqueConstraint +from sqlalchemy import MetaData, Table + +from nova.db.sqlalchemy import utils + + +UC_NAME = "uniq_task_name_x_host_x_period_beginning_x_period_ending" +COLUMNS = ('task_name', 'host', 'period_beginning', 'period_ending') +TABLE_NAME = 'task_log' + + +def upgrade(migrate_engine): + meta = MetaData(bind=migrate_engine) + t = Table(TABLE_NAME, meta, autoload=True) + + utils.drop_old_duplicate_entries_from_table(migrate_engine, TABLE_NAME, + False, *COLUMNS) + uc = UniqueConstraint(*COLUMNS, table=t, name=UC_NAME) + uc.create() + + +def downgrade(migrate_engine): + utils.drop_unique_constraint(migrate_engine, TABLE_NAME, UC_NAME, *COLUMNS) diff --git a/nova/tests/test_db_api.py b/nova/tests/test_db_api.py index 835527219..27ca1ed8b 100644 --- a/nova/tests/test_db_api.py +++ b/nova/tests/test_db_api.py @@ -1792,6 +1792,13 @@ class TaskLogTestCase(test.TestCase): self.end, self.host) self.assertEqual(result['task_name'], 'fake') + def test_task_log_begin_task_duplicate(self): + params = (self.context, 'fake', self.begin, self.end, self.host) + db.task_log_begin_task(*params, message=self.message) + self.assertRaises(exception.TaskAlreadyRunning, + db.task_log_begin_task, + *params, message=self.message) + def test_task_log_end_task(self): errors = 1 db.task_log_end_task(self.context, self.task_name, self.begin, |