~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/knit.py

(gz) Change minimum required testtools version for selftest to 0.9.5 for
 unicode fixes (Martin [gz])

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2011 Canonical Ltd
 
1
# Copyright (C) 2006-2010 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
59
60
 
60
61
from bzrlib.lazy_import import lazy_import
61
62
lazy_import(globals(), """
62
 
import gzip
63
 
 
64
63
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,
69
70
    pack,
70
71
    patiencediff,
 
72
    progress,
71
73
    static_tuple,
72
74
    trace,
73
75
    tsort,
74
76
    tuned_gzip,
75
77
    ui,
76
78
    )
77
 
 
78
 
from bzrlib.repofmt import pack_repo
79
79
""")
80
80
from bzrlib import (
81
 
    annotate,
82
81
    errors,
83
82
    osutils,
84
83
    )
85
84
from bzrlib.errors import (
 
85
    FileExists,
86
86
    NoSuchFile,
 
87
    KnitError,
87
88
    InvalidRevisionId,
88
89
    KnitCorrupt,
89
90
    KnitHeaderError,
90
91
    RevisionNotPresent,
 
92
    RevisionAlreadyPresent,
91
93
    SHA1KnitCorrupt,
92
94
    )
93
95
from bzrlib.osutils import (
94
96
    contains_whitespace,
 
97
    contains_linebreaks,
95
98
    sha_string,
96
99
    sha_strings,
97
100
    split_lines,
98
101
    )
99
102
from bzrlib.versionedfile import (
100
 
    _KeyRefs,
101
103
    AbsentContentFactory,
102
104
    adapter_registry,
103
105
    ConstantMapper,
104
106
    ContentFactory,
 
107
    ChunkedContentFactory,
105
108
    sort_groupcompress,
 
109
    VersionedFile,
106
110
    VersionedFiles,
107
111
    )
108
112
 
801
805
        writer.begin()
802
806
        index = _KnitGraphIndex(graph_index, lambda:True, parents=parents,
803
807
            deltas=delta, add_callback=graph_index.add_nodes)
804
 
        access = pack_repo._DirectPackAccess({})
 
808
        access = _DirectPackAccess({})
805
809
        access.set_writer(writer, graph_index, (transport, 'newpack'))
806
810
        result = KnitVersionedFiles(index, access,
807
811
            max_delta_chain=max_delta_chain)
878
882
            self._factory = KnitAnnotateFactory()
879
883
        else:
880
884
            self._factory = KnitPlainFactory()
881
 
        self._immediate_fallback_vfs = []
 
885
        self._fallback_vfs = []
882
886
        self._reload_func = reload_func
883
887
 
884
888
    def __repr__(self):
892
896
 
893
897
        :param a_versioned_files: A VersionedFiles object.
894
898
        """
895
 
        self._immediate_fallback_vfs.append(a_versioned_files)
 
899
        self._fallback_vfs.append(a_versioned_files)
896
900
 
897
901
    def add_lines(self, key, parents, lines, parent_texts=None,
898
902
        left_matching_blocks=None, nostore_sha=None, random_id=False,
1065
1069
                    raise errors.KnitCorrupt(self,
1066
1070
                        "Missing basis parent %s for %s" % (
1067
1071
                        compression_parent, key))
1068
 
        for fallback_vfs in self._immediate_fallback_vfs:
 
1072
        for fallback_vfs in self._fallback_vfs:
1069
1073
            fallback_vfs.check()
1070
1074
 
1071
1075
    def _check_add(self, key, lines, random_id, check_content):
1191
1195
    def get_known_graph_ancestry(self, keys):
1192
1196
        """Get a KnownGraph instance with the ancestry of keys."""
1193
1197
        parent_map, missing_keys = self._index.find_ancestry(keys)
1194
 
        for fallback in self._transitive_fallbacks():
 
1198
        for fallback in self._fallback_vfs:
1195
1199
            if not missing_keys:
1196
1200
                break
1197
1201
            (f_parent_map, f_missing_keys) = fallback._index.find_ancestry(
1221
1225
            and so on.
1222
1226
        """
1223
1227
        result = {}
1224
 
        sources = [self._index] + self._immediate_fallback_vfs
 
1228
        sources = [self._index] + self._fallback_vfs
1225
1229
        source_results = []
1226
1230
        missing = set(keys)
1227
1231
        for source in sources:
1521
1525
                        yield KnitContentFactory(key, global_map[key],
1522
1526
                            record_details, None, raw_data, self._factory.annotated, None)
1523
1527
                else:
