/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« 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:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2006-2011 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
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(), """
 
62
import gzip
 
63
 
63
64
from bzrlib import (
64
 
    annotate,
65
65
    debug,
66
66
    diff,
67
67
    graph as _mod_graph,
68
68
    index as _mod_index,
69
 
    lru_cache,
70
69
    pack,
71
 
    progress,
 
70
    patiencediff,
72
71
    static_tuple,
73
72
    trace,
74
73
    tsort,
77
76
    )
78
77
""")
79
78
from bzrlib import (
 
79
    annotate,
80
80
    errors,
81
81
    osutils,
82
 
    patiencediff,
83
82
    )
84
83
from bzrlib.errors import (
85
 
    FileExists,
86
84
    NoSuchFile,
87
 
    KnitError,
88
85
    InvalidRevisionId,
89
86
    KnitCorrupt,
90
87
    KnitHeaderError,
91
88
    RevisionNotPresent,
92
 
    RevisionAlreadyPresent,
93
89
    SHA1KnitCorrupt,
94
90
    )
95
91
from bzrlib.osutils import (
96
92
    contains_whitespace,
97
 
    contains_linebreaks,
98
93
    sha_string,
99
94
    sha_strings,
100
95
    split_lines,
101
96
    )
102
97
from bzrlib.versionedfile import (
 
98
    _KeyRefs,
103
99
    AbsentContentFactory,
104
100
    adapter_registry,
105
101
    ConstantMapper,
106
102
    ContentFactory,
107
 
    ChunkedContentFactory,
108
103
    sort_groupcompress,
109
 
    VersionedFile,
110
104
    VersionedFiles,
111
105
    )
112
106
 
805
799
        writer.begin()
806
800
        index = _KnitGraphIndex(graph_index, lambda:True, parents=parents,
807
801
            deltas=delta, add_callback=graph_index.add_nodes)
808
 
        access = _DirectPackAccess({})
 
802
        access = pack._DirectPackAccess({})
809
803
        access.set_writer(writer, graph_index, (transport, 'newpack'))
810
804
        result = KnitVersionedFiles(index, access,
811
805
            max_delta_chain=max_delta_chain)
882
876
            self._factory = KnitAnnotateFactory()
883
877
        else:
884
878
            self._factory = KnitPlainFactory()
885
 
        self._fallback_vfs = []
 
879
        self._immediate_fallback_vfs = []
886
880
        self._reload_func = reload_func
887
881
 
888
882
    def __repr__(self):
896
890
 
897
891
        :param a_versioned_files: A VersionedFiles object.
898
892
        """
899
 
        self._fallback_vfs.append(a_versioned_files)
 
893
        self._immediate_fallback_vfs.append(a_versioned_files)
900
894
 
901
895
    def add_lines(self, key, parents, lines, parent_texts=None,
902
896
        left_matching_blocks=None, nostore_sha=None, random_id=False,
1069
1063
                    raise errors.KnitCorrupt(self,
1070
1064
                        "Missing basis parent %s for %s" % (
1071
1065
                        compression_parent, key))
1072
 
        for fallback_vfs in self._fallback_vfs:
 
1066
        for fallback_vfs in self._immediate_fallback_vfs:
1073
1067
            fallback_vfs.check()
1074
1068
 
1075
1069
    def _check_add(self, key, lines, random_id, check_content):
1195
1189
    def get_known_graph_ancestry(self, keys):
1196
1190
        """Get a KnownGraph instance with the ancestry of keys."""
1197
1191
        parent_map, missing_keys = self._index.find_ancestry(keys)
1198
 
        for fallback in self._fallback_vfs:
 
1192
        for fallback in self._transitive_fallbacks():
1199
1193
            if not missing_keys:
1200
1194
                break
1201
1195
            (f_parent_map, f_missing_keys) = fallback._index.find_ancestry(
1225
1219
            and so on.
1226
1220
        """
1227
1221
        result = {}
1228
 
        sources = [self._index] + self._fallback_vfs
 
1222
        sources = [self._index] + self._immediate_fallback_vfs
1229
1223
        source_results = []
1230
1224
        missing = set(keys)
1231
1225
        for source in sources:
1525
1519
                        yield KnitContentFactory(key, global_map[key],
1526
1520
                            record_details, None, raw_data, self._factory.annotated, None)
1527
1521
                else:
1528
 
                    vf = self._fallback_vfs[parent_maps.index(source) - 1]
 
