diff --git a/cinder/db/api.py b/cinder/db/api.py index b5e66906ac4..b8792edf152 100644 --- a/cinder/db/api.py +++ b/cinder/db/api.py @@ -294,12 +294,12 @@ def service_create(context, values): return IMPL.service_create(context, values) -def service_update(context, service_id, values): +def service_update(context, service_id, values, retry=True): """Set the given properties on an service and update it. Raises NotFound if service does not exist. """ - return IMPL.service_update(context, service_id, values) + return IMPL.service_update(context, service_id, values, retry) def service_get_by_uuid(context, service_uuid): diff --git a/cinder/db/sqlalchemy/api.py b/cinder/db/sqlalchemy/api.py index 0fe7596ba0f..426bd4f65a1 100644 --- a/cinder/db/sqlalchemy/api.py +++ b/cinder/db/sqlalchemy/api.py @@ -936,21 +936,32 @@ def service_create(context, values): @require_admin_context -@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) @main_context_manager.writer -def service_update(context, service_id, values): - query = _service_query(context, id=service_id) +def service_update(context, service_id, values, retry=True): + def _service_update(context, service_id, values): + query = _service_query(context, id=service_id) - if 'disabled' in values: - entity = query.column_descriptions[0]['entity'] + if 'disabled' in values: + entity = query.column_descriptions[0]['entity'] - values = values.copy() - values['modified_at'] = values.get('modified_at', timeutils.utcnow()) - values['updated_at'] = values.get('updated_at', entity.updated_at) + values = values.copy() + values['modified_at'] = values.get('modified_at', + timeutils.utcnow()) + values['updated_at'] = values.get('updated_at', + entity.updated_at) - result = query.update(values) - if not result: - raise exception.ServiceNotFound(service_id=service_id) + result = query.update(values) + if not result: + raise exception.ServiceNotFound(service_id=service_id) + + @oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) + def _service_update_retry(context, service_id, values): + _service_update(context, service_id, values) + + if retry: + _service_update_retry(context, service_id, values) + else: + _service_update(context, service_id, values) ################### diff --git a/cinder/objects/service.py b/cinder/objects/service.py index 347fcebd75f..0464e2ee34a 100644 --- a/cinder/objects/service.py +++ b/cinder/objects/service.py @@ -153,13 +153,13 @@ class Service(base.CinderPersistentObject, base.CinderObject, db_service = db.service_create(self._context, updates) self._from_db_object(self._context, self, db_service) - def save(self): + def save(self, retry=True): updates = self.cinder_obj_get_changes() if 'cluster' in updates: raise exception.ObjectActionError( action='save', reason=_('cluster changed')) if updates: - db.service_update(self._context, self.id, updates) + db.service_update(self._context, self.id, updates, retry) self.obj_reset_changes() def destroy(self): diff --git a/cinder/service.py b/cinder/service.py index 35e771bb67f..ee9eba9380c 100644 --- a/cinder/service.py +++ b/cinder/service.py @@ -486,7 +486,7 @@ class Service(service.Service): if self.availability_zone != service_ref.availability_zone: service_ref.availability_zone = self.availability_zone - service_ref.save() + service_ref.save(retry=False) # TODO(termie): make this pattern be more elegant. if getattr(self, 'model_disconnected', False): diff --git a/cinder/tests/unit/api/contrib/test_services.py b/cinder/tests/unit/api/contrib/test_services.py index ebe728f7cf3..5f1b55be69d 100644 --- a/cinder/tests/unit/api/contrib/test_services.py +++ b/cinder/tests/unit/api/contrib/test_services.py @@ -172,7 +172,7 @@ def fake_service_get_by_id(value): return None -def fake_service_update(context, service_id, values): +def fake_service_update(context, service_id, values, retry=True): service = fake_service_get_by_id(service_id) if service is None: raise exception.ServiceNotFound(service_id=service_id) diff --git a/cinder/tests/unit/objects/test_service.py b/cinder/tests/unit/objects/test_service.py index 91e5b631dbb..17106ae6dfb 100644 --- a/cinder/tests/unit/objects/test_service.py +++ b/cinder/tests/unit/objects/test_service.py @@ -77,7 +77,7 @@ class TestService(test_objects.BaseObjectsTestCase): service.topic = 'foobar' service.save() service_update.assert_called_once_with(self.context, service.id, - {'topic': 'foobar'}) + {'topic': 'foobar'}, True) @mock.patch('oslo_utils.timeutils.utcnow', return_value=timeutils.utcnow()) @mock.patch('cinder.db.sqlalchemy.api.service_destroy')