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-28 15:29:52 +0100
commit8d2946ffd3af038ee33e28c724f3662c7042c573 (patch)
tree915a160b8f1ee97e772344bf8ebe276e9466005c
parent5ef19a0b31df84caed1e41719ef7ea5c6bd8a8bc (diff)
downloadbuildstream-8d2946ffd3af038ee33e28c724f3662c7042c573.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 56e61f915..15301cf5e 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
@@ -190,17 +191,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: