~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/knit.py

  • Committer: Jelmer Vernooij
  • Date: 2011-05-10 07:46:15 UTC
  • mfrom: (5844 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5845.
  • Revision ID: jelmer@samba.org-20110510074615-eptod049ndjxc4i7
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
51
51
 
52
52
"""
53
53
 
54
 
from __future__ import absolute_import
55
 
 
56
54
 
57
55
from cStringIO import StringIO
58
56
from itertools import izip
78
76
    )
79
77
 
80
78
from bzrlib.repofmt import pack_repo
81
 
from bzrlib.i18n import gettext
82
79
""")
83
80
from bzrlib import (
84
81
    annotate,
411
408
class KnitContent(object):
412
409
    """Content of a knit version to which deltas can be applied.
413
410
 
414
 
    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,
415
412
    plus a flag saying if the final ending is really there or not, because that
416
413
    corresponds to the on-disk knit representation.
417
414
    """
1158
1155
 
1159
1156
        A dict of key to (record_details, index_memo, next, parents) is
1160
1157
        returned.
1161
 
 
1162
 
        * method is the way referenced data should be applied.
1163
 
        * index_memo is the handle to pass to the data access to actually get
1164
 
          the data
1165
 
        * next is the build-parent of the version, or None for fulltexts.
1166
 
        * parents is the version_ids of the parents of this version
1167
 
 
1168
 
        :param allow_missing: If True do not raise an error on a missing
1169
 
            component, just ignore it.
 
1158
        method is the way referenced data should be applied.
 
1159
        index_memo is the handle to pass to the data access to actually get the
 
1160
            data
 
1161
        next is the build-parent of the version, or None for fulltexts.
 
1162
        parents is the version_ids of the parents of this version
 
1163
 
 
1164
        :param allow_missing: If True do not raise an error on a missing component,
 
1165
            just ignore it.
1170
1166
        """
1171
1167
        component_data = {}
1172
1168
        pending_components = keys
1198
1194
        generator = _VFContentMapGenerator(self, [key])
1199
1195
        return generator._get_content(key)
1200
1196
 
 
1197
    def get_known_graph_ancestry(self, keys):
 
1198
        """Get a KnownGraph instance with the ancestry of keys."""
 
1199
        parent_map, missing_keys = self._index.find_ancestry(keys)
 
1200
        for fallback in self._transitive_fallbacks():
 
1201
            if not missing_keys:
 
1202
                break
 
1203
            (f_parent_map, f_missing_keys) = fallback._index.find_ancestry(
 
1204
                                                missing_keys)
 
1205
            parent_map.update(f_parent_map)
 
1206
            missing_keys = f_missing_keys
 
1207
        kg = _mod_graph.KnownGraph(parent_map)
 
1208
        return kg
 
1209
 
1201
1210
    def get_parent_map(self, keys):
1202
1211
        """Get a map of the graph parents of keys.
1203
1212
 
1234
1243
        """Produce a dictionary of knit records.
1235
1244
 
1236
1245
        :return: {key:(record, record_details, digest, next)}
1237
 
 
1238
 
            * record: data returned from read_records (a KnitContentobject)
1239
 
            * record_details: opaque information to pass to parse_record
1240
 
            * digest: SHA1 digest of the full text after all steps are done
1241
 
            * next: build-parent of the version, i.e. the leftmost ancestor.
 
1246
            record
 
1247
                data returned from read_records (a KnitContentobject)
 
1248
            record_details
 
1249
                opaque information to pass to parse_record
 
1250
            digest
 
1251
                SHA1 digest of the full text after all steps are done
 
1252
            next
 
1253
                build-parent of the version, i.e. the leftmost ancestor.
1242
1254
                Will be None if the record is not a delta.
1243
 
 
1244
1255
        :param keys: The keys to build a map for
1245
1256
        :param allow_missing: If some records are missing, rather than
1246
1257
            error, just return the data that could be generated.
1763
1774
                        key_records.append((key, details[0]))
1764
1775
                records_iter = enumerate(self._read_records_iter(key_records))
1765
1776
                for (key_idx, (key, data, sha_value)) in records_iter:
1766
 
                    pb.update(gettext('Walking content'), key_idx, total)
 
1777
                    pb.update('Walking content', key_idx, total)
1767
1778
                    compression_parent = build_details[key][1]
1768
1779
                    if compression_parent is None:
1769
1780
                        # fulltext
1799
1810
                source_keys.add(key)
1800
1811
                yield line, key
1801
1812
            keys.difference_update(source_keys)
1802
 
        pb.update(gettext('Walking content'), total, total)
 
1813
        pb.update('Walking content', total, total)
1803
1814
 
1804
1815
    def _make_line_delta(self, delta_seq, new_content):
1805
1816
        """Generate a line delta from delta_seq and new_content."""
1913
1924
        The result will be returned in whatever is the fastest to read.
1914
1925
        Not by the order requested. Also, multiple requests for the same
1915
1926
        record will only yield 1 response.
1916
 
 
1917
1927
        :param records: A list of (key, access_memo) entries
1918
1928
        :return: Yields (key, contents, digest) in the order
1919
1929
                 read, not the order requested
1977
1987
        :param key: The key of the record. Currently keys are always serialised
1978
1988
            using just the trailing component.
1979
1989
        :param dense_lines: The bytes of lines but in a denser form. For
1980
 
            instance, if lines is a list of 1000 bytestrings each ending in
1981
 
            \\n, dense_lines may be a list with one line in it, containing all
1982
 
            the 1000's lines and their \\n's. Using dense_lines if it is
1983
 
            already known is a win because the string join to create bytes in
1984
 
            this function spends less time resizing the final string.
 
1990
            instance, if lines is a list of 1000 bytestrings each ending in \n,
 
1991
            dense_lines may be a list with one line in it, containing all the
 
1992
            1000's lines and their \n's. Using dense_lines if it is already
 
1993
            known is a win because the string join to create bytes in this
 
1994
            function spends less time resizing the final string.
1985
1995
        :return: (len, a StringIO instance with the raw data ready to read.)
1986
1996
        """
1987
1997
        chunks = ["version %s %d %s\n" % (key[-1], len(lines), digest)]
3212
3222
                yield data
3213
3223
 
3214
3224
 
 
3225
class _DirectPackAccess(object):
 
3226
    """Access to data in one or more packs with less translation."""
 
3227
 
 
3228
    def __init__(self, index_to_packs, reload_func=None, flush_func=None):
 
3229
        """Create a _DirectPackAccess object.
 
3230
 
 
3231
        :param index_to_packs: A dict mapping index objects to the transport
 
3232
            and file names for obtaining data.
 
3233
        :param reload_func: A function to call if we determine that the pack
 
3234
            files have moved and we need to reload our caches. See
 
3235
            bzrlib.repo_fmt.pack_repo.AggregateIndex for more details.
 
3236
        """
 
3237
        self._container_writer = None
 
3238
        self._write_index = None
 
3239
        self._indices = index_to_packs
 
3240
        self._reload_func = reload_func
 
3241
        self._flush_func = flush_func
 
3242
 
 
3243
    def add_raw_records(self, key_sizes, raw_data):
 
3244
        """Add raw knit bytes to a storage area.
 
3245
 
 
3246
        The data is spooled to the container writer in one bytes-record per
 
3247
        raw data item.
 
3248
 
 
3249
        :param sizes: An iterable of tuples containing the key and size of each
 
3250
            raw data segment.
 
3251
        :param raw_data: A bytestring containing the data.
 
3252
        :return: A list of memos to retrieve the record later. Each memo is an
 
3253
            opaque index memo. For _DirectPackAccess the memo is (index, pos,
 
3254
            length), where the index field is the write_index object supplied
 
3255
            to the PackAccess object.
 
3256
        """
 
3257
        if type(raw_data) is not str:
 
3258
            raise AssertionError(
 
3259
                'data must be plain bytes was %s' % type(raw_data))
 
3260
        result = []
 
3261
        offset = 0
 
3262
        for key, size in key_sizes:
 
3263
            p_offset, p_length = self._container_writer.add_bytes_record(
 
3264
                raw_data[offset:offset+size], [])
 
3265
            offset += size
 
3266
            result.append((self._write_index, p_offset, p_length))
 
3267
        return result
 
3268
 
 
3269
    def flush(self):
 
3270
        """Flush pending writes on this access object.
 
3271
 
 
3272
        This will flush any buffered writes to a NewPack.
 
3273
        """
 
3274
        if self._flush_func is not None:
 
3275
            self._flush_func()
 
3276
            
 
3277
    def get_raw_records(self, memos_for_retrieval):
 
3278
        """Get the raw bytes for a records.
 
3279
 
 
3280
        :param memos_for_retrieval: An iterable containing the (index, pos,
 
3281
            length) memo for retrieving the bytes. The Pack access method
 
3282
            looks up the pack to use for a given record in its index_to_pack
 
3283
            map.
 
3284
        :return: An iterator over the bytes of the records.
 
3285
        """
 
3286
        # first pass, group into same-index requests
 
3287
        request_lists = []
 
3288
        current_index = None
 
3289
        for (index, offset, length) in memos_for_retrieval:
 
3290
            if current_index == index:
 
3291
                current_list.append((offset, length))
 
3292
            else:
 
3293
                if current_index is not None:
 
3294
                    request_lists.append((current_index, current_list))
 
3295
                current_index = index
 
3296
                current_list = [(offset, length)]
 
3297
        # handle the last entry
 
3298
        if current_index is not None:
 
3299
            request_lists.append((current_index, current_list))
 
3300
        for index, offsets in request_lists:
 
3301
            try:
 
3302
                transport, path = self._indices[index]
 
3303
            except KeyError:
 
3304
                # A KeyError here indicates that someone has triggered an index
 
3305
                # reload, and this index has gone missing, we need to start
 
3306
                # over.
 
3307
                if self._reload_func is None:
 
3308
                    # If we don't have a _reload_func there is nothing that can
 
3309
                    # be done
 
3310
                    raise
 
3311
                raise errors.RetryWithNewPacks(index,
 
3312
                                               reload_occurred=True,
 
3313
                                               exc_info=sys.exc_info())
 
3314
            try:
 
3315
                reader = pack.make_readv_reader(transport, path, offsets)
 
3316
                for names, read_func in reader.iter_records():
 
3317
                    yield read_func(None)
 
3318
            except errors.NoSuchFile:
 
3319
                # A NoSuchFile error indicates that a pack file has gone
 
3320
                # missing on disk, we need to trigger a reload, and start over.
 
3321
                if self._reload_func is None:
 
3322
                    raise
 
3323
                raise errors.RetryWithNewPacks(transport.abspath(path),
 
3324
                                               reload_occurred=False,
 
3325
                                               exc_info=sys.exc_info())
 
3326
 
 
3327
    def set_writer(self, writer, index, transport_packname):
 
3328
        """Set a writer to use for adding data."""
 
3329
        if index is not None:
 
3330
            self._indices[index] = transport_packname
 
3331
        self._container_writer = writer
 
3332
        self._write_index = index
 
3333
 
 
3334
    def reload_or_raise(self, retry_exc):
 
3335
        """Try calling the reload function, or re-raise the original exception.
 
3336
 
 
3337
        This should be called after _DirectPackAccess raises a
 
3338
        RetryWithNewPacks exception. This function will handle the common logic
 
3339
        of determining when the error is fatal versus being temporary.
 
3340
        It will also make sure that the original exception is raised, rather
 
3341
        than the RetryWithNewPacks exception.
 
3342
 
 
3343
        If this function returns, then the calling function should retry
 
3344
        whatever operation was being performed. Otherwise an exception will
 
3345
        be raised.
 
3346
 
 
3347
        :param retry_exc: A RetryWithNewPacks exception.
 
3348
        """
 
3349
        is_error = False
 
3350
        if self._reload_func is None:
 
3351
            is_error = True
 
3352
        elif not self._reload_func():
 
3353
            # The reload claimed that nothing changed
 
3354
            if not retry_exc.reload_occurred:
 
3355
                # If there wasn't an earlier reload, then we really were
 
3356
                # expecting to find changes. We didn't find them, so this is a
 
3357
                # hard error
 
3358
                is_error = True
 
3359
        if is_error:
 
3360
            exc_class, exc_value, exc_traceback = retry_exc.exc_info
 
3361
            raise exc_class, exc_value, exc_traceback
 
3362
 
 
3363
 
3215
3364
def annotate_knit(knit, revision_id):
3216
3365
    """Annotate a knit with no cached annotations.
3217
3366
 
3327
3476
                for idx, (sub_key, text, num_lines) in enumerate(
3328
3477
                                                self._extract_texts(records)):
3329
3478
                    if pb is not None:
3330
 
                        pb.update(gettext('annotating'), idx, len(records))
 
3479
                        pb.update('annotating', idx, len(records))
3331
3480
                    yield sub_key, text, num_lines
3332
3481
                for sub_key in ann_keys:
3333
3482
                    text = self._text_cache[sub_key]