diff --git a/buildstream/_artifactcache/casserver.py b/buildstream/_artifactcache/casserver.py index 56e61f915059c9ff92a4381ea4fed0bf4f2caf63..f636eb6b47c78ad800eb45c06d5dd27691e23f7e 100644 --- a/buildstream/_artifactcache/casserver.py +++ b/buildstream/_artifactcache/casserver.py @@ -24,6 +24,8 @@ import signal import sys import tempfile import uuid +import errno +import ctypes import click import grpc @@ -190,17 +192,34 @@ class _ByteStreamServicer(bytestream_pb2_grpc.ByteStreamServicer): context.set_code(grpc.StatusCode.NOT_FOUND) return response - try: - _clean_up_cache(self.cas, client_digest.size_bytes) - except ArtifactTooLargeException as e: - context.set_code(grpc.StatusCode.RESOURCE_EXHAUSTED) - context.set_details(str(e)) - return response + while True: + if client_digest.size_bytes == 0: + break + try: + _clean_up_cache(self.cas, client_digest.size_bytes) + except ArtifactTooLargeException as e: + context.set_code(grpc.StatusCode.RESOURCE_EXHAUSTED) + context.set_details(str(e)) + return response + + try: + os.unix_fallocate(out.fileno(), 0, client_digest.size_bytes) + break + except OSError as e: + # Multiple upload can happen in the same time + if e.errno != errno.ENOSPC: + raise + elif request.resource_name: # If it is set on subsequent calls, it **must** match the value of the first request. if request.resource_name != resource_name: context.set_code(grpc.StatusCode.FAILED_PRECONDITION) return response + + if (offset + len(request.data)) > client_digest.size_bytes: + context.set_code(grpc.StatusCode.FAILED_PRECONDITION) + return response + out.write(request.data) offset += len(request.data) if request.finish_write: