def set_many(self, kv_dict): """ Set the specified fields to the supplied values. Arguments: kv_dict (dict): A dictionary mapping :class:`~DjangoKeyValueStore.Key` objects to values to set. """ saved_fields = [] for kvs_key, value in sorted(kv_dict.items()): cache_key = self._cache_key_for_kvs_key(kvs_key) field_object = self._cache.get(cache_key) try: serialized_value = json.dumps(value) # It is safe to force an insert or an update, because # a) we should have retrieved the object as part of the # prefetch step, so if it isn't in our cache, it doesn't exist yet. # b) no other code should be modifying these models out of band of # this cache. if field_object is None: field_object = self._create_object(kvs_key, serialized_value) field_object.save(force_insert=True) self._cache[cache_key] = field_object else: field_object.value = serialized_value field_object.save(force_update=True) except DatabaseError: log.exception("Saving field %r failed", kvs_key.field_name) raise KeyValueMultiSaveError(saved_fields) finally: saved_fields.append(kvs_key.field_name)
def set_many(self, kv_dict): """ Set all of the fields specified by the keys of `kv_dict` to the values in that dict. Arguments: kv_dict (dict): dict mapping from `DjangoKeyValueStore.Key`s to field values Raises: DatabaseError if any fields fail to save """ if self.read_only: return saved_fields = [] by_scope = defaultdict(dict) for key, value in six.iteritems(kv_dict): if key.scope.user == UserScope.ONE and not self.user.is_anonymous: # If we're getting user data, we expect that the key matches the # user we were constructed for. assert key.user_id == self.user.id if key.scope not in self.cache: continue by_scope[key.scope][key] = value for scope, set_many_data in six.iteritems(by_scope): try: self.cache[scope].set_many(set_many_data) # If save is successful on these fields, add it to # the list of successful saves saved_fields.extend(key.field_name for key in set_many_data) except KeyValueMultiSaveError as exc: log.exception(u'Error saving fields %r', [key.field_name for key in set_many_data]) raise KeyValueMultiSaveError(saved_fields + exc.saved_field_names) # lint-amnesty, pylint: disable=raise-missing-from
def set_many(self, kv_dict): """ Provide a bulk save mechanism. `kv_dict`: A dictionary of dirty fields that maps xblock.KvsFieldData._key : value """ saved_fields = [] # field_objects maps a field_object to a list of associated fields field_objects = dict() for field in kv_dict: # Check field for validity if field.scope not in self._allowed_scopes: raise InvalidScopeError(field) # If the field is valid and isn't already in the dictionary, add it. field_object = self._field_data_cache.find_or_create(field) if field_object not in field_objects.keys(): field_objects[field_object] = [] # Update the list of associated fields field_objects[field_object].append(field) # Special case when scope is for the user state, because this scope saves fields in a single row if field.scope == Scope.user_state: state = json.loads(field_object.state) state[field.field_name] = kv_dict[field] field_object.state = json.dumps(state) else: # The remaining scopes save fields on different rows, so # we don't have to worry about conflicts field_object.value = json.dumps(kv_dict[field]) for field_object in field_objects: try: # Save the field object that we made above field_object.save() # If save is successful on this scope, add the saved fields to # the list of successful saves saved_fields.extend([ field.field_name for field in field_objects[field_object] ]) except DatabaseError: log.exception('Error saving fields %r', field_objects[field_object]) raise KeyValueMultiSaveError(saved_fields)
def set_many(self, kv_dict): """ Provide a bulk save mechanism. `kv_dict`: A dictionary of dirty fields that maps xblock.KvsFieldData._key : value """ saved_fields = [] # field_objects maps id(field_object) to a the object and a list of associated fields. # We use id() because FieldDataCache might return django models with no primary key # set, but will return the same django model each time the same key is passed in. dirty_field_objects = defaultdict(lambda: (None, [])) for key in kv_dict: # Check key for validity if key.scope not in self._allowed_scopes: raise InvalidScopeError(key) field_object = self._field_data_cache.find_or_create(key) # Update the list dirtied field_objects _, dirty_names = dirty_field_objects.setdefault( id(field_object), (field_object, [])) dirty_names.append(key.field_name) # Special case when scope is for the user state, because this scope saves fields in a single row if key.scope == Scope.user_state: state = json.loads(field_object.state) state[key.field_name] = kv_dict[key] field_object.state = json.dumps(state) else: # The remaining scopes save fields on different rows, so # we don't have to worry about conflicts field_object.value = json.dumps(kv_dict[key]) for field_object, names in dirty_field_objects.values(): try: # Save the field object that we made above field_object.save(force_update=field_object.pk is not None) # If save is successful on this scope, add the saved fields to # the list of successful saves saved_fields.extend(names) except DatabaseError: log.exception('Error saving fields %r', names) raise KeyValueMultiSaveError(saved_fields)
def set_many(self, kv_dict): """ Set the specified fields to the supplied values. Arguments: kv_dict (dict): A dictionary mapping :class:`~DjangoKeyValueStore.Key` objects to values to set. """ pending_updates = defaultdict(dict) for kvs_key, value in kv_dict.items(): cache_key = self._cache_key_for_kvs_key(kvs_key) pending_updates[cache_key][kvs_key.field_name] = value try: self._client.set_many(self.user.username, pending_updates) except DatabaseError: raise KeyValueMultiSaveError([]) finally: self._cache.update(pending_updates)
def set_many(self, kv_dict): """ Set the specified fields to the supplied values. Arguments: kv_dict (dict): A dictionary mapping :class:`~DjangoKeyValueStore.Key` objects to values to set. """ pending_updates = defaultdict(dict) for kvs_key, value in kv_dict.items(): cache_key = self._cache_key_for_kvs_key(kvs_key) pending_updates[cache_key][kvs_key.field_name] = value try: self._client.set_many(self.user.username, pending_updates) except DatabaseError: log.exception("Saving user state failed for %s", self.user.username) raise KeyValueMultiSaveError([]) # lint-amnesty, pylint: disable=raise-missing-from finally: self._cache.update(pending_updates)
def fake_set_many(block, update_dict): # pylint: disable=unused-argument """Mock update method that throws a KeyValueMultiSaveError indicating that no fields were correctly saved.""" raise KeyValueMultiSaveError([])
def fake_set_many(block, update_dict): # pylint: disable=unused-argument """Mock update method that throws a KeyValueMultiSaveError indicating that only one field was correctly saved.""" raise KeyValueMultiSaveError([update_dict.keys()[0]])
def fake_set_many(block, update_dict): """Mock update method that throws a KeyValueMultiSaveError indicating that no fields were correctly saved.""" raise KeyValueMultiSaveError([])