~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/knit.py

  • Committer: Jelmer Vernooij
  • Date: 2012-02-20 12:19:29 UTC
  • mfrom: (6437.23.11 2.5)
  • mto: (6581.1.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 6582.
  • Revision ID: jelmer@samba.org-20120220121929-7ni2psvjoatm1yp4
Merge bzr/2.5.

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
 
54
56
 
55
57
from cStringIO import StringIO
56
58
from itertools import izip
76
78
    )
77
79
 
78
80
from bzrlib.repofmt import pack_repo
 
81
from bzrlib.i18n import gettext
79
82
""")
80
83
from bzrlib import (
81
84
    annotate,
1760
1763
                        key_records.append((key, details[0]))
1761
1764
                records_iter = enumerate(self._read_records_iter(key_records))
1762
1765
                for (key_idx, (key, data, sha_value)) in records_iter:
1763
 
                    pb.update('Walking content', key_idx, total)
 
1766
                    pb.update(gettext('Walking content'), key_idx, total)
1764
1767
                    compression_parent = build_details[key][1]
1765
1768
                    if compression_parent is None:
1766
1769
                        # fulltext
1796
1799
                source_keys.add(key)
1797
1800
                yield line, key
1798
1801
            keys.difference_update(source_keys)
1799
 
        pb.update('Walking content', total, total)
 
1802
        pb.update(gettext('Walking content'), total, total)
1800
1803
 
1801
1804
    def _make_line_delta(self, delta_seq, new_content):
1802
1805
        """Generate a line delta from delta_seq and new_content."""
3209
3212
                yield data
3210
3213
 
3211
3214
 
3212
 
class _DirectPackAccess(object):
3213
 
    """Access to data in one or more packs with less translation."""
3214
 
 
3215
 
    def __init__(self, index_to_packs, reload_func=None, flush_func=None):
3216
 
        """Create a _DirectPackAccess object.
3217
 
 
3218
 
        :param index_to_packs: A dict mapping index objects to the transport
3219
 
            and file names for obtaining data.
3220
 
        :param reload_func: A function to call if we determine that the pack
3221
 
            files have moved and we need to reload our caches. See
3222
 
            bzrlib.repo_fmt.pack_repo.AggregateIndex for more details.
3223
 
        """
3224
 
        self._container_writer = None
3225
 
        self._write_index = None
3226
 
        self._indices = index_to_packs
3227
 
        self._reload_func = reload_func
3228
 
        self._flush_func = flush_func
3229
 
 
3230
 
    def add_raw_records(self, key_sizes, raw_data):
3231
 
        """Add raw knit bytes to a storage area.
3232
 
 
3233
 
        The data is spooled to the container writer in one bytes-record per
3234
 
        raw data item.
3235
 
 
3236
 
        :param sizes: An iterable of tuples containing the key and size of each
3237
 
            raw data segment.
3238
 
        :param raw_data: A bytestring containing the data.
3239
 
        :return: A list of memos to retrieve the record later. Each memo is an
3240
 
            opaque index memo. For _DirectPackAccess the memo is (index, pos,
3241
 
            length), where the index field is the write_index object supplied
3242
 
            to the PackAccess object.
3243
 
        """
3244
 
        if type(raw_data) is not str:
3245
 
            raise AssertionError(
3246
 
                'data must be plain bytes was %s' % type(raw_data))
3247
 
        result = []
3248
 
        offset = 0
3249
 
        for key, size in key_sizes:
3250
 
            p_offset, p_length = self._container_writer.add_bytes_record(
3251
 
                raw_data[offset:offset+size], [])
3252
 
            offset += size
3253
 
            result.append((self._write_index, p_offset, p_length))
3254
 
        return result
3255
 
 
3256
 
    def flush(self):
3257
 
        """Flush pending writes on this access object.
3258
 
 
3259
 
        This will flush any buffered writes to a NewPack.
3260
 
        """
3261
 
        if self._flush_func is not None:
3262
 
            self._flush_func()
3263
 
            
3264
 
    def get_raw_records(self, memos_for_retrieval):
3265
 
        """Get the raw bytes for a records.
3266
 
 
3267
 
        :param memos_for_retrieval: An iterable containing the (index, pos,
3268
 
            length) memo for retrieving the bytes. The Pack access method
3269
 
            looks up the pack to use for a given record in its index_to_pack
3270
 
            map.
3271
 
        :return: An iterator over the bytes of the records.
3272
 
        """
3273
 
        # first pass, group into same-index requests
3274
 
        request_lists = []
3275
 
        current_index = None
3276
 
        for (index, offset, length) in memos_for_retrieval:
3277
 
            if current_index == index:
3278
 
                current_list.append((offset, length))
3279
 
            else:
3280
 
                if current_index is not None:
3281
 
                    request_lists.append((current_index, current_list))
3282
 
                current_index = index
3283
 
                current_list = [(offset, length)]
3284
 
        # handle the last entry
3285
 
        if current_index is not None:
3286
 
            request_lists.append((current_index, current_list))
3287
 
        for index, offsets in request_lists:
3288
 
            try:
3289
 
                transport, path = self._indices[index]
3290
 
            except KeyError:
3291
 
                # A KeyError here indicates that someone has triggered an index
3292
 
                # reload, and this index has gone missing, we need to start
3293
 
                # over.
3294
 
                if self._reload_func is None:
3295
 
                    # If we don't have a _reload_func there is nothing that can
3296
 
                    # be done
3297
 
                    raise
3298
 
                raise errors.RetryWithNewPacks(index,
3299
 
                                               reload_occurred=True,
3300
 
                                               exc_info=sys.exc_info())
3301
 
            try:
3302
 
                reader = pack.make_readv_reader(transport, path, offsets)
3303
 
                for names, read_func in reader.iter_records():
3304
 
                    yield read_func(None)
3305
 
            except errors.NoSuchFile:
3306
 
                # A NoSuchFile error indicates that a pack file has gone
3307
 
                # missing on disk, we need to trigger a reload, and start over.
3308
 
                if self._reload_func is None:
3309
 
                    raise
3310
 
                raise errors.RetryWithNewPacks(transport.abspath(path),
3311
 
                                               reload_occurred=False,
3312
 
                                               exc_info=sys.exc_info())
3313
 
 
3314
 
    def set_writer(self, writer, index, transport_packname):
3315
 
        """Set a writer to use for adding data."""
3316
 
        if index is not None:
3317
 
            self._indices[index] = transport_packname
3318
 
        self._container_writer = writer
3319
 
        self._write_index = index
3320
 
 
3321
 
    def reload_or_raise(self, retry_exc):
3322
 
        """Try calling the reload function, or re-raise the original exception.
3323
 
 
3324
 
        This should be called after _DirectPackAccess raises a
3325
 
        RetryWithNewPacks exception. This function will handle the common logic
3326
 
        of determining when the error is fatal versus being temporary.
3327
 
        It will also make sure that the original exception is raised, rather
3328
 
        than the RetryWithNewPacks exception.
3329
 
 
3330
 
        If this function returns, then the calling function should retry
3331
 
        whatever operation was being performed. Otherwise an exception will
3332
 
        be raised.
3333
 
 
3334
 
        :param retry_exc: A RetryWithNewPacks exception.
3335
 
        """
3336
 
        is_error = False
3337
 
        if self._reload_func is None:
3338
 
            is_error = True
3339
 
        elif not self._reload_func():
3340
 
            # The reload claimed that nothing changed
3341
 
            if not retry_exc.reload_occurred:
3342
 
                # If there wasn't an earlier reload, then we really were
3343
 
                # expecting to find changes. We didn't find them, so this is a
3344
 
                # hard error
3345
 
                is_error = True
3346
 
        if is_error:
3347
 
            exc_class, exc_value, exc_traceback = retry_exc.exc_info
3348
 
            raise exc_class, exc_value, exc_traceback
3349
 
 
3350
 
 
3351
3215
def annotate_knit(knit, revision_id):
3352
3216
    """Annotate a knit with no cached annotations.
3353
3217
 
3463
3327
                for idx, (sub_key, text, num_lines) in enumerate(
3464
3328
                                                self._extract_texts(records)):
3465
3329
                    if pb is not None:
3466
 
                        pb.update('annotating', idx, len(records))
 
3330
                        pb.update(gettext('annotating'), idx, len(records))
3467
3331
                    yield sub_key, text, num_lines
3468
3332
                for sub_key in ann_keys:
3469
3333
                    text = self._text_cache[sub_key]