Merge "Use a lru cache to limit the size of the internal file cache"
This commit is contained in:
commit
4c36d38999
@ -38,5 +38,8 @@ jsonschema>=2.0.0,<3.0.0,!=2.5.0
|
|||||||
oslo.utils>=1.4.0 # Apache-2.0
|
oslo.utils>=1.4.0 # Apache-2.0
|
||||||
oslo.serialization>=1.4.0 # Apache-2.0
|
oslo.serialization>=1.4.0 # Apache-2.0
|
||||||
|
|
||||||
|
# For lru caches and such
|
||||||
|
cachetools>=1.0.0 # MIT License
|
||||||
|
|
||||||
# For deprecation of things
|
# For deprecation of things
|
||||||
debtcollector>=0.3.0 # Apache-2.0
|
debtcollector>=0.3.0 # Apache-2.0
|
||||||
|
@ -20,6 +20,7 @@ import errno
|
|||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
|
import cachetools
|
||||||
import fasteners
|
import fasteners
|
||||||
from oslo_serialization import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
|
|
||||||
@ -54,11 +55,21 @@ class DirBackend(path_based.PathBasedBackend):
|
|||||||
Example configuration::
|
Example configuration::
|
||||||
|
|
||||||
conf = {
|
conf = {
|
||||||
"path": "/tmp/taskflow",
|
"path": "/tmp/taskflow", # save data to this root directory
|
||||||
|
"max_cache_size": 1024, # keep up-to 1024 entries in memory
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, conf):
|
def __init__(self, conf):
|
||||||
super(DirBackend, self).__init__(conf)
|
super(DirBackend, self).__init__(conf)
|
||||||
|
max_cache_size = self._conf.get('max_cache_size')
|
||||||
|
if max_cache_size is not None:
|
||||||
|
max_cache_size = int(max_cache_size)
|
||||||
|
if max_cache_size < 1:
|
||||||
|
raise ValueError("Maximum cache size must be greater than"
|
||||||
|
" or equal to one")
|
||||||
|
self.file_cache = cachetools.LRUCache(max_cache_size)
|
||||||
|
else:
|
||||||
self.file_cache = {}
|
self.file_cache = {}
|
||||||
self.encoding = self._conf.get('encoding', 'utf-8')
|
self.encoding = self._conf.get('encoding', 'utf-8')
|
||||||
if not self._path:
|
if not self._path:
|
||||||
|
@ -19,37 +19,80 @@ import os
|
|||||||
import shutil
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
|
from oslo_utils import uuidutils
|
||||||
|
import testscenarios
|
||||||
|
|
||||||
|
from taskflow import exceptions as exc
|
||||||
from taskflow.persistence import backends
|
from taskflow.persistence import backends
|
||||||
from taskflow.persistence.backends import impl_dir
|
from taskflow.persistence.backends import impl_dir
|
||||||
|
from taskflow.persistence import logbook
|
||||||
from taskflow import test
|
from taskflow import test
|
||||||
from taskflow.tests.unit.persistence import base
|
from taskflow.tests.unit.persistence import base
|
||||||
|
|
||||||
|
|
||||||
class DirPersistenceTest(test.TestCase, base.PersistenceTestMixin):
|
class DirPersistenceTest(testscenarios.TestWithScenarios,
|
||||||
|
test.TestCase, base.PersistenceTestMixin):
|
||||||
|
|
||||||
|
scenarios = [
|
||||||
|
('no_cache', {'max_cache_size': None}),
|
||||||
|
('one', {'max_cache_size': 1}),
|
||||||
|
('tiny', {'max_cache_size': 256}),
|
||||||
|
('medimum', {'max_cache_size': 512}),
|
||||||
|
('large', {'max_cache_size': 1024}),
|
||||||
|
]
|
||||||
|
|
||||||
def _get_connection(self):
|
def _get_connection(self):
|
||||||
conf = {
|
return self.backend.get_connection()
|
||||||
'path': self.path,
|
|
||||||
}
|
|
||||||
return impl_dir.DirBackend(conf).get_connection()
|
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(DirPersistenceTest, self).setUp()
|
super(DirPersistenceTest, self).setUp()
|
||||||
self.path = tempfile.mkdtemp()
|
self.path = tempfile.mkdtemp()
|
||||||
conn = self._get_connection()
|
self.backend = impl_dir.DirBackend({
|
||||||
|
'path': self.path,
|
||||||
|
'max_cache_size': self.max_cache_size,
|
||||||
|
})
|
||||||
|
with contextlib.closing(self._get_connection()) as conn:
|
||||||
conn.upgrade()
|
conn.upgrade()
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
super(DirPersistenceTest, self).tearDown()
|
super(DirPersistenceTest, self).tearDown()
|
||||||
conn = self._get_connection()
|
|
||||||
conn.clear_all()
|
|
||||||
if self.path and os.path.isdir(self.path):
|
if self.path and os.path.isdir(self.path):
|
||||||
shutil.rmtree(self.path)
|
shutil.rmtree(self.path)
|
||||||
self.path = None
|
self.path = None
|
||||||
|
self.backend = None
|
||||||
|
|
||||||
def _check_backend(self, conf):
|
def _check_backend(self, conf):
|
||||||
with contextlib.closing(backends.fetch(conf)) as be:
|
with contextlib.closing(backends.fetch(conf)) as be:
|
||||||
self.assertIsInstance(be, impl_dir.DirBackend)
|
self.assertIsInstance(be, impl_dir.DirBackend)
|
||||||
|
|
||||||
|
def test_dir_backend_invalid_cache_size(self):
|
||||||
|
for invalid_size in [-1024, 0, -1]:
|
||||||
|
conf = {
|
||||||
|
'path': self.path,
|
||||||
|
'max_cache_size': invalid_size,
|
||||||
|
}
|
||||||
|
self.assertRaises(ValueError, impl_dir.DirBackend, conf)
|
||||||
|
|
||||||
|
def test_dir_backend_cache_overfill(self):
|
||||||
|
if self.max_cache_size is not None:
|
||||||
|
# Ensure cache never goes past the desired max size...
|
||||||
|
books_ids_made = []
|
||||||
|
with contextlib.closing(self._get_connection()) as conn:
|
||||||
|
for i in range(0, int(1.5 * self.max_cache_size)):
|
||||||
|
lb_name = 'book-%s' % (i)
|
||||||
|
lb_id = uuidutils.generate_uuid()
|
||||||
|
lb = logbook.LogBook(name=lb_name, uuid=lb_id)
|
||||||
|
self.assertRaises(exc.NotFound, conn.get_logbook, lb_id)
|
||||||
|
conn.save_logbook(lb)
|
||||||
|
books_ids_made.append(lb_id)
|
||||||
|
self.assertLessEqual(self.backend.file_cache.currsize,
|
||||||
|
self.max_cache_size)
|
||||||
|
# Also ensure that we can still read all created books...
|
||||||
|
with contextlib.closing(self._get_connection()) as conn:
|
||||||
|
for lb_id in books_ids_made:
|
||||||
|
lb = conn.get_logbook(lb_id)
|
||||||
|
self.assertIsNotNone(lb)
|
||||||
|
|
||||||
def test_dir_backend_entry_point(self):
|
def test_dir_backend_entry_point(self):
|
||||||
self._check_backend(dict(connection='dir:', path=self.path))
|
self._check_backend(dict(connection='dir:', path=self.path))
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user