Skip to content

Commit 186240b

Browse files
committed
remote_exec.proto: add blob split and splice API
Depending on the software project, possibly large artifacts need to be downloaded from or uploaded to the remote CAS such as executables with debug information, comprehensive libraries, or even whole file system images. Such artifacts generate a lot of traffic when downloaded or uploaded. The blob-split API allows to split such artifacts into chunks at the remote side, to fetch only those parts that are locally missing, and finally to locally assemble the requested blob from its chunks. The blob-splice API allows to split such artifacts into chunks locally, to upload only those parts that are remotely missing, and finally to remotely splice the requested blob from its chunks. Since only the binary differences from the last download/upload are fetched/uploaded, the blob split and splice API can save a lot of network traffic between server and client.
1 parent 6c32c3b commit 186240b

File tree

1 file changed

+133
-0
lines changed

1 file changed

+133
-0
lines changed

build/bazel/remote/execution/v2/remote_execution.proto

+133
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,78 @@ service ContentAddressableStorage {
430430
rpc GetTree(GetTreeRequest) returns (stream GetTreeResponse) {
431431
option (google.api.http) = { get: "/v2/{instance_name=**}/blobs/{root_digest.hash}/{root_digest.size_bytes}:getTree" };
432432
}
433+
434+
// Split a blob into chunks.
435+
//
436+
// This splitting API aims to reduce download traffic between a client and a
437+
// server, e.g., if a client needs to fetch a large blob that just has been
438+
// modified slightly since the last built. In this case, there is no need to
439+
// fetch the entire blob data, but just the binary differences between the two
440+
// blob versions, which are typically determined by content-defined chunking.
441+
//
442+
// Clients can use this API before downloading a blob to determine which parts
443+
// of the blob are already present locally and do not need to be downloaded
444+
// again. The server splits the blob into chunks according to a
445+
// content-defined chunking algorithm and returns a list of the chunk digests
446+
// in the order in which the chunks have to be concatenated to assemble the
447+
// requested blob.
448+
//
449+
// The client can expect certain guarantees from the server if a split request
450+
// is answered successfully:
451+
// 1. The blob chunks are stored in CAS.
452+
// 2. Concatenating the blob chunks in the order of the digest list returned
453+
// by the server results in the original blob.
454+
//
455+
// The usage of this API is optional but it allows clients to download only
456+
// the missing parts of a large blob instead of the entire blob data, which in
457+
// turn can considerably reduce download network traffic.
458+
//
459+
// Servers are free to implement this functionality, but they need to declare
460+
// whether they support it or not by setting the
461+
// [CacheCapabilities.blob_split_support][build.bazel.remote.execution.v2.CacheCapabilities.blob_split_support]
462+
// field accordingly.
463+
//
464+
// Errors:
465+
//
466+
// * `NOT_FOUND`: The requested blob is not present in the CAS.
467+
// * `RESOURCE_EXHAUSTED`: There is insufficient disk quota to store the blob
468+
// chunks.
469+
rpc SplitBlob(SplitBlobRequest) returns (SplitBlobResponse) {
470+
option (google.api.http) = { get: "/v2/{instance_name=**}/blobs/{blob_digest.hash}/{blob_digest.size_bytes}:splitBlob" };
471+
}
472+
473+
// Splice a blob from chunks.
474+
//
475+
// This is the complementary operation to the
476+
// [ContentAddressableStorage.SplitBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SplitBlob]
477+
// function to handle the splitted upload of large blobs to safe upload
478+
// traffic.
479+
//
480+
// If a client needs to upload a large blob and is able to split a blob into
481+
// chunks locally according to some content-defined chunking algorithm, it can
482+
// first determine which parts of the blob are already available in the remote
483+
// CAS and upload the missing chunks, and then use this API to instruct the
484+
// server to splice the original blob from the remotely available blob chunks.
485+
//
486+
// The usage of this API is optional but it allows clients to upload only the
487+
// missing parts of a large blob instead of the entire blob data, which in
488+
// turn can considerably reduce upload network traffic.
489+
//
490+
// Servers are free to implement this functionality, but they need to declare
491+
// whether they support it or not by setting the
492+
// [CacheCapabilities.blob_splice_support][build.bazel.remote.execution.v2.CacheCapabilities.blob_splice_support]
493+
// field accordingly.
494+
//
495+
// Errors:
496+
//
497+
// * `NOT_FOUND`: At least one of the blob chunks is not present in the CAS.
498+
// * `RESOURCE_EXHAUSTED`: There is insufficient disk quota to store the
499+
// spliced blob.
500+
// * `INVALID_ARGUMENT`: The digest of the spliced blob is different from the
501+
// provided expected digest.
502+
rpc SpliceBlob(SpliceBlobRequest) returns (SpliceBlobResponse) {
503+
option (google.api.http) = { post: "/v2/{instance_name=**}/blobs:spliceBlob" body: "*" };
504+
}
433505
}
434506

435507
// The Capabilities service may be used by remote execution clients to query
@@ -1778,6 +1850,53 @@ message GetTreeResponse {
17781850
string next_page_token = 2;
17791851
}
17801852

1853+
// A request message for
1854+
// [ContentAddressableStorage.SplitBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SplitBlob].
1855+
message SplitBlobRequest {
1856+
// The instance of the execution system to operate against. A server may
1857+
// support multiple instances of the execution system (with their own workers,
1858+
// storage, caches, etc.). The server MAY require use of this field to select
1859+
// between them in an implementation-defined fashion, otherwise it can be
1860+
// omitted.
1861+
string instance_name = 1;
1862+
1863+
// The digest of the blob to be splitted.
1864+
Digest blob_digest = 2;
1865+
}
1866+
1867+
// A response message for
1868+
// [ContentAddressableStorage.SplitBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SplitBlob].
1869+
message SplitBlobResponse {
1870+
// The ordered list of digests of the chunks into which the blob was splitted.
1871+
// The original blob is assembled by concatenating the chunk data according to
1872+
// the order of the digests given by this list.
1873+
repeated Digest chunk_digests = 1;
1874+
}
1875+
1876+
// A request message for
1877+
// [ContentAddressableStorage.SpliceBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SpliceBlob].
1878+
message SpliceBlobRequest {
1879+
// The instance of the execution system to operate against. A server may
1880+
// support multiple instances of the execution system (with their own workers,
1881+
// storage, caches, etc.). The server MAY require use of this field to select
1882+
// between them in an implementation-defined fashion, otherwise it can be
1883+
// omitted.
1884+
string instance_name = 1;
1885+
1886+
// Expected digest of the spliced blob.
1887+
Digest blob_digest = 2;
1888+
1889+
// The ordered list of digests of the chunks which need to be concatenated to
1890+
// assemble the original blob.
1891+
repeated Digest chunk_digests = 3;
1892+
}
1893+
1894+
// A response message for
1895+
// [ContentAddressableStorage.SpliceBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SpliceBlob].
1896+
message SpliceBlobResponse {
1897+
// Intentionally empty for now, but might need to be extended in future.
1898+
}
1899+
17811900
// A request message for
17821901
// [Capabilities.GetCapabilities][build.bazel.remote.execution.v2.Capabilities.GetCapabilities].
17831902
message GetCapabilitiesRequest {
@@ -1997,6 +2116,20 @@ message CacheCapabilities {
19972116
// [BatchUpdateBlobs][build.bazel.remote.execution.v2.ContentAddressableStorage.BatchUpdateBlobs]
19982117
// requests.
19992118
repeated Compressor.Value supported_batch_update_compressors = 7;
2119+
2120+
// Whether blob splitting is supported for the particular server/instance. If
2121+
// yes, the server/instance implements the specified behavior for blob
2122+
// splitting and a meaningful result can be expected from the
2123+
// [ContentAddressableStorage.SplitBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SplitBlob]
2124+
// operation.
2125+
bool blob_split_support = 8;
2126+
2127+
// Whether blob splicing is supported for the particular server/instance. If
2128+
// yes, the server/instance implements the specified behavior for blob
2129+
// splicing and a meaningful result can be expected from the
2130+
// [ContentAddressableStorage.SpliceBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SpliceBlob]
2131+
// operation.
2132+
bool blob_splice_support = 9;
20002133
}
20012134

20022135
// Capabilities of the remote execution system.

0 commit comments

Comments
 (0)