summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nova/db/sqlalchemy/api.py36
-rw-r--r--nova/db/sqlalchemy/migrate_repo/versions/155_add_task_log_uc.py40
-rw-r--r--nova/tests/test_db_api.py7
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,