Skip to content

Commit 8683da9

Browse files
coeuvrecopybara-github
authored andcommitted
Implement combined cache in RemoteCache.
Previously, combined cache is implemented by `DiskAndRemoteCacheCliet` which is hidden behind the interface `RemoteCacheClient`. This introduced a lot of issues because disk cache is really not a variant of remote cache and we need to handle them differently. This CL moves the logic from `DiskAndRemoteCacheCliet` to `RemoteCache` so that the code is aware of two caches and: 1. `casUploadCache` is only applied to remote cache. 2. Every functions in `RemoteExecutionCache` only operates remote cache. The class `RemoteCache` should really be renamed to something else because it doesn't only have remote cache. But this should be a follow-up CL. Fixes bazelbuild#20962. Closes bazelbuild#21213. It's also releated to bazelbuild#20296, but I would like the add the mentioned integration test before close it. PiperOrigin-RevId: 671740437 Change-Id: Ia55ef879d313d111874b4f8376f66a7d1fceebf7
1 parent 4f89f43 commit 8683da9

23 files changed

+471
-482
lines changed

src/main/java/com/google/devtools/build/lib/remote/ByteStreamBuildEventArtifactUploader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ private Single<String> getRemoteServerInstanceName(RemoteCache remoteCache) {
338338
return Single.just(remoteBytestreamUriPrefix);
339339
}
340340

