~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/knit.py

  • Committer: Andrew Bennetts
  • Date: 2009-11-25 07:27:43 UTC
  • mto: This revision was merged to the branch mainline in revision 4825.
  • Revision ID: andrew.bennetts@canonical.com-20091125072743-v6sv4m2mkt9iyslp
Terminate SSHSubprocesses when no refs to them are left, in case .close is never called.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2011 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007, 2008 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
 
    patiencediff,
71
 
    static_tuple,
 
71
    progress,
72
72
    trace,
73
73
    tsort,
74
74
    tuned_gzip,
75
 
    ui,
76
75
    )
77
 
 
78
 
from bzrlib.repofmt import pack_repo
79
76
""")
80
77
from bzrlib import (
81
 
    annotate,
82
78
    errors,
83
79
    osutils,
 
80
    patiencediff,
84
81
    )
85
82
from bzrlib.errors import (
 
83
    FileExists,
86
84
    NoSuchFile,
 
85
    KnitError,
87
86
    InvalidRevisionId,
88
87
    KnitCorrupt,
89
88
    KnitHeaderError,
90
89
    RevisionNotPresent,
 
90
    RevisionAlreadyPresent,
91
91
    SHA1KnitCorrupt,
92
92
    )
93
93
from bzrlib.osutils import (
94
94
    contains_whitespace,
 
95
    contains_linebreaks,
95
96
    sha_string,
96
97
    sha_strings,
97
98
    split_lines,
98
99
    )
99
100
from bzrlib.versionedfile import (
100
 
    _KeyRefs,
101
101
    AbsentContentFactory,
102
102
    adapter_registry,
103
103
    ConstantMapper,
104
104
    ContentFactory,
 
105
    ChunkedContentFactory,
105
106
    sort_groupcompress,
106
 
    VersionedFilesWithFallbacks,
 
107
    VersionedFile,
 
108
    VersionedFiles,
107
109
    )
108
110
 
109
111
 
408
410
class KnitContent(object):
409
411
    """Content of a knit version to which deltas can be applied.
410
412
 
411
 
    This is always stored in memory as a list of lines with \\n at the end,
 
413
    This is always stored in memory as a list of lines with \n at the end,
412
414
    plus a flag saying if the final ending is really there or not, because that
413
415
    corresponds to the on-disk knit representation.
414
416
    """
801
803
        writer.begin()
802
804
        index = _KnitGraphIndex(graph_index, lambda:True, parents=parents,
803
805
            deltas=delta, add_callback=graph_index.add_nodes)
804
 
        access = pack_repo._DirectPackAccess({})
 
806
        access = _DirectPackAccess({})
805
807
        access.set_writer(writer, graph_index, (transport, 'newpack'))
806
808
        result = KnitVersionedFiles(index, access,
807
809
            max_delta_chain=max_delta_chain)
845
847
                in all_build_index_memos.itervalues()])
846
848
 
847
849
 
848
 
class KnitVersionedFiles(VersionedFilesWithFallbacks):
 
850
class KnitVersionedFiles(VersionedFiles):
849
851
    """Storage for many versioned files using knit compression.
850
852
 
851
853
    Backend storage is managed by indices and data objects.
878
880
            self._factory = KnitAnnotateFactory()
879
881
        else:
880
882
            self._factory = KnitPlainFactory()
881
 
        self._immediate_fallback_vfs = []
 
883
        self._fallback_vfs = []
882
884
        self._reload_func = reload_func
883
885
 
884
886
    def __repr__(self):
887
889
            self._index,
888
890
            self._access)
889
891
 
890
 
    def without_fallbacks(self):
891
 
        """Return a clone of this object without any fallbacks configured."""
892
 
        return KnitVersionedFiles(self._index, self._access,
893
 
            self._max_delta_chain, self._factory.annotated,
894
 
            self._reload_func)
895
 
 
896
892
    def add_fallback_versioned_files(self, a_versioned_files):
897
893
        """Add a source of texts for texts not present in this knit.
898
894
 
899
895
        :param a_versioned_files: A VersionedFiles object.
900
896
        """
901
 
        self._immediate_fallback_vfs.append(a_versioned_files)
 
897
        self._fallback_vfs.append(a_versioned_files)
902
898
 
903
899
    def add_lines(self, key, parents, lines, parent_texts=None,
904
900
        left_matching_blocks=None, nostore_sha=None, random_id=False,
1071
1067
                    raise errors.KnitCorrupt(self,
1072
1068
                        "Missing basis parent %s for %s" % (
1073
1069
                        compression_parent, key))
1074
 
        for fallback_vfs in self._immediate_fallback_vfs:
 
1070
        for fallback_vfs in self._fallback_vfs:
1075
1071
            fallback_vfs.check()
1076
1072
 
1077
1073
    def _check_add(self, key, lines, random_id, check_content):
1155
1151
 
1156
1152
        A dict of key to (record_details, index_memo, next, parents) is
1157
1153
        returned.
1158
 
 
1159
 
        * method is the way referenced data should be applied.
1160
 
        * index_memo is the handle to pass to the data access to actually get
1161
 
          the data
1162
 
        * next is the build-parent of the version, or None for fulltexts.
1163
 
        * parents is the version_ids of the parents of this version
1164
 
 
1165
 
        :param allow_missing: If True do not raise an error on a missing
1166
 
            component, just ignore it.
 
1154
        method is the way referenced data should be applied.
 
1155
        index_memo is the handle to pass to the data access to actually get the
 
1156
            data
 
1157
        next is the build-parent of the version, or None for fulltexts.
 
1158
        parents is the version_ids of the parents of this version
 
1159
 
 
1160
        :param allow_missing: If True do not raise an error on a missing component,
 
1161
            just ignore it.
1167
1162
        """
1168
1163
        component_data = {}
1169
1164
        pending_components = keys
1195
1190
        generator = _VFContentMapGenerator(self, [key])
1196
1191
        return generator._get_content(key)
1197
1192
 
 
1193
    def get_known_graph_ancestry(self, keys):
 
1194
        """Get a KnownGraph instance with the ancestry of keys."""
 
1195
        parent_map, missing_keys = self._index.find_ancestry(keys)
 
1196
        for fallback in self._fallback_vfs:
 
1197
            if not missing_keys:
 
1198
                break
 
1199
            (f_parent_map, f_missing_keys) = fallback._index.find_ancestry(
 
1200
                                                missing_keys)
 
1201
            parent_map.update(f_parent_map)
 
1202
            missing_keys = f_missing_keys
 
1203
        kg = _mod_graph.KnownGraph(parent_map)
 
1204
        return kg
 
1205
 
1198
1206
    def get_parent_map(self, keys):
1199
1207
        """Get a map of the graph parents of keys.
1200
1208
 
1215
1223
            and so on.
1216
1224
        """
1217
1225
        result = {}
1218
 
        sources = [self._index] + self._immediate_fallback_vfs
 
1226
        sources = [self._index] + self._fallback_vfs
1219
1227
        source_results = []
1220
1228
        missing = set(keys)
1221
1229
        for source in sources:
1231
1239
        """Produce a dictionary of knit records.
1232
1240
 
1233
1241
        :return: {key:(record, record_details, digest, next)}
1234
 
 
1235
 
            * record: data returned from read_records (a KnitContentobject)
1236
 
            * record_details: opaque information to pass to parse_record
1237
 
            * digest: SHA1 digest of the full text after all steps are done
1238
 
            * next: build-parent of the version, i.e. the leftmost ancestor.
 
1242
            record
 
1243
                data returned from read_records (a KnitContentobject)
 
1244
            record_details
 
1245
                opaque information to pass to parse_record
 
1246
            digest
 
1247
                SHA1 digest of the full text after all steps are done
 
1248
            next
 
1249
                build-parent of the version, i.e. the leftmost ancestor.
1239
1250
                Will be None if the record is not a delta.
1240
 
 
1241
1251
        :param keys: The keys to build a map for
1242
1252
        :param allow_missing: If some records are missing, rather than
1243
1253
            error, just return the data that could be generated.
1513
1523
                        yield KnitContentFactory(key, global_map[key],
1514
1524
                            record_details, None, raw_data, self._factory.annotated, None)
1515
1525
                else:
1516
 
                    vf = self._immediate_fallback_vfs[parent_maps.index(source) - 1]
 
1526
                    vf = self._fallback_vfs[parent_maps.index(source) - 1]
1517
1527
                    for record in vf.get_record_stream(keys, ordering,
1518
1528
                        include_delta_closure):
1519
1529
                        yield record
1529
1539
            # record entry 2 is the 'digest'.
1530
1540
            result[key] = details[2]
1531
1541
        missing.difference_update(set(result))
1532
 
        for source in self._immediate_fallback_vfs:
 
1542
        for source in self._fallback_vfs:
1533
1543
            if not missing:
1534
1544
                break
1535
1545
            new_result = source.get_sha1s(missing)
1606
1616
                raise RevisionNotPresent([record.key], self)
1607
1617
            elif ((record.storage_kind in knit_types)
1608
1618
                  and (compression_parent is None
1609
 
                       or not self._immediate_fallback_vfs
 
1619
                       or not self._fallback_vfs
1610
1620
                       or self._index.has_key(compression_parent)
1611
1621
                       or not self.has_key(compression_parent))):
1612
1622
                # we can insert the knit record literally if either it has no
1744
1754
        :return: An iterator over (line, key).
1745
1755
        """
1746
1756
        if pb is None:
1747
 
            pb = ui.ui_factory.nested_progress_bar()
 
1757
            pb = progress.DummyProgress()
1748
1758
        keys = set(keys)
1749
1759
        total = len(keys)
1750
1760
        done = False
1784
1794
        # vfs, and hope to find them there.  Note that if the keys are found
1785
1795
        # but had no changes or no content, the fallback may not return
1786
1796
        # anything.
1787
 
        if keys and not self._immediate_fallback_vfs:
 
1797
        if keys and not self._fallback_vfs:
1788
1798
            # XXX: strictly the second parameter is meant to be the file id
1789
1799
            # but it's not easily accessible here.
1790
1800
            raise RevisionNotPresent(keys, repr(self))
1791
 
        for source in self._immediate_fallback_vfs:
 
1801
        for source in self._fallback_vfs:
1792
1802
            if not keys:
1793
1803
                break
1794
1804
            source_keys = set()
1867
1877
        :return: the header and the decompressor stream.
1868
1878
                 as (stream, header_record)
1869
1879
        """
1870
 
        df = gzip.GzipFile(mode='rb', fileobj=StringIO(raw_data))
 
1880
        df = tuned_gzip.GzipFile(mode='rb', fileobj=StringIO(raw_data))
1871
1881
        try:
1872
1882
            # Current serialise
1873
1883
            rec = self._check_header(key, df.readline())
1882
1892
        # 4168 calls in 2880 217 internal
1883
1893
        # 4168 calls to _parse_record_header in 2121
1884
1894
        # 4168 calls to readlines in 330
1885
 
        df = gzip.GzipFile(mode='rb', fileobj=StringIO(data))
 
1895
        df = tuned_gzip.GzipFile(mode='rb', fileobj=StringIO(data))
1886
1896
        try:
1887
1897
            record_contents = df.readlines()
1888
1898
        except Exception, e:
1910
1920
        The result will be returned in whatever is the fastest to read.
1911
1921
        Not by the order requested. Also, multiple requests for the same
1912
1922
        record will only yield 1 response.
1913
 
 
1914
1923
        :param records: A list of (key, access_memo) entries
1915
1924
        :return: Yields (key, contents, digest) in the order
1916
1925
                 read, not the order requested
1974
1983
        :param key: The key of the record. Currently keys are always serialised
1975
1984
            using just the trailing component.
1976
1985
        :param dense_lines: The bytes of lines but in a denser form. For
1977
 
            instance, if lines is a list of 1000 bytestrings each ending in
1978
 
            \\n, dense_lines may be a list with one line in it, containing all
1979
 
            the 1000's lines and their \\n's. Using dense_lines if it is
1980
 
            already known is a win because the string join to create bytes in
1981
 
            this function spends less time resizing the final string.
 
1986
            instance, if lines is a list of 1000 bytestrings each ending in \n,
 
1987
            dense_lines may be a list with one line in it, containing all the
 
1988
            1000's lines and their \n's. Using dense_lines if it is already
 
1989
            known is a win because the string join to create bytes in this
 
1990
            function spends less time resizing the final string.
1982
1991
        :return: (len, a StringIO instance with the raw data ready to read.)
1983
1992
        """
1984
1993
        chunks = ["version %s %d %s\n" % (key[-1], len(lines), digest)]
2004
2013
        """See VersionedFiles.keys."""
2005
2014
        if 'evil' in debug.debug_flags:
2006
2015
            trace.mutter_callsite(2, "keys scales with size of history")
2007
 
        sources = [self._index] + self._immediate_fallback_vfs
 
2016
        sources = [self._index] + self._fallback_vfs
2008
2017
        result = set()
2009
2018
        for source in sources:
2010
2019
            result.update(source.keys())
2050
2059
 
2051
2060
        missing_keys = set(nonlocal_keys)
2052
2061
        # Read from remote versioned file instances and provide to our caller.
2053
 
        for source in self.vf._immediate_fallback_vfs:
 
2062
        for source in self.vf._fallback_vfs:
2054
2063
            if not missing_keys:
2055
2064
                break
2056
2065
            # Loop over fallback repositories asking them for texts - ignore
2775
2784
        return key[:-1], key[-1]
2776
2785
 
2777
2786
 
 
2787
class _KeyRefs(object):
 
2788
 
 
2789
    def __init__(self, track_new_keys=False):
 
2790
        # dict mapping 'key' to 'set of keys referring to that key'
 
2791
        self.refs = {}
 
2792
        if track_new_keys:
 
2793
            # set remembering all new keys
 
2794
            self.new_keys = set()
 
2795
        else:
 
2796
            self.new_keys = None
 
2797
 
 
2798
    def clear(self):
 
2799
        if self.refs:
 
2800
            self.refs.clear()
 
2801
        if self.new_keys:
 
2802
            self.new_keys.clear()
 
2803
 
 
2804
    def add_references(self, key, refs):
 
2805
        # Record the new references
 
2806
        for referenced in refs:
 
2807
            try:
 
2808
                needed_by = self.refs[referenced]
 
2809
            except KeyError:
 
2810
                needed_by = self.refs[referenced] = set()
 
2811
            needed_by.add(key)
 
2812
        # Discard references satisfied by the new key
 
2813
        self.add_key(key)
 
2814
 
 
2815
    def get_new_keys(self):
 
2816
        return self.new_keys
 
2817
    
 
2818
    def get_unsatisfied_refs(self):
 
2819
        return self.refs.iterkeys()
 
2820
 
 
2821
    def _satisfy_refs_for_key(self, key):
 
2822
        try:
 
2823
            del self.refs[key]
 
2824
        except KeyError:
 
2825
            # No keys depended on this key.  That's ok.
 
2826
            pass
 
2827
 
 
2828
    def add_key(self, key):
 
2829
        # satisfy refs for key, and remember that we've seen this key.
 
2830
        self._satisfy_refs_for_key(key)
 
2831
        if self.new_keys is not None:
 
2832
            self.new_keys.add(key)
 
2833
 
 
2834
    def satisfy_refs_for_keys(self, keys):
 
2835
        for key in keys:
 
2836
            self._satisfy_refs_for_key(key)
 
2837
 
 
2838
    def get_referrers(self):
 
2839
        result = set()
 
2840
        for referrers in self.refs.itervalues():
 
2841
            result.update(referrers)
 
2842
        return result
 
2843
 
 
2844
 
2778
2845
class _KnitGraphIndex(object):
2779
2846
    """A KnitVersionedFiles index layered on GraphIndex."""
2780
2847
 
2877
2944
        if not random_id:
2878
2945
            present_nodes = self._get_entries(keys)
2879
2946
            for (index, key, value, node_refs) in present_nodes:
2880
 
                parents = node_refs[:1]
2881
 
                # Sometimes these are passed as a list rather than a tuple
2882
 
                passed = static_tuple.as_tuples(keys[key])
2883
 
                passed_parents = passed[1][:1]
2884
2947
                if (value[0] != keys[key][0][0] or
2885
 
                    parents != passed_parents):
2886
 
                    node_refs = static_tuple.as_tuples(node_refs)
 
2948
                    node_refs[:1] != keys[key][1][:1]):
2887
2949
                    raise KnitCorrupt(self, "inconsistent details in add_records"
2888
 
                        ": %s %s" % ((value, node_refs), passed))
 
2950
                        ": %s %s" % ((value, node_refs), keys[key]))
2889
2951
                del keys[key]
2890
2952
        result = []
2891
2953
        if self._parents:
3348
3410
            raise exc_class, exc_value, exc_traceback
3349
3411
 
3350
3412
 
 
3413
# Deprecated, use PatienceSequenceMatcher instead
 
3414
KnitSequenceMatcher = patiencediff.PatienceSequenceMatcher
 
3415
 
 
3416
 
3351
3417
def annotate_knit(knit, revision_id):
3352
3418
    """Annotate a knit with no cached annotations.
3353
3419
 
3451
3517
        return records, ann_keys
3452
3518
 
3453
3519
    def _get_needed_texts(self, key, pb=None):
3454
 
        # if True or len(self._vf._immediate_fallback_vfs) > 0:
3455
 
        if len(self._vf._immediate_fallback_vfs) > 0:
 
3520
        # if True or len(self._vf._fallback_vfs) > 0:
 
3521
        if len(self._vf._fallback_vfs) > 0:
3456
3522
            # If we have fallbacks, go to the generic path
3457
3523
            for v in annotate.Annotator._get_needed_texts(self, key, pb=pb):
3458
3524
                yield v