~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/knit.py

  • Committer: Jelmer Vernooij
  • Date: 2011-04-05 17:52:20 UTC
  • mto: This revision was merged to the branch mainline in revision 5801.
  • Revision ID: jelmer@samba.org-20110405175220-07pi4se33fhvore7
Avoid bzrlib.knit imports when using groupcompress repositories.

Add bzrlib.knit to the blacklist in test_import_tariff.

Show diffs side-by-side

added added

removed removed

Lines of Context:
56
56
from itertools import izip
57
57
import operator
58
58
import os
59
 
import sys
60
59
 
61
60
from bzrlib.lazy_import import lazy_import
62
61
lazy_import(globals(), """
96
95
    split_lines,
97
96
    )
98
97
from bzrlib.versionedfile import (
 
98
    _KeyRefs,
99
99
    AbsentContentFactory,
100
100
    adapter_registry,
101
101
    ConstantMapper,
799
799
        writer.begin()
800
800
        index = _KnitGraphIndex(graph_index, lambda:True, parents=parents,
801
801
            deltas=delta, add_callback=graph_index.add_nodes)
802
 
        access = _DirectPackAccess({})
 
802
        access = pack._DirectPackAccess({})
803
803
        access.set_writer(writer, graph_index, (transport, 'newpack'))
804
804
        result = KnitVersionedFiles(index, access,
805
805
            max_delta_chain=max_delta_chain)
2780
2780
        return key[:-1], key[-1]
2781
2781
 
2782
2782
 
2783
 
class _KeyRefs(object):
2784
 
 
2785
 
    def __init__(self, track_new_keys=False):
2786
 
        # dict mapping 'key' to 'set of keys referring to that key'
2787
 
        self.refs = {}
2788
 
        if track_new_keys:
2789
 
            # set remembering all new keys
2790
 
            self.new_keys = set()
2791
 
        else:
2792
 
            self.new_keys = None
2793
 
 
2794
 
    def clear(self):
2795
 
        if self.refs:
2796
 
            self.refs.clear()
2797
 
        if self.new_keys:
2798
 
            self.new_keys.clear()
2799
 
 
2800
 
    def add_references(self, key, refs):
2801
 
        # Record the new references
2802
 
        for referenced in refs:
2803
 
            try:
2804
 
                needed_by = self.refs[referenced]
2805
 
            except KeyError:
2806
 
                needed_by = self.refs[referenced] = set()
2807
 
            needed_by.add(key)
2808
 
        # Discard references satisfied by the new key
2809
 
        self.add_key(key)
2810
 
 
2811
 
    def get_new_keys(self):
2812
 
        return self.new_keys
2813
 
    
2814
 
    def get_unsatisfied_refs(self):
2815
 
        return self.refs.iterkeys()
2816
 
 
2817
 
    def _satisfy_refs_for_key(self, key):
2818
 
        try:
2819
 
            del self.refs[key]
2820
 
        except KeyError:
2821
 
            # No keys depended on this key.  That's ok.
2822
 
            pass
2823
 
 
2824
 
    def add_key(self, key):
2825
 
        # satisfy refs for key, and remember that we've seen this key.
2826
 
        self._satisfy_refs_for_key(key)
2827
 
        if self.new_keys is not None:
2828
 
            self.new_keys.add(key)
2829
 
 
2830
 
    def satisfy_refs_for_keys(self, keys):
2831
 
        for key in keys:
2832
 
            self._satisfy_refs_for_key(key)
2833
 
 
2834
 
    def get_referrers(self):
2835
 
        result = set()
2836
 
        for referrers in self.refs.itervalues():
2837
 
            result.update(referrers)
2838
 
        return result
2839
 
 
2840
 
 
2841
2783
class _KnitGraphIndex(object):
2842
2784
    """A KnitVersionedFiles index layered on GraphIndex."""
2843
2785
 
3272
3214
                yield data
3273
3215
 
3274
3216
 
3275
 
class _DirectPackAccess(object):
3276
 
    """Access to data in one or more packs with less translation."""
3277
 
 
3278
 
    def __init__(self, index_to_packs, reload_func=None, flush_func=None):
3279
 
        """Create a _DirectPackAccess object.
3280
 
 
3281
 
        :param index_to_packs: A dict mapping index objects to the transport
3282
 
            and file names for obtaining data.
3283
 
        :param reload_func: A function to call if we determine that the pack
3284
 
            files have moved and we need to reload our caches. See
3285
 
            bzrlib.repo_fmt.pack_repo.AggregateIndex for more details.
3286
 
        """
3287
 
        self._container_writer = None
3288
 
        self._write_index = None
3289
 
        self._indices = index_to_packs
3290
 
        self._reload_func = reload_func
3291
 
        self._flush_func = flush_func
3292
 
 
3293
 
    def add_raw_records(self, key_sizes, raw_data):
3294
 
        """Add raw knit bytes to a storage area.
3295
 
 
3296
 
        The data is spooled to the container writer in one bytes-record per
3297
 
        raw data item.
3298
 
 
3299
 
        :param sizes: An iterable of tuples containing the key and size of each
3300
 
            raw data segment.
3301
 
        :param raw_data: A bytestring containing the data.
3302
 
        :return: A list of memos to retrieve the record later. Each memo is an
3303
 
            opaque index memo. For _DirectPackAccess the memo is (index, pos,
3304
 
            length), where the index field is the write_index object supplied
3305
 
            to the PackAccess object.
3306
 
        """
3307
 
        if type(raw_data) is not str:
3308
 
            raise AssertionError(
3309
 
                'data must be plain bytes was %s' % type(raw_data))
3310
 
        result = []
3311
 
        offset = 0
3312
 
        for key, size in key_sizes:
3313
 
            p_offset, p_length = self._container_writer.add_bytes_record(
3314
 
                raw_data[offset:offset+size], [])
3315
 
            offset += size
3316
 
            result.append((self._write_index, p_offset, p_length))
3317
 
        return result
3318
 
 
3319
 
    def flush(self):
3320
 
        """Flush pending writes on this access object.
3321
 
 
3322
 
        This will flush any buffered writes to a NewPack.
3323
 
        """
3324
 
        if self._flush_func is not None:
3325
 
            self._flush_func()
3326
 
            
3327
 
    def get_raw_records(self, memos_for_retrieval):
3328
 
        """Get the raw bytes for a records.
3329
 
 
3330
 
        :param memos_for_retrieval: An iterable containing the (index, pos,
3331
 
            length) memo for retrieving the bytes. The Pack access method
3332
 
            looks up the pack to use for a given record in its index_to_pack
3333
 
            map.
3334
 
        :return: An iterator over the bytes of the records.
3335
 
        """
3336
 
        # first pass, group into same-index requests
3337
 
        request_lists = []
3338
 
        current_index = None
3339
 
        for (index, offset, length) in memos_for_retrieval:
3340
 
            if current_index == index:
3341
 
                current_list.append((offset, length))
3342
 
            else:
3343
 
                if current_index is not None:
3344
 
                    request_lists.append((current_index, current_list))
3345
 
                current_index = index
3346
 
                current_list = [(offset, length)]
3347
 
        # handle the last entry
3348
 
        if current_index is not None:
3349
 
            request_lists.append((current_index, current_list))
3350
 
        for index, offsets in request_lists:
3351
 
            try:
3352
 
                transport, path = self._indices[index]
3353
 
            except KeyError:
3354
 
                # A KeyError here indicates that someone has triggered an index
3355
 
                # reload, and this index has gone missing, we need to start
3356
 
                # over.
3357
 
                if self._reload_func is None:
3358
 
                    # If we don't have a _reload_func there is nothing that can
3359
 
                    # be done
3360
 
                    raise
3361
 
                raise errors.RetryWithNewPacks(index,
3362
 
                                               reload_occurred=True,
3363
 
                                               exc_info=sys.exc_info())
3364
 
            try:
3365
 
                reader = pack.make_readv_reader(transport, path, offsets)
3366
 
                for names, read_func in reader.iter_records():
3367
 
                    yield read_func(None)
3368
 
            except errors.NoSuchFile:
3369
 
                # A NoSuchFile error indicates that a pack file has gone
3370
 
                # missing on disk, we need to trigger a reload, and start over.
3371
 
                if self._reload_func is None:
3372
 
                    raise
3373
 
                raise errors.RetryWithNewPacks(transport.abspath(path),
3374
 
                                               reload_occurred=False,
3375
 
                                               exc_info=sys.exc_info())
3376
 
 
3377
 
    def set_writer(self, writer, index, transport_packname):
3378
 
        """Set a writer to use for adding data."""
3379
 
        if index is not None:
3380
 
            self._indices[index] = transport_packname
3381
 
        self._container_writer = writer
3382
 
        self._write_index = index
3383
 
 
3384
 
    def reload_or_raise(self, retry_exc):
3385
 
        """Try calling the reload function, or re-raise the original exception.
3386
 
 
3387
 
        This should be called after _DirectPackAccess raises a
3388
 
        RetryWithNewPacks exception. This function will handle the common logic
3389
 
        of determining when the error is fatal versus being temporary.
3390
 
        It will also make sure that the original exception is raised, rather
3391
 
        than the RetryWithNewPacks exception.
3392
 
 
3393
 
        If this function returns, then the calling function should retry
3394
 
        whatever operation was being performed. Otherwise an exception will
3395
 
        be raised.
3396
 
 
3397
 
        :param retry_exc: A RetryWithNewPacks exception.
3398
 
        """
3399
 
        is_error = False
3400
 
        if self._reload_func is None:
3401
 
            is_error = True
3402
 
        elif not self._reload_func():
3403
 
            # The reload claimed that nothing changed
3404
 
            if not retry_exc.reload_occurred:
3405
 
                # If there wasn't an earlier reload, then we really were
3406
 
                # expecting to find changes. We didn't find them, so this is a
3407
 
                # hard error
3408
 
                is_error = True
3409
 
        if is_error:
3410
 
            exc_class, exc_value, exc_traceback = retry_exc.exc_info
3411
 
            raise exc_class, exc_value, exc_traceback
3412
 
 
3413
 
 
3414
3217
def annotate_knit(knit, revision_id):
3415
3218
    """Annotate a knit with no cached annotations.
3416
3219