summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorValentin David <valentin.david@codethink.co.uk>2018-11-16 15:28:45 +0100
committerValentin David <valentin.david@codethink.co.uk>2018-11-29 17:17:21 +0100
commit1c4b410f7e527cc7fa0efb5af909d9583511573e (patch)
tree74e72b598eead7f6a45470323f6a54329ca25da6
parent9252a18180ce79d70c193768293baa0f0eff9981 (diff)
downloadbuildstream-1c4b410f7e527cc7fa0efb5af909d9583511573e.tar.gz
"Fallocate" object disk space to avoid getting NOSPC error when writing
This locks the temporary object file so that cleanup does not need to be done for every write.
-rw-r--r--buildstream/_artifactcache/casserver.py30
1 files changed, 24 insertions, 6 deletions
diff --git a/buildstream/_artifactcache/casserver.py b/buildstream/_artifactcache/casserver.py
index a9854aa40..c99ef888e 100644
--- a/buildstream/_artifactcache/casserver.py
+++ b/buildstream/_artifactcache/casserver.py
@@ -24,6 +24,7 @@ import signal
import sys
import tempfile
import uuid
+import errno
import click
import grpc
@@ -193,17 +194,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.posix_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: