Пример #1
0
    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)
Пример #2
0
    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
Пример #3
0
    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)
Пример #4
0
    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)
Пример #5
0
    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)
Пример #6
0
    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)
Пример #7
0
 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([])
Пример #8
0
 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]])
Пример #9
0
 def fake_set_many(block, update_dict):
     """Mock update method that throws a KeyValueMultiSaveError indicating
        that no fields were correctly saved."""
     raise KeyValueMultiSaveError([])