673
673
This uses _coalesce_offsets to issue larger reads and fewer seeks.
675
:param fp: A file-like object that supports seek() and read(size)
675
:param fp: A file-like object that supports seek() and read(size).
676
Note that implementations are allowed to call .close() on this file
677
handle, so don't trust that you can use it for other work.
676
678
:param offsets: A list of offsets to be read from the given file.
677
679
:return: yield (pos, data) tuples for each request
690
692
# Cache the results, but only until they have been fulfilled
692
for c_offset in coalesced:
693
# TODO: jam 20060724 it might be faster to not issue seek if
694
# we are already at the right location. This should be
696
fp.seek(c_offset.start)
697
data = fp.read(c_offset.length)
698
if len(data) < c_offset.length:
699
raise errors.ShortReadvError(relpath, c_offset.start,
700
c_offset.length, actual=len(data))
701
for suboffset, subsize in c_offset.ranges:
702
key = (c_offset.start+suboffset, subsize)
703
data_map[key] = data[suboffset:suboffset+subsize]
695
for c_offset in coalesced:
696
# TODO: jam 20060724 it might be faster to not issue seek if
697
# we are already at the right location. This should be
699
fp.seek(c_offset.start)
700
data = fp.read(c_offset.length)
701
if len(data) < c_offset.length:
702
raise errors.ShortReadvError(relpath, c_offset.start,
703
c_offset.length, actual=len(data))
704
for suboffset, subsize in c_offset.ranges:
705
key = (c_offset.start+suboffset, subsize)
706
data_map[key] = data[suboffset:suboffset+subsize]
705
# Now that we've read some data, see if we can yield anything back
706
while cur_offset_and_size in data_map:
707
this_data = data_map.pop(cur_offset_and_size)
708
this_offset = cur_offset_and_size[0]
710
cur_offset_and_size = offset_stack.next()
711
except StopIteration:
712
# Close the file handle as there will be no more data
713
# The handle would normally be cleaned up as this code goes
714
# out of scope, but as we are a generator, not all code
715
# will re-enter once we have consumed all the expected
717
# zip(range(len(requests)), readv(foo, requests))
718
# Will stop because the range is done, and not run the
719
# cleanup code for the readv().
721
cur_offset_and_size = None
722
yield this_offset, this_data
708
# Now that we've read some data, see if we can yield anything back
709
while cur_offset_and_size in data_map:
710
this_data = data_map.pop(cur_offset_and_size)
711
this_offset = cur_offset_and_size[0]
713
cur_offset_and_size = offset_stack.next()
714
except StopIteration:
715
cur_offset_and_size = None
716
yield this_offset, this_data
724
722
def _sort_expand_and_combine(self, offsets, upper_limit):
725
723
"""Helper for readv.