1
# ubuntuone.storagefs.diskcache - disk-backed filesystem cache
3
# Authors: Facundo Batista <facundo@canonical.com>
4
# Guillermo Gonzalez <guillermo.gonzalez@canonical.com>
6
# Copyright 2009 Canonical Ltd.
8
# This program is free software: you can redistribute it and/or modify it
9
# under the terms of the GNU General Public License version 3, as published
10
# by the Free Software Foundation.
12
# This program is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranties of
14
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
15
# PURPOSE. See the GNU General Public License for more details.
17
# You should have received a copy of the GNU General Public License along
18
# with this program. If not, see <http://www.gnu.org/licenses/>.
19
"""storage shelf using a files tree."""
21
from __future__ import with_statement
22
from UserDict import DictMixin
26
class FileShelf(object, DictMixin):
29
It support arbritary python objects as values (anything accepted by
30
cPickle). And support any valid file name as key.
33
def __init__(self, path, depth=3):
34
""" Create a FileShelf.
36
@param path: the path to use as the root of the shelf
37
@param depth: the directory depth to use, can't be < 0. default is 3
41
raise ValueError("depth must be >= 0")
43
self._check_and_create_dirs(self._path)
45
def _check_and_create_dirs(self, path):
46
""" check if the path isn't a file and in case it don't exists,
49
if os.path.exists(path) and os.path.isfile(path):
51
if not os.path.exists(path):
54
def key_file(self, key):
55
""" get the real key used by the storage from a key """
56
# cannot use None to create files in the disk
58
raise ValueError("Invalid key: %r" % key)
60
# length always needs to be longer (we have a uuid after all)
61
if len(key) < self._depth:
62
raise ValueError("The key (%r) needs to be longer!" % key)
64
letters = [key[i] for i in xrange(0, self._depth)]
65
path = os.path.join(self._path, *letters)
66
self._check_and_create_dirs(path)
67
return os.path.join(path, key)
69
def has_key(self, key):
70
""" True if the the shelf has the key """
71
return os.path.exists(self.key_file(key))
74
""" returns a iterator over the keys """
75
for dirpath, dirnames, filenames in os.walk(self._path):
76
for filename in filenames:
80
""" returns the key and deletes the entry """
85
def __contains__(self, key):
86
""" returns if the file storage has that key """
87
# this method surely has some effect! pylint: disable-msg=W0104
95
def __getitem__(self, key):
96
""" getitem backed by the file storage """
98
with open(self.key_file(key), "rb") as fd:
99
data = cPickle.load(fd)
100
except (IOError, OSError, EOFError):
105
def __setitem__(self, key, value):
106
""" setitem backed by the file storage """
107
with open(self.key_file(key), "wb") as fh:
108
cPickle.dump(value, fh, protocol=2)
110
os.fsync(fh.fileno())
112
def __delitem__(self, key):
113
""" delitem backed by the file storage """
114
os.remove(self.key_file(key))
117
""" The len of the shelf.
118
To get len(keys) we need to iterate over the full key set.
121
for key in self.keys():