Skip to content

Commit 24f175f

Browse files
committed
API docs for LRUStoreCache
1 parent dfe1fa7 commit 24f175f

File tree

3 files changed

+64
-5
lines changed

3 files changed

+64
-5
lines changed

docs/api/storage.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,17 @@ Storage (``zarr.storage``)
2121
.. automethod:: close
2222
.. automethod:: flush
2323

24+
.. autoclass:: LRUStoreCache
25+
26+
.. automethod:: clear_values
27+
.. automethod:: clear_keys
28+
2429
.. autofunction:: init_array
2530
.. autofunction:: init_group
31+
.. autofunction:: contains_array
32+
.. autofunction:: contains_group
33+
.. autofunction:: listdir
34+
.. autofunction:: rmdir
35+
.. autofunction:: getsize
36+
.. autofunction:: rename
2637
.. autofunction:: migrate_1to2

zarr/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from zarr.creation import (empty, zeros, ones, full, array, empty_like, zeros_like,
88
ones_like, full_like, open_array, open_like, create)
99
from zarr.storage import (DictStore, DirectoryStore, ZipStore, TempStore,
10-
NestedDirectoryStore, DBMStore, LMDBStore)
10+
NestedDirectoryStore, DBMStore, LMDBStore, LRUStoreCache)
1111
from zarr.hierarchy import group, open_group, Group
1212
from zarr.sync import ThreadSynchronizer, ProcessSynchronizer
1313
from zarr.codecs import *

zarr/storage.py

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@
55
:mod:`collections` module in the Python standard library can be used as a Zarr
66
array store, as long as it accepts string (str) keys and bytes values.
77
8+
In addition to the :class:`MutableMapping` interface, store classes may also implement
9+
optional methods `listdir` (list members of a "directory") and `rmdir` (remove all
10+
members of a "directory"). These methods should be implemented if the store class is
11+
aware of the hierarchical organisation of resources within the store and can provide
12+
efficient implementations. If these methods are not available, Zarr will fall back to
13+
slower implementations that work via the :class:`MutableMapping` interface. Store
14+
classes may also optionally implement a `rename` method (rename all members under a given
15+
path) and a `getsize` method (return the size in bytes of a given value).
16+
817
"""
918
from __future__ import absolute_import, print_function, division
1019
from collections import MutableMapping, OrderedDict
@@ -80,7 +89,9 @@ def _rmdir_from_keys(store, path=None):
8089

8190

8291
def rmdir(store, path=None):
83-
"""Remove all items under the given path."""
92+
"""Remove all items under the given path. If `store` provides a `rmdir` method,
93+
this will be called, otherwise will fall back to implementation via the
94+
`MutableMapping` interface."""
8495
path = normalize_storage_path(path)
8596
if hasattr(store, 'rmdir'):
8697
# pass through
@@ -101,7 +112,9 @@ def _rename_from_keys(store, src_path, dst_path):
101112

102113

103114
def rename(store, src_path, dst_path):
104-
"""Rename all items under the given path."""
115+
"""Rename all items under the given path. If `store` provides a `rename` method,
116+
this will be called, otherwise will fall back to implementation via the
117+
`MutableMapping` interface."""
105118
src_path = normalize_storage_path(src_path)
106119
dst_path = normalize_storage_path(dst_path)
107120
if hasattr(store, 'rename'):
@@ -125,7 +138,9 @@ def _listdir_from_keys(store, path=None):
125138

126139

127140
def listdir(store, path=None):
128-
"""Obtain a directory listing for the given path."""
141+
"""Obtain a directory listing for the given path. If `store` provides a `listdir`
142+
method, this will be called, otherwise will fall back to implementation via the
143+
`MutableMapping` interface."""
129144
path = normalize_storage_path(path)
130145
if hasattr(store, 'listdir'):
131146
# pass through
@@ -136,7 +151,8 @@ def listdir(store, path=None):
136151

137152

138153
def getsize(store, path=None):
139-
"""Compute size of stored items for a given path."""
154+
"""Compute size of stored items for a given path. If `store` provides a `getsize`
155+
method, this will be called, otherwise will return -1."""
140156
path = normalize_storage_path(path)
141157
if hasattr(store, 'getsize'):
142158
# pass through
@@ -868,6 +884,7 @@ def atexit_rmtree(path,
868884
rmtree(path)
869885

870886

887+
# noinspection PyShadowingNames
871888
def atexit_rmglob(path,
872889
glob=glob.glob,
873890
isdir=os.path.isdir,
@@ -1690,6 +1707,35 @@ def __len__(self):
16901707

16911708

16921709
class LRUStoreCache(MutableMapping):
1710+
"""Storage class that implements a least-recently-used (LRU) cache layer over
1711+
some other store. Intended primarily for use with stores that can be slow to
1712+
access, e.g., remote stores that require network communication to store and
1713+
retrieve data.
1714+
1715+
Parameters
1716+
----------
1717+
store : MutableMapping
1718+
The store containing the actual data to be cached.
1719+
max_size : int
1720+
The maximum size that the cache may grow to, in number of bytes. Provide `None`
1721+
if you would like the cache to have unlimited size.
1722+
1723+
Examples
1724+
--------
1725+
The example below wraps an S3 store with an LRU cache::
1726+
1727+
>>> import s3fs
1728+
>>> import zarr
1729+
>>> s3 = s3fs.S3FileSystem(anon=True, client_kwargs=dict(region_name='eu-west-2'))
1730+
>>> store = s3fs.S3Map(root='zarr-demo/store', s3=s3, check=False)
1731+
>>> cache = zarr.LRUStoreCache(store, max_size=2**28)
1732+
>>> root = zarr.group(store=cache)
1733+
>>> z = root['foo/bar/baz']
1734+
>>> from timeit import timeit
1735+
>>> timeit('print(z.tostring())', number=1) # first time is relatively slow
1736+
>>> timeit('print(z.tostring())', number=1) # second time is fast, uses cache
1737+
1738+
"""
16931739

16941740
def __init__(self, store, max_size):
16951741
self._store = store
@@ -1771,10 +1817,12 @@ def _cache_value(self, key, value):
17711817
self._current_size += value_size
17721818

17731819
def clear_values(self):
1820+
"""Clear the values cache."""
17741821
with self._mutex:
17751822
self._values_cache.clear()
17761823

17771824
def clear_keys(self):
1825+
"""Clear the keys cache."""
17781826
with self._mutex:
17791827
self._clear_keys()
17801828

0 commit comments

Comments
 (0)