1977
1981
:param key: The key of the record. Currently keys are always serialised
1978
1982
using just the trailing component.
1979
1983
: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.
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.
1985
1989
:return: (len, a StringIO instance with the raw data ready to read.)
1987
1991
chunks = ["version %s %d %s\n" % (key[-1], len(lines), digest)]
3219
class _DirectPackAccess(object):
3220
"""Access to data in one or more packs with less translation."""
3222
def __init__(self, index_to_packs, reload_func=None, flush_func=None):
3223
"""Create a _DirectPackAccess object.
3225
:param index_to_packs: A dict mapping index objects to the transport
3226
and file names for obtaining data.
3227
:param reload_func: A function to call if we determine that the pack
3228
files have moved and we need to reload our caches. See
3229
bzrlib.repo_fmt.pack_repo.AggregateIndex for more details.
3231
self._container_writer = None
3232
self._write_index = None
3233
self._indices = index_to_packs
3234
self._reload_func = reload_func
3235
self._flush_func = flush_func
3237
def add_raw_records(self, key_sizes, raw_data):
3238
"""Add raw knit bytes to a storage area.
3240
The data is spooled to the container writer in one bytes-record per
3243
:param sizes: An iterable of tuples containing the key and size of each
3245
:param raw_data: A bytestring containing the data.
3246
:return: A list of memos to retrieve the record later. Each memo is an
3247
opaque index memo. For _DirectPackAccess the memo is (index, pos,
3248
length), where the index field is the write_index object supplied
3249
to the PackAccess object.
3251
if type(raw_data) is not str:
3252
raise AssertionError(
3253
'data must be plain bytes was %s' % type(raw_data))
3256
for key, size in key_sizes:
3257
p_offset, p_length = self._container_writer.add_bytes_record(
3258
raw_data[offset:offset+size], [])
3260
result.append((self._write_index, p_offset, p_length))
3264
"""Flush pending writes on this access object.
3266
This will flush any buffered writes to a NewPack.
3268
if self._flush_func is not None:
3271
def get_raw_records(self, memos_for_retrieval):
3272
"""Get the raw bytes for a records.
3274
:param memos_for_retrieval: An iterable containing the (index, pos,
3275
length) memo for retrieving the bytes. The Pack access method
3276
looks up the pack to use for a given record in its index_to_pack
3278
:return: An iterator over the bytes of the records.
3280
# first pass, group into same-index requests
3282
current_index = None
3283
for (index, offset, length) in memos_for_retrieval:
3284
if current_index == index:
3285
current_list.append((offset, length))
3287
if current_index is not None:
3288
request_lists.append((current_index, current_list))
3289
current_index = index
3290
current_list = [(offset, length)]
3291
# handle the last entry
3292
if current_index is not None:
3293
request_lists.append((current_index, current_list))
3294
for index, offsets in request_lists:
3296
transport, path = self._indices[index]
3298
# A KeyError here indicates that someone has triggered an index
3299
# reload, and this index has gone missing, we need to start
3301
if self._reload_func is None:
3302
# If we don't have a _reload_func there is nothing that can
3305
raise errors.RetryWithNewPacks(index,
3306
reload_occurred=True,
3307
exc_info=sys.exc_info())
3309
reader = pack.make_readv_reader(transport, path, offsets)
3310
for names, read_func in reader.iter_records():
3311
yield read_func(None)
3312
except errors.NoSuchFile:
3313
# A NoSuchFile error indicates that a pack file has gone
3314
# missing on disk, we need to trigger a reload, and start over.
3315
if self._reload_func is None:
3317
raise errors.RetryWithNewPacks(transport.abspath(path),
3318
reload_occurred=False,
3319
exc_info=sys.exc_info())
3321
def set_writer(self, writer, index, transport_packname):
3322
"""Set a writer to use for adding data."""
3323
if index is not None:
3324
self._indices[index] = transport_packname
3325
self._container_writer = writer
3326
self._write_index = index
3328
def reload_or_raise(self, retry_exc):
3329
"""Try calling the reload function, or re-raise the original exception.
3331
This should be called after _DirectPackAccess raises a
3332
RetryWithNewPacks exception. This function will handle the common logic
3333
of determining when the error is fatal versus being temporary.
3334
It will also make sure that the original exception is raised, rather
3335
than the RetryWithNewPacks exception.
3337
If this function returns, then the calling function should retry
3338
whatever operation was being performed. Otherwise an exception will
3341
:param retry_exc: A RetryWithNewPacks exception.
3344
if self._reload_func is None:
3346
elif not self._reload_func():
3347
# The reload claimed that nothing changed
3348
if not retry_exc.reload_occurred:
3349
# If there wasn't an earlier reload, then we really were
3350
# expecting to find changes. We didn't find them, so this is a
3354
exc_class, exc_value, exc_traceback = retry_exc.exc_info
3355
raise exc_class, exc_value, exc_traceback
3215
3358
def annotate_knit(knit, revision_id):
3216
3359
"""Annotate a knit with no cached annotations.