~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/knit.py

  • Committer: Patch Queue Manager
  • Date: 2011-09-22 14:12:18 UTC
  • mfrom: (6155.3.1 jam)
  • Revision ID: pqm@pqm.ubuntu.com-20110922141218-86s4uu6nqvourw4f
(jameinel) Cleanup comments bzrlib/smart/__init__.py (John A Meinel)

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
70
    patiencediff,
72
 
    progress,
73
71
    static_tuple,
74
72
    trace,
75
73
    tsort,
76
74
    tuned_gzip,
77
75
    ui,
78
76
    )
 
77
 
 
78
from bzrlib.repofmt import pack_repo
 
79
from bzrlib.i18n import gettext
79
80
""")
80
81
from bzrlib import (
 
82
    annotate,
81
83
    errors,
82
84
    osutils,
83
85
    )
84
86
from bzrlib.errors import (
85
 
    FileExists,
86
87
    NoSuchFile,
87
 
    KnitError,
88
88
    InvalidRevisionId,
89
89
    KnitCorrupt,
90
90
    KnitHeaderError,
91
91
    RevisionNotPresent,
92
 
    RevisionAlreadyPresent,
93
92
    SHA1KnitCorrupt,
94
93
    )
95
94
from bzrlib.osutils import (
96
95
    contains_whitespace,
97
 
    contains_linebreaks,
98
96
    sha_string,
99
97
    sha_strings,
100
98
    split_lines,
101
99
    )
102
100
from bzrlib.versionedfile import (
 
101
    _KeyRefs,
103
102
    AbsentContentFactory,
104
103
    adapter_registry,
105
104
    ConstantMapper,
106
105
    ContentFactory,
107
 
    ChunkedContentFactory,
108
106
    sort_groupcompress,
109
 
    VersionedFile,
110
 
    VersionedFiles,
 
107
    VersionedFilesWithFallbacks,
111
108
    )
112
109
 
113
110
 
412
409
class KnitContent(object):
413
410
    """Content of a knit version to which deltas can be applied.
414
411
 
415
 
    This is always stored in memory as a list of lines with \n at the end,
 
412
    This is always stored in memory as a list of lines with \\n at the end,
416
413
    plus a flag saying if the final ending is really there or not, because that
417
414
    corresponds to the on-disk knit representation.
418
415
    """
805
802
        writer.begin()
806
803
        index = _KnitGraphIndex(graph_index, lambda:True, parents=parents,
807
804
            deltas=delta, add_callback=graph_index.add_nodes)
808
 
        access = _DirectPackAccess({})
 
805
        access = pack_repo._DirectPackAccess({})
809
806
        access.set_writer(writer, graph_index, (transport, 'newpack'))
810
807
        result = KnitVersionedFiles(index, access,
811
808
            max_delta_chain=max_delta_chain)
849
846
                in all_build_index_memos.itervalues()])
850
847
 
851
848
 
852
 
class KnitVersionedFiles(VersionedFiles):
 
849
class KnitVersionedFiles(VersionedFilesWithFallbacks):
853
850
    """Storage for many versioned files using knit compression.
854
851
 
855
852
    Backend storage is managed by indices and data objects.
882
879
            self._factory = KnitAnnotateFactory()
883
880
        else:
884
881
            self._factory = KnitPlainFactory()
885
 
        self._fallback_vfs = []
 
882
        self._immediate_fallback_vfs = []
886
883
        self._reload_func = reload_func
887
884
 
888
885
    def __repr__(self):
891
888
            self._index,
892
889
            self._access)
893
890
 
 
891
    def without_fallbacks(self):
 
892
        """Return a clone of this object without any fallbacks configured."""
 
893
        return KnitVersionedFiles(self._index, self._access,
 
894
            self._max_delta_chain, self._factory.annotated,
 
895
            self._reload_func)
 
896
 
894
897
    def add_fallback_versioned_files(self, a_versioned_files):
895
898
        """Add a source of texts for texts not present in this knit.
896
899
 
897
900
        :param a_versioned_files: A VersionedFiles object.
898
901
        """
899
 
        self._fallback_vfs.append(a_versioned_files)
 
902
        self._immediate_fallback_vfs.append(a_versioned_files)
900
903
 
901
904
    def add_lines(self, key, parents, lines, parent_texts=None,
902
905
        left_matching_blocks=None, nostore_sha=None, random_id=False,
1069
1072
                    raise errors.KnitCorrupt(self,
1070
1073
                        "Missing basis parent %s for %s" % (
1071
1074
                        compression_parent, key))
1072
 
        for fallback_vfs in self._fallback_vfs:
 
1075
        for fallback_vfs in self._immediate_fallback_vfs:
1073
1076
            fallback_vfs.check()
1074
1077
 
1075
1078
    def _check_add(self, key, lines, random_id, check_content):
1153
1156
 
1154
1157
        A dict of key to (record_details, index_memo, next, parents) is
1155
1158
        returned.
1156
 
        method is the way referenced data should be applied.
1157
 
        index_memo is the handle to pass to the data access to actually get the
1158
 
            data
1159
 
        next is the build-parent of the version, or None for fulltexts.
1160
 
        parents is the version_ids of the parents of this version
1161
 
 
1162
 
        :param allow_missing: If True do not raise an error on a missing component,
1163
 
            just ignore it.
 
1159
 
 
1160
        * method is the way referenced data should be applied.
 
1161
        * index_memo is the handle to pass to the data access to actually get
 
1162
          the data
 
1163
        * next is the build-parent of the version, or None for fulltexts.
 
1164
        * parents is the version_ids of the parents of this version
 
1165
 
 
1166
        :param allow_missing: If True do not raise an error on a missing
 
1167
            component, just ignore it.
1164
1168
        """
1165
1169
        component_data = {}
1166
1170
        pending_components = keys
1192
1196
        generator = _VFContentMapGenerator(self, [key])
1193
1197
        return generator._get_content(key)
1194
1198
 
1195
 
    def get_known_graph_ancestry(self, keys):
1196
 
        """Get a KnownGraph instance with the ancestry of keys."""
1197
 
        parent_map, missing_keys = self._index.find_ancestry(keys)
1198
 
        for fallback in self._fallback_vfs:
1199
 
            if not missing_keys:
1200
 
                break
1201
 
            (f_parent_map, f_missing_keys) = fallback._index.find_ancestry(
1202
 
                                                missing_keys)
1203
 
            parent_map.update(f_parent_map)
1204
 
            missing_keys = f_missing_keys
1205
 
        kg = _mod_graph.KnownGraph(parent_map)
1206
 
        return kg
1207
 
 
1208
1199
    def get_parent_map(self, keys):
1209
1200
        """Get a map of the graph parents of keys.
1210
1201
 
1225
1216
            and so on.
1226
1217
        """
1227
1218
        result = {}
1228
 
        sources = [self._index] + self._fallback_vfs
 
1219
        sources = [self._index] + self._immediate_fallback_vfs
1229
1220
        source_results = []
1230
1221
        missing = set(keys)
1231
1222
        for source in sources:
1241
1232
        """Produce a dictionary of knit records.
1242
1233
 
1243
1234
        :return: {key:(record, record_details, digest, next)}
1244
 
            record
1245
 
                data returned from read_records (a KnitContentobject)
1246
 
            record_details
1247
 
                opaque information to pass to parse_record
1248
 
            digest
1249
 
                SHA1 digest of the full text after all steps are done
1250
 
            next
1251
 
                build-parent of the version, i.e. the leftmost ancestor.
 
1235
 
 
1236
            * record: data returned from read_records (a KnitContentobject)
 
1237
            * record_details: opaque information to pass to parse_record
 
1238
            * digest: SHA1 digest of the full text after all steps are done
 
1239
            * next: build-parent of the version, i.e. the leftmost ancestor.
1252
1240
                Will be None if the record is not a delta.
 
1241
 
1253
1242
        :param keys: The keys to build a map for
1254
1243
        :param allow_missing: If some records are missing, rather than
1255
1244
            error, just return the data that could be generated.
1525
1514
                        yield KnitContentFactory(key, global_map[key],
1526
1515
                            record_details, None, raw_data, self._factory.annotated, None)
1527
1516
                else:
1528
 
                    vf = self._fallback_vfs[parent_maps.index(source) - 1]
 
1517
                    vf = self._immediate_fallback_vfs[parent_maps.index(source) - 1]
1529
1518
                    for record in vf.get_record_stream(keys, ordering,
1530
1519
                        include_delta_closure):
1531
1520
                        yield record
1541
1530
            # record entry 2 is the 'digest'.
1542
1531
            result[key] = details[2]
1543
1532
        missing.difference_update(set(result))
1544
 
        for source in self._fallback_vfs:
 
1533
        for source in self._immediate_fallback_vfs:
1545
1534
            if not missing:
1546
1535
                break
1547
1536
            new_result = source.get_sha1s(missing)
1618
1607
                raise RevisionNotPresent([record.key], self)
1619
1608
            elif ((record.storage_kind in knit_types)
1620
1609
                  and (compression_parent is None
1621
 
                       or not self._fallback_vfs
 
1610
                       or not self._immediate_fallback_vfs
1622
1611
                       or self._index.has_key(compression_parent)
1623
1612
                       or not self.has_key(compression_parent))):
1624
1613
                # we can insert the knit record literally if either it has no
1772
1761
                        key_records.append((key, details[0]))
1773
1762
                records_iter = enumerate(self._read_records_iter(key_records))
1774
1763
                for (key_idx, (key, data, sha_value)) in records_iter:
1775
 
                    pb.update('Walking content', key_idx, total)
 
1764
                    pb.update(gettext('Walking content'), key_idx, total)
1776
1765
                    compression_parent = build_details[key][1]
1777
1766
                    if compression_parent is None:
1778
1767
                        # fulltext
1796
1785
        # vfs, and hope to find them there.  Note that if the keys are found
1797
1786
        # but had no changes or no content, the fallback may not return
1798
1787
        # anything.
1799
 
        if keys and not self._fallback_vfs:
 
1788
        if keys and not self._immediate_fallback_vfs:
1800
1789
            # XXX: strictly the second parameter is meant to be the file id
1801
1790
            # but it's not easily accessible here.
1802
1791
            raise RevisionNotPresent(keys, repr(self))
1803
 
        for source in self._fallback_vfs:
 
1792
        for source in self._immediate_fallback_vfs:
1804
1793
            if not keys:
1805
1794
                break
1806
1795
            source_keys = set()
1808
1797
                source_keys.add(key)
1809
1798
                yield line, key
1810
1799
            keys.difference_update(source_keys)
1811
 
        pb.update('Walking content', total, total)
 
1800
        pb.update(gettext('Walking content'), total, total)
1812
1801
 
1813
1802
    def _make_line_delta(self, delta_seq, new_content):
1814
1803
        """Generate a line delta from delta_seq and new_content."""
1879
1868
        :return: the header and the decompressor stream.
1880
1869
                 as (stream, header_record)
1881
1870
        """
1882
 
        df = tuned_gzip.GzipFile(mode='rb', fileobj=StringIO(raw_data))
 
1871
        df = gzip.GzipFile(mode='rb', fileobj=StringIO(raw_data))
1883
1872
        try:
1884
1873
            # Current serialise
1885
1874
            rec = self._check_header(key, df.readline())
1894
1883
        # 4168 calls in 2880 217 internal
1895
1884
        # 4168 calls to _parse_record_header in 2121
1896
1885
        # 4168 calls to readlines in 330
1897
 
        df = tuned_gzip.GzipFile(mode='rb', fileobj=StringIO(data))
 
1886
        df = gzip.GzipFile(mode='rb', fileobj=StringIO(data))
1898
1887
        try:
1899
1888
            record_contents = df.readlines()
1900
1889
        except Exception, e:
1922
1911
        The result will be returned in whatever is the fastest to read.
1923
1912
        Not by the order requested. Also, multiple requests for the same
1924
1913
        record will only yield 1 response.
 
1914
 
1925
1915
        :param records: A list of (key, access_memo) entries
1926
1916
        :return: Yields (key, contents, digest) in the order
1927
1917
                 read, not the order requested
1985
1975
        :param key: The key of the record. Currently keys are always serialised
1986
1976
            using just the trailing component.
1987
1977
        :param dense_lines: The bytes of lines but in a denser form. For
1988
 
            instance, if lines is a list of 1000 bytestrings each ending in \n,
1989
 
            dense_lines may be a list with one line in it, containing all the
1990
 
            1000's lines and their \n's. Using dense_lines if it is already
1991
 
            known is a win because the string join to create bytes in this
1992
 
            function spends less time resizing the final string.
 
1978
            instance, if lines is a list of 1000 bytestrings each ending in
 
1979
            \\n, dense_lines may be a list with one line in it, containing all
 
1980
            the 1000's lines and their \\n's. Using dense_lines if it is
 
1981
            already known is a win because the string join to create bytes in
 
1982
            this function spends less time resizing the final string.
1993
1983
        :return: (len, a StringIO instance with the raw data ready to read.)
1994
1984
        """
1995
1985
        chunks = ["version %s %d %s\n" % (key[-1], len(lines), digest)]
2015
2005
        """See VersionedFiles.keys."""
2016
2006
        if 'evil' in debug.debug_flags:
2017
2007
            trace.mutter_callsite(2, "keys scales with size of history")
2018
 
        sources = [self._index] + self._fallback_vfs
 
2008
        sources = [self._index] + self._immediate_fallback_vfs
2019
2009
        result = set()
2020
2010
        for source in sources:
2021
2011
            result.update(source.keys())
2061
2051
 
2062
2052
        missing_keys = set(nonlocal_keys)
2063
2053
        # Read from remote versioned file instances and provide to our caller.
2064
 
        for source in self.vf._fallback_vfs:
 
2054
        for source in self.vf._immediate_fallback_vfs:
2065
2055
            if not missing_keys:
2066
2056
                break
2067
2057
            # Loop over fallback repositories asking them for texts - ignore
2786
2776
        return key[:-1], key[-1]
2787
2777
 
2788
2778
 
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
2779
class _KnitGraphIndex(object):
2848
2780
    """A KnitVersionedFiles index layered on GraphIndex."""
2849
2781
 
3520
3452
        return records, ann_keys
3521
3453
 
3522
3454
    def _get_needed_texts(self, key, pb=None):
3523
 
        # if True or len(self._vf._fallback_vfs) > 0:
3524
 
        if len(self._vf._fallback_vfs) > 0:
 
3455
        # if True or len(self._vf._immediate_fallback_vfs) > 0:
 
3456
        if len(self._vf._immediate_fallback_vfs) > 0:
3525
3457
            # If we have fallbacks, go to the generic path
3526
3458
            for v in annotate.Annotator._get_needed_texts(self, key, pb=pb):
3527
3459
                yield v
3532
3464
                for idx, (sub_key, text, num_lines) in enumerate(
3533
3465
                                                self._extract_texts(records)):
3534
3466
                    if pb is not None:
3535
 
                        pb.update('annotating', idx, len(records))
 
3467
                        pb.update(gettext('annotating'), idx, len(records))
3536
3468
                    yield sub_key, text, num_lines
3537
3469
                for sub_key in ann_keys:
3538
3470
                    text = self._text_cache[sub_key]