@@ -430,6 +430,79 @@ 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 client and
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 can be amongst other techniques determined by
441
+ // content-defined chunking.
442
+ //
443
+ // Clients can use this API before downloading a blob to determine which parts
444
+ // of the blob are already present locally and do not need to be downloaded
445
+ // again. The server splits the blob into chunks according to a
446
+ // content-defined chunking algorithm and returns a list of the chunk digests
447
+ // in the order in which the chunks have to be concatenated to assemble the
448
+ // requested blob.
449
+ //
450
+ // A client can expect the following guarantees from the server if a split
451
+ // request is answered successfully:
452
+ // 1. The blob chunks are stored in CAS.
453
+ // 2. Concatenating the blob chunks in the order of the digest list returned
454
+ // by the server results in the original blob.
455
+ //
456
+ // The usage of this API is optional for clients but it allows them to
457
+ // download only the missing parts of a large blob instead of the entire blob
458
+ // data, which in turn can considerably reduce download network traffic.
459
+ //
460
+ // Servers are free to implement this functionality, but they need to declare
461
+ // whether they support it or not by setting the
462
+ // [CacheCapabilities.blob_split_support][build.bazel.remote.execution.v2.CacheCapabilities.blob_split_support]
463
+ // field accordingly.
464
+ //
465
+ // Errors:
466
+ //
467
+ // * `NOT_FOUND`: The requested blob is not present in the CAS.
468
+ // * `RESOURCE_EXHAUSTED`: There is insufficient disk quota to store the blob
469
+ // chunks.
470
+ rpc SplitBlob (SplitBlobRequest ) returns (SplitBlobResponse ) {
471
+ option (google.api.http ) = { get : "/v2/{instance_name=**}/blobs/{blob_digest.hash}/{blob_digest.size_bytes}:splitBlob" };
472
+ }
473
+
474
+ // Splice a blob from chunks.
475
+ //
476
+ // This is the complementary operation to the
477
+ // [ContentAddressableStorage.SplitBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SplitBlob]
478
+ // function to handle the splitted upload of large blobs to save upload
479
+ // traffic.
480
+ //
481
+ // If a client needs to upload a large blob and is able to split a blob into
482
+ // chunks locally according to some content-defined chunking algorithm, it can
483
+ // first determine which parts of the blob are already available in the remote
484
+ // CAS and upload the missing chunks, and then use this API to instruct the
485
+ // server to splice the original blob from the remotely available blob chunks.
486
+ //
487
+ // The usage of this API is optional for clients but it allows them to upload
488
+ // only the missing parts of a large blob instead of the entire blob data,
489
+ // which in turn can considerably reduce upload network traffic.
490
+ //
491
+ // Servers are free to implement this functionality, but they need to declare
492
+ // whether they support it or not by setting the
493
+ // [CacheCapabilities.blob_splice_support][build.bazel.remote.execution.v2.CacheCapabilities.blob_splice_support]
494
+ // field accordingly.
495
+ //
496
+ // Errors:
497
+ //
498
+ // * `NOT_FOUND`: At least one of the blob chunks is not present in the CAS.
499
+ // * `RESOURCE_EXHAUSTED`: There is insufficient disk quota to store the
500
+ // spliced blob.
501
+ // * `INVALID_ARGUMENT`: The digest of the spliced blob is different from the
502
+ // provided expected digest.
503
+ rpc SpliceBlob (SpliceBlobRequest ) returns (SpliceBlobResponse ) {
504
+ option (google.api.http ) = { post : "/v2/{instance_name=**}/blobs:spliceBlob" body: "*" };
505
+ }
433
506
}
434
507
435
508
// The Capabilities service may be used by remote execution clients to query
@@ -1778,6 +1851,53 @@ message GetTreeResponse {
1778
1851
string next_page_token = 2 ;
1779
1852
}
1780
1853
1854
+ // A request message for
1855
+ // [ContentAddressableStorage.SplitBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SplitBlob].
1856
+ message SplitBlobRequest {
1857
+ // The instance of the execution system to operate against. A server may
1858
+ // support multiple instances of the execution system (with their own workers,
1859
+ // storage, caches, etc.). The server MAY require use of this field to select
1860
+ // between them in an implementation-defined fashion, otherwise it can be
1861
+ // omitted.
1862
+ string instance_name = 1 ;
1863
+
1864
+ // The digest of the blob to be splitted.
1865
+ Digest blob_digest = 2 ;
1866
+ }
1867
+
1868
+ // A response message for
1869
+ // [ContentAddressableStorage.SplitBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SplitBlob].
1870
+ message SplitBlobResponse {
1871
+ // The ordered list of digests of the chunks into which the blob was splitted.
1872
+ // The original blob is assembled by concatenating the chunk data according to
1873
+ // the order of the digests given by this list.
1874
+ repeated Digest chunk_digests = 1 ;
1875
+ }
1876
+
1877
+ // A request message for
1878
+ // [ContentAddressableStorage.SpliceBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SpliceBlob].
1879
+ message SpliceBlobRequest {
1880
+ // The instance of the execution system to operate against. A server may
1881
+ // support multiple instances of the execution system (with their own workers,
1882
+ // storage, caches, etc.). The server MAY require use of this field to select
1883
+ // between them in an implementation-defined fashion, otherwise it can be
1884
+ // omitted.
1885
+ string instance_name = 1 ;
1886
+
1887
+ // Expected digest of the spliced blob.
1888
+ Digest blob_digest = 2 ;
1889
+
1890
+ // The ordered list of digests of the chunks which need to be concatenated to
1891
+ // assemble the original blob.
1892
+ repeated Digest chunk_digests = 3 ;
1893
+ }
1894
+
1895
+ // A response message for
1896
+ // [ContentAddressableStorage.SpliceBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SpliceBlob].
1897
+ message SpliceBlobResponse {
1898
+ // Intentionally empty for now, but might need to be extended in future.
1899
+ }
1900
+
1781
1901
// A request message for
1782
1902
// [Capabilities.GetCapabilities][build.bazel.remote.execution.v2.Capabilities.GetCapabilities].
1783
1903
message GetCapabilitiesRequest {
@@ -1997,6 +2117,20 @@ message CacheCapabilities {
1997
2117
// [BatchUpdateBlobs][build.bazel.remote.execution.v2.ContentAddressableStorage.BatchUpdateBlobs]
1998
2118
// requests.
1999
2119
repeated Compressor.Value supported_batch_update_compressors = 7 ;
2120
+
2121
+ // Whether blob splitting is supported for the particular server/instance. If
2122
+ // yes, the server/instance implements the specified behavior for blob
2123
+ // splitting and a meaningful result can be expected from the
2124
+ // [ContentAddressableStorage.SplitBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SplitBlob]
2125
+ // operation.
2126
+ bool blob_split_support = 8 ;
2127
+
2128
+ // Whether blob splicing is supported for the particular server/instance. If
2129
+ // yes, the server/instance implements the specified behavior for blob
2130
+ // splicing and a meaningful result can be expected from the
2131
+ // [ContentAddressableStorage.SpliceBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SpliceBlob]
2132
+ // operation.
2133
+ bool blob_splice_support = 9 ;
2000
2134
}
2001
2135
2002
2136
// Capabilities of the remote execution system.
0 commit comments