Implemented DictCacheBackend
This backend is based on dictionary and memorycache client from https://github.com/openstack/oslo-incubator/blob/master/openstack/common/memorycache.py This backend was implemented to be used in Nova because there is no appropriate default backend in dogpile. Co-Authored-By: Pavel Kholkin <pkholkin@mirantis.com> Change-Id: Ie3e6c8a3671bc28bfd6967e8758c1419c3c8d501
This commit is contained in:
parent
e4c7731a78
commit
4b0cac8fb6
@ -16,3 +16,6 @@
|
||||
|
||||
.. automodule:: oslo_cache.backends.noop
|
||||
:members:
|
||||
|
||||
.. automodule:: oslo_cache.backends.dictionary
|
||||
:members:
|
||||
|
84
oslo_cache/backends/dictionary.py
Normal file
84
oslo_cache/backends/dictionary.py
Normal file
@ -0,0 +1,84 @@
|
||||
# Copyright 2015 Mirantis Inc
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""dogpile.cache backend that uses dictionary as a storage"""
|
||||
|
||||
from dogpile.cache import api
|
||||
from oslo_utils import timeutils
|
||||
|
||||
__all__ = [
|
||||
'DictCacheBackend'
|
||||
]
|
||||
|
||||
|
||||
# Value for nonexistent and expired keys
|
||||
NO_VALUE = api.NO_VALUE
|
||||
|
||||
|
||||
class DictCacheBackend(api.CacheBackend):
|
||||
"""A DictCacheBackend based on dictionary.
|
||||
|
||||
Arguments accepted in the arguments dictionary:
|
||||
|
||||
:param expiration_time: interval in seconds to indicate maximum
|
||||
time-to-live value. This parameter is common for a single backend
|
||||
instance. Default expiration_time value is 0, that means that all keys
|
||||
have infinite time-to-live value.
|
||||
:type expiration_time: real
|
||||
"""
|
||||
|
||||
def __init__(self, arguments):
|
||||
self.expiration_time = arguments.get('expiration_time', 0)
|
||||
self.cache = {}
|
||||
|
||||
def get(self, key):
|
||||
"""Retrieves the value for a key or NO_VALUE for nonexistent and
|
||||
expired keys.
|
||||
|
||||
:param key: dictionary key
|
||||
"""
|
||||
(value, timeout) = self.cache.get(key, (NO_VALUE, 0))
|
||||
if self.expiration_time > 0 and timeutils.utcnow_ts() >= timeout:
|
||||
self.cache.pop(key, None)
|
||||
return NO_VALUE
|
||||
|
||||
return value
|
||||
|
||||
def set(self, key, value):
|
||||
"""Sets the value for a key.
|
||||
Expunges expired keys during each set.
|
||||
|
||||
:param key: dictionary key
|
||||
:param value: value associated with the key
|
||||
"""
|
||||
self._clear()
|
||||
timeout = 0
|
||||
if self.expiration_time > 0:
|
||||
timeout = timeutils.utcnow_ts() + self.expiration_time
|
||||
self.cache[key] = (value, timeout)
|
||||
|
||||
def delete(self, key):
|
||||
"""Deletes the value associated with the key if it exists.
|
||||
|
||||
:param key: dictionary key
|
||||
"""
|
||||
self.cache.pop(key, None)
|
||||
|
||||
def _clear(self):
|
||||
"""Expunges expired keys."""
|
||||
now = timeutils.utcnow_ts()
|
||||
for k in list(self.cache):
|
||||
(_value, timeout) = self.cache[k]
|
||||
if timeout > 0 and now >= timeout:
|
||||
del self.cache[k]
|
@ -21,6 +21,8 @@ When this library is imported, it registers the following backends in
|
||||
* ``oslo_cache.mongo`` - :class:`oslo_cache.backends.mongo.MongoCacheBackend`
|
||||
* ``oslo_cache.memcache_pool`` -
|
||||
:class:`oslo_cache.backends.memcache_pool.PooledMemcachedBackend`
|
||||
* ``oslo_cache.dict`` -
|
||||
:class:`oslo_cache.backends.dictionary.DictCacheBackend`
|
||||
|
||||
To use this library:
|
||||
|
||||
@ -62,7 +64,8 @@ _BACKENDS = [
|
||||
('oslo_cache.noop', 'oslo_cache.backends.noop', 'NoopCacheBackend'),
|
||||
('oslo_cache.mongo', 'oslo_cache.backends.mongo', 'MongoCacheBackend'),
|
||||
('oslo_cache.memcache_pool', 'oslo_cache.backends.memcache_pool',
|
||||
'PooledMemcachedBackend')
|
||||
'PooledMemcachedBackend'),
|
||||
('oslo_cache.dict', 'oslo_cache.backends.dictionary', 'DictCacheBackend'),
|
||||
]
|
||||
|
||||
for backend in _BACKENDS:
|
||||
|
94
oslo_cache/tests/test_dict_backend.py
Normal file
94
oslo_cache/tests/test_dict_backend.py
Normal file
@ -0,0 +1,94 @@
|
||||
# Copyright 2015 Mirantis Inc
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from dogpile.cache import api
|
||||
from dogpile.cache import region as dp_region
|
||||
|
||||
from oslo_cache.tests import test_cache
|
||||
from oslo_config import fixture as config_fixture
|
||||
from oslo_utils import fixture as time_fixture
|
||||
|
||||
|
||||
NO_VALUE = api.NO_VALUE
|
||||
KEY = 'test_key'
|
||||
VALUE = 'test_value'
|
||||
|
||||
|
||||
class CacheDictBackendTest(test_cache.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(CacheDictBackendTest, self).setUp()
|
||||
self.config_fixture = self.useFixture(config_fixture.Config())
|
||||
self.config_fixture.config(group='cache', backend='oslo_cache.dict')
|
||||
self.time_fixture = self.useFixture(time_fixture.TimeFixture())
|
||||
self.region = dp_region.make_region()
|
||||
self.region.configure(
|
||||
'oslo_cache.dict', arguments={'expiration_time': 0.5})
|
||||
|
||||
def test_dict_backend(self):
|
||||
self.assertIs(NO_VALUE, self.region.get(KEY))
|
||||
|
||||
self.region.set(KEY, VALUE)
|
||||
self.assertEqual(VALUE, self.region.get(KEY))
|
||||
|
||||
self.region.delete(KEY)
|
||||
self.assertIs(NO_VALUE, self.region.get(KEY))
|
||||
|
||||
def test_dict_backend_expiration_time(self):
|
||||
self.region.set(KEY, VALUE)
|
||||
self.assertEqual(VALUE, self.region.get(KEY))
|
||||
|
||||
self.time_fixture.advance_time_seconds(1)
|
||||
self.assertIs(NO_VALUE, self.region.get(KEY))
|
||||
|
||||
def test_dict_backend_clear_cache(self):
|
||||
self.region.set(KEY, VALUE)
|
||||
|
||||
self.time_fixture.advance_time_seconds(1)
|
||||
|
||||
self.assertEqual(1, len(self.region.backend.cache))
|
||||
self.region.backend._clear()
|
||||
self.assertEqual(0, len(self.region.backend.cache))
|
||||
|
||||
def test_dict_backend_zero_expiration_time(self):
|
||||
self.region = dp_region.make_region()
|
||||
self.region.configure(
|
||||
'oslo_cache.dict', arguments={'expiration_time': 0})
|
||||
|
||||
self.region.set(KEY, VALUE)
|
||||
self.time_fixture.advance_time_seconds(1)
|
||||
|
||||
self.assertEqual(VALUE, self.region.get(KEY))
|
||||
self.assertEqual(1, len(self.region.backend.cache))
|
||||
|
||||
self.region.backend._clear()
|
||||
|
||||
self.assertEqual(VALUE, self.region.get(KEY))
|
||||
self.assertEqual(1, len(self.region.backend.cache))
|
||||
|
||||
def test_dict_backend_multi_keys(self):
|
||||
self.region.set('key1', 'value1')
|
||||
self.region.set('key2', 'value2')
|
||||
self.time_fixture.advance_time_seconds(1)
|
||||
self.region.set('key3', 'value3')
|
||||
|
||||
self.assertEqual(1, len(self.region.backend.cache))
|
||||
self.assertIs(NO_VALUE, self.region.get('key1'))
|
||||
self.assertIs(NO_VALUE, self.region.get('key2'))
|
||||
self.assertEqual('value3', self.region.get('key3'))
|
||||
|
||||
def test_dict_backend_rewrite_value(self):
|
||||
self.region.set(KEY, 'value1')
|
||||
self.region.set(KEY, 'value2')
|
||||
self.assertEqual('value2', self.region.get(KEY))
|
Loading…
x
Reference in New Issue
Block a user