@@ -430,6 +430,78 @@ service ContentAddressableStorage {
430
430
rpc GetTree (GetTreeRequest ) returns (stream GetTreeResponse ) {
431
431
option (google.api.http ) = { get : "/v2/{instance_name=**}/blobs/{root_digest.hash}/{root_digest.size_bytes}:getTree" };
432
432
}
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
+ }
433
505
}
434
506
435
507
// The Capabilities service may be used by remote execution clients to query
@@ -1778,6 +1850,53 @@ message GetTreeResponse {
1778
1850
string next_page_token = 2 ;
1779
1851
}
1780
1852
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
+
1781
1900
// A request message for
1782
1901
// [Capabilities.GetCapabilities][build.bazel.remote.execution.v2.Capabilities.GetCapabilities].
1783
1902
message GetCapabilitiesRequest {
@@ -1997,6 +2116,20 @@ message CacheCapabilities {
1997
2116
// [BatchUpdateBlobs][build.bazel.remote.execution.v2.ContentAddressableStorage.BatchUpdateBlobs]
1998
2117
// requests.
1999
2118
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 ;
2000
2133
}
2001
2134
2002
2135
// Capabilities of the remote execution system.
0 commit comments