~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/store/__init__.py

  • Committer: Martin Pool
  • Date: 2005-10-04 02:27:27 UTC
  • mfrom: (1399)
  • mto: (1185.13.3)
  • mto: This revision was merged to the branch mainline in revision 1400.
  • Revision ID: mbp@sourcefrog.net-20051004022727-aee7064c62e039a7
[merge] merge robertc's format5 integration

 - test status on specific files
 - track x bit
 - baz2bzr fixes
 - remotebranch fixes

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
unique ID.
25
25
"""
26
26
 
 
27
from cStringIO import StringIO
 
28
 
27
29
from bzrlib.errors import BzrError, UnlistableStore, TransportNotPossible
28
30
from bzrlib.trace import mutter
29
31
import bzrlib.transport
 
32
from bzrlib.transport.local import LocalTransport
30
33
 
31
34
######################################################################
32
35
# stores
34
37
class StoreError(Exception):
35
38
    pass
36
39
 
 
40
 
37
41
class Store(object):
38
42
    """This class represents the abstract storage layout for saving information.
 
43
    
 
44
    Files can be added, but not modified once they are in.  Typically
 
45
    the hash is used as the name, or something else known to be unique,
 
46
    such as a UUID.
39
47
    """
40
 
    _transport = None
41
 
    _max_buffered_requests = 10
42
 
 
43
 
    def __init__(self, transport):
44
 
        assert isinstance(transport, bzrlib.transport.Transport)
45
 
        self._transport = transport
46
 
 
47
 
    def __repr__(self):
48
 
        if self._transport is None:
49
 
            return "%s(None)" % (self.__class__.__name__)
50
 
        else:
51
 
            return "%s(%r)" % (self.__class__.__name__, self._transport.base)
52
 
 
53
 
    __str__ = __repr__
54
48
 
55
49
    def __len__(self):
56
50
        raise NotImplementedError('Children should define their length')
187
181
        pb.clear()
188
182
        return len(to_copy), failed
189
183
 
 
184
 
 
185
class TransportStore(Store):
 
186
    """A TransportStore is a Store superclass for Stores that use Transports."""
 
187
 
 
188
    _max_buffered_requests = 10
 
189
 
 
190
    def __init__(self, transport):
 
191
        assert isinstance(transport, bzrlib.transport.Transport)
 
192
        super(TransportStore, self).__init__()
 
193
        self._transport = transport
 
194
 
 
195
    def __repr__(self):
 
196
        if self._transport is None:
 
197
            return "%s(None)" % (self.__class__.__name__)
 
198
        else:
 
199
            return "%s(%r)" % (self.__class__.__name__, self._transport.base)
 
200
 
 
201
    __str__ = __repr__
 
202
 
 
203
 
 
204
class ImmutableMemoryStore(Store):
 
205
    """A memory only store."""
 
206
 
 
207
    def __contains__(self, fileid):
 
208
        return self._contents.has_key(fileid)
 
209
 
 
210
    def __init__(self):
 
211
        super(ImmutableMemoryStore, self).__init__()
 
212
        self._contents = {}
 
213
 
 
214
    def add(self, stream, fileid, compressed=True):
 
215
        if self._contents.has_key(fileid):
 
216
            raise StoreError("fileid %s already in the store" % fileid)
 
217
        self._contents[fileid] = stream.read()
 
218
 
 
219
    def __getitem__(self, fileid):
 
220
        """Returns a file reading from a particular entry."""
 
221
        if not self._contents.has_key(fileid):
 
222
            raise IndexError
 
223
        return StringIO(self._contents[fileid])
 
224
 
 
225
    def _item_size(self, fileid):
 
226
        return len(self._contents[fileid])
 
227
 
 
228
    def __iter__(self):
 
229
        return iter(self._contents.keys())
 
230
 
 
231
    def total_size(self):
 
232
        result = 0
 
233
        count = 0
 
234
        for fileid in self:
 
235
            count += 1
 
236
            result += self._item_size(fileid)
 
237
        return count, result
 
238
        
 
239
 
 
240
class CachedStore(Store):
 
241
    """A store that caches data locally, to avoid repeated downloads.
 
242
    The precacache method should be used to avoid server round-trips for
 
243
    every piece of data.
 
244
    """
 
245
 
 
246
    def __init__(self, store, cache_dir):
 
247
        super(CachedStore, self).__init__()
 
248
        self.source_store = store
 
249
        # This clones the source store type with a locally bound
 
250
        # transport. FIXME: it assumes a constructor is == cloning.
 
251
        # clonable store - it might be nicer to actually have a clone()
 
252
        # or something. RBC 20051003
 
253
        self.cache_store = store.__class__(LocalTransport(cache_dir))
 
254
 
 
255
    def __getitem__(self, id):
 
256
        mutter("Cache add %s" % id)
 
257
        if id not in self.cache_store:
 
258
            self.cache_store.add(self.source_store[id], id)
 
259
        return self.cache_store[id]
 
260
 
 
261
    def __contains__(self, fileid):
 
262
        if fileid in self.cache_store:
 
263
            return True
 
264
        if fileid in self.source_store:
 
265
            # We could copy at this time
 
266
            return True
 
267
        return False
 
268
 
 
269
    def get(self, fileids, permit_failure=False, pb=None):
 
270
        fileids = list(fileids)
 
271
        hasids = self.cache_store.has(fileids)
 
272
        needs = set()
 
273
        for has, fileid in zip(hasids, fileids):
 
274
            if not has:
 
275
                needs.add(fileid)
 
276
        if needs:
 
277
            self.cache_store.copy_multi(self.source_store, needs,
 
278
                    permit_failure=permit_failure)
 
279
        return self.cache_store.get(fileids,
 
280
                permit_failure=permit_failure, pb=pb)
 
281
 
 
282
    def prefetch(self, ids):
 
283
        """Copy a series of ids into the cache, before they are used.
 
284
        For remote stores that support pipelining or async downloads, this can
 
285
        increase speed considerably.
 
286
 
 
287
        Failures while prefetching are ignored.
 
288
        """
 
289
        mutter("Prefetch of ids %s" % ",".join(ids))
 
290
        self.cache_store.copy_multi(self.source_store, ids, 
 
291
                                    permit_failure=True)
 
292
 
 
293
 
190
294
def copy_all(store_from, store_to):
191
295
    """Copy all ids from one store to another."""
192
296
    # TODO: Optional progress indicator