341-
return toSingle(remoteCache.cacheProtocol::getAuthority, directExecutor())
341+
return toSingle(remoteCache::getRemoteAuthority, directExecutor())
342342
.map(
343343
a -> {
344344
if (!Strings.isNullOrEmpty(remoteInstanceName)) {

src/main/java/com/google/devtools/build/lib/remote/RemoteCache.java

Lines changed: 254 additions & 34 deletions
Large diffs are not rendered by default.

src/main/java/com/google/devtools/build/lib/remote/RemoteCacheClientFactory.java

Lines changed: 21 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import com.google.common.collect.ImmutableList;
2121
import com.google.devtools.build.lib.authandtls.AuthAndTLSOptions;
2222
import com.google.devtools.build.lib.remote.common.RemoteCacheClient;
23-
import com.google.devtools.build.lib.remote.disk.DiskAndRemoteCacheClient;
2423
import com.google.devtools.build.lib.remote.disk.DiskCacheClient;
2524
import com.google.devtools.build.lib.remote.http.HttpCacheClient;
2625
import com.google.devtools.build.lib.remote.options.RemoteOptions;
@@ -40,21 +39,11 @@ public final class RemoteCacheClientFactory {
4039

4140
private RemoteCacheClientFactory() {}
4241

43-
public static RemoteCacheClient createDiskAndRemoteClient(
44-
Path workingDirectory,
45-
RemoteOptions options,
46-
DigestUtil digestUtil,
47-
ExecutorService executorService,
48-
boolean remoteVerifyDownloads,
49-
RemoteCacheClient remoteCacheClient)
50-
throws IOException {
51-
DiskCacheClient diskCacheClient =
52-
createDiskCache(
53-
workingDirectory, options, digestUtil, executorService, remoteVerifyDownloads);
54-
return new DiskAndRemoteCacheClient(diskCacheClient, remoteCacheClient);
55-
}
42+
/** A record that hold both a {@link RemoteCacheClient} and {@link DiskCacheClient}. */
43+
public record CombinedCacheClient(
44+
@Nullable RemoteCacheClient remoteCacheClient, @Nullable DiskCacheClient diskCacheClient) {}
5645

57-
public static RemoteCacheClient create(
46+
public static CombinedCacheClient create(
5847
RemoteOptions options,
5948
@Nullable Credentials creds,
6049
AuthAndTLSOptions authAndTlsOptions,
@@ -64,26 +53,26 @@ public static RemoteCacheClient create(
6453
RemoteRetrier retrier)
6554
throws IOException {
6655
Preconditions.checkNotNull(workingDirectory, "workingDirectory");
67-
if (isHttpCache(options) && isDiskCache(options)) {
68-
return createDiskAndHttpCache(
69-
workingDirectory,
70-
options,
71-
creds,
72-
authAndTlsOptions,
73-
digestUtil,
74-
executorService,
75-
retrier);
76-
}
56+
RemoteCacheClient httpCacheClient = null;
57+
DiskCacheClient diskCacheClient = null;
7758
if (isHttpCache(options)) {
78-
return createHttp(options, creds, authAndTlsOptions, digestUtil, retrier);
59+
httpCacheClient = createHttp(options, creds, authAndTlsOptions, digestUtil, retrier);
7960
}
8061
if (isDiskCache(options)) {
81-
return createDiskCache(
82-
workingDirectory, options, digestUtil, executorService, options.remoteVerifyDownloads);
62+
diskCacheClient =
63+
createDiskCache(
64+
workingDirectory,
65+
options,
66+
digestUtil,
67+
executorService,
68+
options.remoteVerifyDownloads);
69+
}
70+
if (httpCacheClient == null && diskCacheClient == null) {
71+
throw new IllegalArgumentException(
72+
"Unrecognized RemoteOptions configuration: remote Http cache URL and/or local disk cache"
73+
+ " options expected.");
8374
}
84-
throw new IllegalArgumentException(
85-
"Unrecognized RemoteOptions configuration: remote Http cache URL and/or local disk cache"
86-
+ " options expected.");
75+
return new CombinedCacheClient(httpCacheClient, diskCacheClient);
8776
}
8877

8978
public static boolean isRemoteCacheOptions(RemoteOptions options) {
@@ -137,7 +126,7 @@ private static RemoteCacheClient createHttp(
137126
}
138127
}
139128

140-
private static DiskCacheClient createDiskCache(
129+
public static DiskCacheClient createDiskCache(
141130
Path workingDirectory,
142131
RemoteOptions options,
143132
DigestUtil digestUtil,
@@ -149,25 +138,6 @@ private static DiskCacheClient createDiskCache(
149138
cacheDir, options.diskCacheMaxSizeBytes, digestUtil, executorService, verifyDownloads);
150139
}
151140

152-
private static RemoteCacheClient createDiskAndHttpCache(
153-
Path workingDirectory,
154-
RemoteOptions options,
155-
Credentials cred,
156-
AuthAndTLSOptions authAndTlsOptions,
157-
DigestUtil digestUtil,
158-
ExecutorService executorService,
159-
RemoteRetrier retrier)
160-
throws IOException {
161-
RemoteCacheClient httpCache = createHttp(options, cred, authAndTlsOptions, digestUtil, retrier);
162-
return createDiskAndRemoteClient(
163-
workingDirectory,
164-
options,
165-
digestUtil,
166-
executorService,
167-
options.remoteVerifyDownloads,
168-
httpCache);
169-
}
170-
171141
public static boolean isDiskCache(RemoteOptions options) {
172142
return options.diskCache != null && !options.diskCache.isEmpty();
173143
}

src/main/java/com/google/devtools/build/lib/remote/RemoteExecutionCache.java

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import com.google.devtools.build.lib.remote.common.LostInputsEvent;
4141
import com.google.devtools.build.lib.remote.common.RemoteActionExecutionContext;
4242
import com.google.devtools.build.lib.remote.common.RemoteCacheClient;
43+
import com.google.devtools.build.lib.remote.disk.DiskCacheClient;
4344
import com.google.devtools.build.lib.remote.merkletree.MerkleTree;
4445
import com.google.devtools.build.lib.remote.merkletree.MerkleTree.PathOrBytes;
4546
import com.google.devtools.build.lib.remote.options.RemoteOptions;
@@ -61,6 +62,7 @@
6162
import java.util.List;
6263
import java.util.Map;
6364
import java.util.concurrent.atomic.AtomicReference;
65+
import javax.annotation.Nullable;
6466

6567
/** A {@link RemoteCache} with additional functionality needed for remote execution. */
6668
public class RemoteExecutionCache extends RemoteCache {
@@ -99,8 +101,11 @@ public boolean isRemote(RemoteActionExecutionContext context, Path path)
99101
};
100102

101103
public RemoteExecutionCache(
102-
RemoteCacheClient protocolImpl, RemoteOptions options, DigestUtil digestUtil) {
103-
super(protocolImpl, options, digestUtil);
104+
RemoteCacheClient remoteCacheClient,
105+
@Nullable DiskCacheClient diskCacheClient,
106+
RemoteOptions options,
107+
DigestUtil digestUtil) {
108+
super(checkNotNull(remoteCacheClient), diskCacheClient, options, digestUtil);
104109
}
105110

106111
@VisibleForTesting
@@ -175,13 +180,13 @@ private ListenableFuture<Void> uploadBlob(
175180
Reporter reporter) {
176181
Directory node = merkleTree.getDirectoryByDigest(digest);
177182
if (node != null) {
178-
return cacheProtocol.uploadBlob(context, digest, node.toByteString());
183+
return remoteCacheClient.uploadBlob(context, digest, node.toByteString());
179184
}
180185

181186
PathOrBytes file = merkleTree.getFileByDigest(digest);
182187
if (file != null) {
183188
if (file.getBytes() != null) {
184-
return cacheProtocol.uploadBlob(context, digest, file.getBytes());
189+
return remoteCacheClient.uploadBlob(context, digest, file.getBytes());
185190
}
186191

187192
var path = checkNotNull(file.getPath());
@@ -196,12 +201,12 @@ private ListenableFuture<Void> uploadBlob(
196201
} catch (IOException e) {
197202
return immediateFailedFuture(e);
198203
}
199-
return cacheProtocol.uploadFile(context, digest, path);
204+
return remoteCacheClient.uploadFile(context, digest, path);
200205
}
201206

202207
Message message = additionalInputs.get(digest);
203208
if (message != null) {
204-
return cacheProtocol.uploadBlob(context, digest, message.toByteString());
209+
return remoteCacheClient.uploadBlob(context, digest, message.toByteString());
205210
}
206211

207212
return immediateFailedFuture(
@@ -315,7 +320,8 @@ private Single<List<UploadTask>> findMissingBlobs(
315320
if (digestsToQuery.isEmpty()) {
316321
return immediateFuture(ImmutableSet.of());
317322
}
318-
return findMissingDigests(context, digestsToQuery);
323+
return remoteCacheClient.findMissingDigests(
324+
context, digestsToQuery);
319325
},
320326
directExecutor())
321327
.map(

src/main/java/com/google/devtools/build/lib/remote/RemoteExecutionService.java

Lines changed: 14 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import static com.google.common.base.Preconditions.checkArgument;
1717
import static com.google.common.base.Preconditions.checkNotNull;
1818
import static com.google.common.base.Preconditions.checkState;
19-
import static com.google.common.base.Strings.isNullOrEmpty;
2019
import static com.google.common.collect.ImmutableMap.toImmutableMap;
2120
import static com.google.common.util.concurrent.Futures.immediateFailedFuture;
2221
import static com.google.common.util.concurrent.Futures.immediateFuture;
@@ -286,33 +285,22 @@ private Command buildCommand(
286285
return command.setWorkingDirectory(remotePathResolver.getWorkingDirectory()).build();
287286
}
288287

289-
private static boolean useRemoteCache(RemoteOptions options) {
290-
return !isNullOrEmpty(options.remoteCache) || !isNullOrEmpty(options.remoteExecutor);
288+
private boolean useRemoteCache() {
289+
return remoteCache != null && remoteCache.hasRemoteCache();
291290
}
292291

293-
private static boolean useDiskCache(RemoteOptions options) {
294-
return options.diskCache != null && !options.diskCache.isEmpty();
292+
private boolean useDiskCache() {
293+
return remoteCache != null && remoteCache.hasDiskCache();
295294
}
296295

297296
public CachePolicy getReadCachePolicy(Spawn spawn) {
298297
if (remoteCache == null) {
299298
return CachePolicy.NO_CACHE;
300299
}
301300

302-
boolean allowDiskCache = false;
303-
boolean allowRemoteCache = false;
304-
305-
if (useRemoteCache(remoteOptions)) {
306-
allowRemoteCache = remoteOptions.remoteAcceptCached && Spawns.mayBeCachedRemotely(spawn);
307-
if (useDiskCache(remoteOptions)) {
308-
// Combined cache. Disk cache is treated as local cache. Actions which are tagged with
309-
// `no-remote-cache` can still hit the disk cache.
310-
allowDiskCache = Spawns.mayBeCached(spawn);
311-
}
312-
} else {
313-
// Disk cache only
314-
allowDiskCache = Spawns.mayBeCached(spawn);
315-
}
301+
boolean allowRemoteCache =
302+
useRemoteCache() && remoteOptions.remoteAcceptCached && Spawns.mayBeCachedRemotely(spawn);
303+
boolean allowDiskCache = useDiskCache() && Spawns.mayBeCached(spawn);
316304

317305
return CachePolicy.create(allowRemoteCache, allowDiskCache);
318306
}
@@ -322,22 +310,11 @@ public CachePolicy getWriteCachePolicy(Spawn spawn) {
322310
return CachePolicy.NO_CACHE;
323311
}
324312

325-
boolean allowDiskCache = false;
326-
boolean allowRemoteCache = false;
327-
328-
if (useRemoteCache(remoteOptions)) {
329-
allowRemoteCache =
330-
shouldUploadLocalResultsToRemoteCache(remoteOptions, spawn.getExecutionInfo())
331-
&& remoteCache.actionCacheSupportsUpdate();
332-
if (useDiskCache(remoteOptions)) {
333-
// Combined cache. Treat the disk cache part as local cache. Actions which are tagged with
334-
// `no-remote-cache` can still hit the disk cache.
335-
allowDiskCache = Spawns.mayBeCached(spawn);
336-
}
337-
} else {
338-
// Disk cache only
339-
allowDiskCache = Spawns.mayBeCached(spawn);
340-
}
313+
boolean allowRemoteCache =
314+
useRemoteCache()
315+
&& shouldUploadLocalResultsToRemoteCache(remoteOptions, spawn.getExecutionInfo())
316+
&& remoteCache.remoteActionCacheSupportsUpdate();
317+
boolean allowDiskCache = useDiskCache() && Spawns.mayBeCached(spawn);
341318

342319
return CachePolicy.create(allowRemoteCache, allowDiskCache);
343320
}
@@ -1310,7 +1287,7 @@ public InMemoryOutput downloadOutputs(RemoteAction action, RemoteActionResult re
13101287
// When downloading outputs from just remotely executed action, the action result comes from
13111288
// Execution response which means, if disk cache is enabled, action result hasn't been
13121289
// uploaded to it. Upload action result to disk cache here so next build could hit it.
1313-
if (useDiskCache(remoteOptions) && result.executeResponse != null) {
1290+
if (useDiskCache() && result.executeResponse != null) {
13141291
getFromFuture(
13151292
remoteCache.uploadActionResult(
13161293
context.withWriteCachePolicy(CachePolicy.DISK_CACHE_ONLY),
@@ -1583,7 +1560,7 @@ private Single<UploadManifest> buildUploadManifestAsync(
15831560

15841561
return UploadManifest.create(
15851562
remoteOptions,
1586-
remoteCache.getCacheCapabilities(),
1563+
remoteCache.getRemoteCacheCapabilities(),
15871564
digestUtil,
15881565
action.getRemotePathResolver(),
15891566
action.getActionKey(),

0 commit comments

Comments
 (0)