X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/5c4d9d38dcee73a7ffb6221c80f707c3924da64f..c56d04266de4e97b1b861c068309476ca562d72f:/sdk/python/arvados/keep.py diff --git a/sdk/python/arvados/keep.py b/sdk/python/arvados/keep.py index 71e101cf4c..86a28f54c4 100644 --- a/sdk/python/arvados/keep.py +++ b/sdk/python/arvados/keep.py @@ -377,7 +377,7 @@ class KeepClient(object): curl.setopt(pycurl.SSL_VERIFYPEER, 0) if method == "HEAD": curl.setopt(pycurl.NOBODY, True) - self._setcurltimeouts(curl, timeout) + self._setcurltimeouts(curl, timeout, method=="HEAD") try: curl.perform() @@ -421,6 +421,10 @@ class KeepClient(object): _logger.info("HEAD %s: %s bytes", self._result['status_code'], self._result.get('content-length')) + if self._result['headers'].get('x-keep-locator'): + # This is a response to a remote block copy request, return + # the local copy block locator. + return self._result['headers'].get('x-keep-locator') return True _logger.info("GET %s: %s bytes in %s msec (%.3f MiB/sec)", @@ -512,7 +516,7 @@ class KeepClient(object): self.upload_counter.add(len(body)) return True - def _setcurltimeouts(self, curl, timeouts): + def _setcurltimeouts(self, curl, timeouts, ignore_bandwidth=False): if not timeouts: return elif isinstance(timeouts, tuple): @@ -525,8 +529,9 @@ class KeepClient(object): conn_t, xfer_t = (timeouts, timeouts) bandwidth_bps = KeepClient.DEFAULT_TIMEOUT[2] curl.setopt(pycurl.CONNECTTIMEOUT_MS, int(conn_t*1000)) - curl.setopt(pycurl.LOW_SPEED_TIME, int(math.ceil(xfer_t))) - curl.setopt(pycurl.LOW_SPEED_LIMIT, int(math.ceil(bandwidth_bps))) + if not ignore_bandwidth: + curl.setopt(pycurl.LOW_SPEED_TIME, int(math.ceil(xfer_t))) + curl.setopt(pycurl.LOW_SPEED_LIMIT, int(math.ceil(bandwidth_bps))) def _headerfunction(self, header_line): if isinstance(header_line, bytes): @@ -786,6 +791,7 @@ class KeepClient(object): if local_store: self.local_store = local_store + self.head = self.local_store_head self.get = self.local_store_get self.put = self.local_store_put else: @@ -975,6 +981,11 @@ class KeepClient(object): else: return None + def refresh_signature(self, loc): + """Ask Keep to get the remote block and return its local signature""" + now = datetime.datetime.utcnow().isoformat("T") + 'Z' + return self.head(loc, headers={'X-Keep-Signature': 'local, {}'.format(now)}) + @retry.retry_method def head(self, loc_s, **kwargs): return self._get_or_head(loc_s, method="HEAD", **kwargs) @@ -983,7 +994,7 @@ class KeepClient(object): def get(self, loc_s, **kwargs): return self._get_or_head(loc_s, method="GET", **kwargs) - def _get_or_head(self, loc_s, method="GET", num_retries=None, request_id=None): + def _get_or_head(self, loc_s, method="GET", num_retries=None, request_id=None, headers=None): """Get data from Keep. This method fetches one or more blocks of data from Keep. It @@ -1024,11 +1035,11 @@ class KeepClient(object): self.misses_counter.add(1) - headers = { - 'X-Request-Id': (request_id or - (hasattr(self, 'api_client') and self.api_client.request_id) or - arvados.util.new_request_id()), - } + if headers is None: + headers = {} + headers['X-Request-Id'] = (request_id or + (hasattr(self, 'api_client') and self.api_client.request_id) or + arvados.util.new_request_id()) # If the locator has hints specifying a prefix (indicating a # remote keepproxy) or the UUID of a local gateway service, @@ -1085,10 +1096,7 @@ class KeepClient(object): # Always cache the result, then return it if we succeeded. if loop.success(): - if method == "HEAD": - return True - else: - return blob + return blob finally: if slot is not None: slot.set(blob) @@ -1109,7 +1117,7 @@ class KeepClient(object): "{} not found".format(loc_s), service_errors) else: raise arvados.errors.KeepReadError( - "failed to read {}".format(loc_s), service_errors, label="service") + "failed to read {} after {}".format(loc_s, loop.attempts_str()), service_errors, label="service") @retry.retry_method def put(self, data, copies=2, num_retries=None, request_id=None): @@ -1188,8 +1196,8 @@ class KeepClient(object): for key in sorted_roots if roots_map[key].last_result()['error']) raise arvados.errors.KeepWriteError( - "failed to write {} (wanted {} copies but wrote {})".format( - data_hash, copies, writer_pool.done()), service_errors, label="service") + "failed to write {} after {} (wanted {} copies but wrote {})".format( + data_hash, loop.attempts_str(), copies, writer_pool.done()), service_errors, label="service") def local_store_put(self, data, copies=1, num_retries=None): """A stub for put(). @@ -1223,5 +1231,17 @@ class KeepClient(object): with open(os.path.join(self.local_store, locator.md5sum), 'rb') as f: return f.read() + def local_store_head(self, loc_s, num_retries=None): + """Companion to local_store_put().""" + try: + locator = KeepLocator(loc_s) + except ValueError: + raise arvados.errors.NotFoundError( + "Invalid data locator: '%s'" % loc_s) + if locator.md5sum == config.EMPTY_BLOCK_LOCATOR.split('+')[0]: + return True + if os.path.exists(os.path.join(self.local_store, locator.md5sum)): + return True + def is_cached(self, locator): return self.block_cache.reserve_cache(expect_hash)