1522
                    vf = self._immediate_fallback_vfs[parent_maps.index(source) - 1]
1529
1523
                    for record in vf.get_record_stream(keys, ordering,
1530
1524
                        include_delta_closure):
1531
1525
                        yield record
1541
1535
            # record entry 2 is the 'digest'.
1542
1536
            result[key] = details[2]
1543
1537
        missing.difference_update(set(result))
1544
 
        for source in self._fallback_vfs:
 
1538
        for source in self._immediate_fallback_vfs:
1545
1539
            if not missing:
1546
1540
                break
1547
1541
            new_result = source.get_sha1s(missing)
1618
1612
                raise RevisionNotPresent([record.key], self)
1619
1613
            elif ((record.storage_kind in knit_types)
1620
1614
                  and (compression_parent is None
1621
 
                       or not self._fallback_vfs
 
1615
                       or not self._immediate_fallback_vfs
1622
1616
                       or self._index.has_key(compression_parent)
1623
1617
                       or not self.has_key(compression_parent))):
1624
1618
                # we can insert the knit record literally if either it has no
1796
1790
        # vfs, and hope to find them there.  Note that if the keys are found
1797
1791
        # but had no changes or no content, the fallback may not return
1798
1792
        # anything.
1799
 
        if keys and not self._fallback_vfs:
 
1793
        if keys and not self._immediate_fallback_vfs:
1800
1794
            # XXX: strictly the second parameter is meant to be the file id
1801
1795
            # but it's not easily accessible here.
1802
1796
            raise RevisionNotPresent(keys, repr(self))
1803
 
        for source in self._fallback_vfs:
 
1797
        for source in self._immediate_fallback_vfs:
1804
1798
            if not keys:
1805
1799
                break
1806
1800
            source_keys = set()
1879
1873
        :return: the header and the decompressor stream.
1880
1874
                 as (stream, header_record)
1881
1875
        """
1882
 
        df = tuned_gzip.GzipFile(mode='rb', fileobj=StringIO(raw_data))
 
1876
        df = gzip.GzipFile(mode='rb', fileobj=StringIO(raw_data))
1883
1877
        try:
1884
1878
            # Current serialise
1885
1879
            rec = self._check_header(key, df.readline())
1894
1888
        # 4168 calls in 2880 217 internal
1895
1889
        # 4168 calls to _parse_record_header in 2121
1896
1890
        # 4168 calls to readlines in 330
1897
 
        df = tuned_gzip.GzipFile(mode='rb', fileobj=StringIO(data))
 
1891
        df = gzip.GzipFile(mode='rb', fileobj=StringIO(data))
1898
1892
        try:
1899
1893
            record_contents = df.readlines()
1900
1894
        except Exception, e:
2015
2009
        """See VersionedFiles.keys."""
2016
2010
        if 'evil' in debug.debug_flags:
2017
2011
            trace.mutter_callsite(2, "keys scales with size of history")
2018
 
        sources = [self._index] + self._fallback_vfs
 
2012
        sources = [self._index] + self._immediate_fallback_vfs
2019
2013
        result = set()
2020
2014
        for source in sources:
2021
2015
            result.update(source.keys())
2061
2055
 
2062
2056
        missing_keys = set(nonlocal_keys)
2063
2057
        # Read from remote versioned file instances and provide to our caller.
2064
 
        for source in self.vf._fallback_vfs:
 
2058
        for source in self.vf._immediate_fallback_vfs:
2065
2059
            if not missing_keys:
2066
2060
                break
2067
2061
            # Loop over fallback repositories asking them for texts - ignore
2786
2780
        return key[:-1], key[-1]
2787
2781
 
2788
2782
 
2789
 
class _KeyRefs(object):
2790
 
 
2791
 
    def __init__(self, track_new_keys=False):
2792
 
        # dict mapping 'key' to 'set of keys referring to that key'
2793
 
        self.refs = {}
2794
 
        if track_new_keys:
2795
 
            # set remembering all new keys
2796
 
            self.new_keys = set()
2797
 
        else:
2798
 
            self.new_keys = None
2799
 
 
2800
 
    def clear(self):
2801
 
        if self.refs:
2802
 
            self.refs.clear()
2803
 
        if self.new_keys:
2804
 
            self.new_keys.clear()
2805
 
 
2806
 
    def add_references(self, key, refs):
2807
 
        # Record the new references
2808
 
        for referenced in refs:
2809
 
            try:
2810
 
                needed_by = self.refs[referenced]
2811
 
            except KeyError:
2812
 
                needed_by = self.refs[referenced] = set()
2813
 
            needed_by.add(key)
2814
 
        # Discard references satisfied by the new key
2815
 
        self.add_key(key)
2816
 
 
2817
 
    def get_new_keys(self):
2818
 
        return self.new_keys
2819
 
    
2820
 
    def get_unsatisfied_refs(self):
2821
 
        return self.refs.iterkeys()
2822
 
 
2823
 
    def _satisfy_refs_for_key(self, key):
2824
 
        try:
2825
 
            del self.refs[key]
2826
 
        except KeyError:
2827
 
            # No keys depended on this key.  That's ok.
2828
 
            pass
2829
 
 
2830
 
    def add_key(self, key):
2831
 
        # satisfy refs for key, and remember that we've seen this key.
2832
 
        self._satisfy_refs_for_key(key)
2833
 
        if self.new_keys is not None:
2834
 
            self.new_keys.add(key)
2835
 
 
2836
 
    def satisfy_refs_for_keys(self, keys):
2837
 
        for key in keys:
2838
 
            self._satisfy_refs_for_key(key)
2839
 
 
2840
 
    def get_referrers(self):
2841
 
        result = set()
2842
 
        for referrers in self.refs.itervalues():
2843
 
            result.update(referrers)
2844
 
        return result
2845
 
 
2846
 
 
2847
2783
class _KnitGraphIndex(object):
2848
2784
    """A KnitVersionedFiles index layered on GraphIndex."""
2849
2785
 
3278
3214
                yield data
3279
3215
 
3280
3216
 
3281
 
class _DirectPackAccess(object):
3282
 
    """Access to data in one or more packs with less translation."""
3283
 
 
3284
 
    def __init__(self, index_to_packs, reload_func=None, flush_func=None):
3285
 
        """Create a _DirectPackAccess object.
