5
5
:mod:`collections` module in the Python standard library can be used as a Zarr
6
6
array store, as long as it accepts string (str) keys and bytes values.
7
7
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
+
8
17
"""
9
18
from __future__ import absolute_import , print_function , division
10
19
from collections import MutableMapping , OrderedDict
@@ -80,7 +89,9 @@ def _rmdir_from_keys(store, path=None):
80
89
81
90
82
91
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."""
84
95
path = normalize_storage_path (path )
85
96
if hasattr (store , 'rmdir' ):
86
97
# pass through
@@ -101,7 +112,9 @@ def _rename_from_keys(store, src_path, dst_path):
101
112
102
113
103
114
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."""
105
118
src_path = normalize_storage_path (src_path )
106
119
dst_path = normalize_storage_path (dst_path )
107
120
if hasattr (store , 'rename' ):
@@ -125,7 +138,9 @@ def _listdir_from_keys(store, path=None):
125
138
126
139
127
140
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."""
129
144
path = normalize_storage_path (path )
130
145
if hasattr (store , 'listdir' ):
131
146
# pass through
@@ -136,7 +151,8 @@ def listdir(store, path=None):
136
151
137
152
138
153
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."""
140
156
path = normalize_storage_path (path )
141
157
if hasattr (store , 'getsize' ):
142
158
# pass through
@@ -868,6 +884,7 @@ def atexit_rmtree(path,
868
884
rmtree (path )
869
885
870
886
887
+ # noinspection PyShadowingNames
871
888
def atexit_rmglob (path ,
872
889
glob = glob .glob ,
873
890
isdir = os .path .isdir ,
@@ -1690,6 +1707,35 @@ def __len__(self):
1690
1707
1691
1708
1692
1709
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
+ """
1693
1739
1694
1740
def __init__ (self , store , max_size ):
1695
1741
self ._store = store
@@ -1771,10 +1817,12 @@ def _cache_value(self, key, value):
1771
1817
self ._current_size += value_size
1772
1818
1773
1819
def clear_values (self ):
1820
+ """Clear the values cache."""
1774
1821
with self ._mutex :
1775
1822
self ._values_cache .clear ()
1776
1823
1777
1824
def clear_keys (self ):
1825
+ """Clear the keys cache."""
1778
1826
with self ._mutex :
1779
1827
self ._clear_keys ()
1780
1828
0 commit comments