1524
 
                    vf = self._immediate_fallback_vfs[parent_maps.index(source) - 1]
 
1528
                    vf = self._fallback_vfs[parent_maps.index(source) - 1]
1525
1529
                    for record in vf.get_record_stream(keys, ordering,
1526
1530
                        include_delta_closure):
1527
1531
                        yield record
1537
1541
            # record entry 2 is the 'digest'.
1538
1542
            result[key] = details[2]
1539
1543
        missing.difference_update(set(result))
1540
 
        for source in self._immediate_fallback_vfs:
 
1544
        for source in self._fallback_vfs:
1541
1545
            if not missing:
1542
1546
                break
1543
1547
            new_result = source.get_sha1s(missing)
1614
1618
                raise RevisionNotPresent([record.key], self)
1615
1619
            elif ((record.storage_kind in knit_types)
1616
1620
                  and (compression_parent is None
1617
 
                       or not self._immediate_fallback_vfs
 
1621
                       or not self._fallback_vfs
1618
1622
                       or self._index.has_key(compression_parent)
1619
1623
                       or not self.has_key(compression_parent))):
1620
1624
                # we can insert the knit record literally if either it has no
1792
1796
        # vfs, and hope to find them there.  Note that if the keys are found
1793
1797
        # but had no changes or no content, the fallback may not return
1794
1798
        # anything.
1795
 
        if keys and not self._immediate_fallback_vfs:
 
1799
        if keys and not self._fallback_vfs:
1796
1800
            # XXX: strictly the second parameter is meant to be the file id
1797
1801
            # but it's not easily accessible here.
1798
1802
            raise RevisionNotPresent(keys, repr(self))
1799
 
        for source in self._immediate_fallback_vfs:
 
1803
        for source in self._fallback_vfs:
1800
1804
            if not keys:
1801
1805
                break
1802
1806
            source_keys = set()
1875
1879
        :return: the header and the decompressor stream.
1876
1880
                 as (stream, header_record)
1877
1881
        """
1878
 
        df = gzip.GzipFile(mode='rb', fileobj=StringIO(raw_data))
 
1882
        df = tuned_gzip.GzipFile(mode='rb', fileobj=StringIO(raw_data))
1879
1883
        try:
1880
1884
            # Current serialise
1881
1885
            rec = self._check_header(key, df.readline())
1890
1894
        # 4168 calls in 2880 217 internal
1891
1895
        # 4168 calls to _parse_record_header in 2121
1892
1896
        # 4168 calls to readlines in 330
1893
 
        df = gzip.GzipFile(mode='rb', fileobj=StringIO(data))
 
1897
        df = tuned_gzip.GzipFile(mode='rb', fileobj=StringIO(data))
1894
1898
        try:
1895
1899
            record_contents = df.readlines()
1896
1900
        except Exception, e:
2011
2015
        """See VersionedFiles.keys."""
2012
2016
        if 'evil' in debug.debug_flags:
2013
2017
            trace.mutter_callsite(2, "keys scales with size of history")
2014
 
        sources = [self._index] + self._immediate_fallback_vfs
 
2018
        sources = [self._index] + self._fallback_vfs
2015
2019
        result = set()
2016
2020
        for source in sources:
2017
2021
            result.update(source.keys())
2057
2061
 
2058
2062
        missing_keys = set(nonlocal_keys)
2059
2063
        # Read from remote versioned file instances and provide to our caller.
2060
 
        for source in self.vf._immediate_fallback_vfs:
 
2064
        for source in self.vf._fallback_vfs:
2061
2065
            if not missing_keys:
2062
2066
                break
2063
2067
            # Loop over fallback repositories asking them for texts - ignore
2782
2786
        return key[:-1], key[-1]
2783
2787
 
2784
2788
 
 
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
 
2785
2847
class _KnitGraphIndex(object):
2786
2848
    """A KnitVersionedFiles index layered on GraphIndex."""
2787
2849
 
3458
3520
        return records, ann_keys
3459
3521
 
3460
3522
    def _get_needed_texts(self, key, pb=None):
3461
 
        # if True or len(self._vf._immediate_fallback_vfs) > 0:
3462
 
        if len(self._vf._immediate_fallback_vfs) > 0:
 
3523
        # if True or len(self._vf._fallback_vfs) > 0:
 
3524
        if len(self._vf._fallback_vfs) > 0:
3463
3525
            # If we have fallbacks, go to the generic path
3464
3526
            for v in annotate.Annotator._get_needed_texts(self, key, pb=pb):
3465
3527
                yield v