3286
 
 
3287
 
        :param index_to_packs: A dict mapping index objects to the transport
3288
 
            and file names for obtaining data.
3289
 
        :param reload_func: A function to call if we determine that the pack
3290
 
            files have moved and we need to reload our caches. See
3291
 
            bzrlib.repo_fmt.pack_repo.AggregateIndex for more details.
3292
 
        """
3293
 
        self._container_writer = None
3294
 
        self._write_index = None
3295
 
        self._indices = index_to_packs
3296
 
        self._reload_func = reload_func
3297
 
        self._flush_func = flush_func
3298
 
 
3299
 
    def add_raw_records(self, key_sizes, raw_data):
3300
 
        """Add raw knit bytes to a storage area.
3301
 
 
3302
 
        The data is spooled to the container writer in one bytes-record per
3303
 
        raw data item.
3304
 
 
3305
 
        :param sizes: An iterable of tuples containing the key and size of each
3306
 
            raw data segment.
3307
 
        :param raw_data: A bytestring containing the data.
3308
 
        :return: A list of memos to retrieve the record later. Each memo is an
3309
 
            opaque index memo. For _DirectPackAccess the memo is (index, pos,
3310
 
            length), where the index field is the write_index object supplied
3311
 
            to the PackAccess object.
3312
 
        """
3313
 
        if type(raw_data) is not str:
3314
 
            raise AssertionError(
3315
 
                'data must be plain bytes was %s' % type(raw_data))
3316
 
        result = []
3317
 
        offset = 0
3318
 
        for key, size in key_sizes:
3319
 
            p_offset, p_length = self._container_writer.add_bytes_record(
3320
 
                raw_data[offset:offset+size], [])
3321
 
            offset += size
3322
 
            result.append((self._write_index, p_offset, p_length))
3323
 
        return result
3324
 
 
3325
 
    def flush(self):
3326
 
        """Flush pending writes on this access object.
3327
 
 
3328
 
        This will flush any buffered writes to a NewPack.
3329
 
        """
3330
 
        if self._flush_func is not None:
3331
 
            self._flush_func()
3332
 
            
3333
 
    def get_raw_records(self, memos_for_retrieval):
3334
 
        """Get the raw bytes for a records.
3335
 
 
3336
 
        :param memos_for_retrieval: An iterable containing the (index, pos,
3337
 
            length) memo for retrieving the bytes. The Pack access method
3338
 
            looks up the pack to use for a given record in its index_to_pack
3339
 
            map.
3340
 
        :return: An iterator over the bytes of the records.
3341
 
        """
3342
 
        # first pass, group into same-index requests
3343
 
        request_lists = []
3344
 
        current_index = None
3345
 
        for (index, offset, length) in memos_for_retrieval:
3346
 
            if current_index == index:
3347
 
                current_list.append((offset, length))
3348
 
            else:
3349
 
                if current_index is not None:
3350
 
                    request_lists.append((current_index, current_list))
3351
 
                current_index = index
3352
 
                current_list = [(offset, length)]
3353
 
        # handle the last entry
3354
 
        if current_index is not None:
3355
 
            request_lists.append((current_index, current_list))
3356
 
        for index, offsets in request_lists:
3357
 
            try:
3358
 
                transport, path = self._indices[index]
3359
 
            except KeyError:
3360
 
                # A KeyError here indicates that someone has triggered an index
3361
 
                # reload, and this index has gone missing, we need to start
3362
 
                # over.
3363
 
                if self._reload_func is None:
3364
 
                    # If we don't have a _reload_func there is nothing that can
3365
 
                    # be done
3366
 
                    raise
3367
 
                raise errors.RetryWithNewPacks(index,
3368
 
                                               reload_occurred=True,
3369
 
                                               exc_info=sys.exc_info())
3370
 
            try:
3371
 
                reader = pack.make_readv_reader(transport, path, offsets)
3372
 
                for names, read_func in reader.iter_records():
3373
 
                    yield read_func(None)
3374
 
            except errors.NoSuchFile:
3375
 
                # A NoSuchFile error indicates that a pack file has gone
3376
 
                # missing on disk, we need to trigger a reload, and start over.
3377
 
                if self._reload_func is None:
3378
 
                    raise
3379
 
                raise errors.RetryWithNewPacks(transport.abspath(path),
3380
 
                                               reload_occurred=False,
3381
 
                                               exc_info=sys.exc_info())
3382
 
 
3383
 
    def set_writer(self, writer, index, transport_packname):
3384
 
        """Set a writer to use for adding data."""
3385
 
        if index is not None:
3386
 
            self._indices[index] = transport_packname
3387
 
        self._container_writer = writer
3388
 
        self._write_index = index
3389
 
 
3390
 
    def reload_or_raise(self, retry_exc):
3391
 
        """Try calling the reload function, or re-raise the original exception.
3392
 
 
3393
 
        This should be called after _DirectPackAccess raises a
3394
 
        RetryWithNewPacks exception. This function will handle the common logic
3395
 
        of determining when the error is fatal versus being temporary.
3396
 
        It will also make sure that the original exception is raised, rather
3397
 
        than the RetryWithNewPacks exception.
3398
 
 
3399
 
        If this function returns, then the calling function should retry
3400
 
        whatever operation was being performed. Otherwise an exception will
3401
 
        be raised.
3402
 
 
3403
 
        :param retry_exc: A RetryWithNewPacks exception.
3404
 
        """
3405
 
        is_error = False
3406
 
        if self._reload_func is None:
3407
 
            is_error = True
3408
 
        elif not self._reload_func():
3409
 
            # The reload claimed that nothing changed
3410
 
            if not retry_exc.reload_occurred:
3411
 
                # If there wasn't an earlier reload, then we really were
3412
 
                # expecting to find changes. We didn't find them, so this is a
3413
 
                # hard error
3414
 
                is_error = True
3415
 
        if is_error:
3416
 
            exc_class, exc_value, exc_traceback = retry_exc.exc_info
3417
 
            raise exc_class, exc_value, exc_traceback
3418
 
 
3419
 
 
3420
 
# Deprecated, use PatienceSequenceMatcher instead
3421
 
KnitSequenceMatcher = patiencediff.PatienceSequenceMatcher
3422
 
 
3423
 
 
3424
3217
def annotate_knit(knit, revision_id):
3425
3218
    """Annotate a knit with no cached annotations.
3426
3219
 
3524
3317
        return records, ann_keys
3525
3318
 
3526
3319
    def _get_needed_texts(self, key, pb=None):
3527
 
        # if True or len(self._vf._fallback_vfs) > 0:
3528
 
        if len(self._vf._fallback_vfs) > 0:
 
3320
        # if True or len(self._vf._immediate_fallback_vfs) > 0:
 
3321
        if len(self._vf._immediate_fallback_vfs) > 0:
3529
3322
            # If we have fallbacks, go to the generic path
3530
3323
            for v in annotate.Annotator._get_needed_texts(self, key, pb=pb):
3531
3324
                yield v