Ticket #14299: django-cache-add_many.diff

File django-cache-add_many.diff, 7.9 KB (added by Michael Manfre, 14 years ago)
  • django/core/cache/backends/base.py

     
    100100        # if a subclass overrides it.
    101101        return self.has_key(key)
    102102
     103    def add_many(self, data, timeout=None):
     104        """
     105        Set a bunch of values in the cache at once from a dict of key/value
     106        pairs.  For certain backends (memcached), this is much more efficient
     107        than calling add() multiple times.
     108
     109        If timeout is given, that timeout will be used for the key; otherwise
     110        the default cache timeout will be used.
     111
     112        Returns  dict() of key/bool pairs indicating whether or not the values
     113        were stored.
     114        """
     115        results = {}
     116        for key, value in data.items():
     117            results[key] = self.add(key, value, timeout)
     118        return results
     119
     120    def offset_many(self, data):
     121        """
     122        Add/Subtract a bunch of values in the cache at once from a dict of
     123        key/delta pairs. For certain backends (memcached), this is much more
     124        efficient than calling incr()/decr() multiple times.
     125       
     126        Returna  dict() of key/value pairs containing the new values. Value
     127        is False if the key did not exist.
     128        """
     129        results = {}
     130        for key, value in data.items():
     131            try:
     132                results[key] = self.incr(key, value)
     133            except ValueError:
     134                results[key] = False
     135        return results
     136
    103137    def set_many(self, data, timeout=None):
    104138        """
    105139        Set a bunch of values in the cache at once from a dict of key/value
  • django/core/cache/backends/dummy.py

     
    2727        self.validate_key(key)
    2828        return False
    2929
     30    def add_many(self, *args, **kwargs):
     31        pass
     32   
    3033    def set_many(self, *args, **kwargs):
    3134        pass
    3235
  • django/core/cache/backends/memcached.py

     
    6363        self._cache.disconnect_all()
    6464
    6565    def incr(self, key, delta=1):
     66        # memcached doesn't support a negative delta
     67        if delta < 0:
     68            return self.decr(key, -delta)
    6669        try:
    67             val = self._cache.incr(key, delta)
     70            val = self._cache.incr(smart_str(key), delta)
    6871
    6972        # python-memcache responds to incr on non-existent keys by
    7073        # raising a ValueError. Cmemcache returns None. In both
     
    7780        return val
    7881
    7982    def decr(self, key, delta=1):
     83        # memcached doesn't support a negative delta
     84        if delta < 0:
     85            return self.incr(key, -delta)
    8086        try:
    81             val = self._cache.decr(key, delta)
     87            val = self._cache.decr(smart_str(key), delta)
    8288
    8389        # python-memcache responds to decr on non-existent keys by
    8490        # raising a ValueError. Cmemcache returns None. In both
  • docs/topics/cache.txt

     
    594594
    595595Like ``cache.set()``, ``set_many()`` takes an optional ``timeout`` parameter.
    596596
     597.. versionadded:: 1.3
     598
     599To add multiple values more efficiently, use ``add_many()`` to pass a dictionary
     600of key-value pairs. ``add_many()`` returns a dictionary with all the keys passed
     601and their values being a bool indicating whether or not the value was added::
     602
     603        >>> cache.set('a', 1)
     604        >>> cache.add_many({'a': 2, 'b': 1})
     605        {'a': False, 'b': 1}
     606
    597607You can delete keys explicitly with ``delete()``. This is an easy way of
    598608clearing the cache for a particular object::
    599609
     
    641651    However, if the backend doesn't natively provide an increment/decrement
    642652    operation, it will be implemented using a two-step retrieve/update.
    643653
     654.. versionadded:: 1.3
     655
     656To increment and decrement multiple values more efficiently, use
     657``offset_many()`` to pass a dictionary of key-value pairs, where the value is
     658the delta you would like apply to the existing value. ``offset_many()``
     659returns a dictionary with all the keys passed and their new value. If a key is
     660not found or there was an error, its value will be False::
     661
     662        >>> cache.set_many({'a': 10, 'b': 10})
     663        >>> cache.offset_many({'a': 1, 'b': -1, 'c': 1})
     664        {'a': 11, 'b': 9, 'c': False}
     665
     666
     667
    644668Cache key warnings
    645669------------------
    646670
  • tests/regressiontests/cache/tests.py

     
    132132            self.cache.set(key, value)
    133133            self.assertEqual(self.cache.get(key), None)
    134134
     135    def test_add_many(self):
     136        "add_many does nothing for the dummy cache backend"
     137        self.cache.add_many({'a': 1, 'b': 2})
     138
     139    def test_offset_many(self):
     140        "offset_many does nothing for the dummy cache backend"
     141        results = self.cache.offset_many({'a': 1, 'b': -1})
     142        self.assertEqual(results['a'], False)
     143        self.assertEqual(results['b'], False)
     144
    135145    def test_set_many(self):
    136146        "set_many does nothing for the dummy cache backend"
    137147        self.cache.set_many({'a': 1, 'b': 2})
     
    206216        self.assertEqual(self.cache.incr('answer', 10), 52)
    207217        self.assertEqual(self.cache.get('answer'), 52)
    208218        self.assertRaises(ValueError, self.cache.incr, 'does_not_exist')
     219        self.assertEqual(self.cache.incr('answer', -10), 42)
    209220
    210221    def test_decr(self):
    211222        # Cache values can be decremented
     
    215226        self.assertEqual(self.cache.decr('answer', 10), 32)
    216227        self.assertEqual(self.cache.get('answer'), 32)
    217228        self.assertRaises(ValueError, self.cache.decr, 'does_not_exist')
     229        self.assertEqual(self.cache.decr('answer', -10), 42)
    218230
    219231    def test_data_types(self):
    220232        # Many different data types can be cached
     
    306318        self.assertEqual(compressed_value, compressed_result)
    307319        self.assertEqual(value, decompress(compressed_result))
    308320
     321    def test_add_many(self):
     322        # Multiple keys can be added using add_many
     323        data = {"addmany1": "one", "addmany2": "two"}
     324        self.cache.add_many(data)
     325        results = self.cache.add_many({"addmany1": "a", "addmany2": "b"})
     326        for key, result in results.items():
     327            self.assertEqual(result, False)
     328            self.assertEqual(self.cache.get(key), data.get(key))
     329
     330    def test_add_many_expiration(self):
     331        # add_many takes a second ``timeout`` parameter
     332       
     333        # ensure keys do not exist, otherwise timeout may not be set
     334        self.cache.delete_many(["addmany1", "addmany2"])
     335        self.cache.add_many({"addmany1": "one", "addmany2": "two"}, 1)
     336        time.sleep(2)
     337        self.assertEqual(self.cache.get("addmany1"), None)
     338        self.assertEqual(self.cache.get("addmany2"), None)
     339
     340    def test_offset_many(self):
     341        # Multiple keys can be incremented or decremented using offset_many
     342        self.cache.set("offset1", 10)
     343        self.cache.set("offset2", 10)
     344        self.cache.delete("offset3")       
     345        results = self.cache.offset_many({
     346            "offset1" : 1,
     347            "offset2" : -1,
     348            "offset3" : 1,
     349        })
     350        self.assertEqual(results.get("offset1"), 11)
     351        self.assertEqual(results.get("offset2"), 9)
     352        self.assertEqual(results.get("offset3"), False)
     353
    309354    def test_set_many(self):
    310355        # Multiple keys can be set using set_many
    311356        self.cache.set_many({"key1": "spam", "key2": "eggs"})
Back to Top