~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/knit.py

(gz) Fix test failure on alpha by correcting format string for
 gc_chk_sha1_record (Martin [gz])

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
59
60
 
60
61
from bzrlib.lazy_import import lazy_import
61
62
lazy_import(globals(), """
62
63
import gzip
63
64
 
64
65
from bzrlib import (
 
66
    annotate,
65
67
    debug,
66
68
    diff,
67
69
    graph as _mod_graph,
68
70
    index as _mod_index,
 
71
    lru_cache,
69
72
    pack,
70
73
    patiencediff,
 
74
    progress,
71
75
    static_tuple,
72
76
    trace,
73
77
    tsort,
74
78
    tuned_gzip,
75
79
    ui,
76
80
    )
77
 
 
78
 
from bzrlib.repofmt import pack_repo
79
 
from bzrlib.i18n import gettext
80
81
""")
81
82
from bzrlib import (
82
 
    annotate,
83
83
    errors,
84
84
    osutils,
85
85
    )
98
98
    split_lines,
99
99
    )
100
100
from bzrlib.versionedfile import (
101
 
    _KeyRefs,
102
101
    AbsentContentFactory,
103
102
    adapter_registry,
104
103
    ConstantMapper,
105
104
    ContentFactory,
106
105
    sort_groupcompress,
107
 
    VersionedFilesWithFallbacks,
 
106
    VersionedFiles,
108
107
    )
109
108
 
110
109
 
409
408
class KnitContent(object):
410
409
    """Content of a knit version to which deltas can be applied.
411
410
 
412
 
    This is always stored in memory as a list of lines with \\n at the end,
 
411
    This is always stored in memory as a list of lines with \n at the end,
413
412
    plus a flag saying if the final ending is really there or not, because that
414
413
    corresponds to the on-disk knit representation.
415
414
    """
802
801
        writer.begin()
803
802
        index = _KnitGraphIndex(graph_index, lambda:True, parents=parents,
804
803
            deltas=delta, add_callback=graph_index.add_nodes)
805
 
        access = pack_repo._DirectPackAccess({})
 
804
        access = _DirectPackAccess({})
806
805
        access.set_writer(writer, graph_index, (transport, 'newpack'))
807
806
        result = KnitVersionedFiles(index, access,
808
807
            max_delta_chain=max_delta_chain)
846
845
                in all_build_index_memos.itervalues()])
847
846
 
848
847
 
849
 
class KnitVersionedFiles(VersionedFilesWithFallbacks):
 
848
class KnitVersionedFiles(VersionedFiles):
850
849
    """Storage for many versioned files using knit compression.
851
850
 
852
851
    Backend storage is managed by indices and data objects.
888
887
            self._index,
889
888
            self._access)
890
889
 
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
 
 
897
890
    def add_fallback_versioned_files(self, a_versioned_files):
898
891
        """Add a source of texts for texts not present in this knit.
899
892
 
1156
1149
 
1157
1150
        A dict of key to (record_details, index_memo, next, parents) is
1158
1151
        returned.
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.
 
1152
        method is the way referenced data should be applied.
 
1153
        index_memo is the handle to pass to the data access to actually get the
 
1154
            data
 
1155
        next is the build-parent of the version, or None for fulltexts.
 
1156
        parents is the version_ids of the parents of this version
 
1157
 
 
1158
        :param allow_missing: If True do not raise an error on a missing component,
 
1159
            just ignore it.
1168
1160
        """
1169
1161
        component_data = {}
1170
1162
        pending_components = keys
1196
1188
        generator = _VFContentMapGenerator(self, [key])
1197
1189
        return generator._get_content(key)
1198
1190
 
 
1191
    def get_known_graph_ancestry(self, keys):
 
1192
        """Get a KnownGraph instance with the ancestry of keys."""
 
1193
        parent_map, missing_keys = self._index.find_ancestry(keys)
 
1194
        for fallback in self._transitive_fallbacks():
 
1195
            if not missing_keys:
 
1196
                break
 
1197
            (f_parent_map, f_missing_keys) = fallback._index.find_ancestry(
 
1198
                                                missing_keys)
 
1199
            parent_map.update(f_parent_map)
 
1200
            missing_keys = f_missing_keys
 
1201
        kg = _mod_graph.KnownGraph(parent_map)
 
1202
        return kg
 
1203
 
1199
1204
    def get_parent_map(self, keys):
1200
1205
        """Get a map of the graph parents of keys.
1201
1206
 
1232
1237
        """Produce a dictionary of knit records.
1233
1238
 
1234
1239
        :return: {key:(record, record_details, digest, next)}
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.
 
1240
            record
 
1241
                data returned from read_records (a KnitContentobject)
 
1242
            record_details
 
1243
                opaque information to pass to parse_record
 
1244
            digest
 
1245
                SHA1 digest of the full text after all steps are done
 
1246
            next
 
1247
                build-parent of the version, i.e. the leftmost ancestor.
1240
1248
                Will be None if the record is not a delta.
1241
 
 
1242
1249
        :param keys: The keys to build a map for
1243
1250
        :param allow_missing: If some records are missing, rather than
1244
1251
            error, just return the data that could be generated.
1761
1768
                        key_records.append((key, details[0]))
1762
1769
                records_iter = enumerate(self._read_records_iter(key_records))
1763
1770
                for (key_idx, (key, data, sha_value)) in records_iter:
1764
 
                    pb.update(gettext('Walking content'), key_idx, total)
 
1771
                    pb.update('Walking content', key_idx, total)
1765
1772
                    compression_parent = build_details[key][1]
1766
1773
                    if compression_parent is None:
1767
1774
                        # fulltext
1797
1804
                source_keys.add(key)
1798
1805
                yield line, key
1799
1806
            keys.difference_update(source_keys)
1800
 
        pb.update(gettext('Walking content'), total, total)
 
1807
        pb.update('Walking content', total, total)
1801
1808
 
1802
1809
    def _make_line_delta(self, delta_seq, new_content):
1803
1810
        """Generate a line delta from delta_seq and new_content."""
1911
1918
        The result will be returned in whatever is the fastest to read.
1912
1919
        Not by the order requested. Also, multiple requests for the same
1913
1920
        record will only yield 1 response.
1914
 
 
1915
1921
        :param records: A list of (key, access_memo) entries
1916
1922
        :return: Yields (key, contents, digest) in the order
1917
1923
                 read, not the order requested
1975
1981
        :param key: The key of the record. Currently keys are always serialised
1976
1982
            using just the trailing component.
1977
1983
        :param dense_lines: The bytes of lines but in a denser form. For
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.
 
1984
            instance, if lines is a list of 1000 bytestrings each ending in \n,
 
1985
            dense_lines may be a list with one line in it, containing all the
 
1986
            1000's lines and their \n's. Using dense_lines if it is already
 
1987
            known is a win because the string join to create bytes in this
 
1988
            function spends less time resizing the final string.
1983
1989
        :return: (len, a StringIO instance with the raw data ready to read.)
1984
1990
        """
1985
1991
        chunks = ["version %s %d %s\n" % (key[-1], len(lines), digest)]
2776
2782
        return key[:-1], key[-1]
2777
2783
 
2778
2784
 
 
2785
class _KeyRefs(object):
 
2786
 
 
2787
    def __init__(self, track_new_keys=False):
 
2788
        # dict mapping 'key' to 'set of keys referring to that key'
 
2789
        self.refs = {}
 
2790
        if track_new_keys:
 
2791
            # set remembering all new keys
 
2792
            self.new_keys = set()
 
2793
        else:
 
2794
            self.new_keys = None
 
2795
 
 
2796
    def clear(self):
 
2797
        if self.refs:
 
2798
            self.refs.clear()
 
2799
        if self.new_keys:
 
2800
            self.new_keys.clear()
 
2801
 
 
2802
    def add_references(self, key, refs):
 
2803
        # Record the new references
 
2804
        for referenced in refs:
 
2805
            try:
 
2806
                needed_by = self.refs[referenced]
 
2807
            except KeyError:
 
2808
                needed_by = self.refs[referenced] = set()
 
2809
            needed_by.add(key)
 
2810
        # Discard references satisfied by the new key
 
2811
        self.add_key(key)
 
2812
 
 
2813
    def get_new_keys(self):
 
2814
        return self.new_keys
 
2815
    
 
2816
    def get_unsatisfied_refs(self):
 
2817
        return self.refs.iterkeys()
 
2818
 
 
2819
    def _satisfy_refs_for_key(self, key):
 
2820
        try:
 
2821
            del self.refs[key]
 
2822
        except KeyError:
 
2823
            # No keys depended on this key.  That's ok.
 
2824
            pass
 
2825
 
 
2826
    def add_key(self, key):
 
2827
        # satisfy refs for key, and remember that we've seen this key.
 
2828
        self._satisfy_refs_for_key(key)
 
2829
        if self.new_keys is not None:
 
2830
            self.new_keys.add(key)
 
2831
 
 
2832
    def satisfy_refs_for_keys(self, keys):
 
2833
        for key in keys:
 
2834
            self._satisfy_refs_for_key(key)
 
2835
 
 
2836
    def get_referrers(self):
 
2837
        result = set()
 
2838
        for referrers in self.refs.itervalues():
 
2839
            result.update(referrers)
 
2840
        return result
 
2841
 
 
2842
 
2779
2843
class _KnitGraphIndex(object):
2780
2844
    """A KnitVersionedFiles index layered on GraphIndex."""
2781
2845
 
3210
3274
                yield data
3211
3275
 
3212
3276
 
 
3277
class _DirectPackAccess(object):
 
3278
    """Access to data in one or more packs with less translation."""
 
3279
 
 
3280
    def __init__(self, index_to_packs, reload_func=None, flush_func=None):
 
3281
        """Create a _DirectPackAccess object.
 
3282
 
 
3283
        :param index_to_packs: A dict mapping index objects to the transport
 
3284
            and file names for obtaining data.
 
3285
        :param reload_func: A function to call if we determine that the pack
 
3286
            files have moved and we need to reload our caches. See
 
3287
            bzrlib.repo_fmt.pack_repo.AggregateIndex for more details.
 
3288
        """
 
3289
        self._container_writer = None
 
3290
        self._write_index = None
 
3291
        self._indices = index_to_packs
 
3292
        self._reload_func = reload_func
 
3293
        self._flush_func = flush_func
 
3294
 
 
3295
    def add_raw_records(self, key_sizes, raw_data):
 
3296
        """Add raw knit bytes to a storage area.
 
3297
 
 
3298
        The data is spooled to the container writer in one bytes-record per
 
3299
        raw data item.
 
3300
 
 
3301
        :param sizes: An iterable of tuples containing the key and size of each
 
3302
            raw data segment.
 
3303
        :param raw_data: A bytestring containing the data.
 
3304
        :return: A list of memos to retrieve the record later. Each memo is an
 
3305
            opaque index memo. For _DirectPackAccess the memo is (index, pos,
 
3306
            length), where the index field is the write_index object supplied
 
3307
            to the PackAccess object.
 
3308
        """
 
3309
        if type(raw_data) is not str:
 
3310
            raise AssertionError(
 
3311
                'data must be plain bytes was %s' % type(raw_data))
 
3312
        result = []
 
3313
        offset = 0
 
3314
        for key, size in key_sizes:
 
3315
            p_offset, p_length = self._container_writer.add_bytes_record(
 
3316
                raw_data[offset:offset+size], [])
 
3317
            offset += size
 
3318
            result.append((self._write_index, p_offset, p_length))
 
3319
        return result
 
3320
 
 
3321
    def flush(self):
 
3322
        """Flush pending writes on this access object.
 
3323
 
 
3324
        This will flush any buffered writes to a NewPack.
 
3325
        """
 
3326
        if self._flush_func is not None:
 
3327
            self._flush_func()
 
3328
            
 
3329
    def get_raw_records(self, memos_for_retrieval):
 
3330
        """Get the raw bytes for a records.
 
3331
 
 
3332
        :param memos_for_retrieval: An iterable containing the (index, pos,
 
3333
            length) memo for retrieving the bytes. The Pack access method
 
3334
            looks up the pack to use for a given record in its index_to_pack
 
3335
            map.
 
3336
        :return: An iterator over the bytes of the records.
 
3337
        """
 
3338
        # first pass, group into same-index requests
 
3339
        request_lists = []
 
3340
        current_index = None
 
3341
        for (index, offset, length) in memos_for_retrieval:
 
3342
            if current_index == index:
 
3343
                current_list.append((offset, length))
 
3344
            else:
 
3345
                if current_index is not None:
 
3346
                    request_lists.append((current_index, current_list))
 
3347
                current_index = index
 
3348
                current_list = [(offset, length)]
 
3349
        # handle the last entry
 
3350
        if current_index is not None:
 
3351
            request_lists.append((current_index, current_list))
 
3352
        for index, offsets in request_lists:
 
3353
            try:
 
3354
                transport, path = self._indices[index]
 
3355
            except KeyError:
 
3356
                # A KeyError here indicates that someone has triggered an index
 
3357
                # reload, and this index has gone missing, we need to start
 
3358
                # over.
 
3359
                if self._reload_func is None:
 
3360
                    # If we don't have a _reload_func there is nothing that can
 
3361
                    # be done
 
3362
                    raise
 
3363
                raise errors.RetryWithNewPacks(index,
 
3364
                                               reload_occurred=True,
 
3365
                                               exc_info=sys.exc_info())
 
3366
            try:
 
3367
                reader = pack.make_readv_reader(transport, path, offsets)
 
3368
                for names, read_func in reader.iter_records():
 
3369
                    yield read_func(None)
 
3370
            except errors.NoSuchFile:
 
3371
                # A NoSuchFile error indicates that a pack file has gone
 
3372
                # missing on disk, we need to trigger a reload, and start over.
 
3373
                if self._reload_func is None:
 
3374
                    raise
 
3375
                raise errors.RetryWithNewPacks(transport.abspath(path),
 
3376
                                               reload_occurred=False,
 
3377
                                               exc_info=sys.exc_info())
 
3378
 
 
3379
    def set_writer(self, writer, index, transport_packname):
 
3380
        """Set a writer to use for adding data."""
 
3381
        if index is not None:
 
3382
            self._indices[index] = transport_packname
 
3383
        self._container_writer = writer
 
3384
        self._write_index = index
 
3385
 
 
3386
    def reload_or_raise(self, retry_exc):
 
3387
        """Try calling the reload function, or re-raise the original exception.
 
3388
 
 
3389
        This should be called after _DirectPackAccess raises a
 
3390
        RetryWithNewPacks exception. This function will handle the common logic
 
3391
        of determining when the error is fatal versus being temporary.
 
3392
        It will also make sure that the original exception is raised, rather
 
3393
        than the RetryWithNewPacks exception.
 
3394
 
 
3395
        If this function returns, then the calling function should retry
 
3396
        whatever operation was being performed. Otherwise an exception will
 
3397
        be raised.
 
3398
 
 
3399
        :param retry_exc: A RetryWithNewPacks exception.
 
3400
        """
 
3401
        is_error = False
 
3402
        if self._reload_func is None:
 
3403
            is_error = True
 
3404
        elif not self._reload_func():
 
3405
            # The reload claimed that nothing changed
 
3406
            if not retry_exc.reload_occurred:
 
3407
                # If there wasn't an earlier reload, then we really were
 
3408
                # expecting to find changes. We didn't find them, so this is a
 
3409
                # hard error
 
3410
                is_error = True
 
3411
        if is_error:
 
3412
            exc_class, exc_value, exc_traceback = retry_exc.exc_info
 
3413
            raise exc_class, exc_value, exc_traceback
 
3414
 
 
3415
 
3213
3416
def annotate_knit(knit, revision_id):
3214
3417
    """Annotate a knit with no cached annotations.
3215
3418
 
3325
3528
                for idx, (sub_key, text, num_lines) in enumerate(
3326
3529
                                                self._extract_texts(records)):
3327
3530
                    if pb is not None:
3328
 
                        pb.update(gettext('annotating'), idx, len(records))
 
3531
                        pb.update('annotating', idx, len(records))
3329
3532
                    yield sub_key, text, num_lines
3330
3533
                for sub_key in ann_keys:
3331
3534
                    text = self._text_cache[sub_key]