Skip to content

Instantly share code, notes, and snippets.

@patrick-east
Created June 1, 2016 15:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save patrick-east/52c8b3782ea4a578e3cac3c45d5d7182 to your computer and use it in GitHub Desktop.
Save patrick-east/52c8b3782ea4a578e3cac3c45d5d7182 to your computer and use it in GitHub Desktop.
diff --git a/cinder/db/api.py b/cinder/db/api.py
index 73a48cf..5fc5566 100644
--- a/cinder/db/api.py
+++ b/cinder/db/api.py
@@ -1071,14 +1071,25 @@ def get_booleans_for_table(table_name):
###################
-def driver_initiator_data_update(context, initiator, namespace, updates):
- """Create DriverPrivateData from the values dictionary."""
- return IMPL.driver_initiator_data_update(context, initiator,
- namespace, updates)
+def driver_initiator_data_set_by_key(context, initiator, namespace, key,
+ value, expected):
+ """Updates DriverInitiatorData entry.
+
+ Sets the value for the specified key within the namespace.
+
+ If expected values are provided a conditional update is done, if it fails
+ this will return false.
+ """
+ return IMPL.driver_initiator_data_set_by_key(context,
+ initiator,
+ namespace,
+ key,
+ value,
+ expected)
def driver_initiator_data_get(context, initiator, namespace):
- """Query for an DriverPrivateData that has the specified key"""
+ """Query for an DriverInitiatorData that has the specified key"""
return IMPL.driver_initiator_data_get(context, initiator, namespace)
diff --git a/cinder/db/sqlalchemy/api.py b/cinder/db/sqlalchemy/api.py
index b1566ec..66d313b 100644
--- a/cinder/db/sqlalchemy/api.py
+++ b/cinder/db/sqlalchemy/api.py
@@ -4346,35 +4346,33 @@ def message_destroy(context, message):
@require_context
-def driver_initiator_data_update(context, initiator, namespace, updates):
- session = get_session()
- with session.begin():
- set_values = updates.get('set_values', {})
- for key, value in set_values.items():
- data = session.query(models.DriverInitiatorData).\
- filter_by(initiator=initiator).\
- filter_by(namespace=namespace).\
- filter_by(key=key).\
- first()
+def driver_initiator_data_set_by_key(context, initiator, namespace,
+ key, value, expected):
+ if expected is None:
+ expected_values = {}
+ else:
+ expected_values = expected.copy()
+
+ expected_values.update({
+ 'initiator': initiator,
+ 'namespace': namespace,
+ 'key': key,
+ })
+
+ result = _conditional_update(context, models.DriverInitiatorData,
+ {'value': value}, expected_values)
+
+ # Didn't update anything, so add the new key
+ if 0 == result:
+ data = models.DriverInitiatorData()
+ data.initiator = initiator
+ data.namespace = namespace
+ data.key = key
+ data.value = value
+ session = get_session()
+ with session.begin():
+ session.add(data)
- if data:
- data.update({'value': value})
- data.save(session=session)
- else:
- data = models.DriverInitiatorData()
- data.initiator = initiator
- data.namespace = namespace
- data.key = key
- data.value = value
- session.add(data)
-
- remove_values = updates.get('remove_values', [])
- for key in remove_values:
- session.query(models.DriverInitiatorData).\
- filter_by(initiator=initiator).\
- filter_by(namespace=namespace).\
- filter_by(key=key).\
- delete()
@require_context
@@ -4590,9 +4588,17 @@ def _check_is_not_multitable(values, model):
@require_context
-@_retry_on_deadlock
def conditional_update(context, model, values, expected_values, filters=(),
include_deleted='no', project_only=False, order=None):
+ result = _conditional_update(context, model, values, expected_values,
+ filters, include_deleted, project_only, order)
+ # Return True if we were able to change any DB entry, False otherwise
+ return 0 != result
+
+
+@_retry_on_deadlock
+def _conditional_update(context, model, values, expected_values, filters=(),
+ include_deleted='no', project_only=False, order=None):
"""Compare-and-swap conditional update SQLAlchemy implementation."""
_check_is_not_multitable(values, model)
@@ -4659,6 +4665,4 @@ def conditional_update(context, model, values, expected_values, filters=(),
# And we have to tell SQLAlchemy that we want to preserve the order
update_args['update_args'] = {'preserve_parameter_order': True}
- # Return True if we were able to change any DB entry, False otherwise
- result = query.update(values, **update_args)
- return 0 != result
+ return query.update(values, **update_args)
diff --git a/cinder/volume/driver_utils.py b/cinder/volume/driver_utils.py
index cc408f4..c851eb4 100644
--- a/cinder/volume/driver_utils.py
+++ b/cinder/volume/driver_utils.py
@@ -48,12 +48,26 @@ class VolumeDriverUtils(object):
'namespace': self._data_namespace})
raise
- def save_driver_initiator_data(self, initiator, model_update, ctxt=None):
+ def save_driver_initiator_data(self, initiator, key, value,
+ expected=None, ctxt=None):
+ """ Update the initiator data at key with value.
+
+ If expected has been provided we will do a conditional update. If it
+ fails then this will return False. Otherwise return True.
+
+ Expected should be a dictionary in the form of
+ {'value': expected_value}. This allows for an expected value of None
+ to be specified. Any fields other than 'value' are ignored.
+ """
try:
- self._db.driver_initiator_data_update(self._get_context(ctxt),
- initiator,
- self._data_namespace,
- model_update)
+ return self._db.driver_initiator_data_set_by_key(
+ self._get_context(ctxt),
+ initiator,
+ self._data_namespace,
+ key,
+ value,
+ expected
+ )
except exception.CinderException:
LOG.exception(_LE("Failed to update initiator data for"
" initiator %(initiator)s and backend"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment