~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/knit.py

Abbreviate pack_stat struct format to '>6L'

Show diffs side-by-side

added added

removed removed

Lines of Context:
76
76
    )
77
77
 
78
78
from bzrlib.repofmt import pack_repo
 
79
from bzrlib.i18n import gettext
79
80
""")
80
81
from bzrlib import (
81
82
    annotate,
408
409
class KnitContent(object):
409
410
    """Content of a knit version to which deltas can be applied.
410
411
 
411
 
    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,
412
413
    plus a flag saying if the final ending is really there or not, because that
413
414
    corresponds to the on-disk knit representation.
414
415
    """
1155
1156
 
1156
1157
        A dict of key to (record_details, index_memo, next, parents) is
1157
1158
        returned.
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.
 
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.
1166
1168
        """
1167
1169
        component_data = {}
1168
1170
        pending_components = keys
1194
1196
        generator = _VFContentMapGenerator(self, [key])
1195
1197
        return generator._get_content(key)
1196
1198
 
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
 
 
1210
1199
    def get_parent_map(self, keys):
1211
1200
        """Get a map of the graph parents of keys.
1212
1201
 
1243
1232
        """Produce a dictionary of knit records.
1244
1233
 
1245
1234
        :return: {key:(record, record_details, digest, next)}
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.
 
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.
1254
1240
                Will be None if the record is not a delta.
 
1241
 
1255
1242
        :param keys: The keys to build a map for
1256
1243
        :param allow_missing: If some records are missing, rather than
1257
1244
            error, just return the data that could be generated.
1774
1761
                        key_records.append((key, details[0]))
1775
1762
                records_iter = enumerate(self._read_records_iter(key_records))
1776
1763
                for (key_idx, (key, data, sha_value)) in records_iter:
1777
 
                    pb.update('Walking content', key_idx, total)
 
1764
                    pb.update(gettext('Walking content'), key_idx, total)
1778
1765
                    compression_parent = build_details[key][1]
1779
1766
                    if compression_parent is None:
1780
1767
                        # fulltext
1810
1797
                source_keys.add(key)
1811
1798
                yield line, key
1812
1799
            keys.difference_update(source_keys)
1813
 
        pb.update('Walking content', total, total)
 
1800
        pb.update(gettext('Walking content'), total, total)
1814
1801
 
1815
1802
    def _make_line_delta(self, delta_seq, new_content):
1816
1803
        """Generate a line delta from delta_seq and new_content."""
1924
1911
        The result will be returned in whatever is the fastest to read.
1925
1912
        Not by the order requested. Also, multiple requests for the same
1926
1913
        record will only yield 1 response.
 
1914
 
1927
1915
        :param records: A list of (key, access_memo) entries
1928
1916
        :return: Yields (key, contents, digest) in the order
1929
1917
                 read, not the order requested
1987
1975
        :param key: The key of the record. Currently keys are always serialised
1988
1976
            using just the trailing component.
1989
1977
        :param dense_lines: The bytes of lines but in a denser form. For
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.
 
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.
1995
1983
        :return: (len, a StringIO instance with the raw data ready to read.)
1996
1984
        """
1997
1985
        chunks = ["version %s %d %s\n" % (key[-1], len(lines), digest)]
3222
3210
                yield data
3223
3211
 
3224
3212
 
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
 
 
3364
3213
def annotate_knit(knit, revision_id):
3365
3214
    """Annotate a knit with no cached annotations.
3366
3215
 
3476
3325
                for idx, (sub_key, text, num_lines) in enumerate(
3477
3326
                                                self._extract_texts(records)):
3478
3327
                    if pb is not None:
3479
 
                        pb.update('annotating', idx, len(records))
 
3328
                        pb.update(gettext('annotating'), idx, len(records))
3480
3329
                    yield sub_key, text, num_lines
3481
3330
                for sub_key in ann_keys:
3482
3331
                    text = self._text_cache[sub_key]