summaryrefslogtreecommitdiff
path: root/buildstream
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 /buildstream
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.
Diffstat (limited to 'buildstream')
-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: