X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/3e271eb8bc19f67465a33a69dc66a27021301fae..1cd7fd3867acabeb29196da4cf505a0eb703b287:/sdk/python/arvados/arvfile.py diff --git a/sdk/python/arvados/arvfile.py b/sdk/python/arvados/arvfile.py index 7742c45c4d..95dcea0ad3 100644 --- a/sdk/python/arvados/arvfile.py +++ b/sdk/python/arvados/arvfile.py @@ -10,7 +10,7 @@ import copy import errno import re -from .errors import KeepWriteError, AssertionError +from .errors import KeepWriteError, AssertionError, ArgumentError from .keep import KeepLocator from ._normalize_stream import normalize_stream from ._ranges import locators_and_ranges, replace_range, Range @@ -703,7 +703,7 @@ class ArvadosFile(object): # segment is past the trucate size, all done break elif size < range_end: - nr = Range(r.locator, r.range_start, size - r.range_start) + nr = Range(r.locator, r.range_start, size - r.range_start, 0) nr.segment_offset = r.segment_offset new_segs.append(nr) break @@ -715,8 +715,15 @@ class ArvadosFile(object): elif size > self.size(): raise IOError("truncate() does not support extending the file size") - def readfrom(self, offset, size, num_retries): - """Read upto `size` bytes from the file starting at `offset`.""" + + def readfrom(self, offset, size, num_retries, exact=False): + """Read up to `size` bytes from the file starting at `offset`. + + :exact: + If False (default), return less data than requested if the read + crosses a block boundary and the next block isn't cached. If True, + only return less data than requested when hitting EOF. + """ with self.lock: if size == 0 or offset >= self.size(): @@ -729,7 +736,7 @@ class ArvadosFile(object): data = [] for lr in readsegs: - block = self.parent._my_block_manager().get_block_contents(lr.locator, num_retries=num_retries, cache_only=bool(data)) + block = self.parent._my_block_manager().get_block_contents(lr.locator, num_retries=num_retries, cache_only=(bool(data) and not exact)) if block: data.append(block[lr.segment_offset:lr.segment_offset+lr.segment_size]) else: @@ -778,7 +785,13 @@ class ArvadosFile(object): raise ArgumentError("Offset is past the end of the file") if len(data) > config.KEEP_BLOCK_SIZE: - raise ArgumentError("Please append data in chunks smaller than %i bytes (config.KEEP_BLOCK_SIZE)" % (config.KEEP_BLOCK_SIZE)) + # Chunk it up into smaller writes + n = 0 + dataview = memoryview(data) + while n < len(data): + self.writeto(offset+n, dataview[n:n + config.KEEP_BLOCK_SIZE].tobytes(), num_retries) + n += config.KEEP_BLOCK_SIZE + return self._modified = True @@ -816,7 +829,7 @@ class ArvadosFile(object): """Internal implementation of add_segment.""" self._modified = True for lr in locators_and_ranges(blocks, pos, size): - last = self._segments[-1] if self._segments else Range(0, 0, 0) + last = self._segments[-1] if self._segments else Range(0, 0, 0, 0) r = Range(lr.locator, last.range_start+last.range_size, lr.segment_size, lr.segment_offset) self._segments.append(r) @@ -868,7 +881,7 @@ class ArvadosFileReader(ArvadosFileReaderBase): @retry_method def read(self, size, num_retries=None): """Read up to `size` bytes from the stream, starting at the current file position.""" - data = self.arvadosfile.readfrom(self._filepos, size, num_retries) + data = self.arvadosfile.readfrom(self._filepos, size, num_retries, exact=True) self._filepos += len(data) return data