From 82a485fca83c49a084074bc6d050f97b4a10417f Mon Sep 17 00:00:00 2001 From: George Gensure Date: Fri, 2 Jun 2023 20:37:01 -0400 Subject: [PATCH 001/311] Handle null Throwable message in asExecutionStatus (#1357) Throwable indicates that the response to getMessage() may be null. --- src/main/java/build/buildfarm/common/Actions.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/build/buildfarm/common/Actions.java b/src/main/java/build/buildfarm/common/Actions.java index ab3c3d8432..d6d1f18ba0 100644 --- a/src/main/java/build/buildfarm/common/Actions.java +++ b/src/main/java/build/buildfarm/common/Actions.java @@ -71,7 +71,12 @@ public static Status asExecutionStatus(Throwable t) { status.setCode(grpcStatus.getCode().value()); } - return status.setMessage(t.getMessage()).build(); + String message = t.getMessage(); + if (message != null) { + status.setMessage(message); + } + + return status.build(); } public static boolean isRetriable(Status status) { From 4b5f2a97f5548b3f89f8f41632549527bee6a780 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Sun, 4 Jun 2023 10:22:18 -0400 Subject: [PATCH 002/311] Update docs to include redis requirement (#1359) Cleaned up some links and language --- _site/docs/quick_start.md | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/_site/docs/quick_start.md b/_site/docs/quick_start.md index 2e32dc30ce..5383c31199 100644 --- a/_site/docs/quick_start.md +++ b/_site/docs/quick_start.md @@ -6,7 +6,19 @@ nav_order: 3 # Quick Start -Here we describe how to use bazel remote caching or remote execution with buildfarm. We'll start by creating a single workspace that can be used for both. +Here we describe how to use bazel remote caching or remote execution with buildfarm. We will create a single client workspace that can be used for both. + +## Setup + +You can run this quick start on a single computer running nearly any flavor of linux. This computer is the localhost for the rest of the description. + +### Backplane + +Buildfarm requires a backplane to store information that is shared between cluster members. A [redis](https://redis.io) server can be used to meet this requirement. + +Download/Install a redis-server instance and run it on your localhost. The default redis port of 6379 will be used by the default buildfarm configs. + +## Workspace Let's start with a bazel workspace with a single file to compile into an executable: @@ -68,7 +80,7 @@ INFO: 2 processes: 2 remote cache hit. ## Remote Execution (and caching) -Now we will use buildfarm for remote execution with a minimal configuration - a single memory instance, with a host-colocated worker that can execute a single process at a time - via a bazel invocation on our workspace. +Now we will use buildfarm for remote execution with a minimal configuration - a single memory instance, with a worker on the localhost that can execute a single process at a time - via a bazel invocation on our workspace. First, we should restart the buildfarm server to ensure that we get remote execution (this can also be forced from the client by using `--noremote_accept_cached`). From the buildfarm server prompt and directory: @@ -107,7 +119,7 @@ To stop the containers, run: ## Buildfarm Manager -You can now easily launch a new Buildfarm cluster locally or in AWS using an open sourced Buildfarm Manager. +You can now easily launch a new Buildfarm cluster locally or in AWS using an open sourced [Buildfarm Manager](https://github.com/80degreeswest/bfmgr). ``` wget https://github.com/80degreeswest/bfmgr/releases/download/1.0.7/bfmgr-1.0.7.jar From 74455c872fad0f3f43fe4bad0d13b1c9fa3c144d Mon Sep 17 00:00:00 2001 From: George Gensure Date: Mon, 5 Jun 2023 23:07:27 -0400 Subject: [PATCH 003/311] Update worker image tag to jammy-java11-gcc (#1362) --- BUILD | 4 ++-- images.bzl | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/BUILD b/BUILD index 380d6b8564..f552ea9d7b 100644 --- a/BUILD +++ b/BUILD @@ -148,14 +148,14 @@ oss_audit( # Download cgroup-tools so that the worker is able to restrict actions via control groups. download_pkgs( name = "worker_pkgs", - image_tar = "@ubuntu-bionic//image", + image_tar = "@ubuntu-jammy//image", packages = ["cgroup-tools"], tags = ["container"], ) install_pkgs( name = "worker_pkgs_image", - image_tar = "@ubuntu-bionic//image", + image_tar = "@ubuntu-jammy//image", installables_tar = ":worker_pkgs.tar", installation_cleanup_commands = "rm -rf /var/lib/apt/lists/*", output_image_name = "worker_pkgs_image", diff --git a/images.bzl b/images.bzl index 89d5fd22da..9ab0a8b0b7 100644 --- a/images.bzl +++ b/images.bzl @@ -34,6 +34,14 @@ def buildfarm_images(): tag = "bionic-java11-gcc", ) + container_pull( + name = "ubuntu-jammy", + digest = "sha256:da847ee259ebe7f00631a2f0146d9add60ff0f94b031a2e522ce94c78b1335c2", + registry = "index.docker.io", + repository = "bazelbuild/buildfarm-worker-base", + tag = "jammy-java11-gcc", + ) + container_pull( name = "amazon_corretto_java_image_base", registry = "index.docker.io", From 0f512d36ba2cff602d8d334b262ca6786d0ae6e6 Mon Sep 17 00:00:00 2001 From: "Jacob(Jianqiu) Mou" <54453872+jacobmou@users.noreply.github.com> Date: Tue, 6 Jun 2023 10:34:03 -0400 Subject: [PATCH 004/311] [docs]Update troubleshooting-bazel-remote-execution.md (#1361) --- _site/docs/tools/troubleshooting-bazel-remote-execution.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_site/docs/tools/troubleshooting-bazel-remote-execution.md b/_site/docs/tools/troubleshooting-bazel-remote-execution.md index 3c18e9432c..0d8661561e 100644 --- a/_site/docs/tools/troubleshooting-bazel-remote-execution.md +++ b/_site/docs/tools/troubleshooting-bazel-remote-execution.md @@ -11,7 +11,7 @@ A typical use case: Something works locally, but breaks when remote execution is ## bazel logging -Use `bazel [build|run|test] --experimental_remote_grpc_log=` to produce a binary log of all of the grpc activity bazel performs during an invocation. This log is written to at the completion of each request, and may not contain a complete picture if a build is interrupted, or a request is currently ongoing. +Use `bazel [build|run|test] --remote_grpc_log=` (`--experimental_remote_grpc_log=` if you are using bazel older than 6.0 release) to produce a binary log of all of the grpc activity bazel performs during an invocation. This log is written to at the completion of each request, and may not contain a complete picture if a build is interrupted, or a request is currently ongoing. ## Dumping the log From bb6ba79abb543eb4cd72dcf5ac8c640838e7e15b Mon Sep 17 00:00:00 2001 From: George Gensure Date: Tue, 13 Jun 2023 00:37:42 -0400 Subject: [PATCH 005/311] Remove unused ActionAmounts (#1366) --- .../build/buildfarm/instance/shard/RedisShardBackplane.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java index 5c5e06d01a..d4c239efe1 100644 --- a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java +++ b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java @@ -122,12 +122,6 @@ public class RedisShardBackplane implements Backplane { .add(PreconditionFailure.getDescriptor()) .build()); - private static class ActionAmounts { - Integer build = 0; - Integer test = 0; - Integer unknown = 0; - } - private final String source; // used in operation change publication private final Function onPublish; private final Function onComplete; From c084fa17c9cc41ae47a32b52696e41c860f614e6 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Wed, 14 Jun 2023 08:04:59 -0400 Subject: [PATCH 006/311] Correct executeWorkers removal and expire (#1367) Removed short circuit for executeWorkers which should never inspire publish Added memoized recentExecuteWorkers which will be delayed by currently const workerSetMaxAge Cleaned up getStorageWorkers, used grpc Deadline as premium, though already expired is awkward Storage removal is overzealous and will remove matching execute workers. Received worker changes continue to only affect storage. --- .../instance/shard/RedisShardBackplane.java | 89 +++++++++++++------ 1 file changed, 61 insertions(+), 28 deletions(-) diff --git a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java index d4c239efe1..681cda1325 100644 --- a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java +++ b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java @@ -15,6 +15,7 @@ package build.buildfarm.instance.shard; import static java.lang.String.format; +import static java.util.concurrent.TimeUnit.SECONDS; import build.bazel.remote.execution.v2.ActionResult; import build.bazel.remote.execution.v2.Digest; @@ -56,6 +57,8 @@ import build.buildfarm.v1test.ShardWorker; import build.buildfarm.v1test.WorkerChange; import build.buildfarm.v1test.WorkerType; +import com.google.common.base.Suppliers; +import com.google.common.base.Throwables; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ListMultimap; @@ -73,6 +76,7 @@ import com.google.rpc.Code; import com.google.rpc.PreconditionFailure; import com.google.rpc.Status; +import io.grpc.Deadline; import java.io.IOException; import java.time.Instant; import java.util.ArrayList; @@ -83,7 +87,6 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutorService; -import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; @@ -99,6 +102,7 @@ public class RedisShardBackplane implements Backplane { private static BuildfarmConfigs configs = BuildfarmConfigs.getInstance(); + private static final int workerSetMaxAge = 3; // seconds private static final JsonFormat.Parser operationParser = JsonFormat.parser() .usingTypeRegistry( @@ -135,8 +139,9 @@ public class RedisShardBackplane implements Backplane { private ExecutorService subscriberService = null; private @Nullable RedisClient client = null; + private Deadline storageWorkersDeadline = null; private final Set storageWorkerSet = Collections.synchronizedSet(new HashSet<>()); - private long workerSetExpiresAt = 0; + private final Supplier> recentExecuteWorkers; private DistributedState state = new DistributedState(); @@ -157,6 +162,17 @@ public RedisShardBackplane( this.onPublish = onPublish; this.onComplete = onComplete; this.jedisClusterFactory = jedisClusterFactory; + recentExecuteWorkers = + Suppliers.memoizeWithExpiration( + () -> { + try { + return client.call(this::fetchAndExpireExecuteWorkers); + } catch (IOException e) { + throw new RuntimeException(e); + } + }, + workerSetMaxAge, + SECONDS); } @SuppressWarnings("NullableProblems") @@ -477,7 +493,7 @@ private void startFailsafeOperationThread() { () -> { while (!Thread.currentThread().isInterrupted()) { try { - TimeUnit.SECONDS.sleep(10); + SECONDS.sleep(10); client.run(this::updateWatchers); } catch (InterruptedException e) { Thread.currentThread().interrupt(); @@ -530,7 +546,7 @@ public synchronized void stop() throws InterruptedException { } if (subscriberService != null) { subscriberService.shutdown(); - subscriberService.awaitTermination(10, TimeUnit.SECONDS); + subscriberService.awaitTermination(10, SECONDS); log.log(Level.FINE, "subscriberService has been stopped"); } if (client != null) { @@ -597,12 +613,14 @@ private boolean addWorkerByType(JedisCluster jedis, ShardWorker shardWorker, Str return result; } - private boolean removeWorkerAndPublish(JedisCluster jedis, String name, String changeJson) { - if (state.storageWorkers.remove(jedis, name) || state.executeWorkers.remove(jedis, name)) { + private boolean removeWorkerAndPublish( + JedisCluster jedis, String name, String changeJson, boolean storage) { + boolean removedAny = state.executeWorkers.remove(jedis, name); + if (storage && state.storageWorkers.remove(jedis, name)) { jedis.publish(configs.getBackplane().getWorkerChannel(), changeJson); return true; } - return false; + return removedAny; } @SuppressWarnings("ConstantConditions") @@ -615,7 +633,8 @@ public boolean removeWorker(String name, String reason) throws IOException { .build(); String workerChangeJson = JsonFormat.printer().print(workerChange); return subscriber.removeWorker(name) - && client.call(jedis -> removeWorkerAndPublish(jedis, name, workerChangeJson)); + && client.call( + jedis -> removeWorkerAndPublish(jedis, name, workerChangeJson, /* storage=*/ true)); } @SuppressWarnings("ConstantConditions") @@ -665,20 +684,26 @@ public void deregisterWorker(String workerName) throws IOException { @SuppressWarnings("ConstantConditions") @Override public synchronized Set getStorageWorkers() throws IOException { - long now = System.currentTimeMillis(); - if (now < workerSetExpiresAt) { - return new HashSet<>(storageWorkerSet); + if (storageWorkersDeadline == null || storageWorkersDeadline.isExpired()) { + synchronized (storageWorkerSet) { + Set newWorkerSet = client.call(jedis -> fetchAndExpireStorageWorkers(jedis)); + storageWorkerSet.clear(); + storageWorkerSet.addAll(newWorkerSet); + } + storageWorkersDeadline = Deadline.after(workerSetMaxAge, SECONDS); } + return new HashSet<>(storageWorkerSet); + } - synchronized (storageWorkerSet) { - Set newWorkerSet = client.call(jedis -> fetchAndExpireStorageWorkers(jedis, now)); - storageWorkerSet.clear(); - storageWorkerSet.addAll(newWorkerSet); + private synchronized Set getExecuteWorkers() throws IOException { + try { + return recentExecuteWorkers.get(); + } catch (RuntimeException e) { + // unwrap checked exception mask + Throwable cause = e.getCause(); + Throwables.throwIfInstanceOf(cause, IOException.class); + throw e; } - - // fetch every 3 seconds - workerSetExpiresAt = now + 3000; - return new HashSet<>(storageWorkerSet); } // When performing a graceful scale down of workers, the backplane can provide worker names to the @@ -701,7 +726,8 @@ public static List randomN(List list, int n) { .collect(Collectors.toList()); } - private void removeInvalidWorkers(JedisCluster jedis, long testedAt, List workers) { + private void removeInvalidWorkers( + JedisCluster jedis, long testedAt, List workers, boolean storage) { if (!workers.isEmpty()) { for (ShardWorker worker : workers) { String name = worker.getEndpoint(); @@ -716,7 +742,7 @@ private void removeInvalidWorkers(JedisCluster jedis, long testedAt, List fetchAndExpireStorageWorkers(JedisCluster jedis, long now) { + private Set fetchAndExpireStorageWorkers(JedisCluster jedis) { + return fetchAndExpireWorkers(jedis, state.storageWorkers.asMap(jedis), /* storage=*/ true); + } + + private Set fetchAndExpireExecuteWorkers(JedisCluster jedis) { + return fetchAndExpireWorkers(jedis, state.executeWorkers.asMap(jedis), /* storage=*/ false); + } + + private Set fetchAndExpireWorkers( + JedisCluster jedis, Map workers, boolean publish) { + long now = System.currentTimeMillis(); Set returnWorkers = Sets.newConcurrentHashSet(); ImmutableList.Builder invalidWorkers = ImmutableList.builder(); - for (Map.Entry entry : state.storageWorkers.asMap(jedis).entrySet()) { + for (Map.Entry entry : workers.entrySet()) { String json = entry.getValue(); String name = entry.getKey(); try { @@ -747,7 +783,7 @@ private Set fetchAndExpireStorageWorkers(JedisCluster jedis, long now) { invalidWorkers.add(ShardWorker.newBuilder().setEndpoint(name).build()); } } - removeInvalidWorkers(jedis, now, invalidWorkers.build()); + removeInvalidWorkers(jedis, now, invalidWorkers.build(), publish); return returnWorkers; } @@ -1390,10 +1426,7 @@ public boolean canPrequeue() throws IOException { @Override public BackplaneStatus backplaneStatus() throws IOException { BackplaneStatus.Builder builder = BackplaneStatus.newBuilder(); - builder.addAllActiveWorkers( - client.call( - jedis -> - Sets.union(state.executeWorkers.keys(jedis), state.storageWorkers.keys(jedis)))); + builder.addAllActiveWorkers(Sets.union(getExecuteWorkers(), getStorageWorkers())); builder.setDispatchedSize(client.call(jedis -> state.dispatchedOperations.size(jedis))); builder.setOperationQueue(state.operationQueue.status(client.call(jedis -> jedis))); builder.setPrequeue(state.prequeue.status(client.call(jedis -> jedis))); From d0b1d1df9df0f5ba50e0cb2bc2389beb699e6f9e Mon Sep 17 00:00:00 2001 From: George Gensure Date: Wed, 14 Jun 2023 22:57:18 -0400 Subject: [PATCH 007/311] Adjust Server/Worker configs after parser (#1370) Adjustments will make use of options. Ensure that they have the specified values from the commandline, and they have no checked exception throws. --- .../java/build/buildfarm/common/config/BuildfarmConfigs.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java b/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java index 081722cbac..432a11a90a 100644 --- a/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java +++ b/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java @@ -68,7 +68,6 @@ public static BuildfarmConfigs loadServerConfigs(String[] args) throws Configura ServerOptions options = parser.getOptions(ServerOptions.class); try { buildfarmConfigs = loadConfigs(getConfigurationPath(parser)); - adjustServerConfigs(buildfarmConfigs); } catch (IOException e) { log.severe("Could not parse yml configuration file." + e); throw new RuntimeException(e); @@ -79,6 +78,7 @@ public static BuildfarmConfigs loadServerConfigs(String[] args) throws Configura if (options.port > 0) { buildfarmConfigs.getServer().setPort(options.port); } + adjustServerConfigs(buildfarmConfigs); return buildfarmConfigs; } @@ -87,7 +87,6 @@ public static BuildfarmConfigs loadWorkerConfigs(String[] args) throws Configura ShardWorkerOptions options = parser.getOptions(ShardWorkerOptions.class); try { buildfarmConfigs = loadConfigs(getConfigurationPath(parser)); - adjustWorkerConfigs(buildfarmConfigs); } catch (IOException e) { log.severe("Could not parse yml configuration file." + e); throw new RuntimeException(e); @@ -95,6 +94,7 @@ public static BuildfarmConfigs loadWorkerConfigs(String[] args) throws Configura if (!Strings.isNullOrEmpty(options.publicName)) { buildfarmConfigs.getWorker().setPublicName(options.publicName); } + adjustWorkerConfigs(buildfarmConfigs); return buildfarmConfigs; } From d953f424708af7a567f202ffbe61a39eb6d12af3 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Sat, 17 Jun 2023 22:21:54 -0400 Subject: [PATCH 008/311] Handle oversized FMBs in StubInstance by splitting (#1377) FMBs over a specified size limit (4MB in practice from grpc limits) will be split log2n until under the limit to make requests. Tests added to verify this. Coverage of split behavior confirmed. Fixes #1375 --- .../buildfarm/instance/stub/StubInstance.java | 24 ++++++++++--- .../instance/stub/StubInstanceTest.java | 35 ++++++++++++++++++- 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/src/main/java/build/buildfarm/instance/stub/StubInstance.java b/src/main/java/build/buildfarm/instance/stub/StubInstance.java index 0cde9a0d41..219e5d54ec 100644 --- a/src/main/java/build/buildfarm/instance/stub/StubInstance.java +++ b/src/main/java/build/buildfarm/instance/stub/StubInstance.java @@ -18,6 +18,7 @@ import static build.buildfarm.common.grpc.TracingMetadataUtils.attachMetadataInterceptor; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; +import static com.google.common.util.concurrent.Futures.allAsList; import static com.google.common.util.concurrent.Futures.catching; import static com.google.common.util.concurrent.Futures.transform; import static com.google.common.util.concurrent.MoreExecutors.directExecutor; @@ -105,6 +106,7 @@ import com.google.bytestream.ByteStreamGrpc.ByteStreamStub; import com.google.bytestream.ByteStreamProto.ReadRequest; import com.google.bytestream.ByteStreamProto.ReadResponse; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Functions; import com.google.common.base.Supplier; import com.google.common.base.Suppliers; @@ -164,6 +166,8 @@ public class StubInstance implements Instance { private boolean isStopped = false; private final long maxBatchUpdateBlobsSize = Size.mbToBytes(3); + @VisibleForTesting long maxRequestSize = Size.mbToBytes(4); + public StubInstance(String name, DigestUtil digestUtil, ManagedChannel channel) { this(name, "no-identifier", digestUtil, channel, Durations.fromDays(DEFAULT_DEADLINE_DAYS)); } @@ -412,11 +416,16 @@ public ListenableFuture> findMissingBlobs( .setInstanceName(getName()) .addAllBlobDigests(digests) .build(); - if (request.getSerializedSize() > Size.mbToBytes(4)) { - throw new IllegalStateException( - String.format( - "FINDMISSINGBLOBS IS TOO LARGE: %d digests are required in one request!", - request.getBlobDigestsCount())); + if (request.getSerializedSize() > maxRequestSize) { + // log2n partition for size reduction as needed + int partitionSize = (request.getBlobDigestsCount() + 1) / 2; + return transform( + allAsList( + Iterables.transform( + Iterables.partition(digests, partitionSize), + subDigests -> findMissingBlobs(subDigests, requestMetadata))), + subMissings -> Iterables.concat(subMissings), + directExecutor()); } return transform( deadlined(casFutureStub) @@ -586,6 +595,7 @@ public void getBlob( ServerCallStreamObserver blobObserver, RequestMetadata requestMetadata) { throwIfStopped(); + checkNotNull(io.grpc.Context.current().getDeadline()); bsStub .get() .withInterceptors(attachMetadataInterceptor(requestMetadata)) @@ -886,6 +896,7 @@ public WorkerProfileMessage getWorkerProfile() { @Override public WorkerListMessage getWorkerList() { + checkNotNull(io.grpc.Context.current().getDeadline()); return workerProfileBlockingStub.get().getWorkerList(WorkerListRequest.newBuilder().build()); } @@ -897,6 +908,7 @@ public GetClientStartTimeResult getClientStartTime(GetClientStartTimeRequest req @Override public CasIndexResults reindexCas() { throwIfStopped(); + checkNotNull(io.grpc.Context.current().getDeadline()); ReindexCasRequestResults proto = adminBlockingStub.get().reindexCas(ReindexCasRequest.newBuilder().build()); CasIndexResults results = new CasIndexResults(); @@ -910,6 +922,7 @@ public CasIndexResults reindexCas() { @Override public void deregisterWorker(String workerName) { throwIfStopped(); + checkNotNull(io.grpc.Context.current().getDeadline()); adminBlockingStub .get() .shutDownWorkerGracefully( @@ -919,6 +932,7 @@ public void deregisterWorker(String workerName) { @Override public PrepareWorkerForGracefulShutDownRequestResults shutDownWorkerGracefully() { throwIfStopped(); + checkNotNull(io.grpc.Context.current().getDeadline()); return shutDownWorkerBlockingStub .get() .prepareWorkerForGracefulShutdown( diff --git a/src/test/java/build/buildfarm/instance/stub/StubInstanceTest.java b/src/test/java/build/buildfarm/instance/stub/StubInstanceTest.java index e50e3f0028..e3845494b8 100644 --- a/src/test/java/build/buildfarm/instance/stub/StubInstanceTest.java +++ b/src/test/java/build/buildfarm/instance/stub/StubInstanceTest.java @@ -64,6 +64,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; @@ -98,7 +99,7 @@ public void tearDown() throws InterruptedException { fakeServer.awaitTermination(); } - private Instance newStubInstance(String instanceName) { + private StubInstance newStubInstance(String instanceName) { return new StubInstance( instanceName, DIGEST_UTIL, @@ -197,6 +198,38 @@ public void findMissingBlobs( instance.stop(); } + @Test + public void findMissingBlobsOverSizeLimitRecombines() + throws ExecutionException, InterruptedException { + AtomicReference reference = new AtomicReference<>(); + serviceRegistry.addService( + new ContentAddressableStorageImplBase() { + @Override + public void findMissingBlobs( + FindMissingBlobsRequest request, + StreamObserver responseObserver) { + reference.set(request); + responseObserver.onNext( + FindMissingBlobsResponse.newBuilder() + .addAllMissingBlobDigests(request.getBlobDigestsList()) + .build()); + responseObserver.onCompleted(); + } + }); + StubInstance instance = newStubInstance("findMissingBlobs-test"); + instance.maxRequestSize = 1024; + ImmutableList.Builder builder = ImmutableList.builder(); + // generates digest size * 1024 serialized size at least + for (int i = 0; i < 1024; i++) { + ByteString content = ByteString.copyFromUtf8("Hello, World! " + UUID.randomUUID()); + builder.add(DIGEST_UTIL.compute(content)); + } + ImmutableList digests = builder.build(); + assertThat(instance.findMissingBlobs(digests, RequestMetadata.getDefaultInstance()).get()) + .containsExactlyElementsIn(digests); + instance.stop(); + } + @Test public void outputStreamWrites() throws IOException, InterruptedException { AtomicReference writtenContent = new AtomicReference<>(); From dd52f13072384eff5c15d35c0a3c4cf2f4bf50cf Mon Sep 17 00:00:00 2001 From: George Gensure Date: Sun, 18 Jun 2023 10:29:13 -0400 Subject: [PATCH 009/311] Missing directories not visited in validation (#1378) A directory which is missing during the course of validation should not be identified as missing. This prevents a NPE and inspires validation to emit one MISSING violation per path to a missing directory for preconditions. Fixes #1374 --- .../server/AbstractServerInstance.java | 5 +- .../server/AbstractServerInstanceTest.java | 47 ++++++++++++++++++- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/main/java/build/buildfarm/instance/server/AbstractServerInstance.java b/src/main/java/build/buildfarm/instance/server/AbstractServerInstance.java index 388c18ab77..52cb1448e6 100644 --- a/src/main/java/build/buildfarm/instance/server/AbstractServerInstance.java +++ b/src/main/java/build/buildfarm/instance/server/AbstractServerInstance.java @@ -934,7 +934,10 @@ private static void validateActionInputDirectoryDigest( preconditionFailure); } pathDigests.pop(); - visited.add(directoryDigest); + if (directory != null) { + // missing directories are not visited and will appear in violations list each time + visited.add(directoryDigest); + } } protected ListenableFuture getTreeFuture( diff --git a/src/test/java/build/buildfarm/instance/server/AbstractServerInstanceTest.java b/src/test/java/build/buildfarm/instance/server/AbstractServerInstanceTest.java index f8e46e5d0f..dcd4936c1f 100644 --- a/src/test/java/build/buildfarm/instance/server/AbstractServerInstanceTest.java +++ b/src/test/java/build/buildfarm/instance/server/AbstractServerInstanceTest.java @@ -16,6 +16,7 @@ import static build.buildfarm.common.Actions.checkPreconditionFailure; import static build.buildfarm.common.Errors.VIOLATION_TYPE_INVALID; +import static build.buildfarm.common.Errors.VIOLATION_TYPE_MISSING; import static build.buildfarm.instance.server.AbstractServerInstance.ACTION_INPUT_ROOT_DIRECTORY_PATH; import static build.buildfarm.instance.server.AbstractServerInstance.DIRECTORY_NOT_SORTED; import static build.buildfarm.instance.server.AbstractServerInstance.DUPLICATE_DIRENT; @@ -365,7 +366,6 @@ public void duplicateDirectoryInputIsInvalid() { /* onInputDigests=*/ digest -> {}, preconditionFailure); - assertThat(preconditionFailure.getViolationsCount()).isEqualTo(1); assertThat(preconditionFailure.getViolationsCount()).isEqualTo(1); Violation violation = preconditionFailure.getViolationsList().get(0); assertThat(violation.getType()).isEqualTo(VIOLATION_TYPE_INVALID); @@ -519,6 +519,51 @@ public void undeclaredWorkingDirectoryIsInvalid() { assertThat(violation.getDescription()).isEqualTo("working directory is not an input directory"); } + /** + * / -> valid dir bar/ -> missing dir with digest 'missing' and non-zero size foo/ -> missing dir + * with digest 'missing' and non-zero size + */ + @Test + public void multipleIdenticalDirectoryMissingAreAllPreconditionFailures() { + Digest missingDirectoryDigest = Digest.newBuilder().setHash("missing").setSizeBytes(1).build(); + PreconditionFailure.Builder preconditionFailure = PreconditionFailure.newBuilder(); + Directory root = + Directory.newBuilder() + .addAllDirectories( + ImmutableList.of( + DirectoryNode.newBuilder() + .setName("bar") + .setDigest(missingDirectoryDigest) + .build(), + DirectoryNode.newBuilder() + .setName("foo") + .setDigest(missingDirectoryDigest) + .build())) + .build(); + AbstractServerInstance.validateActionInputDirectory( + ACTION_INPUT_ROOT_DIRECTORY_PATH, + root, + /* pathDigests=*/ new Stack<>(), + /* visited=*/ Sets.newHashSet(), + /* directoriesIndex=*/ ImmutableMap.of(), + /* onInputFiles=*/ file -> {}, + /* onInputDirectories=*/ directory -> {}, + /* onInputDigests=*/ digest -> {}, + preconditionFailure); + + String missingSubject = "blobs/" + DigestUtil.toString(missingDirectoryDigest); + String missingFmt = "The directory `/%s` was not found in the CAS."; + assertThat(preconditionFailure.getViolationsCount()).isEqualTo(2); + Violation violation = preconditionFailure.getViolationsList().get(0); + assertThat(violation.getType()).isEqualTo(VIOLATION_TYPE_MISSING); + assertThat(violation.getSubject()).isEqualTo(missingSubject); + assertThat(violation.getDescription()).isEqualTo(String.format(missingFmt, "bar")); + violation = preconditionFailure.getViolationsList().get(1); + assertThat(violation.getType()).isEqualTo(VIOLATION_TYPE_MISSING); + assertThat(violation.getSubject()).isEqualTo(missingSubject); + assertThat(violation.getDescription()).isEqualTo(String.format(missingFmt, "foo")); + } + @SuppressWarnings("unchecked") private static void doBlob( ContentAddressableStorage contentAddressableStorage, From 212e8a55c437d0e42991e462435895758e8a5fb8 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Sun, 18 Jun 2023 12:24:13 -0400 Subject: [PATCH 010/311] Guard directory revisit with empty/missing checks (#1379) Directories reevaluated only under the enumeration hierarchy must still be guarded against empty child directories in their checks, and must handle child directories missing in the index safely, with precondition failures matching their outputs. Order is not guaranteed in precondition output, but tests now guard this case. Fixes #1299 --- .../server/AbstractServerInstance.java | 38 ++++++++--- .../server/AbstractServerInstanceTest.java | 68 ++++++++++++++++++- 2 files changed, 94 insertions(+), 12 deletions(-) diff --git a/src/main/java/build/buildfarm/instance/server/AbstractServerInstance.java b/src/main/java/build/buildfarm/instance/server/AbstractServerInstance.java index 52cb1448e6..95b737725b 100644 --- a/src/main/java/build/buildfarm/instance/server/AbstractServerInstance.java +++ b/src/main/java/build/buildfarm/instance/server/AbstractServerInstance.java @@ -739,7 +739,8 @@ private static void enumerateActionInputDirectory( Directory directory, Map directoriesIndex, Consumer onInputFile, - Consumer onInputDirectory) { + Consumer onInputDirectory, + PreconditionFailure.Builder preconditionFailure) { Stack directoriesStack = new Stack<>(); directoriesStack.addAll(directory.getDirectoriesList()); @@ -751,15 +752,29 @@ private static void enumerateActionInputDirectory( directoryPath.isEmpty() ? directoryName : (directoryPath + "/" + directoryName); onInputDirectory.accept(subDirectoryPath); - for (FileNode fileNode : directoriesIndex.get(directoryDigest).getFilesList()) { - String fileName = fileNode.getName(); - String filePath = subDirectoryPath + "/" + fileName; - onInputFile.accept(filePath); + Directory subDirectory; + if (directoryDigest.getSizeBytes() == 0) { + subDirectory = Directory.getDefaultInstance(); + } else { + subDirectory = directoriesIndex.get(directoryDigest); } - for (DirectoryNode subDirectoryNode : - directoriesIndex.get(directoryDigest).getDirectoriesList()) { - directoriesStack.push(subDirectoryNode); + if (subDirectory == null) { + preconditionFailure + .addViolationsBuilder() + .setType(VIOLATION_TYPE_MISSING) + .setSubject("blobs/" + DigestUtil.toString(directoryDigest)) + .setDescription("The directory `/" + subDirectoryPath + "` was not found in the CAS."); + } else { + for (FileNode fileNode : subDirectory.getFilesList()) { + String fileName = fileNode.getName(); + String filePath = subDirectoryPath + "/" + fileName; + onInputFile.accept(filePath); + } + + for (DirectoryNode subDirectoryNode : subDirectory.getDirectoriesList()) { + directoriesStack.push(subDirectoryNode); + } } } } @@ -881,7 +896,12 @@ public static void validateActionInputDirectory( subDirectory = directoriesIndex.get(directoryDigest); } enumerateActionInputDirectory( - subDirectoryPath, subDirectory, directoriesIndex, onInputFile, onInputDirectory); + subDirectoryPath, + subDirectory, + directoriesIndex, + onInputFile, + onInputDirectory, + preconditionFailure); } else { validateActionInputDirectoryDigest( subDirectoryPath, diff --git a/src/test/java/build/buildfarm/instance/server/AbstractServerInstanceTest.java b/src/test/java/build/buildfarm/instance/server/AbstractServerInstanceTest.java index dcd4936c1f..add9136633 100644 --- a/src/test/java/build/buildfarm/instance/server/AbstractServerInstanceTest.java +++ b/src/test/java/build/buildfarm/instance/server/AbstractServerInstanceTest.java @@ -519,9 +519,10 @@ public void undeclaredWorkingDirectoryIsInvalid() { assertThat(violation.getDescription()).isEqualTo("working directory is not an input directory"); } - /** - * / -> valid dir bar/ -> missing dir with digest 'missing' and non-zero size foo/ -> missing dir - * with digest 'missing' and non-zero size + /*- + * / -> valid dir + * bar/ -> missing dir with digest 'missing' and non-zero size + * foo/ -> missing dir with digest 'missing' and non-zero size */ @Test public void multipleIdenticalDirectoryMissingAreAllPreconditionFailures() { @@ -564,6 +565,67 @@ public void multipleIdenticalDirectoryMissingAreAllPreconditionFailures() { assertThat(violation.getDescription()).isEqualTo(String.format(missingFmt, "foo")); } + /*- + * / -> valid dir + * bar/ -> valid dir + * baz/ -> missing dir with digest 'missing-empty' and zero size + * quux/ -> missing dir with digest 'missing' and non-zero size + * foo/ -> valid dir with digest from /bar/, making it a copy of above + * + * Only duplicated-bar appears in the index + * Empty directory needs short circuit in all cases + * Result should be 2 missing directory paths, no errors + */ + @Test + public void validationRevisitReplicatesPreconditionFailures() { + Digest missingEmptyDirectoryDigest = Digest.newBuilder().setHash("missing-empty").build(); + Digest missingDirectoryDigest = Digest.newBuilder().setHash("missing").setSizeBytes(1).build(); + Directory foo = + Directory.newBuilder() + .addAllDirectories( + ImmutableList.of( + DirectoryNode.newBuilder() + .setName("baz") + .setDigest(missingEmptyDirectoryDigest) + .build(), + DirectoryNode.newBuilder() + .setName("quux") + .setDigest(missingDirectoryDigest) + .build())) + .build(); + Digest fooDigest = DIGEST_UTIL.compute(foo); + PreconditionFailure.Builder preconditionFailure = PreconditionFailure.newBuilder(); + Directory root = + Directory.newBuilder() + .addAllDirectories( + ImmutableList.of( + DirectoryNode.newBuilder().setName("bar").setDigest(fooDigest).build(), + DirectoryNode.newBuilder().setName("foo").setDigest(fooDigest).build())) + .build(); + AbstractServerInstance.validateActionInputDirectory( + ACTION_INPUT_ROOT_DIRECTORY_PATH, + root, + /* pathDigests=*/ new Stack<>(), + /* visited=*/ Sets.newHashSet(), + /* directoriesIndex=*/ ImmutableMap.of(fooDigest, foo), + /* onInputFiles=*/ file -> {}, + /* onInputDirectories=*/ directory -> {}, + /* onInputDigests=*/ digest -> {}, + preconditionFailure); + + String missingSubject = "blobs/" + DigestUtil.toString(missingDirectoryDigest); + String missingFmt = "The directory `/%s` was not found in the CAS."; + assertThat(preconditionFailure.getViolationsCount()).isEqualTo(2); + Violation violation = preconditionFailure.getViolationsList().get(0); + assertThat(violation.getType()).isEqualTo(VIOLATION_TYPE_MISSING); + assertThat(violation.getSubject()).isEqualTo(missingSubject); + assertThat(violation.getDescription()).isEqualTo(String.format(missingFmt, "bar/quux")); + violation = preconditionFailure.getViolationsList().get(1); + assertThat(violation.getType()).isEqualTo(VIOLATION_TYPE_MISSING); + assertThat(violation.getSubject()).isEqualTo(missingSubject); + assertThat(violation.getDescription()).isEqualTo(String.format(missingFmt, "foo/quux")); + } + @SuppressWarnings("unchecked") private static void doBlob( ContentAddressableStorage contentAddressableStorage, From fe0fe8b5ffe51b661ab64933f4a76b4c68a01d02 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Sun, 18 Jun 2023 13:26:31 -0400 Subject: [PATCH 011/311] Output additions to RequestMetadata (#1380) Include Action Mnemonic, Target Id, and Configuration Id in the bf-cat output suite for RequestMetadata. --- src/main/java/build/buildfarm/tools/Cat.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/build/buildfarm/tools/Cat.java b/src/main/java/build/buildfarm/tools/Cat.java index b8008e434a..399ca7f1fb 100644 --- a/src/main/java/build/buildfarm/tools/Cat.java +++ b/src/main/java/build/buildfarm/tools/Cat.java @@ -483,6 +483,9 @@ private static void printRequestMetadata(RequestMetadata metadata) { System.out.println("ActionId: " + metadata.getActionId()); System.out.println("ToolInvocationId: " + metadata.getToolInvocationId()); System.out.println("CorrelatedInvocationsId: " + metadata.getCorrelatedInvocationsId()); + System.out.println("ActionMnemonic: " + metadata.getActionMnemonic()); + System.out.println("TargetId: " + metadata.getTargetId()); + System.out.println("ConfigurationId: " + metadata.getConfigurationId()); } private static void printStatus(com.google.rpc.Status status) From 5a1747dac027d4f021b3400619eaee8e2d068973 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Tue, 20 Jun 2023 14:51:18 -0400 Subject: [PATCH 012/311] SEVERE for app.run failure (#1382) An invocation of app.run which fails for any reason in the spring framework will exit silently. Ensure that errors are presented before exiting the application. --- src/main/java/build/buildfarm/server/BuildFarmServer.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/build/buildfarm/server/BuildFarmServer.java b/src/main/java/build/buildfarm/server/BuildFarmServer.java index 76b36d5366..d0d26a6f52 100644 --- a/src/main/java/build/buildfarm/server/BuildFarmServer.java +++ b/src/main/java/build/buildfarm/server/BuildFarmServer.java @@ -218,6 +218,10 @@ public static void main(String[] args) throws ConfigurationException { springConfig.put("server.port", configs.getUi().getPort()); app.setDefaultProperties(springConfig); - app.run(args); + try { + app.run(args); + } catch (Throwable t) { + log.log(SEVERE, "Error running application", t); + } } } From e99878b76b663c9bb78e056946864a5603428317 Mon Sep 17 00:00:00 2001 From: amishra-u <119983081+amishra-u@users.noreply.github.com> Date: Wed, 21 Jun 2023 12:25:06 -0700 Subject: [PATCH 013/311] Enable custom latency buckets (#1376) * Enable custom latency buckets * run formatter * Remove unused load from build * Run buildifier * update example config with infinity bucket --------- Co-authored-by: Trevor Hickey --- examples/config.yml | 6 ++- .../buildfarm/common/config/GrpcMetrics.java | 8 +++- .../java/build/buildfarm/common/config/BUILD | 13 +++++++ .../common/config/GrpcMetricsTest.java | 37 +++++++++++++++++++ 4 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 src/test/java/build/buildfarm/common/config/BUILD create mode 100644 src/test/java/build/buildfarm/common/config/GrpcMetricsTest.java diff --git a/examples/config.yml b/examples/config.yml index bdd92e6697..3c435fccc7 100644 --- a/examples/config.yml +++ b/examples/config.yml @@ -9,8 +9,9 @@ server: actionCacheReadOnly: false port: 8980 grpcMetrics: - enabled: false - provideLatencyHistograms: false + enabled: true + provideLatencyHistograms: true + latencyBuckets: [0.001, 0.01, 0.1, 1, 5, 10, 20, 40, 60, +Infinity] maxInboundMessageSizeBytes: 0 maxInboundMetadataSize: 0 casWriteTimeout: 3600 @@ -93,6 +94,7 @@ worker: grpcMetrics: enabled: false provideLatencyHistograms: false + latencyBuckets: [0.001, 0.005, 0.01, 0.05, 0.075, 0.1, 0.25, 0.5, 1.0, 2.0, 5.0, 10.0] capabilities: cas: true execution: true diff --git a/src/main/java/build/buildfarm/common/config/GrpcMetrics.java b/src/main/java/build/buildfarm/common/config/GrpcMetrics.java index cdd8f05f30..a028035673 100644 --- a/src/main/java/build/buildfarm/common/config/GrpcMetrics.java +++ b/src/main/java/build/buildfarm/common/config/GrpcMetrics.java @@ -9,6 +9,7 @@ public class GrpcMetrics { private boolean enabled = false; private boolean provideLatencyHistograms = false; + private double[] latencyBuckets; public static void handleGrpcMetricIntercepts( ServerBuilder serverBuilder, GrpcMetrics grpcMetrics) { @@ -21,7 +22,12 @@ public static void handleGrpcMetricIntercepts( // Enable latency buckets. if (grpcMetrics.isProvideLatencyHistograms()) { - grpcConfig = grpcConfig.allMetrics(); + grpcConfig = Configuration.allMetrics(); + } + + // provide custom latency buckets + if (grpcMetrics.getLatencyBuckets() != null) { + grpcConfig.withLatencyBuckets(grpcMetrics.getLatencyBuckets()); } // Apply config to create an interceptor and apply it to the GRPC server. diff --git a/src/test/java/build/buildfarm/common/config/BUILD b/src/test/java/build/buildfarm/common/config/BUILD new file mode 100644 index 0000000000..4819a6bca8 --- /dev/null +++ b/src/test/java/build/buildfarm/common/config/BUILD @@ -0,0 +1,13 @@ +java_test( + name = "tests", + srcs = glob(["*Test.java"]), + test_class = "build.buildfarm.AllTests", + deps = [ + "//src/main/java/build/buildfarm/common/config", + "//src/test/java/build/buildfarm:test_runner", + "@maven//:io_grpc_grpc_api", + "@maven//:io_grpc_grpc_testing", + "@maven//:me_dinowernli_java_grpc_prometheus", + "@maven//:org_mockito_mockito_core", + ], +) diff --git a/src/test/java/build/buildfarm/common/config/GrpcMetricsTest.java b/src/test/java/build/buildfarm/common/config/GrpcMetricsTest.java new file mode 100644 index 0000000000..5301b82608 --- /dev/null +++ b/src/test/java/build/buildfarm/common/config/GrpcMetricsTest.java @@ -0,0 +1,37 @@ +package build.buildfarm.common.config; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import io.grpc.ServerBuilder; +import me.dinowernli.grpc.prometheus.MonitoringServerInterceptor; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class GrpcMetricsTest { + @Mock private ServerBuilder serverBuilder; + private final GrpcMetrics grpcMetrics = new GrpcMetrics(); + + @Test + public void testHandleGrpcMetricIntercepts_disabled() { + grpcMetrics.setEnabled(false); + + GrpcMetrics.handleGrpcMetricIntercepts(serverBuilder, grpcMetrics); + verify(serverBuilder, never()).intercept(any(MonitoringServerInterceptor.class)); + } + + @Test + public void testHandleGrpcMetricIntercepts_withLatencyBucket() { + grpcMetrics.setEnabled(true); + grpcMetrics.setProvideLatencyHistograms(true); + grpcMetrics.setLatencyBuckets(new double[] {1, 2, 3}); + + GrpcMetrics.handleGrpcMetricIntercepts(serverBuilder, grpcMetrics); + verify(serverBuilder, times(1)).intercept(any(MonitoringServerInterceptor.class)); + } +} From 3d72cbdad63c96a87396462f44d14036f2563c2b Mon Sep 17 00:00:00 2001 From: George Gensure Date: Wed, 21 Jun 2023 17:06:37 -0400 Subject: [PATCH 014/311] Require fileStore for Directories interactions (#1385) Avoid fileStore recalculation for entire trees to be deleted, instead expect the callers to provide a fileStore, and that the entire tree exists within it. --- .../build/buildfarm/cas/cfc/CASFileCache.java | 12 +++++----- .../buildfarm/common/io/Directories.java | 23 ++++++++++--------- .../worker/shard/CFCExecFileSystem.java | 14 +++++++---- .../buildfarm/cas/cfc/CASFileCacheTest.java | 3 ++- .../buildfarm/common/io/DirectoriesTest.java | 19 +++++++++++---- .../build/buildfarm/common/io/UtilsTest.java | 3 ++- 6 files changed, 45 insertions(+), 29 deletions(-) diff --git a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java index e0af926bc3..f570b300f3 100644 --- a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java +++ b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java @@ -1271,7 +1271,7 @@ public StartupCacheResults start( loadResults = loadCache(onStartPut, removeDirectoryService); } else { // Skip loading the cache and ensure it is empty - Directories.remove(root, removeDirectoryService); + Directories.remove(root, fileStore, removeDirectoryService); initializeRootDirectory(); } @@ -1336,7 +1336,7 @@ private void deleteInvalidFileContent(List files, ExecutorService removeDi try { for (Path path : files) { if (Files.isDirectory(path)) { - Directories.remove(path, removeDirectoryService); + Directories.remove(path, fileStore, removeDirectoryService); } else { Files.delete(path); } @@ -1936,7 +1936,7 @@ private ListenableFuture expireDirectory(Digest digest, ExecutorService se return immediateFuture(null); } - return Directories.remove(getDirectoryPath(digest), service); + return Directories.remove(getDirectoryPath(digest), fileStore, service); } @SuppressWarnings("ConstantConditions") @@ -2062,7 +2062,7 @@ private void removeFilePath(Path path) throws IOException { if (Files.exists(path)) { if (Files.isDirectory(path)) { log.log(Level.FINE, "removing existing directory " + path + " for fetch"); - Directories.remove(path); + Directories.remove(path, fileStore); } else { Files.delete(path); } @@ -2295,7 +2295,7 @@ private ListenableFuture putDirectorySynchronized( fetchFuture, (result) -> { try { - disableAllWriteAccess(path); + disableAllWriteAccess(path, fileStore); } catch (IOException e) { log.log(Level.SEVERE, "error while disabling write permissions on " + path, e); return immediateFailedFuture(e); @@ -2326,7 +2326,7 @@ private ListenableFuture putDirectorySynchronized( } try { log.log(Level.FINE, "removing directory to roll back " + path); - Directories.remove(path); + Directories.remove(path, fileStore); } catch (IOException removeException) { log.log( Level.SEVERE, diff --git a/src/main/java/build/buildfarm/common/io/Directories.java b/src/main/java/build/buildfarm/common/io/Directories.java index 9e7b272d70..b861664e25 100644 --- a/src/main/java/build/buildfarm/common/io/Directories.java +++ b/src/main/java/build/buildfarm/common/io/Directories.java @@ -48,8 +48,8 @@ public class Directories { private Directories() {} - private static void makeWritable(Path dir, boolean writable) throws IOException { - FileStore fileStore = Files.getFileStore(dir); + private static void makeWritable(Path dir, boolean writable, FileStore fileStore) + throws IOException { if (fileStore.supportsFileAttributeView("posix")) { if (writable) { Files.setPosixFilePermissions(dir, writablePerms); @@ -82,14 +82,15 @@ private static void makeWritable(Path dir, boolean writable) throws IOException } } - public static ListenableFuture remove(Path path, ExecutorService service) { + public static ListenableFuture remove( + Path path, FileStore fileStore, ExecutorService service) { String suffix = UUID.randomUUID().toString(); Path filename = path.getFileName(); String tmpFilename = filename + ".tmp." + suffix; Path tmpPath = path.resolveSibling(tmpFilename); try { // MacOS does not permit renames unless the directory is permissioned appropriately - makeWritable(path, true); + makeWritable(path, true, fileStore); // rename must be synchronous to call Files.move(path, tmpPath); } catch (IOException e) { @@ -99,7 +100,7 @@ public static ListenableFuture remove(Path path, ExecutorService service) .submit( () -> { try { - remove(tmpPath); + remove(tmpPath, fileStore); } catch (IOException e) { log.log(Level.SEVERE, "error removing directory " + tmpPath, e); } @@ -107,14 +108,14 @@ public static ListenableFuture remove(Path path, ExecutorService service) null); } - public static void remove(Path directory) throws IOException { + public static void remove(Path directory, FileStore fileStore) throws IOException { Files.walkFileTree( directory, new SimpleFileVisitor() { @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { - makeWritable(dir, true); + makeWritable(dir, true, fileStore); return FileVisitResult.CONTINUE; } @@ -158,12 +159,12 @@ public FileVisitResult postVisitDirectory(Path dir, IOException e) throws IOExce }); } - public static void disableAllWriteAccess(Path directory) throws IOException { - forAllPostDirs(directory, dir -> makeWritable(dir, false)); + public static void disableAllWriteAccess(Path directory, FileStore fileStore) throws IOException { + forAllPostDirs(directory, dir -> makeWritable(dir, false, fileStore)); } - public static void enableAllWriteAccess(Path directory) throws IOException { - forAllPostDirs(directory, dir -> makeWritable(dir, true)); + public static void enableAllWriteAccess(Path directory, FileStore fileStore) throws IOException { + forAllPostDirs(directory, dir -> makeWritable(dir, true, fileStore)); } public static void setAllOwner(Path directory, UserPrincipal owner) throws IOException { diff --git a/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java b/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java index b8400fa8a2..525d696d5c 100644 --- a/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java +++ b/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java @@ -49,6 +49,7 @@ import com.google.common.util.concurrent.ListenableFuture; import java.io.IOException; import java.io.InputStream; +import java.nio.file.FileStore; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.attribute.UserPrincipal; @@ -80,6 +81,7 @@ class CFCExecFileSystem implements ExecFileSystem { private final ExecutorService fetchService = BuildfarmExecutors.getFetchServicePool(); private final ExecutorService removeDirectoryService; private final ExecutorService accessRecorder; + private FileStore fileStore; // initialized with start CFCExecFileSystem( Path root, @@ -102,9 +104,10 @@ class CFCExecFileSystem implements ExecFileSystem { @Override public void start(Consumer> onDigests, boolean skipLoad) throws IOException, InterruptedException { + fileStore = Files.getFileStore(root); List dirents = null; try { - dirents = readdir(root, /* followSymlinks= */ false, Files.getFileStore(root)); + dirents = readdir(root, /* followSymlinks= */ false, fileStore); } catch (IOException e) { log.log(Level.SEVERE, "error reading directory " + root.toString(), e); } @@ -116,7 +119,8 @@ public void start(Consumer> onDigests, boolean skipLoad) String name = dirent.getName(); Path child = root.resolve(name); if (!child.equals(fileCache.getRoot())) { - removeDirectoryFutures.add(Directories.remove(root.resolve(name), removeDirectoryService)); + removeDirectoryFutures.add( + Directories.remove(root.resolve(name), fileStore, removeDirectoryService)); } } @@ -364,7 +368,7 @@ public Path createExecDir( Path execDir = root.resolve(operationName); if (Files.exists(execDir)) { - Directories.remove(execDir); + Directories.remove(execDir, fileStore); } Files.createDirectories(execDir); @@ -416,7 +420,7 @@ public Path createExecDir( } finally { if (!success) { fileCache.decrementReferences(inputFiles.build(), inputDirectories.build()); - Directories.remove(execDir); + Directories.remove(execDir, fileStore); } } @@ -451,7 +455,7 @@ public void destroyExecDir(Path execDir) throws IOException, InterruptedExceptio inputDirectories == null ? ImmutableList.of() : inputDirectories); } if (Files.exists(execDir)) { - Directories.remove(execDir); + Directories.remove(execDir, fileStore); } } } diff --git a/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java b/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java index 07971e50cd..7631118fdb 100644 --- a/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java +++ b/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java @@ -175,10 +175,11 @@ protected InputStream newExternalInput(Compressor.Value compressor, Digest diges @After public void tearDown() throws IOException, InterruptedException { + FileStore fileStore = Files.getFileStore(root); // bazel appears to have a problem with us creating directories under // windows that are marked as no-delete. clean up after ourselves with // our utils - Directories.remove(root); + Directories.remove(root, fileStore); if (!shutdownAndAwaitTermination(putService, 1, SECONDS)) { throw new RuntimeException("could not shut down put service"); } diff --git a/src/test/java/build/buildfarm/common/io/DirectoriesTest.java b/src/test/java/build/buildfarm/common/io/DirectoriesTest.java index 1c7e55ba63..1759154bef 100644 --- a/src/test/java/build/buildfarm/common/io/DirectoriesTest.java +++ b/src/test/java/build/buildfarm/common/io/DirectoriesTest.java @@ -22,26 +22,35 @@ import com.google.common.jimfs.Jimfs; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.nio.file.FileStore; import java.nio.file.Files; import java.nio.file.Path; import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; class DirectoriesTest { protected final Path root; + protected FileStore fileStore; protected DirectoriesTest(Path root) { this.root = root; } + @Before + public void setUp() throws IOException { + fileStore = Files.getFileStore(root); + } + @After public void tearDown() throws IOException { // restore write permissions if (Files.exists(root)) { - Directories.enableAllWriteAccess(root); + Directories.enableAllWriteAccess(root, fileStore); } + fileStore = null; } @Test @@ -56,7 +65,7 @@ public void removeDirectoryDeletesTree() throws IOException { ImmutableList.of("A file in a subdirectory"), StandardCharsets.UTF_8); - Directories.remove(tree); + Directories.remove(tree, fileStore); assertThat(Files.exists(tree)).isFalse(); } @@ -75,11 +84,11 @@ public void changePermissionsForDelete() throws IOException { StandardCharsets.UTF_8); // remove write permissions - Directories.disableAllWriteAccess(tree); + Directories.disableAllWriteAccess(tree, fileStore); // directories are able to be removed, because the algorithm // changes the write permissions before performing the delete. - Directories.remove(tree); + Directories.remove(tree, fileStore); assertThat(Files.exists(tree)).isFalse(); } @@ -114,7 +123,7 @@ public void checkWriteDisabled() throws IOException { assertThat(Files.isWritable(subdir)).isTrue(); // remove write permissions - Directories.disableAllWriteAccess(tree); + Directories.disableAllWriteAccess(tree, fileStore); // check that write conditions have changed // If the unit tests were run as root, diff --git a/src/test/java/build/buildfarm/common/io/UtilsTest.java b/src/test/java/build/buildfarm/common/io/UtilsTest.java index 34896e1eab..1422f27e35 100644 --- a/src/test/java/build/buildfarm/common/io/UtilsTest.java +++ b/src/test/java/build/buildfarm/common/io/UtilsTest.java @@ -47,7 +47,8 @@ public void setUp() throws IOException { @After public void tearDown() throws IOException { - Directories.remove(root); + fileStore = Files.getFileStore(root); + Directories.remove(root, fileStore); } @Test From 58044625c4dc1594db1799633132826ae4d570d4 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Wed, 21 Jun 2023 17:13:28 -0400 Subject: [PATCH 015/311] Unwrap EEs on PutDirectoryException creation (#1386) ExceutionExceptions wrap the actual exceptions of futures experienced during putDirectory, and add no tracing capacity. Unwrap these when thrown from failed futures. --- src/main/java/build/buildfarm/cas/cfc/CASFileCache.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java index f570b300f3..77360c0182 100644 --- a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java +++ b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java @@ -2275,7 +2275,10 @@ private ListenableFuture putDirectorySynchronized( try { putFutures.get(i).get(); // should never get here + } catch (ExecutionException e) { + failures.add(e.getCause()); } catch (Throwable t) { + // cancelled or interrupted during get failures.add(t); } } From 7e9dd51eb27277680c344d97b1ed5ad7c7493cc1 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Thu, 22 Jun 2023 07:22:54 -0400 Subject: [PATCH 016/311] Retry downloads in CFC with copyExternalInput (#1387) Bleed grpc exposure into a retrier for copyExternalInput invocations, and ensure that enough bytes have been provided from the requested blob before returning. --- .../cas/ContentAddressableStorages.java | 4 +- .../build/buildfarm/cas/cfc/CASFileCache.java | 41 +++++++++- .../build/buildfarm/common/grpc/Retrier.java | 9 +++ .../java/build/buildfarm/tools/CacheLoad.java | 2 +- .../worker/shard/ShardCASFileCache.java | 4 +- .../buildfarm/cas/cfc/CASFileCacheTest.java | 81 +++++++++++++++++-- 6 files changed, 124 insertions(+), 17 deletions(-) diff --git a/src/main/java/build/buildfarm/cas/ContentAddressableStorages.java b/src/main/java/build/buildfarm/cas/ContentAddressableStorages.java index 3d766017a6..ade381ff50 100644 --- a/src/main/java/build/buildfarm/cas/ContentAddressableStorages.java +++ b/src/main/java/build/buildfarm/cas/ContentAddressableStorages.java @@ -88,8 +88,8 @@ public static ContentAddressableStorage createFilesystemCAS(Cas config) /* expireService=*/ newDirectExecutorService(), /* accessRecorder=*/ directExecutor()) { @Override - protected InputStream newExternalInput(Compressor.Value compressor, Digest digest) - throws IOException { + protected InputStream newExternalInput( + Compressor.Value compressor, Digest digest, long offset) throws IOException { throw new NoSuchFileException(digest.getHash()); } }; diff --git a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java index 77360c0182..ce157645fe 100644 --- a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java +++ b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java @@ -63,6 +63,8 @@ import build.buildfarm.common.ZstdCompressingInputStream; import build.buildfarm.common.ZstdDecompressingOutputStream; import build.buildfarm.common.config.Cas; +import build.buildfarm.common.grpc.Retrier; +import build.buildfarm.common.grpc.Retrier.Backoff; import build.buildfarm.common.io.CountingOutputStream; import build.buildfarm.common.io.Directories; import build.buildfarm.common.io.FeedbackOutputStream; @@ -87,6 +89,8 @@ import com.google.common.util.concurrent.UncheckedExecutionException; import com.google.protobuf.ByteString; import io.grpc.Deadline; +import io.grpc.StatusException; +import io.grpc.StatusRuntimeException; import io.grpc.stub.ServerCallStreamObserver; import io.prometheus.client.Counter; import io.prometheus.client.Gauge; @@ -2425,11 +2429,40 @@ Path putAndCopy(Digest digest, boolean isExecutable) throws IOException, Interru return getPath(key); } + private void copyExternalInputProgressive(Digest digest, CancellableOutputStream out) + throws IOException, InterruptedException { + try (InputStream in = newExternalInput(Compressor.Value.IDENTITY, digest, out.getWritten())) { + ByteStreams.copy(in, out); + } + } + + private static Exception extractStatusException(IOException e) { + for (Throwable cause = e.getCause(); cause != null; cause = cause.getCause()) { + if (cause instanceof StatusException) { + return (StatusException) cause; + } else if (cause instanceof StatusRuntimeException) { + return (StatusRuntimeException) cause; + } + } + return e; + } + private void copyExternalInput(Digest digest, CancellableOutputStream out) throws IOException, InterruptedException { + Retrier retrier = new Retrier(Backoff.sequential(5), Retrier.DEFAULT_IS_RETRIABLE); log.log(Level.FINE, format("downloading %s", DigestUtil.toString(digest))); - try (InputStream in = newExternalInput(Compressor.Value.IDENTITY, digest)) { - ByteStreams.copy(in, out); + try { + retrier.execute( + () -> { + while (out.getWritten() < digest.getSizeBytes()) { + try { + copyExternalInputProgressive(digest, out); + } catch (IOException e) { + throw extractStatusException(e); + } + } + return null; + }); } catch (IOException e) { out.cancel(); log.log( @@ -3070,8 +3103,8 @@ public DirectoryEntry(Directory directory, Deadline existsDeadline) { } } - protected abstract InputStream newExternalInput(Compressor.Value compressor, Digest digest) - throws IOException; + protected abstract InputStream newExternalInput( + Compressor.Value compressor, Digest digest, long offset) throws IOException; // CAS fallback methods diff --git a/src/main/java/build/buildfarm/common/grpc/Retrier.java b/src/main/java/build/buildfarm/common/grpc/Retrier.java index 72960e9f9c..6fd7802e79 100644 --- a/src/main/java/build/buildfarm/common/grpc/Retrier.java +++ b/src/main/java/build/buildfarm/common/grpc/Retrier.java @@ -98,6 +98,15 @@ public int getRetryAttempts() { } }; + static Supplier sequential(int maxAttempts) { + return exponential( + /* initial=*/ Duration.ZERO, + /* max=*/ Duration.ZERO, + /* multiplier=*/ 1.1, + /* jitter=*/ 0.0, + maxAttempts); + } + /** * Creates a Backoff supplier for an optionally jittered exponential backoff. The supplier is * ThreadSafe (non-synchronized calls to get() are fine), but the returned Backoff is not. diff --git a/src/main/java/build/buildfarm/tools/CacheLoad.java b/src/main/java/build/buildfarm/tools/CacheLoad.java index 0c7a866d72..1694f32da9 100644 --- a/src/main/java/build/buildfarm/tools/CacheLoad.java +++ b/src/main/java/build/buildfarm/tools/CacheLoad.java @@ -48,7 +48,7 @@ private static class LocalCASFileCache extends CASFileCache { } @Override - protected InputStream newExternalInput(Compressor.Value compressor, Digest digest) + protected InputStream newExternalInput(Compressor.Value compressor, Digest digest, long offset) throws IOException { throw new IOException(); } diff --git a/src/main/java/build/buildfarm/worker/shard/ShardCASFileCache.java b/src/main/java/build/buildfarm/worker/shard/ShardCASFileCache.java index 191612342e..c1a56beb06 100644 --- a/src/main/java/build/buildfarm/worker/shard/ShardCASFileCache.java +++ b/src/main/java/build/buildfarm/worker/shard/ShardCASFileCache.java @@ -83,8 +83,8 @@ private static InputStreamFactory createInputStreamFactory( } @Override - protected InputStream newExternalInput(Compressor.Value compressor, Digest digest) + protected InputStream newExternalInput(Compressor.Value compressor, Digest digest, long offset) throws IOException { - return inputStreamFactory.newInput(compressor, digest, 0); + return inputStreamFactory.newInput(compressor, digest, offset); } } diff --git a/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java b/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java index 7631118fdb..984275f3f3 100644 --- a/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java +++ b/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java @@ -64,6 +64,7 @@ import com.google.common.util.concurrent.SettableFuture; import com.google.protobuf.ByteString; import io.grpc.Deadline; +import io.grpc.Status; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -159,14 +160,14 @@ public void setUp() throws IOException, InterruptedException { delegate, /* delegateSkipLoad=*/ false) { @Override - protected InputStream newExternalInput(Compressor.Value compressor, Digest digest) - throws IOException { + protected InputStream newExternalInput( + Compressor.Value compressor, Digest digest, long offset) throws IOException { ByteString content = blobs.get(digest); if (content == null) { - return fileCache.newTransparentInput(compressor, digest, 0); + return fileCache.newTransparentInput(compressor, digest, offset); } checkArgument(compressor == Compressor.Value.IDENTITY); - return content.substring((int) (long) 0).newInput(); + return content.substring((int) offset).newInput(); } }; // do this so that we can remove the cache root dir @@ -1102,6 +1103,70 @@ public void findMissingBlobsPopulatesUnknownSize() throws Exception { assertThat(responseDigest).isEqualTo(blob.getDigest()); } + @Test + public void copyExternalInputRetries() throws Exception { + CASFileCache flakyExternalCAS = + new CASFileCache( + root, + /* maxSizeInBytes=*/ 1024, + /* maxEntrySizeInBytes=*/ 1024, + /* hexBucketLevels=*/ 1, + storeFileDirsIndexInMemory, + /* publishTtlMetric=*/ false, + /* execRootFallback=*/ false, + DIGEST_UTIL, + expireService, + /* accessRecorder=*/ directExecutor(), + storage, + /* directoriesIndexDbName=*/ ":memory:", + /* onPut=*/ digest -> {}, + /* onExpire=*/ digests -> {}, + /* delegate=*/ null, + /* delegateSkipLoad=*/ false) { + boolean throwUnavailable = true; + + @Override + protected InputStream newExternalInput( + Compressor.Value compressor, Digest digest, long offset) throws IOException { + ByteString content = blobs.get(digest); + if (throwUnavailable) { + throwUnavailable = false; + return new InputStream() { + int count = 0; + + @Override + public int read(byte[] buf) throws IOException { + return read(buf, 0, buf.length); + } + + @Override + public int read() { + throw new UnsupportedOperationException(); + } + + @Override + public int read(byte[] buf, int offset, int len) throws IOException { + if (count >= digest.getSizeBytes() / 2) { + throw new IOException(Status.UNAVAILABLE.asRuntimeException()); + } + len = Math.min((int) digest.getSizeBytes() / 2 - count, len); + content.substring(count, count + len).copyTo(buf, offset); + count += len; + return len; + } + }; + } + return content.substring((int) offset).newInput(); + } + }; + flakyExternalCAS.initializeRootDirectory(); + ByteString blob = ByteString.copyFromUtf8("Flaky Entry"); + Digest blobDigest = DIGEST_UTIL.compute(blob); + blobs.put(blobDigest, blob); + Path path = flakyExternalCAS.put(blobDigest, false); + assertThat(Files.exists(path)).isTrue(); // would not have been created if not valid + } + @Test public void newInputThrowsNoSuchFileExceptionWithoutDelegate() throws Exception { ContentAddressableStorage undelegatedCAS = @@ -1123,14 +1188,14 @@ public void newInputThrowsNoSuchFileExceptionWithoutDelegate() throws Exception /* delegate=*/ null, /* delegateSkipLoad=*/ false) { @Override - protected InputStream newExternalInput(Compressor.Value compressor, Digest digest) - throws IOException { + protected InputStream newExternalInput( + Compressor.Value compressor, Digest digest, long offset) throws IOException { ByteString content = blobs.get(digest); if (content == null) { - return fileCache.newTransparentInput(compressor, digest, 0); + return fileCache.newTransparentInput(compressor, digest, offset); } checkArgument(compressor == Compressor.Value.IDENTITY); - return content.substring((int) (long) 0).newInput(); + return content.substring((int) offset).newInput(); } }; ByteString blob = ByteString.copyFromUtf8("Missing Entry"); From 7be02644c1781a866bc0ebf9f042c2801a0c0aa1 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Thu, 22 Jun 2023 10:32:41 -0400 Subject: [PATCH 017/311] Skip isReadOnlyExecutable on symlinks (#1383) The only presence of arbitrary symlinks in the CAS Filesystem is under directories. Symlinks are explicitly identified as non-readonly-executables. Prevent a dead symlink from throwing NSFE due to the readonly check. --- src/main/java/build/buildfarm/common/io/Utils.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/build/buildfarm/common/io/Utils.java b/src/main/java/build/buildfarm/common/io/Utils.java index 64a4ebcf50..3457cc3d62 100644 --- a/src/main/java/build/buildfarm/common/io/Utils.java +++ b/src/main/java/build/buildfarm/common/io/Utils.java @@ -291,7 +291,8 @@ public static FileStatus stat(final Path path, final boolean followSymlinks, Fil boolean isReadOnlyExecutable; try { attributes = Files.readAttributes(path, BasicFileAttributes.class, linkOpts(followSymlinks)); - isReadOnlyExecutable = EvenMoreFiles.isReadOnlyExecutable(path, fileStore); + isReadOnlyExecutable = + !attributes.isSymbolicLink() && EvenMoreFiles.isReadOnlyExecutable(path, fileStore); } catch (java.nio.file.FileSystemException e) { throw new NoSuchFileException(path + ERR_NO_SUCH_FILE_OR_DIR); } From 6de1473b91393f07825fcff61761d2c259c28b43 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Thu, 22 Jun 2023 11:13:01 -0400 Subject: [PATCH 018/311] Support UTF8 Strings in ffiReaddir (#1388) Files are delivered via readdir in utf8 encoding (on linux for xfs at least), assume that posix will mandate this. --- src/main/java/build/buildfarm/common/io/FFIdirent.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/build/buildfarm/common/io/FFIdirent.java b/src/main/java/build/buildfarm/common/io/FFIdirent.java index d3880b2722..6c9fd7ddf5 100644 --- a/src/main/java/build/buildfarm/common/io/FFIdirent.java +++ b/src/main/java/build/buildfarm/common/io/FFIdirent.java @@ -32,5 +32,5 @@ public java.lang.String getName() { public final Signed64 d_off = new Signed64(); public final Unsigned16 d_reclen = new Unsigned16(); public final Unsigned8 d_type = new Unsigned8(); - public final AsciiString d_name = new AsciiString(MAX_NAME_LEN); + public final UTF8String d_name = new UTF8String(MAX_NAME_LEN); } From ee8b171841e124249d7eaaeaea9d11aef4e02a53 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Thu, 22 Jun 2023 14:30:58 -0400 Subject: [PATCH 019/311] Revert context deadline guarantee from (#1377)" (#1389) This reverts mistakenly added checks for non-null deadlines in StubInstance. --- .../buildfarm/instance/stub/StubInstance.java | 19 +++------- .../instance/stub/StubInstanceTest.java | 35 +------------------ 2 files changed, 6 insertions(+), 48 deletions(-) diff --git a/src/main/java/build/buildfarm/instance/stub/StubInstance.java b/src/main/java/build/buildfarm/instance/stub/StubInstance.java index 219e5d54ec..ee8ca9523f 100644 --- a/src/main/java/build/buildfarm/instance/stub/StubInstance.java +++ b/src/main/java/build/buildfarm/instance/stub/StubInstance.java @@ -18,7 +18,6 @@ import static build.buildfarm.common.grpc.TracingMetadataUtils.attachMetadataInterceptor; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; -import static com.google.common.util.concurrent.Futures.allAsList; import static com.google.common.util.concurrent.Futures.catching; import static com.google.common.util.concurrent.Futures.transform; import static com.google.common.util.concurrent.MoreExecutors.directExecutor; @@ -106,7 +105,6 @@ import com.google.bytestream.ByteStreamGrpc.ByteStreamStub; import com.google.bytestream.ByteStreamProto.ReadRequest; import com.google.bytestream.ByteStreamProto.ReadResponse; -import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Functions; import com.google.common.base.Supplier; import com.google.common.base.Suppliers; @@ -166,8 +164,6 @@ public class StubInstance implements Instance { private boolean isStopped = false; private final long maxBatchUpdateBlobsSize = Size.mbToBytes(3); - @VisibleForTesting long maxRequestSize = Size.mbToBytes(4); - public StubInstance(String name, DigestUtil digestUtil, ManagedChannel channel) { this(name, "no-identifier", digestUtil, channel, Durations.fromDays(DEFAULT_DEADLINE_DAYS)); } @@ -416,16 +412,11 @@ public ListenableFuture> findMissingBlobs( .setInstanceName(getName()) .addAllBlobDigests(digests) .build(); - if (request.getSerializedSize() > maxRequestSize) { - // log2n partition for size reduction as needed - int partitionSize = (request.getBlobDigestsCount() + 1) / 2; - return transform( - allAsList( - Iterables.transform( - Iterables.partition(digests, partitionSize), - subDigests -> findMissingBlobs(subDigests, requestMetadata))), - subMissings -> Iterables.concat(subMissings), - directExecutor()); + if (request.getSerializedSize() > Size.mbToBytes(4)) { + throw new IllegalStateException( + String.format( + "FINDMISSINGBLOBS IS TOO LARGE: %d digests are required in one request!", + request.getBlobDigestsCount())); } return transform( deadlined(casFutureStub) diff --git a/src/test/java/build/buildfarm/instance/stub/StubInstanceTest.java b/src/test/java/build/buildfarm/instance/stub/StubInstanceTest.java index e3845494b8..e50e3f0028 100644 --- a/src/test/java/build/buildfarm/instance/stub/StubInstanceTest.java +++ b/src/test/java/build/buildfarm/instance/stub/StubInstanceTest.java @@ -64,7 +64,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; @@ -99,7 +98,7 @@ public void tearDown() throws InterruptedException { fakeServer.awaitTermination(); } - private StubInstance newStubInstance(String instanceName) { + private Instance newStubInstance(String instanceName) { return new StubInstance( instanceName, DIGEST_UTIL, @@ -198,38 +197,6 @@ public void findMissingBlobs( instance.stop(); } - @Test - public void findMissingBlobsOverSizeLimitRecombines() - throws ExecutionException, InterruptedException { - AtomicReference reference = new AtomicReference<>(); - serviceRegistry.addService( - new ContentAddressableStorageImplBase() { - @Override - public void findMissingBlobs( - FindMissingBlobsRequest request, - StreamObserver responseObserver) { - reference.set(request); - responseObserver.onNext( - FindMissingBlobsResponse.newBuilder() - .addAllMissingBlobDigests(request.getBlobDigestsList()) - .build()); - responseObserver.onCompleted(); - } - }); - StubInstance instance = newStubInstance("findMissingBlobs-test"); - instance.maxRequestSize = 1024; - ImmutableList.Builder builder = ImmutableList.builder(); - // generates digest size * 1024 serialized size at least - for (int i = 0; i < 1024; i++) { - ByteString content = ByteString.copyFromUtf8("Hello, World! " + UUID.randomUUID()); - builder.add(DIGEST_UTIL.compute(content)); - } - ImmutableList digests = builder.build(); - assertThat(instance.findMissingBlobs(digests, RequestMetadata.getDefaultInstance()).get()) - .containsExactlyElementsIn(digests); - instance.stop(); - } - @Test public void outputStreamWrites() throws IOException, InterruptedException { AtomicReference writtenContent = new AtomicReference<>(); From 41a90bed1dc2c71148827be64bfcf9a9171ffd75 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Thu, 22 Jun 2023 15:00:18 -0400 Subject: [PATCH 020/311] Rollback ensure deadline (#1390) * Guard against fetchBlobFromWorker orphanization Any exception thrown by fetchBlobFromWorker will leave the blobObserver hanging. Ensure that the observer sees a failure and does not hang. * Restore FMB functionality included in revert. --- .../instance/shard/ShardInstance.java | 18 +++++++--- .../buildfarm/instance/stub/StubInstance.java | 24 +++++++------ .../instance/stub/StubInstanceTest.java | 35 ++++++++++++++++++- 3 files changed, 62 insertions(+), 15 deletions(-) diff --git a/src/main/java/build/buildfarm/instance/shard/ShardInstance.java b/src/main/java/build/buildfarm/instance/shard/ShardInstance.java index 3ec8f98da5..26c7928c24 100644 --- a/src/main/java/build/buildfarm/instance/shard/ShardInstance.java +++ b/src/main/java/build/buildfarm/instance/shard/ShardInstance.java @@ -1037,7 +1037,8 @@ public void onError(Throwable t) { @Override public void onQueue(Deque workers) { ctx.run( - () -> + () -> { + try { fetchBlobFromWorker( compressor, blobDigest, @@ -1045,7 +1046,11 @@ public void onQueue(Deque workers) { offset, count, checkedChunkObserver, - requestMetadata)); + requestMetadata); + } catch (Exception e) { + onFailure(e); + } + }); } @Override @@ -1070,7 +1075,8 @@ public void onCompleted() { @Override public void onQueue(Deque workers) { ctx.run( - () -> + () -> { + try { fetchBlobFromWorker( compressor, blobDigest, @@ -1078,7 +1084,11 @@ public void onQueue(Deque workers) { offset, count, chunkObserver, - requestMetadata)); + requestMetadata); + } catch (Exception e) { + onFailure(e); + } + }); } @Override diff --git a/src/main/java/build/buildfarm/instance/stub/StubInstance.java b/src/main/java/build/buildfarm/instance/stub/StubInstance.java index ee8ca9523f..dd647a327d 100644 --- a/src/main/java/build/buildfarm/instance/stub/StubInstance.java +++ b/src/main/java/build/buildfarm/instance/stub/StubInstance.java @@ -18,6 +18,7 @@ import static build.buildfarm.common.grpc.TracingMetadataUtils.attachMetadataInterceptor; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; +import static com.google.common.util.concurrent.Futures.allAsList; import static com.google.common.util.concurrent.Futures.catching; import static com.google.common.util.concurrent.Futures.transform; import static com.google.common.util.concurrent.MoreExecutors.directExecutor; @@ -105,6 +106,7 @@ import com.google.bytestream.ByteStreamGrpc.ByteStreamStub; import com.google.bytestream.ByteStreamProto.ReadRequest; import com.google.bytestream.ByteStreamProto.ReadResponse; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Functions; import com.google.common.base.Supplier; import com.google.common.base.Suppliers; @@ -164,6 +166,8 @@ public class StubInstance implements Instance { private boolean isStopped = false; private final long maxBatchUpdateBlobsSize = Size.mbToBytes(3); + @VisibleForTesting long maxRequestSize = Size.mbToBytes(4); + public StubInstance(String name, DigestUtil digestUtil, ManagedChannel channel) { this(name, "no-identifier", digestUtil, channel, Durations.fromDays(DEFAULT_DEADLINE_DAYS)); } @@ -412,11 +416,16 @@ public ListenableFuture> findMissingBlobs( .setInstanceName(getName()) .addAllBlobDigests(digests) .build(); - if (request.getSerializedSize() > Size.mbToBytes(4)) { - throw new IllegalStateException( - String.format( - "FINDMISSINGBLOBS IS TOO LARGE: %d digests are required in one request!", - request.getBlobDigestsCount())); + if (request.getSerializedSize() > maxRequestSize) { + // log2n partition for size reduction as needed + int partitionSize = (request.getBlobDigestsCount() + 1) / 2; + return transform( + allAsList( + Iterables.transform( + Iterables.partition(digests, partitionSize), + subDigests -> findMissingBlobs(subDigests, requestMetadata))), + subMissings -> Iterables.concat(subMissings), + directExecutor()); } return transform( deadlined(casFutureStub) @@ -586,7 +595,6 @@ public void getBlob( ServerCallStreamObserver blobObserver, RequestMetadata requestMetadata) { throwIfStopped(); - checkNotNull(io.grpc.Context.current().getDeadline()); bsStub .get() .withInterceptors(attachMetadataInterceptor(requestMetadata)) @@ -887,7 +895,6 @@ public WorkerProfileMessage getWorkerProfile() { @Override public WorkerListMessage getWorkerList() { - checkNotNull(io.grpc.Context.current().getDeadline()); return workerProfileBlockingStub.get().getWorkerList(WorkerListRequest.newBuilder().build()); } @@ -899,7 +906,6 @@ public GetClientStartTimeResult getClientStartTime(GetClientStartTimeRequest req @Override public CasIndexResults reindexCas() { throwIfStopped(); - checkNotNull(io.grpc.Context.current().getDeadline()); ReindexCasRequestResults proto = adminBlockingStub.get().reindexCas(ReindexCasRequest.newBuilder().build()); CasIndexResults results = new CasIndexResults(); @@ -913,7 +919,6 @@ public CasIndexResults reindexCas() { @Override public void deregisterWorker(String workerName) { throwIfStopped(); - checkNotNull(io.grpc.Context.current().getDeadline()); adminBlockingStub .get() .shutDownWorkerGracefully( @@ -923,7 +928,6 @@ public void deregisterWorker(String workerName) { @Override public PrepareWorkerForGracefulShutDownRequestResults shutDownWorkerGracefully() { throwIfStopped(); - checkNotNull(io.grpc.Context.current().getDeadline()); return shutDownWorkerBlockingStub .get() .prepareWorkerForGracefulShutdown( diff --git a/src/test/java/build/buildfarm/instance/stub/StubInstanceTest.java b/src/test/java/build/buildfarm/instance/stub/StubInstanceTest.java index e50e3f0028..e3845494b8 100644 --- a/src/test/java/build/buildfarm/instance/stub/StubInstanceTest.java +++ b/src/test/java/build/buildfarm/instance/stub/StubInstanceTest.java @@ -64,6 +64,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; @@ -98,7 +99,7 @@ public void tearDown() throws InterruptedException { fakeServer.awaitTermination(); } - private Instance newStubInstance(String instanceName) { + private StubInstance newStubInstance(String instanceName) { return new StubInstance( instanceName, DIGEST_UTIL, @@ -197,6 +198,38 @@ public void findMissingBlobs( instance.stop(); } + @Test + public void findMissingBlobsOverSizeLimitRecombines() + throws ExecutionException, InterruptedException { + AtomicReference reference = new AtomicReference<>(); + serviceRegistry.addService( + new ContentAddressableStorageImplBase() { + @Override + public void findMissingBlobs( + FindMissingBlobsRequest request, + StreamObserver responseObserver) { + reference.set(request); + responseObserver.onNext( + FindMissingBlobsResponse.newBuilder() + .addAllMissingBlobDigests(request.getBlobDigestsList()) + .build()); + responseObserver.onCompleted(); + } + }); + StubInstance instance = newStubInstance("findMissingBlobs-test"); + instance.maxRequestSize = 1024; + ImmutableList.Builder builder = ImmutableList.builder(); + // generates digest size * 1024 serialized size at least + for (int i = 0; i < 1024; i++) { + ByteString content = ByteString.copyFromUtf8("Hello, World! " + UUID.randomUUID()); + builder.add(DIGEST_UTIL.compute(content)); + } + ImmutableList digests = builder.build(); + assertThat(instance.findMissingBlobs(digests, RequestMetadata.getDefaultInstance()).get()) + .containsExactlyElementsIn(digests); + instance.stop(); + } + @Test public void outputStreamWrites() throws IOException, InterruptedException { AtomicReference writtenContent = new AtomicReference<>(); From b0ca1c2b9691c8c60baa72c70986ed335a17d374 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Sat, 24 Jun 2023 23:09:03 -0400 Subject: [PATCH 021/311] Interpret ExecDirException to Status (#1391) Handle ExecDirExceptions in InputFetcher such that the client can observe a FAILED_PRECONDITION with PreconditionFailures that include Violations with VIOLATION_TYPE_MISSING to inspire virtuous loop reestablishment. A ViolationException acts as a container for this, and can be extended to include the components of a putDirectory. Interpret PutDirectoryExceptions with their imposed violations. Missing inputs at the time of execute, whether linked as immediate files or through the directory cache, will be interpreted as VIOLATION_TYPE_MISSING. --- .../build/buildfarm/cas/cfc/CASFileCache.java | 33 ----- .../cas/cfc/PutDirectoryException.java | 53 +++++++ .../java/build/buildfarm/common/Errors.java | 3 + .../buildfarm/common/OperationFailer.java | 35 +---- .../server/AbstractServerInstance.java | 4 +- src/main/java/build/buildfarm/worker/BUILD | 1 + .../buildfarm/worker/ExecDirException.java | 139 ++++++++++++++++++ .../build/buildfarm/worker/InputFetcher.java | 32 ++-- .../worker/shard/CFCExecFileSystem.java | 88 +++++------ .../buildfarm/cas/cfc/CASFileCacheTest.java | 1 - src/test/java/build/buildfarm/worker/BUILD | 2 + .../buildfarm/worker/InputFetcherTest.java | 135 +++++++++++++++++ .../buildfarm/worker/StubWorkerContext.java | 7 +- 13 files changed, 405 insertions(+), 128 deletions(-) create mode 100644 src/main/java/build/buildfarm/cas/cfc/PutDirectoryException.java create mode 100644 src/main/java/build/buildfarm/worker/ExecDirException.java create mode 100644 src/test/java/build/buildfarm/worker/InputFetcherTest.java diff --git a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java index ce157645fe..84fd0f3382 100644 --- a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java +++ b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java @@ -2159,39 +2159,6 @@ private boolean directoryEntryExists( return false; } - static class PutDirectoryException extends IOException { - private final Path path; - private final Digest digest; - private final List exceptions; - - PutDirectoryException(Path path, Digest digest, List exceptions) { - // When printing the exception, show the captured sub-exceptions. - super(getErrorMessage(path, exceptions)); - this.path = path; - this.digest = digest; - this.exceptions = exceptions; - for (Throwable exception : exceptions) { - addSuppressed(exception); - } - } - - Path getPath() { - return path; - } - - Digest getDigest() { - return digest; - } - - List getExceptions() { - return exceptions; - } - } - - private static String getErrorMessage(Path path, List exceptions) { - return String.format("%s: %d %s: %s", path, exceptions.size(), "exceptions", exceptions); - } - @SuppressWarnings("ConstantConditions") private ListenableFuture putDirectorySynchronized( Path path, Digest digest, Map directoriesByDigest, ExecutorService service) diff --git a/src/main/java/build/buildfarm/cas/cfc/PutDirectoryException.java b/src/main/java/build/buildfarm/cas/cfc/PutDirectoryException.java new file mode 100644 index 0000000000..d635a7217b --- /dev/null +++ b/src/main/java/build/buildfarm/cas/cfc/PutDirectoryException.java @@ -0,0 +1,53 @@ +// Copyright 2023 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package build.buildfarm.cas.cfc; + +import build.bazel.remote.execution.v2.Digest; +import java.io.IOException; +import java.nio.file.Path; +import java.util.List; + +public class PutDirectoryException extends IOException { + private final Path path; + private final Digest digest; + private final List exceptions; + + private static String getErrorMessage(Path path, List exceptions) { + return String.format("%s: %d %s: %s", path, exceptions.size(), "exceptions", exceptions); + } + + public PutDirectoryException(Path path, Digest digest, List exceptions) { + // When printing the exception, show the captured sub-exceptions. + super(getErrorMessage(path, exceptions)); + this.path = path; + this.digest = digest; + this.exceptions = exceptions; + for (Throwable exception : exceptions) { + addSuppressed(exception); + } + } + + Path getPath() { + return path; + } + + public Digest getDigest() { + return digest; + } + + public List getExceptions() { + return exceptions; + } +} diff --git a/src/main/java/build/buildfarm/common/Errors.java b/src/main/java/build/buildfarm/common/Errors.java index 24932b994e..603c015d23 100644 --- a/src/main/java/build/buildfarm/common/Errors.java +++ b/src/main/java/build/buildfarm/common/Errors.java @@ -19,5 +19,8 @@ public final class Errors { public static final String VIOLATION_TYPE_INVALID = "INVALID"; + public static final String MISSING_INPUT = + "A requested input (or the `Action` or its `Command`) was not found in the CAS."; + private Errors() {} } diff --git a/src/main/java/build/buildfarm/common/OperationFailer.java b/src/main/java/build/buildfarm/common/OperationFailer.java index d3a2f33639..c06b0f2dcc 100644 --- a/src/main/java/build/buildfarm/common/OperationFailer.java +++ b/src/main/java/build/buildfarm/common/OperationFailer.java @@ -20,8 +20,7 @@ import build.buildfarm.v1test.ExecuteEntry; import com.google.longrunning.Operation; import com.google.protobuf.Any; -import com.google.rpc.PreconditionFailure; -import io.grpc.Status.Code; +import com.google.rpc.Status; /** * @class OperationFailer @@ -30,20 +29,14 @@ * finished and failed. */ public class OperationFailer { - public static Operation get( - Operation operation, - ExecuteEntry executeEntry, - String failureType, - String failureMessage, - String failureDetails) { + public static Operation get(Operation operation, ExecuteEntry executeEntry, Status status) { return operation .toBuilder() - .setName(executeEntry.getOperationName()) .setDone(true) + .setName(executeEntry.getOperationName()) .setMetadata( Any.pack(executeOperationMetadata(executeEntry, ExecutionStage.Value.COMPLETED))) - .setResponse( - Any.pack(failResponse(executeEntry, failureType, failureMessage, failureDetails))) + .setResponse(Any.pack(ExecuteResponse.newBuilder().setStatus(status).build())) .build(); } @@ -56,24 +49,4 @@ private static ExecuteOperationMetadata executeOperationMetadata( .setStage(stage) .build(); } - - private static ExecuteResponse failResponse( - ExecuteEntry executeEntry, String failureType, String failureMessage, String failureDetails) { - PreconditionFailure.Builder preconditionFailureBuilder = PreconditionFailure.newBuilder(); - preconditionFailureBuilder - .addViolationsBuilder() - .setType(failureType) - .setSubject("blobs/" + DigestUtil.toString(executeEntry.getActionDigest())) - .setDescription(failureDetails); - PreconditionFailure preconditionFailure = preconditionFailureBuilder.build(); - - return ExecuteResponse.newBuilder() - .setStatus( - com.google.rpc.Status.newBuilder() - .setCode(Code.FAILED_PRECONDITION.value()) - .setMessage(failureMessage) - .addDetails(Any.pack(preconditionFailure)) - .build()) - .build(); - } } diff --git a/src/main/java/build/buildfarm/instance/server/AbstractServerInstance.java b/src/main/java/build/buildfarm/instance/server/AbstractServerInstance.java index 95b737725b..57d827ffa8 100644 --- a/src/main/java/build/buildfarm/instance/server/AbstractServerInstance.java +++ b/src/main/java/build/buildfarm/instance/server/AbstractServerInstance.java @@ -16,6 +16,7 @@ import static build.buildfarm.common.Actions.asExecutionStatus; import static build.buildfarm.common.Actions.checkPreconditionFailure; +import static build.buildfarm.common.Errors.MISSING_INPUT; import static build.buildfarm.common.Errors.VIOLATION_TYPE_INVALID; import static build.buildfarm.common.Errors.VIOLATION_TYPE_MISSING; import static build.buildfarm.common.Trees.enumerateTreeFileDigests; @@ -177,9 +178,6 @@ public abstract class AbstractServerInstance implements Instance { public static final String ENVIRONMENT_VARIABLES_NOT_SORTED = "The `Command`'s `environment_variables` are not correctly sorted by `name`."; - public static final String MISSING_INPUT = - "A requested input (or the `Action` or its `Command`) was not found in the CAS."; - public static final String MISSING_ACTION = "The action was not found in the CAS."; public static final String MISSING_COMMAND = "The command was not found in the CAS."; diff --git a/src/main/java/build/buildfarm/worker/BUILD b/src/main/java/build/buildfarm/worker/BUILD index 3ab09723b7..417d530e9a 100644 --- a/src/main/java/build/buildfarm/worker/BUILD +++ b/src/main/java/build/buildfarm/worker/BUILD @@ -4,6 +4,7 @@ java_library( plugins = ["//src/main/java/build/buildfarm/common:lombok"], visibility = ["//visibility:public"], deps = [ + "//src/main/java/build/buildfarm/cas", "//src/main/java/build/buildfarm/common", "//src/main/java/build/buildfarm/common/config", "//src/main/java/build/buildfarm/instance", diff --git a/src/main/java/build/buildfarm/worker/ExecDirException.java b/src/main/java/build/buildfarm/worker/ExecDirException.java new file mode 100644 index 0000000000..40c625232c --- /dev/null +++ b/src/main/java/build/buildfarm/worker/ExecDirException.java @@ -0,0 +1,139 @@ +// Copyright 2023 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package build.buildfarm.worker; + +import static build.buildfarm.common.Errors.MISSING_INPUT; +import static build.buildfarm.common.Errors.VIOLATION_TYPE_INVALID; +import static build.buildfarm.common.Errors.VIOLATION_TYPE_MISSING; +import static java.util.logging.Level.SEVERE; + +import build.bazel.remote.execution.v2.Digest; +import build.buildfarm.cas.cfc.PutDirectoryException; +import build.buildfarm.common.DigestUtil; +import com.google.protobuf.Any; +import com.google.rpc.Code; +import com.google.rpc.PreconditionFailure; +import com.google.rpc.PreconditionFailure.Violation; +import com.google.rpc.Status; +import java.io.IOException; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.util.List; +import lombok.extern.java.Log; + +@Log +public class ExecDirException extends IOException { + private final Path path; + private final List exceptions; + + public static class ViolationException extends Exception { + private final Digest digest; + private final Path path; + private final boolean isExecutable; + + public ViolationException(Digest digest, Path path, boolean isExecutable, Throwable cause) { + super(cause); + this.digest = digest; + this.path = path; + this.isExecutable = isExecutable; + } + + private static String getDescription(Path path, boolean isExecutable) { + if (path != null) { + return "The file `/" + path + (isExecutable ? "*" : "") + "` was not found in the CAS."; + } + return MISSING_INPUT; + } + + static void toViolation( + Violation.Builder violation, Throwable cause, Path path, boolean isExecutable) { + if (cause instanceof NoSuchFileException) { + violation + .setType(VIOLATION_TYPE_MISSING) + .setDescription(getDescription(path, isExecutable)); + } else { + violation.setType(VIOLATION_TYPE_INVALID).setDescription(cause.getMessage()); + } + } + + public Violation getViolation() { + Violation.Builder violation = Violation.newBuilder(); + toViolation(violation, getCause(), path, isExecutable); + violation.setSubject("blobs/" + DigestUtil.toString(digest)); + return violation.build(); + } + } + + private static String getErrorMessage(Path path, List exceptions) { + return String.format("%s: %d %s: %s", path, exceptions.size(), "exceptions", exceptions); + } + + public ExecDirException(Path path, List exceptions) { + // When printing the exception, show the captured sub-exceptions. + super(getErrorMessage(path, exceptions)); + this.path = path; + this.exceptions = exceptions; + for (Throwable exception : exceptions) { + addSuppressed(exception); + } + } + + Path getPath() { + return path; + } + + List getExceptions() { + return exceptions; + } + + Status.Builder toStatus(Status.Builder status) { + status.setCode(Code.FAILED_PRECONDITION.getNumber()); + + // aggregate into a single preconditionFailure + PreconditionFailure.Builder preconditionFailure = PreconditionFailure.newBuilder(); + for (Throwable exception : exceptions) { + if (exception instanceof ViolationException) { + ViolationException violationException = (ViolationException) exception; + preconditionFailure.addViolations(violationException.getViolation()); + } else if (exception instanceof PutDirectoryException) { + PutDirectoryException putDirException = (PutDirectoryException) exception; + for (Throwable putDirCause : putDirException.getExceptions()) { + if (putDirCause instanceof IOException) { + Violation.Builder violation = preconditionFailure.addViolationsBuilder(); + ViolationException.toViolation( + violation, putDirCause, /* path=*/ null, /* isExecutable=*/ false); + if (putDirCause instanceof NoSuchFileException) { + violation.setSubject("blobs/" + putDirCause.getMessage()); + } else { + log.log(SEVERE, "unrecognized put dir cause exception", putDirCause); + violation.setSubject("blobs/" + DigestUtil.toString(putDirException.getDigest())); + } + } else { + log.log(SEVERE, "unrecognized put dir exception", putDirCause); + status.setCode(Code.INTERNAL.getNumber()); + } + } + } else { + log.log(SEVERE, "unrecognized exec dir exception", exception); + status.setCode(Code.INTERNAL.getNumber()); + } + } + if (preconditionFailure.getViolationsCount() > 0) { + status.addDetails(Any.pack(preconditionFailure.build())); + } + + return status; + } +} diff --git a/src/main/java/build/buildfarm/worker/InputFetcher.java b/src/main/java/build/buildfarm/worker/InputFetcher.java index 667ccfa0e5..1c99df6a91 100644 --- a/src/main/java/build/buildfarm/worker/InputFetcher.java +++ b/src/main/java/build/buildfarm/worker/InputFetcher.java @@ -15,7 +15,6 @@ package build.buildfarm.worker; import static build.bazel.remote.execution.v2.ExecutionStage.Value.QUEUED; -import static build.buildfarm.common.Errors.VIOLATION_TYPE_INVALID; import static java.lang.String.format; import static java.util.concurrent.TimeUnit.DAYS; import static java.util.concurrent.TimeUnit.MICROSECONDS; @@ -30,13 +29,17 @@ import build.bazel.remote.execution.v2.FileNode; import build.buildfarm.common.OperationFailer; import build.buildfarm.common.ProxyDirectoriesIndex; +import build.buildfarm.v1test.ExecuteEntry; import build.buildfarm.v1test.QueuedOperation; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Stopwatch; import com.google.common.collect.Iterables; import com.google.longrunning.Operation; import com.google.protobuf.Duration; import com.google.protobuf.util.Durations; import com.google.protobuf.util.Timestamps; +import com.google.rpc.Code; +import com.google.rpc.Status; import io.grpc.Deadline; import java.io.IOException; import java.nio.file.Path; @@ -162,7 +165,8 @@ static String getExecutablePath( return null; } - private long fetchPolled(Stopwatch stopwatch) throws InterruptedException { + @VisibleForTesting + long fetchPolled(Stopwatch stopwatch) throws InterruptedException { String operationName = operationContext.queueEntry.getExecuteEntry().getOperationName(); log.log(Level.FINE, format("fetching inputs: %s", operationName)); @@ -196,8 +200,15 @@ private long fetchPolled(Stopwatch stopwatch) throws InterruptedException { queuedOperation.getAction(), queuedOperation.getCommand()); } catch (IOException e) { - log.log(Level.SEVERE, format("error creating exec dir for %s", operationName), e); - failOperation("Error creating exec dir", e.toString()); + Status.Builder status = Status.newBuilder().setMessage("Error creating exec dir"); + if (e instanceof ExecDirException) { + ExecDirException execDirEx = (ExecDirException) e; + execDirEx.toStatus(status); + } else { + status.setCode(Code.INTERNAL.getNumber()); + log.log(Level.SEVERE, format("error creating exec dir for %s", operationName), e); + } + failOperation(status.build()); return 0; } success = true; @@ -311,15 +322,10 @@ public void run() { } } - private void failOperation(String failureMessage, String failureDetails) - throws InterruptedException { + private void failOperation(Status status) throws InterruptedException { + ExecuteEntry executeEntry = operationContext.queueEntry.getExecuteEntry(); Operation failedOperation = - OperationFailer.get( - operationContext.operation, - operationContext.queueEntry.getExecuteEntry(), - VIOLATION_TYPE_INVALID, - failureMessage, - failureDetails); + OperationFailer.get(operationContext.operation, executeEntry, status); try { workerContext.putOperation(failedOperation); @@ -327,7 +333,7 @@ private void failOperation(String failureMessage, String failureDetails) operationContext.toBuilder().setOperation(failedOperation).build(); owner.error().put(newOperationContext); } catch (Exception e) { - String operationName = operationContext.queueEntry.getExecuteEntry().getOperationName(); + String operationName = executeEntry.getOperationName(); log.log(Level.SEVERE, format("Cannot report failed operation %s", operationName), e); } } diff --git a/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java b/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java index 525d696d5c..c8336f7481 100644 --- a/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java +++ b/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java @@ -21,10 +21,12 @@ import static com.google.common.collect.Iterables.concat; import static com.google.common.collect.Iterables.filter; import static com.google.common.util.concurrent.Futures.allAsList; +import static com.google.common.util.concurrent.Futures.catchingAsync; import static com.google.common.util.concurrent.Futures.immediateFailedFuture; import static com.google.common.util.concurrent.Futures.immediateFuture; import static com.google.common.util.concurrent.Futures.transform; import static com.google.common.util.concurrent.Futures.transformAsync; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static com.google.common.util.concurrent.MoreExecutors.listeningDecorator; import static com.google.common.util.concurrent.MoreExecutors.shutdownAndAwaitTermination; import static java.util.concurrent.TimeUnit.MINUTES; @@ -35,7 +37,6 @@ import build.bazel.remote.execution.v2.Digest; import build.bazel.remote.execution.v2.Directory; import build.bazel.remote.execution.v2.DirectoryNode; -import build.bazel.remote.execution.v2.FileNode; import build.bazel.remote.execution.v2.SymlinkNode; import build.buildfarm.cas.ContentAddressableStorage; import build.buildfarm.cas.cfc.CASFileCache; @@ -43,6 +44,8 @@ import build.buildfarm.common.DigestUtil; import build.buildfarm.common.io.Directories; import build.buildfarm.common.io.Dirent; +import build.buildfarm.worker.ExecDirException; +import build.buildfarm.worker.ExecDirException.ViolationException; import build.buildfarm.worker.OutputDirectory; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; @@ -181,30 +184,26 @@ private ListenableFuture putSymlink(Path path, SymlinkNode symlinkNode) { @SuppressWarnings("ConstantConditions") private ListenableFuture put( - Path path, FileNode fileNode, ImmutableList.Builder inputFiles) { - Path filePath = path.resolve(fileNode.getName()); - Digest digest = fileNode.getDigest(); + Digest digest, Path path, boolean isExecutable, Consumer onKey) { if (digest.getSizeBytes() == 0) { return listeningDecorator(fetchService) .submit( () -> { - Files.createFile(filePath); + Files.createFile(path); // ignore executable return null; }); } - String key = fileCache.getKey(digest, fileNode.getIsExecutable()); + String key = fileCache.getKey(digest, isExecutable); return transformAsync( - fileCache.put(digest, fileNode.getIsExecutable(), fetchService), + fileCache.put(digest, isExecutable, fetchService), (fileCachePath) -> { checkNotNull(key); // we saw null entries in the built immutable list without synchronization - synchronized (inputFiles) { - inputFiles.add(key); - } - if (fileNode.getDigest().getSizeBytes() != 0) { + onKey.accept(key); + if (digest.getSizeBytes() != 0) { try { - Files.createLink(filePath, fileCachePath); + Files.createLink(path, fileCachePath); } catch (IOException e) { return immediateFailedFuture(e); } @@ -214,12 +213,29 @@ private ListenableFuture put( fetchService); } + private ListenableFuture catchingPut( + Digest digest, Path root, Path path, boolean isExecutable, Consumer onKey) { + return catchingAsync( + put(digest, path, isExecutable, onKey), + Throwable.class, // required per docs + t -> { + if (t instanceof IOException) { + return immediateFailedFuture( + new ViolationException( + digest, root.relativize(path), isExecutable, (IOException) t)); + } + return immediateFailedFuture(t); + }, + directExecutor()); + } + private Iterable> fetchInputs( + Path root, Path path, Digest directoryDigest, Map directoriesIndex, OutputDirectory outputDirectory, - ImmutableList.Builder inputFiles, + Consumer onKey, ImmutableList.Builder inputDirectories) throws IOException { Directory directory = directoriesIndex.get(directoryDigest); @@ -231,7 +247,14 @@ private Iterable> fetchInputs( Iterable> downloads = directory.getFilesList().stream() - .map(fileNode -> put(path, fileNode, inputFiles)) + .map( + fileNode -> + catchingPut( + fileNode.getDigest(), + root, + path.resolve(fileNode.getName()), + fileNode.getIsExecutable(), + onKey)) .collect(ImmutableList.toImmutableList()); downloads = @@ -253,11 +276,12 @@ private Iterable> fetchInputs( concat( downloads, fetchInputs( + root, dirPath, digest, directoriesIndex, childOutputDirectory, - inputFiles, + onKey, inputDirectories)); } else { downloads = @@ -294,33 +318,6 @@ private ListenableFuture linkDirectory( fetchService); } - private static class ExecDirException extends IOException { - private final Path path; - private final List exceptions; - - ExecDirException(Path path, List exceptions) { - // When printing the exception, show the captured sub-exceptions. - super(getErrorMessage(path, exceptions)); - this.path = path; - this.exceptions = exceptions; - for (Throwable exception : exceptions) { - addSuppressed(exception); - } - } - - Path getPath() { - return path; - } - - List getExceptions() { - return exceptions; - } - } - - private static String getErrorMessage(Path path, List exceptions) { - return String.format("%s: %d %s: %s", path, exceptions.size(), "exceptions", exceptions); - } - private static void checkExecErrors(Path path, List errors) throws ExecDirException { if (!errors.isEmpty()) { throw new ExecDirException(path, errors); @@ -378,11 +375,16 @@ public Path createExecDir( log.log(Level.FINE, "ExecFileSystem::createExecDir(" + operationName + ") calling fetchInputs"); Iterable> fetchedFutures = fetchInputs( + execDir, execDir, inputRootDigest, directoriesIndex, outputDirectory, - inputFiles, + key -> { + synchronized (inputFiles) { + inputFiles.add(key); + } + }, inputDirectories); boolean success = false; try { diff --git a/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java b/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java index 984275f3f3..1bd1791999 100644 --- a/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java +++ b/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java @@ -43,7 +43,6 @@ import build.buildfarm.cas.DigestMismatchException; import build.buildfarm.cas.cfc.CASFileCache.CancellableOutputStream; import build.buildfarm.cas.cfc.CASFileCache.Entry; -import build.buildfarm.cas.cfc.CASFileCache.PutDirectoryException; import build.buildfarm.cas.cfc.CASFileCache.StartupCacheResults; import build.buildfarm.common.DigestUtil; import build.buildfarm.common.DigestUtil.HashFunction; diff --git a/src/test/java/build/buildfarm/worker/BUILD b/src/test/java/build/buildfarm/worker/BUILD index e8307784b6..999aea0910 100644 --- a/src/test/java/build/buildfarm/worker/BUILD +++ b/src/test/java/build/buildfarm/worker/BUILD @@ -17,6 +17,7 @@ java_test( plugins = ["//src/main/java/build/buildfarm/common:lombok"], test_class = "build.buildfarm.AllTests", deps = [ + "//src/main/java/build/buildfarm/cas", "//src/main/java/build/buildfarm/common", "//src/main/java/build/buildfarm/common/config", "//src/main/java/build/buildfarm/instance", @@ -25,6 +26,7 @@ java_test( "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", "@googleapis//:google_rpc_code_java_proto", + "@googleapis//:google_rpc_error_details_java_proto", "@maven//:com_github_jnr_jnr_constants", "@maven//:com_github_jnr_jnr_ffi", "@maven//:com_github_serceman_jnr_fuse", diff --git a/src/test/java/build/buildfarm/worker/InputFetcherTest.java b/src/test/java/build/buildfarm/worker/InputFetcherTest.java new file mode 100644 index 0000000000..ec69ad2f0e --- /dev/null +++ b/src/test/java/build/buildfarm/worker/InputFetcherTest.java @@ -0,0 +1,135 @@ +// Copyright 2018 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package build.buildfarm.worker; + +import static build.buildfarm.common.Errors.VIOLATION_TYPE_MISSING; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import build.bazel.remote.execution.v2.Action; +import build.bazel.remote.execution.v2.Command; +import build.bazel.remote.execution.v2.Digest; +import build.bazel.remote.execution.v2.Directory; +import build.bazel.remote.execution.v2.ExecuteResponse; +import build.buildfarm.cas.cfc.PutDirectoryException; +import build.buildfarm.v1test.ExecuteEntry; +import build.buildfarm.v1test.QueueEntry; +import build.buildfarm.v1test.QueuedOperation; +import build.buildfarm.worker.ExecDirException.ViolationException; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import com.google.longrunning.Operation; +import com.google.protobuf.Any; +import com.google.rpc.Code; +import com.google.rpc.DebugInfo; +import com.google.rpc.Help; +import com.google.rpc.LocalizedMessage; +import com.google.rpc.PreconditionFailure; +import com.google.rpc.RequestInfo; +import com.google.rpc.ResourceInfo; +import com.google.rpc.Status; +import java.io.IOException; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class InputFetcherTest { + @Test + public void onlyMissingFilesIsViolationMissingFailedPrecondition() throws Exception { + PipelineStage error = mock(PipelineStage.class); + Operation operation = Operation.newBuilder().setName("missing-inputs").build(); + ExecuteEntry executeEntry = + ExecuteEntry.newBuilder().setOperationName(operation.getName()).build(); + QueueEntry queueEntry = QueueEntry.newBuilder().setExecuteEntry(executeEntry).build(); + OperationContext operationContext = + OperationContext.newBuilder().setQueueEntry(queueEntry).setOperation(operation).build(); + Command command = Command.newBuilder().addArguments("/bin/false").build(); + QueuedOperation queuedOperation = QueuedOperation.newBuilder().setCommand(command).build(); + AtomicReference failedOperationRef = new AtomicReference<>(); + WorkerContext workerContext = + new StubWorkerContext() { + @Override + public QueuedOperation getQueuedOperation(QueueEntry queueEntry) { + return queuedOperation; + } + + @Override + public boolean putOperation(Operation operation) { + return failedOperationRef.compareAndSet(null, operation); + } + + @Override + public Path createExecDir( + String operationName, + Map directoriesIndex, + Action action, + Command command) + throws IOException { + Path root = Paths.get(operationName); + throw new ExecDirException( + Paths.get(operationName), + ImmutableList.of( + new ViolationException( + Digest.getDefaultInstance(), + root.resolve("input"), + /* isExecutable=*/ false, + new NoSuchFileException("input-digest")), + new PutDirectoryException( + root.resolve("dir"), + Digest.getDefaultInstance(), + ImmutableList.of(new NoSuchFileException("dir/input-digest"))))); + } + + @Override + public int getInputFetchStageWidth() { + return 1; + } + }; + InputFetchStage owner = new InputFetchStage(workerContext, /* output=*/ null, error); + InputFetcher inputFetcher = new InputFetcher(workerContext, operationContext, owner); + inputFetcher.fetchPolled(/* stopwatch=*/ null); + Operation failedOperation = checkNotNull(failedOperationRef.get()); + verify(error, times(1)).put(any(OperationContext.class)); + ExecuteResponse executeResponse = failedOperation.getResponse().unpack(ExecuteResponse.class); + Status status = executeResponse.getStatus(); + assertThat(status.getCode()).isEqualTo(Code.FAILED_PRECONDITION.getNumber()); + for (Any detail : status.getDetailsList()) { + if (!(detail.is(DebugInfo.class) + || detail.is(Help.class) + || detail.is(LocalizedMessage.class) + || detail.is(RequestInfo.class) + || detail.is(ResourceInfo.class))) { + assertThat(detail.is(PreconditionFailure.class)).isTrue(); + PreconditionFailure preconditionFailure = detail.unpack(PreconditionFailure.class); + assertThat(preconditionFailure.getViolationsCount()).isGreaterThan(0); + assertThat( + Iterables.all( + preconditionFailure.getViolationsList(), + violation -> violation.getType().equals(VIOLATION_TYPE_MISSING))) + .isTrue(); + } + } + } +} diff --git a/src/test/java/build/buildfarm/worker/StubWorkerContext.java b/src/test/java/build/buildfarm/worker/StubWorkerContext.java index 1b0272a0b6..d288d67a6f 100644 --- a/src/test/java/build/buildfarm/worker/StubWorkerContext.java +++ b/src/test/java/build/buildfarm/worker/StubWorkerContext.java @@ -34,6 +34,7 @@ import com.google.longrunning.Operation; import com.google.protobuf.Duration; import io.grpc.Deadline; +import java.io.IOException; import java.nio.file.Path; import java.util.List; import java.util.Map; @@ -142,10 +143,8 @@ public QueuedOperation getQueuedOperation(QueueEntry queueEntry) { @Override public Path createExecDir( - String operationName, - Map directoriesIndex, - Action action, - Command command) { + String operationName, Map directoriesIndex, Action action, Command command) + throws IOException, InterruptedException { throw new UnsupportedOperationException(); } From 653da3f119071d8ab95b76b90ea5a6239c913db0 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Sun, 25 Jun 2023 00:57:23 -0400 Subject: [PATCH 022/311] Initialize fileStore when skipping load (#1392) --- src/main/java/build/buildfarm/cas/cfc/CASFileCache.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java index 84fd0f3382..225a4bdcfa 100644 --- a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java +++ b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java @@ -1275,6 +1275,7 @@ public StartupCacheResults start( loadResults = loadCache(onStartPut, removeDirectoryService); } else { // Skip loading the cache and ensure it is empty + fileStore = Files.getFileStore(root); Directories.remove(root, fileStore, removeDirectoryService); initializeRootDirectory(); } From ccee33bd746bcaa97f4459aae33ec41aa97a4d33 Mon Sep 17 00:00:00 2001 From: amishra-u <119983081+amishra-u@users.noreply.github.com> Date: Tue, 27 Jun 2023 17:10:54 -0700 Subject: [PATCH 023/311] Handle inaccurate information in backplane for fmb call (#1381) ### Problem When workers die, their stored references are not removed from the backplane. This creates the possibility that new workers may come up with the same IP address or use an IP address previously used by another terminated host. As a result, the backplane becomes unreliable, requiring us to query each worker individually to find missing blobs. Clearly, this approach is not scalable since any problems encountered by a single worker can significantly impact the performance of the buildfarm. ### Past Work We made code modifications for the `findMissingBlobs` function to exclusively query the backplane, prs: #1310, #1333, and #1342. This update implemented the `findMissingViaBackplane` flag. However, the above issues made the `findMissingViaBackplane` flag ineffective. ### Solution To address the issue of imposter workers, updated code to compare the start time of each worker (first_registered_at) with the insertion time of the digest. Any worker whose start time is later than the digest insertion time is considered an imposter worker. Also, the code removes imposter workers associated with the digest in the same function call. **first_registered_at**: Added new field first_registered_at to the worker data type. This field stores the initial start time of the worker. Worker informs the backplane about its start time, which is the same as the creation time of the cache directory (where all digests are stored) on the worker's disk. **digest insert time**: The digest insertion time is calculated using the Time to Live (TTL) of the digest and the casExpire time. The formula for determining the digest insertion time is now() - configured casExpire + remaining ttl. In the current implementation, each worker updates the TTL of the digest upon completing the write operation. This means that the cas insert time in the backplane corresponds to the time when the last worker finished writing the digest on its disk. ### Testing Deployed the change to our buildfarm staging, and ran full monorepo build. To make sure that the code change solve terminated worker problem, terminated bunch of workers in the middle of build. This caused temporary not_found `error`, which eventually faded away (fmb call autocorrect blob location). Screenshot 2023-06-21 at 12 36 47 PM In the above graph terminated workers during first build. ### Future Improvement The above solution might not work if user updates `cas_expire` time between two deployments as algorithm to calculate `digest_insert_time` depends to `cas_expire` time. closes #1371 --- .../build/buildfarm/backplane/Backplane.java | 6 ++ .../buildfarm/common/redis/RedisHashMap.java | 12 ++++ .../instance/shard/CasWorkerMap.java | 8 +++ .../instance/shard/JedisCasWorkerMap.java | 7 ++ .../instance/shard/RedisShardBackplane.java | 36 +++++++++- .../instance/shard/RedissonCasWorkerMap.java | 7 ++ .../instance/shard/ShardInstance.java | 49 +++++++++++-- .../build/buildfarm/worker/shard/Worker.java | 14 ++++ .../build/buildfarm/v1test/buildfarm.proto | 2 + .../common/redis/RedisHashMapTest.java | 15 ++++ .../shard/RedisShardBackplaneTest.java | 53 ++++++++++++++ .../instance/shard/ShardInstanceTest.java | 72 +++++++++++++------ 12 files changed, 252 insertions(+), 29 deletions(-) diff --git a/src/main/java/build/buildfarm/backplane/Backplane.java b/src/main/java/build/buildfarm/backplane/Backplane.java index 411a971766..557a7dc163 100644 --- a/src/main/java/build/buildfarm/backplane/Backplane.java +++ b/src/main/java/build/buildfarm/backplane/Backplane.java @@ -98,6 +98,12 @@ FindOperationsResults findEnrichedOperations(Instance instance, String filterPre Iterable> getOperations(Set operationIds) throws IOException; + /** Returns a map of the worker name and its start time for given workers. */ + Map getWorkersStartTimeInEpochSecs(Set workerNames) throws IOException; + + /** Returns the insert time epoch in seconds for the digest. */ + long getDigestInsertTime(Digest blobDigest) throws IOException; + /** Returns a set of the names of all active storage workers. */ Set getStorageWorkers() throws IOException; diff --git a/src/main/java/build/buildfarm/common/redis/RedisHashMap.java b/src/main/java/build/buildfarm/common/redis/RedisHashMap.java index 64ab462fbe..374a64131a 100644 --- a/src/main/java/build/buildfarm/common/redis/RedisHashMap.java +++ b/src/main/java/build/buildfarm/common/redis/RedisHashMap.java @@ -14,6 +14,8 @@ package build.buildfarm.common.redis; +import com.google.common.collect.Iterables; +import java.util.List; import java.util.Map; import java.util.Set; import redis.clients.jedis.JedisCluster; @@ -136,4 +138,14 @@ public Set keys(JedisCluster jedis) { public Map asMap(JedisCluster jedis) { return jedis.hgetAll(name); } + + /** + * @brief Get values associated with the specified fields from the hashmap. + * @param jedis Jedis cluster client. + * @param fields The name of the fields. + * @return Values associated with the specified fields + */ + public List mget(JedisCluster jedis, Iterable fields) { + return jedis.hmget(name, Iterables.toArray(fields, String.class)); + } } diff --git a/src/main/java/build/buildfarm/instance/shard/CasWorkerMap.java b/src/main/java/build/buildfarm/instance/shard/CasWorkerMap.java index 4e6f7bb617..794b296a1f 100644 --- a/src/main/java/build/buildfarm/instance/shard/CasWorkerMap.java +++ b/src/main/java/build/buildfarm/instance/shard/CasWorkerMap.java @@ -94,6 +94,14 @@ void removeAll(RedisClient client, Iterable blobDigests, String workerNa */ Set get(RedisClient client, Digest blobDigest) throws IOException; + /** + * @brief Get insert time for the digest. + * @param client Client used for interacting with redis when not using cacheMap. + * @param blobDigest The blob digest to lookup for insert time. + * @return insert time of the digest. + */ + long insertTime(RedisClient client, Digest blobDigest) throws IOException; + /** * @brief Get all of the key values as a map from the digests given. * @details If there are no workers for the digest, the key is left out of the returned map. diff --git a/src/main/java/build/buildfarm/instance/shard/JedisCasWorkerMap.java b/src/main/java/build/buildfarm/instance/shard/JedisCasWorkerMap.java index 097bc2e085..d035d10491 100644 --- a/src/main/java/build/buildfarm/instance/shard/JedisCasWorkerMap.java +++ b/src/main/java/build/buildfarm/instance/shard/JedisCasWorkerMap.java @@ -20,6 +20,7 @@ import build.buildfarm.common.redis.RedisClient; import com.google.common.collect.ImmutableMap; import java.io.IOException; +import java.time.Instant; import java.util.Map; import java.util.Set; import redis.clients.jedis.JedisClusterPipeline; @@ -189,6 +190,12 @@ public Set get(RedisClient client, Digest blobDigest) throws IOException return client.call(jedis -> jedis.smembers(key)); } + @Override + public long insertTime(RedisClient client, Digest blobDigest) throws IOException { + String key = redisCasKey(blobDigest); + return Instant.now().getEpochSecond() - keyExpiration_s + client.call(jedis -> jedis.ttl(key)); + } + /** * @brief Get all of the key values as a map from the digests given. * @details If there are no workers for the digest, the key is left out of the returned map. diff --git a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java index 681cda1325..864c808369 100644 --- a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java +++ b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java @@ -79,12 +79,14 @@ import io.grpc.Deadline; import java.io.IOException; import java.time.Instant; +import java.util.AbstractMap; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.function.Consumer; @@ -686,7 +688,7 @@ public void deregisterWorker(String workerName) throws IOException { public synchronized Set getStorageWorkers() throws IOException { if (storageWorkersDeadline == null || storageWorkersDeadline.isExpired()) { synchronized (storageWorkerSet) { - Set newWorkerSet = client.call(jedis -> fetchAndExpireStorageWorkers(jedis)); + Set newWorkerSet = client.call(this::fetchAndExpireStorageWorkers); storageWorkerSet.clear(); storageWorkerSet.addAll(newWorkerSet); } @@ -695,6 +697,38 @@ public synchronized Set getStorageWorkers() throws IOException { return new HashSet<>(storageWorkerSet); } + @Override + public Map getWorkersStartTimeInEpochSecs(Set workerNames) + throws IOException { + if (workerNames.isEmpty()) { + return Collections.emptyMap(); + } + List workerList = client.call(jedis -> state.storageWorkers.mget(jedis, workerNames)); + + return workerList.stream() + .filter(Objects::nonNull) + .map( + workerJson -> { + try { + ShardWorker.Builder builder = ShardWorker.newBuilder(); + JsonFormat.parser().merge(workerJson, builder); + ShardWorker worker = builder.build(); + return new AbstractMap.SimpleEntry<>( + worker.getEndpoint(), worker.getFirstRegisteredAt() / 1000L); + } catch (InvalidProtocolBufferException e) { + return null; + } + }) + .filter(Objects::nonNull) + .collect( + Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue)); + } + + @Override + public long getDigestInsertTime(Digest blobDigest) throws IOException { + return state.casWorkerMap.insertTime(client, blobDigest); + } + private synchronized Set getExecuteWorkers() throws IOException { try { return recentExecuteWorkers.get(); diff --git a/src/main/java/build/buildfarm/instance/shard/RedissonCasWorkerMap.java b/src/main/java/build/buildfarm/instance/shard/RedissonCasWorkerMap.java index 8800a051da..234e15fb15 100644 --- a/src/main/java/build/buildfarm/instance/shard/RedissonCasWorkerMap.java +++ b/src/main/java/build/buildfarm/instance/shard/RedissonCasWorkerMap.java @@ -18,6 +18,7 @@ import build.buildfarm.common.DigestUtil; import build.buildfarm.common.redis.RedisClient; import com.google.common.collect.ImmutableMap; +import java.time.Instant; import java.util.Map; import java.util.Random; import java.util.Set; @@ -169,6 +170,12 @@ public Set get(RedisClient client, Digest blobDigest) { return cacheMap.get(key).readAll(); } + @Override + public long insertTime(RedisClient client, Digest blobDigest) { + String key = cacheMapCasKey(blobDigest); + return Instant.now().getEpochSecond() - keyExpiration_s + cacheMap.get(key).remainTimeToLive(); + } + /** * @brief Get all of the key values as a map from the digests given. * @details If there are no workers for the digest, the key is left out of the returned map. diff --git a/src/main/java/build/buildfarm/instance/shard/ShardInstance.java b/src/main/java/build/buildfarm/instance/shard/ShardInstance.java index 26c7928c24..129741d00e 100644 --- a/src/main/java/build/buildfarm/instance/shard/ShardInstance.java +++ b/src/main/java/build/buildfarm/instance/shard/ShardInstance.java @@ -132,6 +132,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.time.Instant; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collections; @@ -660,7 +661,7 @@ public ListenableFuture> findMissingBlobs( // risk of returning expired workers despite filtering by active workers below. This is because // the strategy may return workers that have expired in the last 30 seconds. However, checking // workers directly is not a guarantee either since workers could leave the cluster after being - // queried. Ultimitely, it will come down to the client's resiliency if the backplane is + // queried. Ultimately, it will come down to the client's resiliency if the backplane is // out-of-date and the server lies about which blobs are actually present. We provide this // alternative strategy for calculating missing blobs. @@ -670,15 +671,45 @@ public ListenableFuture> findMissingBlobs( nonEmptyDigests.forEach(uniqueDigests::add); Map> foundBlobs = backplane.getBlobDigestsWorkers(uniqueDigests); Set workerSet = backplane.getStorageWorkers(); + Map workersStartTime = backplane.getWorkersStartTimeInEpochSecs(workerSet); return immediateFuture( uniqueDigests.stream() .filter( // best effort to present digests only missing on active workers - digest -> - Sets.intersection( - foundBlobs.getOrDefault(digest, Collections.emptySet()), workerSet) - .isEmpty()) + digest -> { + try { + Set initialWorkers = + foundBlobs.getOrDefault(digest, Collections.emptySet()); + Set activeWorkers = Sets.intersection(initialWorkers, workerSet); + long insertTime = backplane.getDigestInsertTime(digest); + Set workersStartedBeforeDigestInsertion = + activeWorkers.stream() + .filter( + worker -> + workersStartTime.getOrDefault( + worker, Instant.now().getEpochSecond()) + < insertTime) + .collect(Collectors.toSet()); + Set workersToBeRemoved = + Sets.difference(initialWorkers, workersStartedBeforeDigestInsertion) + .immutableCopy(); + if (!workersToBeRemoved.isEmpty()) { + log.log( + Level.INFO, format("adjusting locations for the digest %s", digest)); + backplane.adjustBlobLocations( + digest, Collections.emptySet(), workersToBeRemoved); + } + return workersStartedBeforeDigestInsertion.isEmpty(); + } catch (IOException e) { + // Treat error as missing digest. + log.log( + Level.WARNING, + format("failed to get digest (%s) insertion time", digest)); + return true; + } + }) .collect(Collectors.toList())); } catch (Exception e) { + log.log(Level.SEVERE, "find missing blob via backplane failed", e); return immediateFailedFuture(Status.fromThrowable(e).asException()); } } @@ -855,13 +886,19 @@ public void onError(Throwable t) { } else if (status.getCode() == Code.NOT_FOUND) { casMissCounter.inc(); log.log( - Level.FINE, worker + " did not contain " + DigestUtil.toString(blobDigest)); + configs.getServer().isEnsureOutputsPresent() ? Level.WARNING : Level.FINE, + worker + " did not contain " + DigestUtil.toString(blobDigest)); // ignore this, the worker will update the backplane eventually } else if (status.getCode() != Code.DEADLINE_EXCEEDED && SHARD_IS_RETRIABLE.test(status)) { // why not, always workers.addLast(worker); } else { + log.log( + Level.WARNING, + format( + "DEADLINE_EXCEEDED: read(%s) on worker %s after %d bytes of content", + DigestUtil.toString(blobDigest), worker, received)); blobObserver.onError(t); return; } diff --git a/src/main/java/build/buildfarm/worker/shard/Worker.java b/src/main/java/build/buildfarm/worker/shard/Worker.java index 271ee47b16..e1b0919fda 100644 --- a/src/main/java/build/buildfarm/worker/shard/Worker.java +++ b/src/main/java/build/buildfarm/worker/shard/Worker.java @@ -72,7 +72,9 @@ import java.io.File; import java.io.IOException; import java.nio.file.FileSystem; +import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.UserPrincipal; import java.util.Arrays; import java.util.List; @@ -448,6 +450,7 @@ private void startFailsafeRegistration() { String endpoint = configs.getWorker().getPublicName(); ShardWorker.Builder worker = ShardWorker.newBuilder().setEndpoint(endpoint); worker.setWorkerType(configs.getWorker().getWorkerType()); + worker.setFirstRegisteredAt(loadWorkerStartTimeInMillis()); int registrationIntervalMillis = 10000; int registrationOffsetMillis = registrationIntervalMillis * 3; new Thread( @@ -512,6 +515,17 @@ public void run() { .start(); } + private long loadWorkerStartTimeInMillis() { + try { + File cache = new File(configs.getWorker().getRoot() + "/cache"); + return Files.readAttributes(cache.toPath(), BasicFileAttributes.class) + .creationTime() + .toMillis(); + } catch (IOException e) { + return System.currentTimeMillis(); + } + } + public void start() throws ConfigurationException, InterruptedException, IOException { String session = UUID.randomUUID().toString(); ServerBuilder serverBuilder = ServerBuilder.forPort(configs.getWorker().getPort()); diff --git a/src/main/protobuf/build/buildfarm/v1test/buildfarm.proto b/src/main/protobuf/build/buildfarm/v1test/buildfarm.proto index 15afe1065a..b4c78b3c03 100644 --- a/src/main/protobuf/build/buildfarm/v1test/buildfarm.proto +++ b/src/main/protobuf/build/buildfarm/v1test/buildfarm.proto @@ -270,6 +270,8 @@ message ShardWorker { int64 expire_at = 2; int32 worker_type = 3; + + int64 first_registered_at = 4; } message WorkerChange { diff --git a/src/test/java/build/buildfarm/common/redis/RedisHashMapTest.java b/src/test/java/build/buildfarm/common/redis/RedisHashMapTest.java index 95a530982c..dc6d559b3e 100644 --- a/src/test/java/build/buildfarm/common/redis/RedisHashMapTest.java +++ b/src/test/java/build/buildfarm/common/redis/RedisHashMapTest.java @@ -21,6 +21,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import org.junit.After; @@ -255,4 +256,18 @@ public void redisRemoveAll() throws Exception { Map elements = map.asMap(redis); assertThat(elements.equals(expected)).isTrue(); } + + @Test + public void redisMget() { + RedisHashMap map = new RedisHashMap("test"); + map.insert(redis, "key1", "value1"); + map.insert(redis, "key2", "value2"); + map.insert(redis, "key3", "value3"); + map.insert(redis, "key4", "value4"); + + Iterable fields = Arrays.asList("key2", "key3"); + List expected = Arrays.asList("value2", "value3"); + + assertThat(map.mget(redis, fields)).containsExactlyElementsIn(expected); + } } diff --git a/src/test/java/build/buildfarm/instance/shard/RedisShardBackplaneTest.java b/src/test/java/build/buildfarm/instance/shard/RedisShardBackplaneTest.java index a893540fd1..97d8fb5d0f 100644 --- a/src/test/java/build/buildfarm/instance/shard/RedisShardBackplaneTest.java +++ b/src/test/java/build/buildfarm/instance/shard/RedisShardBackplaneTest.java @@ -23,6 +23,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import build.bazel.remote.execution.v2.Digest; import build.bazel.remote.execution.v2.Platform; import build.bazel.remote.execution.v2.RequestMetadata; import build.buildfarm.common.config.BuildfarmConfigs; @@ -33,11 +34,16 @@ import build.buildfarm.v1test.QueueEntry; import build.buildfarm.v1test.WorkerChange; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import com.google.longrunning.Operation; import com.google.protobuf.util.JsonFormat; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.UUID; import java.util.function.Supplier; import org.junit.Before; @@ -350,4 +356,51 @@ public void invocationsCanBeBlacklisted() throws IOException { verify(mockJedisClusterFactory, times(1)).get(); verify(jedisCluster, times(1)).exists(invocationBlacklistKey); } + + @Test + public void testGetWorkersStartTime() throws IOException { + JedisCluster jedisCluster = mock(JedisCluster.class); + when(mockJedisClusterFactory.get()).thenReturn(jedisCluster); + backplane = + new RedisShardBackplane("workers-starttime-test", o -> o, o -> o, mockJedisClusterFactory); + backplane.start("startTime/test:0000"); + + Set workerNames = ImmutableSet.of("worker1", "worker2", "missing_worker"); + + String storageWorkerKey = configs.getBackplane().getWorkersHashName() + "_storage"; + List workersJson = + Arrays.asList( + "{\"endpoint\": \"worker1\", \"expireAt\": \"1686981022917\", \"workerType\": 3, \"firstRegisteredAt\": \"1685292624000\"}", + "{\"endpoint\": \"worker2\", \"expireAt\": \"1686981022917\", \"workerType\": 3, \"firstRegisteredAt\": \"1685282624000\"}", + null); + when(jedisCluster.hmget(storageWorkerKey, "worker1", "worker2", "missing_worker")) + .thenReturn(workersJson); + Map workersStartTime = backplane.getWorkersStartTimeInEpochSecs(workerNames); + assertThat(workersStartTime.size()).isEqualTo(2); + assertThat(workersStartTime.get("worker1")).isEqualTo(1685292624L); + assertThat(workersStartTime.get("worker2")).isEqualTo(1685282624L); + assertThat(workersStartTime.get("missing_worker")).isNull(); + } + + @Test + public void getDigestInsertTime() throws IOException { + JedisCluster jedisCluster = mock(JedisCluster.class); + when(mockJedisClusterFactory.get()).thenReturn(jedisCluster); + backplane = + new RedisShardBackplane("digest-inserttime-test", o -> o, o -> o, mockJedisClusterFactory); + backplane.start("startTime/test:0000"); + long ttl = 3600L; + long expirationInSecs = configs.getBackplane().getCasExpire(); + when(jedisCluster.ttl("ContentAddressableStorage:abc/0")).thenReturn(ttl); + + Digest digest = Digest.newBuilder().setHash("abc").build(); + + Long insertTimeInSecs = backplane.getDigestInsertTime(digest); + + // Assuming there could be at most 2s delay in execution of both + // `Instant.now().getEpochSecond()` call. + assertThat(insertTimeInSecs) + .isGreaterThan(Instant.now().getEpochSecond() - expirationInSecs + ttl - 2); + assertThat(insertTimeInSecs).isAtMost(Instant.now().getEpochSecond() - expirationInSecs + ttl); + } } diff --git a/src/test/java/build/buildfarm/instance/shard/ShardInstanceTest.java b/src/test/java/build/buildfarm/instance/shard/ShardInstanceTest.java index 6613d68fac..1fdb7fc460 100644 --- a/src/test/java/build/buildfarm/instance/shard/ShardInstanceTest.java +++ b/src/test/java/build/buildfarm/instance/shard/ShardInstanceTest.java @@ -79,6 +79,7 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import com.google.common.util.concurrent.ListenableFuture; import com.google.longrunning.Operation; import com.google.protobuf.Any; @@ -1052,26 +1053,31 @@ public void containsBlobReflectsWorkerWithUnknownSize() throws Exception { @Test public void findMissingBlobsTest_ViaBackPlane() throws Exception { - Set activeWorkers = new HashSet<>(Arrays.asList("worker1", "worker2", "worker3")); - Set expiredWorker = new HashSet<>(Arrays.asList("workerX", "workerY", "workerZ")); + Set activeWorkers = ImmutableSet.of("worker1", "worker2", "worker3"); + Set expiredWorkers = ImmutableSet.of("workerX", "workerY", "workerZ"); + Set imposterWorkers = ImmutableSet.of("imposter1", "imposter2", "imposter3"); Set availableDigests = - new HashSet<>( - Arrays.asList( - Digest.newBuilder().setHash("toBeFound1").setSizeBytes(1).build(), - Digest.newBuilder().setHash("toBeFound2").setSizeBytes(1).build(), - Digest.newBuilder().setHash("toBeFound3").setSizeBytes(1).build(), - // a copy is added in final digest list - Digest.newBuilder().setHash("toBeFoundDuplicate").setSizeBytes(1).build())); + ImmutableSet.of( + Digest.newBuilder().setHash("toBeFound1").setSizeBytes(1).build(), + Digest.newBuilder().setHash("toBeFound2").setSizeBytes(1).build(), + Digest.newBuilder().setHash("toBeFound3").setSizeBytes(1).build(), + // a copy is added in final digest list + Digest.newBuilder().setHash("toBeFoundDuplicate").setSizeBytes(1).build()); Set missingDigests = - new HashSet<>( - Arrays.asList( - Digest.newBuilder().setHash("missing1").setSizeBytes(1).build(), - Digest.newBuilder().setHash("missing2").setSizeBytes(1).build(), - Digest.newBuilder().setHash("missing3").setSizeBytes(1).build(), - // a copy is added in final digest list - Digest.newBuilder().setHash("missingDuplicate").setSizeBytes(1).build())); + ImmutableSet.of( + Digest.newBuilder().setHash("missing1").setSizeBytes(1).build(), + Digest.newBuilder().setHash("missing2").setSizeBytes(1).build(), + Digest.newBuilder().setHash("missing3").setSizeBytes(1).build(), + // a copy is added in final digest list + Digest.newBuilder().setHash("missingDuplicate").setSizeBytes(1).build()); + + Set digestAvailableOnImposters = + ImmutableSet.of( + Digest.newBuilder().setHash("toBeFoundOnImposter1").setSizeBytes(1).build(), + Digest.newBuilder().setHash("toBeFoundOnImposter2").setSizeBytes(1).build(), + Digest.newBuilder().setHash("toBeFoundOnImposter3").setSizeBytes(1).build()); Set emptyDigests = new HashSet<>( @@ -1084,6 +1090,7 @@ public void findMissingBlobsTest_ViaBackPlane() throws Exception { availableDigests, missingDigests, emptyDigests, + digestAvailableOnImposters, Arrays.asList( Digest.newBuilder().setHash("toBeFoundDuplicate").setSizeBytes(1).build(), Digest.newBuilder().setHash("missingDuplicate").setSizeBytes(1).build())); @@ -1094,24 +1101,45 @@ public void findMissingBlobsTest_ViaBackPlane() throws Exception { digestAndWorkersMap.put(digest, getRandomSubset(activeWorkers)); } for (Digest digest : missingDigests) { - digestAndWorkersMap.put(digest, getRandomSubset(expiredWorker)); + digestAndWorkersMap.put(digest, getRandomSubset(expiredWorkers)); + } + for (Digest digest : digestAvailableOnImposters) { + digestAndWorkersMap.put(digest, getRandomSubset(imposterWorkers)); } BuildfarmConfigs buildfarmConfigs = instance.getBuildFarmConfigs(); buildfarmConfigs.getServer().setFindMissingBlobsViaBackplane(true); - when(mockBackplane.getStorageWorkers()).thenReturn(activeWorkers); + Set activeAndImposterWorkers = + Sets.newHashSet(Iterables.concat(activeWorkers, imposterWorkers)); + when(mockBackplane.getStorageWorkers()).thenReturn(activeAndImposterWorkers); when(mockBackplane.getBlobDigestsWorkers(any(Iterable.class))).thenReturn(digestAndWorkersMap); + long serverStartTime = 1686951033L; // june 15th, 2023 + Map workersStartTime = new HashMap<>(); + for (String worker : activeAndImposterWorkers) { + workersStartTime.put(worker, serverStartTime); + } + when(mockBackplane.getWorkersStartTimeInEpochSecs(activeAndImposterWorkers)) + .thenReturn(workersStartTime); + long oneDay = 86400L; + for (Digest digest : availableDigests) { + when(mockBackplane.getDigestInsertTime(digest)).thenReturn(serverStartTime + oneDay); + } + for (Digest digest : digestAvailableOnImposters) { + when(mockBackplane.getDigestInsertTime(digest)).thenReturn(serverStartTime - oneDay); + } + Iterable actualMissingDigests = instance.findMissingBlobs(allDigests, RequestMetadata.getDefaultInstance()).get(); + Iterable expectedMissingDigests = + Iterables.concat(missingDigests, digestAvailableOnImposters); + + assertThat(actualMissingDigests).containsExactlyElementsIn(expectedMissingDigests); for (Digest digest : actualMissingDigests) { assertThat(digest).isNotIn(availableDigests); assertThat(digest).isNotIn(emptyDigests); - assertThat(digest).isIn(missingDigests); - } - for (Digest digest : missingDigests) { - assertThat(digest).isIn(actualMissingDigests); + assertThat(digest).isIn(expectedMissingDigests); } // reset BuildfarmConfigs From e0e7f2ca34ea2b6f9611d4c326e557c5f54dacf0 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Sun, 7 May 2023 20:07:44 -0400 Subject: [PATCH 024/311] Attempt to resolve commit vs expire race --- .../build/buildfarm/cas/cfc/CASFileCache.java | 82 +++++++++++++++++-- 1 file changed, 75 insertions(+), 7 deletions(-) diff --git a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java index 225a4bdcfa..11b6b3ba23 100644 --- a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java +++ b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java @@ -126,6 +126,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import java.util.function.BooleanSupplier; import java.util.function.Consumer; import java.util.function.Supplier; @@ -175,6 +176,19 @@ public abstract class CASFileCache implements ContentAddressableStorage { private final LockMap locks = new LockMap(); @Nullable private final ContentAddressableStorage delegate; private final boolean delegateSkipLoad; + private final LoadingCache keyLocks = + CacheBuilder.newBuilder() + .expireAfterAccess( + 1, MINUTES) // hopefully long enough for any of our file ops to take place and prevent + // collision + .build( + new CacheLoader() { + @Override + public Lock load(String key) { + // should be sufficient for what we're doing + return new ReentrantLock(); + } + }); private final LoadingCache writes = CacheBuilder.newBuilder() .expireAfterAccess(1, HOURS) @@ -1297,7 +1311,7 @@ public StartupCacheResults start( try { casSizeMetric.set(size()); casEntryCountMetric.set(entryCount()); - TimeUnit.MINUTES.sleep(5); + MINUTES.sleep(5); } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; @@ -1605,7 +1619,7 @@ private void joinThreads(ExecutorService pool, String message) throws Interrupte pool.shutdown(); while (!pool.isTerminated()) { log.log(Level.INFO, message); - pool.awaitTermination(1, TimeUnit.MINUTES); + pool.awaitTermination(1, MINUTES); } } @@ -1687,6 +1701,10 @@ public Path getPath(String filename) { return entryPathStrategy.getPath(filename); } + public Path getRemovingPath(String filename) { + return entryPathStrategy.getPath(filename + "_removed"); + } + private synchronized void dischargeAndNotify(long size) { discharge(size); notify(); @@ -1873,6 +1891,55 @@ private static boolean causedByInterrupted(Exception e) { || e instanceof ClosedByInterruptException; } + private Entry safeStorageInsertion(String key, Entry entry) { + Lock lock; + try { + lock = keyLocks.get(key); + } catch (ExecutionException e) { + // impossible without exception instantiating lock + throw new RuntimeException(e); + } + + lock.lock(); + try { + return storage.putIfAbsent(key, entry); + } finally { + lock.unlock(); + } + } + + private Entry safeStorageRemoval(String key) throws IOException { + Path path = getPath(key); + Path expiredPath = getRemovingPath(key); + boolean deleteExpiredPath = false; + + Lock lock; + try { + lock = keyLocks.get(key); + } catch (ExecutionException e) { + // impossible without exception instantiating lock + throw new IOException(e); + } + + lock.lock(); + try { + Files.createLink(expiredPath, path); + deleteExpiredPath = true; + Files.delete(path); + deleteExpiredPath = false; + return storage.remove(key); + } finally { + if (deleteExpiredPath) { + try { + Files.delete(expiredPath); + } catch (IOException e) { + log.log(Level.SEVERE, "error cleaning up after failed safeStorageRemoval", e); + } + } + lock.unlock(); + } + } + @SuppressWarnings("NonAtomicOperationOnVolatileField") @GuardedBy("this") private ListenableFuture expireEntry(long blobSizeInBytes, ExecutorService service) @@ -1894,7 +1961,7 @@ private ListenableFuture expireEntry(long blobSizeInBytes, ExecutorServic } catch (IOException ioEx) { interrupted = causedByInterrupted(ioEx); } - Entry removedEntry = storage.remove(e.key); + Entry removedEntry = safeStorageRemoval(e.key); // reference compare on purpose if (removedEntry == e) { ListenableFuture entryFuture = dischargeEntryFuture(e, service); @@ -2616,10 +2683,11 @@ private CancellableOutputStream putOrReference( } } - private void deleteExpiredKey(Path path) throws IOException { + private void deleteExpiredKey(String key) throws IOException { // We don't want publishing the metric to delay the deletion of the file. // We publish the metric only after the file has been deleted. long createdTime = 0; + Path path = getRemovingPath(key); if (publishTtlMetric) { createdTime = path.toFile().lastModified(); } @@ -2661,8 +2729,7 @@ private boolean charge(String key, long blobSizeInBytes, AtomicBoolean requiresD (expiredEntry) -> { String expiredKey = expiredEntry.key; try { - Path path = getPath(expiredKey); - deleteExpiredKey(path); + deleteExpiredKey(expiredKey); } catch (NoSuchFileException eNoEnt) { log.log( Level.SEVERE, @@ -2876,8 +2943,9 @@ void commit() throws IOException { Entry existingEntry = null; boolean inserted = false; try { + // acquire the key lock Files.createLink(CASFileCache.this.getPath(key), writePath); - existingEntry = storage.putIfAbsent(key, entry); + existingEntry = safeStorageInsertion(key, entry); inserted = existingEntry == null; } catch (FileAlreadyExistsException e) { log.log(Level.FINE, "file already exists for " + key + ", nonexistent entry will fail"); From 8d858261bf8578de60112de183158024257718a2 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Sun, 4 Jun 2023 11:24:09 -0400 Subject: [PATCH 025/311] Exit server on transform token exhaustion When a server cannot acquire a transform token for an extended period of time, assume that it is malfunctioning and initiate a shutdown. --- .../java/build/buildfarm/instance/shard/ShardInstance.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/build/buildfarm/instance/shard/ShardInstance.java b/src/main/java/build/buildfarm/instance/shard/ShardInstance.java index 129741d00e..bc80520bf5 100644 --- a/src/main/java/build/buildfarm/instance/shard/ShardInstance.java +++ b/src/main/java/build/buildfarm/instance/shard/ShardInstance.java @@ -450,8 +450,7 @@ public void onFailure(Throwable t) { public void run() { log.log(Level.FINE, "OperationQueuer: Running"); try { - for (; ; ) { - transformTokensQueue.put(new Object()); + while (transformTokensQueue.offer(new Object(), 5, MINUTES)) { stopwatch.start(); try { iterate() @@ -474,6 +473,7 @@ public void run() { stopwatch.reset(); } } + log.severe("OperationQueuer: Transform lease token timed out"); } catch (InterruptedException e) { // treat with exit operationQueuer = null; From a9936f008d975e0ccb3d1a7bd26e97902b28f080 Mon Sep 17 00:00:00 2001 From: amishra-u <119983081+amishra-u@users.noreply.github.com> Date: Mon, 3 Jul 2023 09:27:32 -0700 Subject: [PATCH 026/311] Fix: custom latency buckets #1376 (#1396) --- src/main/java/build/buildfarm/common/config/GrpcMetrics.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/build/buildfarm/common/config/GrpcMetrics.java b/src/main/java/build/buildfarm/common/config/GrpcMetrics.java index a028035673..8855ae5fdb 100644 --- a/src/main/java/build/buildfarm/common/config/GrpcMetrics.java +++ b/src/main/java/build/buildfarm/common/config/GrpcMetrics.java @@ -27,7 +27,7 @@ public static void handleGrpcMetricIntercepts( // provide custom latency buckets if (grpcMetrics.getLatencyBuckets() != null) { - grpcConfig.withLatencyBuckets(grpcMetrics.getLatencyBuckets()); + grpcConfig = grpcConfig.withLatencyBuckets(grpcMetrics.getLatencyBuckets()); } // Apply config to create an interceptor and apply it to the GRPC server. From f74f270a01397f47409ec0276aaa5c4a611b5c68 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Thu, 6 Jul 2023 12:30:09 -0400 Subject: [PATCH 027/311] Supply a basic retrier to remote cas writes Worker loss can signal cascading failure and shutdown for execute-only peers. Ensure that a ReportResultStage seeing an SRE does not close the stage, and that there are basic retries for remote uploads. --- .../buildfarm/worker/ReportResultStage.java | 3 +- .../worker/shard/RemoteCasWriter.java | 43 +++++++++++++------ .../build/buildfarm/worker/shard/Worker.java | 5 ++- 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/src/main/java/build/buildfarm/worker/ReportResultStage.java b/src/main/java/build/buildfarm/worker/ReportResultStage.java index a3d959dc06..d7bf8eeba2 100644 --- a/src/main/java/build/buildfarm/worker/ReportResultStage.java +++ b/src/main/java/build/buildfarm/worker/ReportResultStage.java @@ -35,6 +35,7 @@ import com.google.rpc.Status; import io.grpc.Deadline; import io.grpc.StatusException; +import io.grpc.StatusRuntimeException; import io.grpc.protobuf.StatusProto; import java.io.IOException; import java.nio.channels.ClosedByInterruptException; @@ -99,7 +100,7 @@ private OperationContext reportPolled(OperationContext operationContext) resultBuilder, operationContext.execDir, operationContext.command); - } catch (StatusException e) { + } catch (StatusException | StatusRuntimeException e) { ExecuteResponse executeResponse = operationContext.executeResponse.build(); if (executeResponse.getStatus().getCode() == Code.OK.getNumber() && executeResponse.getResult().getExitCode() == 0) { diff --git a/src/main/java/build/buildfarm/worker/shard/RemoteCasWriter.java b/src/main/java/build/buildfarm/worker/shard/RemoteCasWriter.java index 1ec624dcb4..c7b21bbd0b 100644 --- a/src/main/java/build/buildfarm/worker/shard/RemoteCasWriter.java +++ b/src/main/java/build/buildfarm/worker/shard/RemoteCasWriter.java @@ -23,6 +23,8 @@ import build.bazel.remote.execution.v2.RequestMetadata; import build.buildfarm.common.Size; import build.buildfarm.common.Write; +import build.buildfarm.common.grpc.Retrier; +import build.buildfarm.common.grpc.RetryException; import build.buildfarm.common.io.FeedbackOutputStream; import build.buildfarm.instance.Instance; import com.google.common.base.Throwables; @@ -46,12 +48,15 @@ @Log public class RemoteCasWriter implements CasWriter { - private Set workerSet; - private LoadingCache workerStubs; + private final Set workerSet; + private final LoadingCache workerStubs; + private final Retrier retrier; - public RemoteCasWriter(Set workerSet, LoadingCache workerStubs) { + public RemoteCasWriter( + Set workerSet, LoadingCache workerStubs, Retrier retrier) { this.workerSet = workerSet; this.workerStubs = workerStubs; + this.retrier = retrier; } public void write(Digest digest, Path file) throws IOException, InterruptedException { @@ -63,19 +68,30 @@ public void write(Digest digest, Path file) throws IOException, InterruptedExcep private void insertFileToCasMember(Digest digest, Path file) throws IOException, InterruptedException { try (InputStream in = Files.newInputStream(file)) { - writeToCasMember(digest, in); - } catch (ExecutionException e) { - throw new IOException(Status.RESOURCE_EXHAUSTED.withCause(e).asRuntimeException()); + retrier.execute(() -> writeToCasMember(digest, in)); + } catch (RetryException e) { + Throwable cause = e.getCause(); + Throwables.throwIfInstanceOf(cause, IOException.class); + Throwables.throwIfUnchecked(cause); + throw new RuntimeException(cause); } } - private void writeToCasMember(Digest digest, InputStream in) - throws IOException, InterruptedException, ExecutionException { + private long writeToCasMember(Digest digest, InputStream in) + throws IOException, InterruptedException { // create a write for inserting into another CAS member. String workerName = getRandomWorker(); Write write = getCasMemberWrite(digest, workerName); - streamIntoWriteFuture(in, write, digest).get(); + try { + return streamIntoWriteFuture(in, write, digest).get(); + } catch (ExecutionException e) { + Throwable cause = e.getCause(); + Throwables.throwIfInstanceOf(cause, IOException.class); + // prevent a discard of this frame + Status status = Status.fromThrowable(cause); + throw status.asRuntimeException(); + } } private Write getCasMemberWrite(Digest digest, String workerName) throws IOException { @@ -93,13 +109,12 @@ public void insertBlob(Digest digest, ByteString content) private void insertBlobToCasMember(Digest digest, ByteString content) throws IOException, InterruptedException { try (InputStream in = content.newInput()) { - writeToCasMember(digest, in); - } catch (ExecutionException e) { + retrier.execute(() -> writeToCasMember(digest, in)); + } catch (RetryException e) { Throwable cause = e.getCause(); - Throwables.throwIfUnchecked(cause); Throwables.throwIfInstanceOf(cause, IOException.class); - Status status = Status.fromThrowable(cause); - throw new IOException(status.asException()); + Throwables.throwIfUnchecked(cause); + throw new RuntimeException(cause); } } diff --git a/src/main/java/build/buildfarm/worker/shard/Worker.java b/src/main/java/build/buildfarm/worker/shard/Worker.java index e1b0919fda..da698726de 100644 --- a/src/main/java/build/buildfarm/worker/shard/Worker.java +++ b/src/main/java/build/buildfarm/worker/shard/Worker.java @@ -39,6 +39,8 @@ import build.buildfarm.common.config.BuildfarmConfigs; import build.buildfarm.common.config.Cas; import build.buildfarm.common.config.GrpcMetrics; +import build.buildfarm.common.grpc.Retrier; +import build.buildfarm.common.grpc.Retrier.Backoff; import build.buildfarm.common.services.ByteStreamService; import build.buildfarm.common.services.ContentAddressableStorageService; import build.buildfarm.instance.Instance; @@ -577,7 +579,8 @@ public void start() throws ConfigurationException, InterruptedException, IOExcep // Create the appropriate writer for the context CasWriter writer; if (!configs.getWorker().getCapabilities().isCas()) { - writer = new RemoteCasWriter(backplane.getStorageWorkers(), workerStubs); + Retrier retrier = new Retrier(Backoff.sequential(5), Retrier.DEFAULT_IS_RETRIABLE); + writer = new RemoteCasWriter(backplane.getStorageWorkers(), workerStubs, retrier); } else { writer = new LocalCasWriter(execFileSystem); } From f7eb74aa55db6158a87c5eb8cfc1c2c51082adfa Mon Sep 17 00:00:00 2001 From: George Gensure Date: Wed, 12 Jul 2023 12:12:08 -0400 Subject: [PATCH 028/311] Update buildfarm-indexer for upstream updates Works with current redis-py-cluster 2.1.3 --- tools/buildfarm-indexer.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/tools/buildfarm-indexer.py b/tools/buildfarm-indexer.py index 824763dd21..b020cb91d5 100755 --- a/tools/buildfarm-indexer.py +++ b/tools/buildfarm-indexer.py @@ -1,5 +1,5 @@ from redis.client import Pipeline -from rediscluster import StrictRedisCluster +from rediscluster import RedisCluster import sys def get_cas_page(r, cursor, count): @@ -15,7 +15,7 @@ def get_cas_page(r, cursor, count): print ("usage: buildfarm-indexer.py ") sys.exit(1) -r = StrictRedisCluster(startup_nodes=[{"host": redis_host, "port": 6379}], skip_full_coverage_check=True) +r = RedisCluster(startup_nodes=[{"host": redis_host, "port": 6379}], skip_full_coverage_check=True) nodes = r.connection_pool.nodes @@ -30,14 +30,15 @@ def get_cas_page(r, cursor, count): slots.remove(slot) node_keys[slot] = str(node_key) -workers = r.hkeys("Workers") +# config f"{backplane.workersHashName}_storage" +workers = r.hkeys("Workers_storage") worker_count = len(workers) print ("%d workers" % worker_count) p = r.pipeline() -for node_key in node_keys.viewvalues(): +for node_key in node_keys.values(): p.delete("{%s}:intersecting-workers" % node_key) p.sadd("{%s}:intersecting-workers" % node_key, *workers) p.execute() @@ -101,8 +102,9 @@ def process(self, cas_names, conn): count = len(cas_names) p = self.pipeline(conn) for i in range(count): - name = cas_names[i] - node_key = node_keys[nodes.keyslot(str(name))] + name = cas_names[i].decode() + keyslot = nodes.keyslot(name) + node_key = node_keys[keyslot] set_key = "{%s}:intersecting-workers" % node_key p.sinterstore(name, set_key, name) p.execute() @@ -116,8 +118,8 @@ def process(self, cas_names, conn): map_cas_page(r, 10000, indexer.process) p = r.pipeline() -for node_key in node_keys.viewvalues(): +for node_key in node_keys.values(): p.delete("{%s}:intersecting-workers" % node_key) p.execute() -print("\n%d processed" % (indexer.processed)) \ No newline at end of file +print("\n%d processed" % (indexer.processed)) From f893b5a270b1e98890bdf572adbce219bca8b3d0 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Wed, 12 Jul 2023 13:34:03 -0400 Subject: [PATCH 029/311] Commonize grpc createChannel with TLS selection --- .../build/buildfarm/admin/aws/AwsAdmin.java | 8 ++-- src/main/java/build/buildfarm/admin/aws/BUILD | 2 +- src/main/java/build/buildfarm/cas/BUILD | 1 - .../cas/ContentAddressableStorages.java | 9 +---- .../java/build/buildfarm/common/grpc/BUILD | 1 + .../build/buildfarm/common/grpc/Channels.java | 40 +++++++++++++++++++ .../build/buildfarm/common/services/BUILD | 1 - .../build/buildfarm/instance/server/BUILD | 1 - .../java/build/buildfarm/instance/shard/BUILD | 1 - .../buildfarm/instance/shard/WorkerStubs.java | 10 +---- .../java/build/buildfarm/instance/stub/BUILD | 1 - .../build/buildfarm/operations/finder/BUILD | 1 - .../server/services/AdminService.java | 8 ++-- .../build/buildfarm/server/services/BUILD | 1 - src/main/java/build/buildfarm/tools/Ac.java | 10 +---- src/main/java/build/buildfarm/tools/BUILD | 22 +++++----- .../java/build/buildfarm/tools/Cancel.java | 10 +---- src/main/java/build/buildfarm/tools/Cat.java | 9 +---- .../java/build/buildfarm/tools/Executor.java | 9 +---- .../java/build/buildfarm/tools/Extract.java | 9 +---- .../build/buildfarm/tools/FindOperations.java | 10 +---- .../buildfarm/tools/GracefulShutdownTest.java | 10 +---- src/main/java/build/buildfarm/tools/Hist.java | 10 +---- .../build/buildfarm/tools/IndexWorker.java | 10 +---- .../java/build/buildfarm/tools/Mount.java | 9 +---- .../build/buildfarm/tools/WorkerProfile.java | 11 +---- src/main/java/build/buildfarm/worker/BUILD | 1 - .../java/build/buildfarm/worker/shard/BUILD | 1 - 28 files changed, 78 insertions(+), 138 deletions(-) create mode 100644 src/main/java/build/buildfarm/common/grpc/Channels.java diff --git a/src/main/java/build/buildfarm/admin/aws/AwsAdmin.java b/src/main/java/build/buildfarm/admin/aws/AwsAdmin.java index 5b971405cd..ebb3746b63 100644 --- a/src/main/java/build/buildfarm/admin/aws/AwsAdmin.java +++ b/src/main/java/build/buildfarm/admin/aws/AwsAdmin.java @@ -14,6 +14,8 @@ package build.buildfarm.admin.aws; +import static build.buildfarm.common.grpc.Channels.createChannel; + import build.buildfarm.admin.Admin; import build.buildfarm.common.config.BuildfarmConfigs; import build.buildfarm.v1test.AdminGrpc; @@ -41,8 +43,6 @@ import com.amazonaws.services.simplesystemsmanagement.model.SendCommandRequest; import com.google.protobuf.util.Timestamps; import io.grpc.ManagedChannel; -import io.grpc.netty.NegotiationType; -import io.grpc.netty.NettyChannelBuilder; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; @@ -206,9 +206,7 @@ public void disableHostScaleInProtection(String privateDnsName) { public void disableHostScaleInProtection(String clusterEndpoint, String instanceIp) { ManagedChannel channel = null; try { - NettyChannelBuilder builder = - NettyChannelBuilder.forTarget(clusterEndpoint).negotiationType(NegotiationType.PLAINTEXT); - channel = builder.build(); + channel = createChannel(clusterEndpoint); AdminGrpc.AdminBlockingStub adminBlockingStub = AdminGrpc.newBlockingStub(channel); adminBlockingStub.disableScaleInProtection( DisableScaleInProtectionRequest.newBuilder().setInstanceName(instanceIp).build()); diff --git a/src/main/java/build/buildfarm/admin/aws/BUILD b/src/main/java/build/buildfarm/admin/aws/BUILD index ea544e0b68..a49e431bfd 100644 --- a/src/main/java/build/buildfarm/admin/aws/BUILD +++ b/src/main/java/build/buildfarm/admin/aws/BUILD @@ -6,6 +6,7 @@ java_library( deps = [ "//src/main/java/build/buildfarm/admin", "//src/main/java/build/buildfarm/common/config", + "//src/main/java/build/buildfarm/common/grpc", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_grpc", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "@googleapis//:google_rpc_code_java_proto", @@ -19,7 +20,6 @@ java_library( "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:io_grpc_grpc_api", - "@maven//:io_grpc_grpc_netty", "@maven//:org_projectlombok_lombok", "@maven//:org_springframework_spring_beans", "@maven//:org_springframework_spring_context", diff --git a/src/main/java/build/buildfarm/cas/BUILD b/src/main/java/build/buildfarm/cas/BUILD index 301e922e13..146206caee 100644 --- a/src/main/java/build/buildfarm/cas/BUILD +++ b/src/main/java/build/buildfarm/cas/BUILD @@ -25,7 +25,6 @@ java_library( "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_context", "@maven//:io_grpc_grpc_core", - "@maven//:io_grpc_grpc_netty", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", "@maven//:io_prometheus_simpleclient", diff --git a/src/main/java/build/buildfarm/cas/ContentAddressableStorages.java b/src/main/java/build/buildfarm/cas/ContentAddressableStorages.java index ade381ff50..e1df38fae4 100644 --- a/src/main/java/build/buildfarm/cas/ContentAddressableStorages.java +++ b/src/main/java/build/buildfarm/cas/ContentAddressableStorages.java @@ -14,6 +14,7 @@ package build.buildfarm.cas; +import static build.buildfarm.common.grpc.Channels.createChannel; import static build.buildfarm.common.grpc.Retrier.NO_RETRIES; import static com.google.common.collect.Multimaps.synchronizedListMultimap; import static com.google.common.util.concurrent.MoreExecutors.directExecutor; @@ -29,8 +30,6 @@ import com.google.common.collect.ListMultimap; import com.google.common.collect.MultimapBuilder; import io.grpc.Channel; -import io.grpc.netty.NegotiationType; -import io.grpc.netty.NettyChannelBuilder; import java.io.IOException; import java.io.InputStream; import java.nio.file.NoSuchFileException; @@ -40,12 +39,6 @@ public final class ContentAddressableStorages { private static BuildfarmConfigs configs = BuildfarmConfigs.getInstance(); - private static Channel createChannel(String target) { - NettyChannelBuilder builder = - NettyChannelBuilder.forTarget(target).negotiationType(NegotiationType.PLAINTEXT); - return builder.build(); - } - public static ContentAddressableStorage createGrpcCAS(Cas cas) { Channel channel = createChannel(cas.getTarget()); ByteStreamUploader byteStreamUploader = diff --git a/src/main/java/build/buildfarm/common/grpc/BUILD b/src/main/java/build/buildfarm/common/grpc/BUILD index 7bff874ad8..af68ba7d63 100644 --- a/src/main/java/build/buildfarm/common/grpc/BUILD +++ b/src/main/java/build/buildfarm/common/grpc/BUILD @@ -13,6 +13,7 @@ java_library( "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_context", "@maven//:io_grpc_grpc_core", + "@maven//:io_grpc_grpc_netty", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", "@maven//:org_projectlombok_lombok", diff --git a/src/main/java/build/buildfarm/common/grpc/Channels.java b/src/main/java/build/buildfarm/common/grpc/Channels.java new file mode 100644 index 0000000000..0531218f23 --- /dev/null +++ b/src/main/java/build/buildfarm/common/grpc/Channels.java @@ -0,0 +1,40 @@ +// Copyright 2023 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package build.buildfarm.common.grpc; + +import io.grpc.ManagedChannel; +import io.grpc.netty.NegotiationType; +import io.grpc.netty.NettyChannelBuilder; + +public final class Channels { + private static final String GRPCS_URL_PREFIX = "grpcs://"; + private static final String GRPC_URL_PREFIX = "grpc://"; + + private Channels() {} + + public static ManagedChannel createChannel(String target) { + NegotiationType negotiationType = NegotiationType.PLAINTEXT; + if (target.startsWith(GRPCS_URL_PREFIX)) { + target = target.substring(GRPCS_URL_PREFIX.length()); + negotiationType = NegotiationType.TLS; + } else if (target.startsWith(GRPC_URL_PREFIX)) { + target = target.substring(GRPC_URL_PREFIX.length()); + negotiationType = NegotiationType.PLAINTEXT; + } + NettyChannelBuilder builder = + NettyChannelBuilder.forTarget(target).negotiationType(negotiationType); + return builder.build(); + } +} diff --git a/src/main/java/build/buildfarm/common/services/BUILD b/src/main/java/build/buildfarm/common/services/BUILD index f2f643001e..9a885cbafe 100644 --- a/src/main/java/build/buildfarm/common/services/BUILD +++ b/src/main/java/build/buildfarm/common/services/BUILD @@ -23,7 +23,6 @@ java_library( "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_context", "@maven//:io_grpc_grpc_core", - "@maven//:io_grpc_grpc_netty", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_services", "@maven//:io_grpc_grpc_stub", diff --git a/src/main/java/build/buildfarm/instance/server/BUILD b/src/main/java/build/buildfarm/instance/server/BUILD index 601519c867..ecff968e79 100644 --- a/src/main/java/build/buildfarm/instance/server/BUILD +++ b/src/main/java/build/buildfarm/instance/server/BUILD @@ -27,7 +27,6 @@ java_library( "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_context", "@maven//:io_grpc_grpc_core", - "@maven//:io_grpc_grpc_netty", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", "@maven//:io_netty_netty_codec_http", diff --git a/src/main/java/build/buildfarm/instance/shard/BUILD b/src/main/java/build/buildfarm/instance/shard/BUILD index 9b11f1543e..38e6992aae 100644 --- a/src/main/java/build/buildfarm/instance/shard/BUILD +++ b/src/main/java/build/buildfarm/instance/shard/BUILD @@ -28,7 +28,6 @@ java_library( "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_context", "@maven//:io_grpc_grpc_core", - "@maven//:io_grpc_grpc_netty", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", "@maven//:io_prometheus_simpleclient", diff --git a/src/main/java/build/buildfarm/instance/shard/WorkerStubs.java b/src/main/java/build/buildfarm/instance/shard/WorkerStubs.java index 28a29afd7f..e0015f6fc4 100644 --- a/src/main/java/build/buildfarm/instance/shard/WorkerStubs.java +++ b/src/main/java/build/buildfarm/instance/shard/WorkerStubs.java @@ -14,6 +14,7 @@ package build.buildfarm.instance.shard; +import static build.buildfarm.common.grpc.Channels.createChannel; import static com.google.common.util.concurrent.MoreExecutors.listeningDecorator; import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor; @@ -28,9 +29,6 @@ import com.google.common.cache.RemovalListener; import com.google.common.util.concurrent.ListeningScheduledExecutorService; import com.google.protobuf.Duration; -import io.grpc.ManagedChannel; -import io.grpc.netty.NegotiationType; -import io.grpc.netty.NettyChannelBuilder; import java.util.concurrent.TimeUnit; public final class WorkerStubs { @@ -64,12 +62,6 @@ private static Instance newStubInstance(String worker, DigestUtil digestUtil, Du newStubRetryService()); } - private static ManagedChannel createChannel(String target) { - NettyChannelBuilder builder = - NettyChannelBuilder.forTarget(target).negotiationType(NegotiationType.PLAINTEXT); - return builder.build(); - } - private static Retrier newStubRetrier() { return new Retrier( Backoff.exponential( diff --git a/src/main/java/build/buildfarm/instance/stub/BUILD b/src/main/java/build/buildfarm/instance/stub/BUILD index c8b2b82e77..1f5a2b916d 100644 --- a/src/main/java/build/buildfarm/instance/stub/BUILD +++ b/src/main/java/build/buildfarm/instance/stub/BUILD @@ -23,7 +23,6 @@ java_library( "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_context", "@maven//:io_grpc_grpc_core", - "@maven//:io_grpc_grpc_netty", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", "@maven//:org_projectlombok_lombok", diff --git a/src/main/java/build/buildfarm/operations/finder/BUILD b/src/main/java/build/buildfarm/operations/finder/BUILD index 5c8342609b..8b6a2cc557 100644 --- a/src/main/java/build/buildfarm/operations/finder/BUILD +++ b/src/main/java/build/buildfarm/operations/finder/BUILD @@ -22,7 +22,6 @@ java_library( "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_context", "@maven//:io_grpc_grpc_core", - "@maven//:io_grpc_grpc_netty", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", "@maven//:org_apache_commons_commons_pool2", diff --git a/src/main/java/build/buildfarm/server/services/AdminService.java b/src/main/java/build/buildfarm/server/services/AdminService.java index 968edc1572..94178fbf27 100644 --- a/src/main/java/build/buildfarm/server/services/AdminService.java +++ b/src/main/java/build/buildfarm/server/services/AdminService.java @@ -14,6 +14,8 @@ package build.buildfarm.server.services; +import static build.buildfarm.common.grpc.Channels.createChannel; + import build.buildfarm.admin.Admin; import build.buildfarm.admin.aws.AwsAdmin; import build.buildfarm.admin.gcp.GcpAdmin; @@ -39,8 +41,6 @@ import com.google.rpc.Code; import com.google.rpc.Status; import io.grpc.ManagedChannel; -import io.grpc.netty.NegotiationType; -import io.grpc.netty.NettyChannelBuilder; import io.grpc.stub.StreamObserver; import java.util.logging.Level; import lombok.extern.java.Log; @@ -191,9 +191,7 @@ public void shutDownWorkerGracefully( private void informWorkerToPrepareForShutdown(String host) { ManagedChannel channel = null; try { - NettyChannelBuilder builder = - NettyChannelBuilder.forTarget(host).negotiationType(NegotiationType.PLAINTEXT); - channel = builder.build(); + channel = createChannel(host); ShutDownWorkerGrpc.ShutDownWorkerBlockingStub shutDownWorkerBlockingStub = ShutDownWorkerGrpc.newBlockingStub(channel); shutDownWorkerBlockingStub.prepareWorkerForGracefulShutdown( diff --git a/src/main/java/build/buildfarm/server/services/BUILD b/src/main/java/build/buildfarm/server/services/BUILD index aff642ed7a..54b7af993c 100644 --- a/src/main/java/build/buildfarm/server/services/BUILD +++ b/src/main/java/build/buildfarm/server/services/BUILD @@ -30,7 +30,6 @@ java_library( "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_context", "@maven//:io_grpc_grpc_core", - "@maven//:io_grpc_grpc_netty", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_services", "@maven//:io_grpc_grpc_stub", diff --git a/src/main/java/build/buildfarm/tools/Ac.java b/src/main/java/build/buildfarm/tools/Ac.java index adfca598ff..9515fe0ec4 100644 --- a/src/main/java/build/buildfarm/tools/Ac.java +++ b/src/main/java/build/buildfarm/tools/Ac.java @@ -14,6 +14,8 @@ package build.buildfarm.tools; +import static build.buildfarm.common.grpc.Channels.createChannel; + import build.bazel.remote.execution.v2.ActionResult; import build.buildfarm.common.DigestUtil; import build.buildfarm.common.DigestUtil.HashFunction; @@ -21,18 +23,10 @@ import build.buildfarm.instance.stub.StubInstance; import com.google.protobuf.ByteString; import io.grpc.ManagedChannel; -import io.grpc.netty.NegotiationType; -import io.grpc.netty.NettyChannelBuilder; // This tool can be used to interact directly with the Action Cache API. // ./tool shard SHA256 class Ac { - private static ManagedChannel createChannel(String target) { - NettyChannelBuilder builder = - NettyChannelBuilder.forTarget(target).negotiationType(NegotiationType.PLAINTEXT); - return builder.build(); - } - public static void main(String[] args) throws Exception { // get arguments for establishing an instance String host = args[0]; diff --git a/src/main/java/build/buildfarm/tools/BUILD b/src/main/java/build/buildfarm/tools/BUILD index c2f9d94ece..37c6bdb58a 100644 --- a/src/main/java/build/buildfarm/tools/BUILD +++ b/src/main/java/build/buildfarm/tools/BUILD @@ -5,6 +5,7 @@ java_binary( visibility = ["//visibility:public"], deps = [ "//src/main/java/build/buildfarm/common", + "//src/main/java/build/buildfarm/common/grpc", "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/instance/stub", "//src/main/java/build/buildfarm/worker", @@ -15,7 +16,6 @@ java_binary( "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_context", "@maven//:io_grpc_grpc_core", - "@maven//:io_grpc_grpc_netty", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", ], @@ -57,6 +57,7 @@ java_binary( visibility = ["//visibility:public"], deps = [ "//src/main/java/build/buildfarm/common", + "//src/main/java/build/buildfarm/common/grpc", "//src/main/java/build/buildfarm/instance/stub", "@googleapis//:google_bytestream_bytestream_java_grpc", "@googleapis//:google_bytestream_bytestream_java_proto", @@ -67,7 +68,6 @@ java_binary( "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_context", "@maven//:io_grpc_grpc_core", - "@maven//:io_grpc_grpc_netty", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_grpc", @@ -90,7 +90,6 @@ java_binary( "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_context", "@maven//:io_grpc_grpc_core", - "@maven//:io_grpc_grpc_netty", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", @@ -108,6 +107,7 @@ java_binary( deps = [ ":worker-profiler-printer", "//src/main/java/build/buildfarm/common", + "//src/main/java/build/buildfarm/common/grpc", "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/instance/stub", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", @@ -119,7 +119,6 @@ java_binary( "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_context", "@maven//:io_grpc_grpc_core", - "@maven//:io_grpc_grpc_netty", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", ], @@ -137,6 +136,7 @@ java_binary( ":worker-profiler-printer", "//src/main/java/build/buildfarm/common", "//src/main/java/build/buildfarm/common/config", + "//src/main/java/build/buildfarm/common/grpc", "//src/main/java/build/buildfarm/common/redis", "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/instance/shard", @@ -151,7 +151,6 @@ java_binary( "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_context", "@maven//:io_grpc_grpc_core", - "@maven//:io_grpc_grpc_netty", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", ], @@ -168,6 +167,7 @@ java_binary( deps = [ ":worker-profiler-printer", "//src/main/java/build/buildfarm/common", + "//src/main/java/build/buildfarm/common/grpc", "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/instance/stub", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", @@ -179,7 +179,6 @@ java_binary( "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_context", "@maven//:io_grpc_grpc_core", - "@maven//:io_grpc_grpc_netty", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", ], @@ -191,10 +190,10 @@ java_binary( main_class = "build.buildfarm.tools.GracefulShutdownTest", visibility = ["//visibility:public"], deps = [ + "//src/main/java/build/buildfarm/common/grpc", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_grpc", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "@maven//:io_grpc_grpc_api", - "@maven//:io_grpc_grpc_netty", ], ) @@ -205,6 +204,7 @@ java_binary( visibility = ["//visibility:public"], deps = [ "//src/main/java/build/buildfarm/common", + "//src/main/java/build/buildfarm/common/grpc", "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/instance/stub", "@googleapis//:google_longrunning_operations_java_proto", @@ -214,7 +214,6 @@ java_binary( "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_context", "@maven//:io_grpc_grpc_core", - "@maven//:io_grpc_grpc_netty", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", @@ -228,6 +227,7 @@ java_binary( visibility = ["//visibility:public"], deps = [ "//src/main/java/build/buildfarm/common", + "//src/main/java/build/buildfarm/common/grpc", "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/instance/stub", "@googleapis//:google_longrunning_operations_java_proto", @@ -237,7 +237,6 @@ java_binary( "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_context", "@maven//:io_grpc_grpc_core", - "@maven//:io_grpc_grpc_netty", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", @@ -251,6 +250,7 @@ java_binary( visibility = ["//visibility:public"], deps = [ "//src/main/java/build/buildfarm/common", + "//src/main/java/build/buildfarm/common/grpc", "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/instance/stub", "@googleapis//:google_longrunning_operations_java_proto", @@ -260,7 +260,6 @@ java_binary( "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_context", "@maven//:io_grpc_grpc_core", - "@maven//:io_grpc_grpc_netty", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", @@ -281,12 +280,12 @@ java_binary( visibility = ["//visibility:public"], deps = [ "//src/main/java/build/buildfarm/common", + "//src/main/java/build/buildfarm/common/grpc", "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/instance/stub", "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_context", "@maven//:io_grpc_grpc_core", - "@maven//:io_grpc_grpc_netty", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", ], @@ -313,7 +312,6 @@ java_library( "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_context", "@maven//:io_grpc_grpc_core", - "@maven//:io_grpc_grpc_netty", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", ], diff --git a/src/main/java/build/buildfarm/tools/Cancel.java b/src/main/java/build/buildfarm/tools/Cancel.java index 5945df708e..24805034dc 100644 --- a/src/main/java/build/buildfarm/tools/Cancel.java +++ b/src/main/java/build/buildfarm/tools/Cancel.java @@ -14,20 +14,14 @@ package build.buildfarm.tools; +import static build.buildfarm.common.grpc.Channels.createChannel; + import build.buildfarm.common.DigestUtil; import build.buildfarm.instance.Instance; import build.buildfarm.instance.stub.StubInstance; import io.grpc.ManagedChannel; -import io.grpc.netty.NegotiationType; -import io.grpc.netty.NettyChannelBuilder; class Cancel { - private static ManagedChannel createChannel(String target) { - NettyChannelBuilder builder = - NettyChannelBuilder.forTarget(target).negotiationType(NegotiationType.PLAINTEXT); - return builder.build(); - } - public static void main(String[] args) throws Exception { String host = args[0]; String instanceName = args[1]; diff --git a/src/main/java/build/buildfarm/tools/Cat.java b/src/main/java/build/buildfarm/tools/Cat.java index 399ca7f1fb..7c8e561454 100644 --- a/src/main/java/build/buildfarm/tools/Cat.java +++ b/src/main/java/build/buildfarm/tools/Cat.java @@ -14,6 +14,7 @@ package build.buildfarm.tools; +import static build.buildfarm.common.grpc.Channels.createChannel; import static build.buildfarm.instance.Utils.getBlob; import static com.google.common.util.concurrent.MoreExecutors.shutdownAndAwaitTermination; import static java.lang.String.format; @@ -68,8 +69,6 @@ import io.grpc.Context; import io.grpc.ManagedChannel; import io.grpc.Status; -import io.grpc.netty.NegotiationType; -import io.grpc.netty.NettyChannelBuilder; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -86,12 +85,6 @@ import java.util.stream.StreamSupport; class Cat { - private static ManagedChannel createChannel(String target) { - NettyChannelBuilder builder = - NettyChannelBuilder.forTarget(target).negotiationType(NegotiationType.PLAINTEXT); - return builder.build(); - } - private static void printCapabilities(ServerCapabilities capabilities) { System.out.println(capabilities); } diff --git a/src/main/java/build/buildfarm/tools/Executor.java b/src/main/java/build/buildfarm/tools/Executor.java index 77ca4002c1..4f2f9f3d6f 100644 --- a/src/main/java/build/buildfarm/tools/Executor.java +++ b/src/main/java/build/buildfarm/tools/Executor.java @@ -15,6 +15,7 @@ package build.buildfarm.tools; import static build.bazel.remote.execution.v2.ExecutionStage.Value.EXECUTING; +import static build.buildfarm.common.grpc.Channels.createChannel; import static build.buildfarm.common.io.Utils.stat; import static build.buildfarm.instance.stub.ByteStreamUploader.uploadResourceName; import static com.google.common.base.Preconditions.checkState; @@ -53,8 +54,6 @@ import com.google.rpc.Code; import io.grpc.Channel; import io.grpc.ManagedChannel; -import io.grpc.netty.NegotiationType; -import io.grpc.netty.NettyChannelBuilder; import io.grpc.stub.StreamObserver; import java.io.IOException; import java.io.InputStream; @@ -223,12 +222,6 @@ static void executeActions( shutdownAndAwaitTermination(service, 1, SECONDS); } - private static ManagedChannel createChannel(String target) { - NettyChannelBuilder builder = - NettyChannelBuilder.forTarget(target).negotiationType(NegotiationType.PLAINTEXT); - return builder.build(); - } - private static void loadFilesIntoCAS(String instanceName, Channel channel, Path blobsDir) throws Exception { ContentAddressableStorageBlockingStub casStub = diff --git a/src/main/java/build/buildfarm/tools/Extract.java b/src/main/java/build/buildfarm/tools/Extract.java index e4de193ae2..fed81ac267 100644 --- a/src/main/java/build/buildfarm/tools/Extract.java +++ b/src/main/java/build/buildfarm/tools/Extract.java @@ -14,6 +14,7 @@ package build.buildfarm.tools; +import static build.buildfarm.common.grpc.Channels.createChannel; import static com.google.common.util.concurrent.MoreExecutors.listeningDecorator; import static java.util.concurrent.Executors.newSingleThreadExecutor; import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor; @@ -41,8 +42,6 @@ import io.grpc.ManagedChannel; import io.grpc.Status; import io.grpc.Status.Code; -import io.grpc.netty.NegotiationType; -import io.grpc.netty.NettyChannelBuilder; import io.grpc.stub.StreamObserver; import java.io.IOException; import java.io.InputStream; @@ -61,12 +60,6 @@ import java.util.concurrent.atomic.AtomicLong; class Extract { - static ManagedChannel createChannel(String target) { - NettyChannelBuilder builder = - NettyChannelBuilder.forTarget(target).negotiationType(NegotiationType.PLAINTEXT); - return builder.build(); - } - public static void main(String[] args) throws Exception { String host = args[0]; String instanceName = args[1]; diff --git a/src/main/java/build/buildfarm/tools/FindOperations.java b/src/main/java/build/buildfarm/tools/FindOperations.java index c858f121f6..f1d8494dff 100644 --- a/src/main/java/build/buildfarm/tools/FindOperations.java +++ b/src/main/java/build/buildfarm/tools/FindOperations.java @@ -14,14 +14,14 @@ package build.buildfarm.tools; +import static build.buildfarm.common.grpc.Channels.createChannel; + import build.buildfarm.common.DigestUtil; import build.buildfarm.instance.Instance; import build.buildfarm.instance.stub.StubInstance; import com.google.common.collect.ImmutableList; import com.google.longrunning.Operation; import io.grpc.ManagedChannel; -import io.grpc.netty.NegotiationType; -import io.grpc.netty.NettyChannelBuilder; // This tool can be used to find Operations based on their particular properties. // For example, it could find all of the operations executed by a particular user or particular @@ -29,12 +29,6 @@ // ./tool shard SHA256 // The operations that match the query will be printed. class FindOperations { - private static ManagedChannel createChannel(String target) { - NettyChannelBuilder builder = - NettyChannelBuilder.forTarget(target).negotiationType(NegotiationType.PLAINTEXT); - return builder.build(); - } - public static void main(String[] args) throws Exception { // get arguments for establishing an instance String host = args[0]; diff --git a/src/main/java/build/buildfarm/tools/GracefulShutdownTest.java b/src/main/java/build/buildfarm/tools/GracefulShutdownTest.java index f98cddbde4..85ae5ab78d 100644 --- a/src/main/java/build/buildfarm/tools/GracefulShutdownTest.java +++ b/src/main/java/build/buildfarm/tools/GracefulShutdownTest.java @@ -14,22 +14,16 @@ package build.buildfarm.tools; +import static build.buildfarm.common.grpc.Channels.createChannel; + import build.buildfarm.v1test.AdminGrpc; import build.buildfarm.v1test.DisableScaleInProtectionRequest; import build.buildfarm.v1test.PrepareWorkerForGracefulShutDownRequest; import build.buildfarm.v1test.ShutDownWorkerGracefullyRequest; import build.buildfarm.v1test.ShutDownWorkerGrpc; import io.grpc.ManagedChannel; -import io.grpc.netty.NegotiationType; -import io.grpc.netty.NettyChannelBuilder; class GracefulShutdownTest { - private static ManagedChannel createChannel(String target) { - NettyChannelBuilder builder = - NettyChannelBuilder.forTarget(target).negotiationType(NegotiationType.PLAINTEXT); - return builder.build(); - } - /** * Example command: GracefulShutdownTest ShutDown workerIp buildfarm-endpoint * diff --git a/src/main/java/build/buildfarm/tools/Hist.java b/src/main/java/build/buildfarm/tools/Hist.java index c8ec6c2bfa..2abdf55f7d 100644 --- a/src/main/java/build/buildfarm/tools/Hist.java +++ b/src/main/java/build/buildfarm/tools/Hist.java @@ -14,6 +14,8 @@ package build.buildfarm.tools; +import static build.buildfarm.common.grpc.Channels.createChannel; + import build.bazel.remote.execution.v2.ExecuteOperationMetadata; import build.bazel.remote.execution.v2.ExecutionStage; import build.buildfarm.common.DigestUtil; @@ -23,16 +25,8 @@ import com.google.longrunning.Operation; import com.google.protobuf.InvalidProtocolBufferException; import io.grpc.ManagedChannel; -import io.grpc.netty.NegotiationType; -import io.grpc.netty.NettyChannelBuilder; class Hist { - private static ManagedChannel createChannel(String target) { - NettyChannelBuilder builder = - NettyChannelBuilder.forTarget(target).negotiationType(NegotiationType.PLAINTEXT); - return builder.build(); - } - @SuppressWarnings("ConstantConditions") private static void printHistogramValue(int executing) { StringBuilder s = new StringBuilder(); diff --git a/src/main/java/build/buildfarm/tools/IndexWorker.java b/src/main/java/build/buildfarm/tools/IndexWorker.java index a36e3f9217..317a5ff637 100644 --- a/src/main/java/build/buildfarm/tools/IndexWorker.java +++ b/src/main/java/build/buildfarm/tools/IndexWorker.java @@ -14,25 +14,19 @@ package build.buildfarm.tools; +import static build.buildfarm.common.grpc.Channels.createChannel; + import build.buildfarm.common.CasIndexResults; import build.buildfarm.common.DigestUtil; import build.buildfarm.instance.Instance; import build.buildfarm.instance.stub.StubInstance; import io.grpc.ManagedChannel; -import io.grpc.netty.NegotiationType; -import io.grpc.netty.NettyChannelBuilder; // This tool can be used to remove worker entries from the CAS. // This is usually done via the admin service when a worker is departing from the cluster. // ./tool shard SHA256 // The results of the removal are printed after the CAS entries have been removed. class IndexWorker { - private static ManagedChannel createChannel(String target) { - NettyChannelBuilder builder = - NettyChannelBuilder.forTarget(target).negotiationType(NegotiationType.PLAINTEXT); - return builder.build(); - } - public static void main(String[] args) throws Exception { String host = args[0]; String instanceName = args[1]; diff --git a/src/main/java/build/buildfarm/tools/Mount.java b/src/main/java/build/buildfarm/tools/Mount.java index 43061d12bc..a0a4528d22 100644 --- a/src/main/java/build/buildfarm/tools/Mount.java +++ b/src/main/java/build/buildfarm/tools/Mount.java @@ -14,6 +14,7 @@ package build.buildfarm.tools; +import static build.buildfarm.common.grpc.Channels.createChannel; import static build.buildfarm.instance.Utils.getBlob; import static com.google.common.base.Preconditions.checkArgument; @@ -27,8 +28,6 @@ import build.buildfarm.worker.FuseCAS; import com.google.protobuf.ByteString; import io.grpc.ManagedChannel; -import io.grpc.netty.NegotiationType; -import io.grpc.netty.NettyChannelBuilder; import java.io.IOException; import java.io.InputStream; import java.nio.file.Path; @@ -37,12 +36,6 @@ import java.util.Map; class Mount { - private static ManagedChannel createChannel(String target) { - NettyChannelBuilder builder = - NettyChannelBuilder.forTarget(target).negotiationType(NegotiationType.PLAINTEXT); - return builder.build(); - } - @SuppressWarnings("BusyWait") public static void main(String[] args) throws Exception { String host = args[0]; diff --git a/src/main/java/build/buildfarm/tools/WorkerProfile.java b/src/main/java/build/buildfarm/tools/WorkerProfile.java index d820446a53..ee36bf035a 100644 --- a/src/main/java/build/buildfarm/tools/WorkerProfile.java +++ b/src/main/java/build/buildfarm/tools/WorkerProfile.java @@ -14,6 +14,8 @@ package build.buildfarm.tools; +import static build.buildfarm.common.grpc.Channels.createChannel; + import build.buildfarm.common.DigestUtil; import build.buildfarm.common.config.BuildfarmConfigs; import build.buildfarm.common.config.ShardWorkerOptions; @@ -30,10 +32,7 @@ import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.util.Durations; import com.google.protobuf.util.JsonFormat; -import io.grpc.ManagedChannel; import io.grpc.StatusRuntimeException; -import io.grpc.netty.NegotiationType; -import io.grpc.netty.NettyChannelBuilder; import java.io.IOException; import java.nio.file.Paths; import java.util.HashMap; @@ -46,12 +45,6 @@ class WorkerProfile { private static BuildfarmConfigs configs = BuildfarmConfigs.getInstance(); - private static ManagedChannel createChannel(String target) { - NettyChannelBuilder builder = - NettyChannelBuilder.forTarget(target).negotiationType(NegotiationType.PLAINTEXT); - return builder.build(); - } - /** * Transform worker string from "ip-10-135-31-210.ec2:8981" to "10.135.31.210". * diff --git a/src/main/java/build/buildfarm/worker/BUILD b/src/main/java/build/buildfarm/worker/BUILD index 417d530e9a..c25b9e74d6 100644 --- a/src/main/java/build/buildfarm/worker/BUILD +++ b/src/main/java/build/buildfarm/worker/BUILD @@ -32,7 +32,6 @@ java_library( "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_context", "@maven//:io_grpc_grpc_core", - "@maven//:io_grpc_grpc_netty", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", "@maven//:io_prometheus_simpleclient", diff --git a/src/main/java/build/buildfarm/worker/shard/BUILD b/src/main/java/build/buildfarm/worker/shard/BUILD index 3df1ab7e77..beeaaae918 100644 --- a/src/main/java/build/buildfarm/worker/shard/BUILD +++ b/src/main/java/build/buildfarm/worker/shard/BUILD @@ -32,7 +32,6 @@ java_library( "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_context", "@maven//:io_grpc_grpc_core", - "@maven//:io_grpc_grpc_netty", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_services", "@maven//:io_grpc_grpc_stub", From 70903df60f272f807177c46e769894a2fd230849 Mon Sep 17 00:00:00 2001 From: Anshuman Mishra Date: Thu, 29 Jun 2023 00:02:03 -0700 Subject: [PATCH 030/311] Refactor findMissingBlobs method --- .../instance/shard/ShardInstance.java | 178 ++++++++++-------- 1 file changed, 100 insertions(+), 78 deletions(-) diff --git a/src/main/java/build/buildfarm/instance/shard/ShardInstance.java b/src/main/java/build/buildfarm/instance/shard/ShardInstance.java index bc80520bf5..528f29dfa4 100644 --- a/src/main/java/build/buildfarm/instance/shard/ShardInstance.java +++ b/src/main/java/build/buildfarm/instance/shard/ShardInstance.java @@ -643,81 +643,42 @@ public ListenableFuture> findMissingBlobs( return immediateFailedFuture(Status.fromThrowable(e).asException()); } - // Empty blobs are an exceptional case. Filter them out. - // If the user only requested empty blobs we can immedaitely tell them we already have it. + // Empty blobs are an exceptional case. Filter them out. + // If the user only requested empty blobs we can immediately tell them we already have it. Iterable nonEmptyDigests = Iterables.filter(blobDigests, (digest) -> digest.getSizeBytes() != 0); if (Iterables.isEmpty(nonEmptyDigests)) { return immediateFuture(ImmutableList.of()); } - // This is a faster strategy to check missing blobs which does not require querying the CAS. - // With hundreds of worker machines, it may be too expensive to query all of them for "find - // missing blobs". - // Workers register themselves with the backplane for a 30-second window, and if they fail to - // re-register within this time frame, they are automatically removed from the backplane. While - // this alternative strategy for finding missing blobs is faster and more cost-effective than - // the exhaustive approach of querying each worker to find the digest, it comes with a higher - // risk of returning expired workers despite filtering by active workers below. This is because - // the strategy may return workers that have expired in the last 30 seconds. However, checking - // workers directly is not a guarantee either since workers could leave the cluster after being - // queried. Ultimately, it will come down to the client's resiliency if the backplane is - // out-of-date and the server lies about which blobs are actually present. We provide this - // alternative strategy for calculating missing blobs. - if (configs.getServer().isFindMissingBlobsViaBackplane()) { - try { - Set uniqueDigests = new HashSet<>(); - nonEmptyDigests.forEach(uniqueDigests::add); - Map> foundBlobs = backplane.getBlobDigestsWorkers(uniqueDigests); - Set workerSet = backplane.getStorageWorkers(); - Map workersStartTime = backplane.getWorkersStartTimeInEpochSecs(workerSet); - return immediateFuture( - uniqueDigests.stream() - .filter( // best effort to present digests only missing on active workers - digest -> { - try { - Set initialWorkers = - foundBlobs.getOrDefault(digest, Collections.emptySet()); - Set activeWorkers = Sets.intersection(initialWorkers, workerSet); - long insertTime = backplane.getDigestInsertTime(digest); - Set workersStartedBeforeDigestInsertion = - activeWorkers.stream() - .filter( - worker -> - workersStartTime.getOrDefault( - worker, Instant.now().getEpochSecond()) - < insertTime) - .collect(Collectors.toSet()); - Set workersToBeRemoved = - Sets.difference(initialWorkers, workersStartedBeforeDigestInsertion) - .immutableCopy(); - if (!workersToBeRemoved.isEmpty()) { - log.log( - Level.INFO, format("adjusting locations for the digest %s", digest)); - backplane.adjustBlobLocations( - digest, Collections.emptySet(), workersToBeRemoved); - } - return workersStartedBeforeDigestInsertion.isEmpty(); - } catch (IOException e) { - // Treat error as missing digest. - log.log( - Level.WARNING, - format("failed to get digest (%s) insertion time", digest)); - return true; - } - }) - .collect(Collectors.toList())); - } catch (Exception e) { - log.log(Level.SEVERE, "find missing blob via backplane failed", e); - return immediateFailedFuture(Status.fromThrowable(e).asException()); - } + return findMissingBlobsViaBackplane(nonEmptyDigests); } - // A more accurate way to verify missing blobs is to ask the CAS participants directly if they - // have the blobs. To do this, we get all of the worker nodes that are particpating in the CAS - // as a random list to begin our search. If there are no workers avaiable, tell the client all - // blobs are missing. + return findMissingBlobsQueryingEachWorker(nonEmptyDigests, requestMetadata); + } + + class FindMissingResponseEntry { + final String worker; + final long elapsedMicros; + final Throwable exception; + final int stillMissingAfter; + + FindMissingResponseEntry( + String worker, long elapsedMicros, Throwable exception, int stillMissingAfter) { + this.worker = worker; + this.elapsedMicros = elapsedMicros; + this.exception = exception; + this.stillMissingAfter = stillMissingAfter; + } + } + + // A more accurate way to verify missing blobs is to ask the CAS participants directly if they + // have the blobs. To do this, we get all the worker nodes that are participating in the CAS + // as a random list to begin our search. If there are no workers available, tell the client all + // blobs are missing. + private ListenableFuture> findMissingBlobsQueryingEachWorker( + Iterable nonEmptyDigests, RequestMetadata requestMetadata) { Deque workers; try { List workersList = new ArrayList<>(backplane.getStorageWorkers()); @@ -730,7 +691,7 @@ public ListenableFuture> findMissingBlobs( return immediateFuture(nonEmptyDigests); } - // Search through all of the workers to decide how many CAS blobs are missing. + // Search through all the workers to decide which CAS blobs are missing. SettableFuture> missingDigestsFuture = SettableFuture.create(); findMissingBlobsOnWorker( UUID.randomUUID().toString(), @@ -744,19 +705,80 @@ public ListenableFuture> findMissingBlobs( return missingDigestsFuture; } - class FindMissingResponseEntry { - final String worker; - final long elapsedMicros; - final Throwable exception; - final int stillMissingAfter; + // This is a faster strategy to check missing blobs which does not require querying the CAS. + // With hundreds of worker machines, it may be too expensive to query all of them for "find + // missing blobs". + // Workers register themselves with the backplane for a 30-second window, and if they fail to + // re-register within this time frame, they are automatically removed from the backplane. While + // this alternative strategy for finding missing blobs is faster and more cost-effective than + // the exhaustive approach of querying each worker to find the digest, it comes with a higher + // risk of returning expired workers despite filtering by active workers below. This is because + // the strategy may return workers that have expired in the last 30 seconds. However, checking + // workers directly is not a guarantee either since workers could leave the cluster after being + // queried. Ultimately, it will come down to the client's resiliency if the backplane is + // out-of-date and the server lies about which blobs are actually present. We provide this + // alternative strategy for calculating missing blobs. + private ListenableFuture> findMissingBlobsViaBackplane( + Iterable nonEmptyDigests) { + try { + Set uniqueDigests = new HashSet<>(); + nonEmptyDigests.forEach(uniqueDigests::add); + Map> foundBlobs = backplane.getBlobDigestsWorkers(uniqueDigests); + Set workerSet = backplane.getStorageWorkers(); + Map workersStartTime = backplane.getWorkersStartTimeInEpochSecs(workerSet); + return immediateFuture( + uniqueDigests.stream() + .filter( // best effort to present digests only missing on active workers + digest -> { + Set initialWorkers = + foundBlobs.getOrDefault(digest, Collections.emptySet()); + return filterAndAdjustWorkersForDigest( + digest, initialWorkers, workerSet, workersStartTime) + .isEmpty(); + }) + .collect(Collectors.toList())); + } catch (Exception e) { + log.log(Level.SEVERE, "find missing blob via backplane failed", e); + return immediateFailedFuture(Status.fromThrowable(e).asException()); + } + } - FindMissingResponseEntry( - String worker, long elapsedMicros, Throwable exception, int stillMissingAfter) { - this.worker = worker; - this.elapsedMicros = elapsedMicros; - this.exception = exception; - this.stillMissingAfter = stillMissingAfter; + private Set filterAndAdjustWorkersForDigest( + Digest digest, + Set originalWorkerSetWithDigest, + Set activeWorkers, + Map workersStartTime) { + long insertTime; + try { + insertTime = backplane.getDigestInsertTime(digest); + } catch (IOException e) { + log.log(Level.WARNING, format("failed to get digest (%s) insertion time", digest)); + return Collections.emptySet(); + } + Set activeWorkersWithDigest = + Sets.intersection(originalWorkerSetWithDigest, activeWorkers); + Set workersStartedBeforeDigestInsertion = + activeWorkersWithDigest.stream() + .filter( + worker -> + workersStartTime.getOrDefault(worker, Instant.now().getEpochSecond()) + < insertTime) + .collect(Collectors.toSet()); + Set workersToBeRemoved = + Sets.difference(originalWorkerSetWithDigest, workersStartedBeforeDigestInsertion) + .immutableCopy(); + if (!workersToBeRemoved.isEmpty()) { + try { + log.log(Level.INFO, format("adjusting locations for the digest %s", digest)); + backplane.adjustBlobLocations(digest, Collections.emptySet(), workersToBeRemoved); + } catch (IOException e) { + log.log( + Level.WARNING, + format("error adjusting blob location for %s", DigestUtil.toString(digest)), + e); + } } + return workersStartedBeforeDigestInsertion; } private void findMissingBlobsOnWorker( From 68318c5f80ecaf5242e9f051188214c35add7a86 Mon Sep 17 00:00:00 2001 From: Anshuman Mishra Date: Wed, 5 Jul 2023 23:27:30 -0700 Subject: [PATCH 031/311] incorporate feedback --- src/main/java/build/buildfarm/instance/shard/ShardInstance.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/build/buildfarm/instance/shard/ShardInstance.java b/src/main/java/build/buildfarm/instance/shard/ShardInstance.java index 528f29dfa4..bf1a972eb9 100644 --- a/src/main/java/build/buildfarm/instance/shard/ShardInstance.java +++ b/src/main/java/build/buildfarm/instance/shard/ShardInstance.java @@ -691,7 +691,7 @@ private ListenableFuture> findMissingBlobsQueryingEachWorker( return immediateFuture(nonEmptyDigests); } - // Search through all the workers to decide which CAS blobs are missing. + // Search through all of the workers to decide which CAS blobs are missing. SettableFuture> missingDigestsFuture = SettableFuture.create(); findMissingBlobsOnWorker( UUID.randomUUID().toString(), From 95719e5ac3f311eff8108f4dbbacc0ff481a7180 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Sun, 16 Jul 2023 17:06:38 -0400 Subject: [PATCH 032/311] Upgrade grpc repo/maven deps for java_common Fixes #1403 --- defs.bzl | 4 ++-- deps.bzl | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/defs.bzl b/defs.bzl index 8ab50597f1..65087518d5 100644 --- a/defs.bzl +++ b/defs.bzl @@ -107,8 +107,8 @@ def buildfarm_init(name = "buildfarm"): "io.github.lognet:grpc-spring-boot-starter:4.5.4", "org.bouncycastle:bcprov-jdk15on:1.70", "net.jcip:jcip-annotations:1.0", - ] + ["io.netty:netty-%s:4.1.90.Final" % module for module in IO_NETTY_MODULES] + - ["io.grpc:grpc-%s:1.53.0" % module for module in IO_GRPC_MODULES] + + ] + ["io.netty:netty-%s:4.1.94.Final" % module for module in IO_NETTY_MODULES] + + ["io.grpc:grpc-%s:1.56.1" % module for module in IO_GRPC_MODULES] + [ "io.prometheus:simpleclient:0.10.0", "io.prometheus:simpleclient_hotspot:0.10.0", diff --git a/deps.bzl b/deps.bzl index 1a0dd5f80e..28a66281f4 100644 --- a/deps.bzl +++ b/deps.bzl @@ -50,9 +50,9 @@ def archive_dependencies(third_party): # Needed for @grpc_java//compiler:grpc_java_plugin. { "name": "io_grpc_grpc_java", - "sha256": "78bf175f9a8fa23cda724bbef52ad9d0d555cdd1122bcb06484b91174f931239", - "strip_prefix": "grpc-java-1.54.1", - "urls": ["https://github.com/grpc/grpc-java/archive/v1.54.1.zip"], + "sha256": "b8fb7ae4824fb5a5ae6e6fa26ffe2ad7ab48406fdeee54e8965a3b5948dd957e", + "strip_prefix": "grpc-java-1.56.1", + "urls": ["https://github.com/grpc/grpc-java/archive/v1.56.1.zip"], }, { "name": "rules_pkg", From abcd8fc89c9e23e6b39139c15cb504383d346a65 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Wed, 26 Jul 2023 06:19:15 -0400 Subject: [PATCH 033/311] Shut down prometheus collector thread on CFC stop Prevents a hang on shutdown when redis is disconnected --- src/main/java/build/buildfarm/cas/cfc/CASFileCache.java | 9 ++++++++- .../build/buildfarm/worker/shard/CFCExecFileSystem.java | 3 ++- .../build/buildfarm/worker/shard/ExecFileSystem.java | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java index 11b6b3ba23..4e4a8472c5 100644 --- a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java +++ b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java @@ -168,7 +168,7 @@ public abstract class CASFileCache implements ContentAddressableStorage { private final Consumer> onExpire; private final Executor accessRecorder; private final ExecutorService expireService; - private Thread prometheusMetricsThread; // TODO make this final, stop on shutdown + private Thread prometheusMetricsThread; private final Map directoryStorage = Maps.newConcurrentMap(); private final DirectoriesIndex directoriesIndex; @@ -1258,6 +1258,13 @@ public void initializeRootDirectory() throws IOException { fileStore = Files.getFileStore(root); } + public void stop() throws InterruptedException { + if (prometheusMetricsThread != null) { + prometheusMetricsThread.interrupt(); + prometheusMetricsThread.join(); + } + } + public StartupCacheResults start(boolean skipLoad) throws IOException, InterruptedException { return start(newDirectExecutorService(), skipLoad); } diff --git a/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java b/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java index c8336f7481..96e8f1f218 100644 --- a/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java +++ b/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java @@ -142,7 +142,8 @@ public void start(Consumer> onDigests, boolean skipLoad) } @Override - public void stop() { + public void stop() throws InterruptedException { + fileCache.stop(); if (!shutdownAndAwaitTermination(fetchService, 1, MINUTES)) { log.log(Level.SEVERE, "could not terminate fetchService"); } diff --git a/src/main/java/build/buildfarm/worker/shard/ExecFileSystem.java b/src/main/java/build/buildfarm/worker/shard/ExecFileSystem.java index 916b43cef0..b55601d598 100644 --- a/src/main/java/build/buildfarm/worker/shard/ExecFileSystem.java +++ b/src/main/java/build/buildfarm/worker/shard/ExecFileSystem.java @@ -30,7 +30,7 @@ public interface ExecFileSystem extends InputStreamFactory { void start(Consumer> onDigests, boolean skipLoad) throws IOException, InterruptedException; - void stop(); + void stop() throws InterruptedException; Path root(); From 9b4bd6f7ef8dbc9e33c83d2b13a9808b97b819cc Mon Sep 17 00:00:00 2001 From: George Gensure Date: Sun, 30 Jul 2023 21:43:38 -0400 Subject: [PATCH 034/311] Output status code name on shard read error Use the proper name for a status code as presented when the read will not be retried. --- .../java/build/buildfarm/instance/shard/ShardInstance.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/build/buildfarm/instance/shard/ShardInstance.java b/src/main/java/build/buildfarm/instance/shard/ShardInstance.java index bf1a972eb9..edbeb168f3 100644 --- a/src/main/java/build/buildfarm/instance/shard/ShardInstance.java +++ b/src/main/java/build/buildfarm/instance/shard/ShardInstance.java @@ -919,8 +919,11 @@ public void onError(Throwable t) { log.log( Level.WARNING, format( - "DEADLINE_EXCEEDED: read(%s) on worker %s after %d bytes of content", - DigestUtil.toString(blobDigest), worker, received)); + "%s: read(%s) on worker %s after %d bytes of content", + status.getCode().name(), + DigestUtil.toString(blobDigest), + worker, + received)); blobObserver.onError(t); return; } From 87106426d567d8d015ffd04fbe7753d63ec7d653 Mon Sep 17 00:00:00 2001 From: Yuriy Belenitsky Date: Tue, 1 Aug 2023 11:31:00 -0400 Subject: [PATCH 035/311] Reduce log levels to make log files more meaningful (#1414) --- .../build/buildfarm/admin/aws/AwsAdmin.java | 2 +- .../build/buildfarm/cas/cfc/CASFileCache.java | 53 ++++++++++--------- .../common/services/ByteStreamService.java | 6 +-- .../ContentAddressableStorageService.java | 2 +- .../common/services/WriteStreamObserver.java | 21 ++++---- .../instance/shard/RedisShardBackplane.java | 20 +++---- .../instance/shard/RedisShardSubscriber.java | 6 +-- .../instance/shard/ShardInstance.java | 44 +++++++-------- .../build/buildfarm/instance/shard/Util.java | 6 +-- .../metrics/AbstractMetricsPublisher.java | 2 +- .../java/build/buildfarm/worker/Executor.java | 6 +-- .../build/buildfarm/worker/InputFetcher.java | 4 +- .../java/build/buildfarm/worker/Pipeline.java | 4 +- .../build/buildfarm/worker/PipelineStage.java | 4 +- .../worker/shard/CFCExecFileSystem.java | 5 +- .../worker/shard/ShardWorkerContext.java | 14 ++--- 16 files changed, 101 insertions(+), 98 deletions(-) diff --git a/src/main/java/build/buildfarm/admin/aws/AwsAdmin.java b/src/main/java/build/buildfarm/admin/aws/AwsAdmin.java index ebb3746b63..f40dd72c95 100644 --- a/src/main/java/build/buildfarm/admin/aws/AwsAdmin.java +++ b/src/main/java/build/buildfarm/admin/aws/AwsAdmin.java @@ -127,7 +127,7 @@ public GetHostsResult getHosts(String filter, int ageInMinutes, String status) { } resultBuilder.addAllHosts(hosts); resultBuilder.setNumHosts(hosts.size()); - log.log(Level.FINE, String.format("Got %d hosts for filter: %s", hosts.size(), filter)); + log.log(Level.FINER, String.format("Got %d hosts for filter: %s", hosts.size(), filter)); return resultBuilder.build(); } diff --git a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java index 4e4a8472c5..a112c37bb2 100644 --- a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java +++ b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java @@ -550,7 +550,7 @@ private InputStream compressorInputStream(Compressor.Value compressor, InputStre @SuppressWarnings("ResultOfMethodCallIgnored") InputStream newLocalInput(Compressor.Value compressor, Digest digest, long offset) throws IOException { - log.log(Level.FINE, format("getting input stream for %s", DigestUtil.toString(digest))); + log.log(Level.FINER, format("getting input stream for %s", DigestUtil.toString(digest))); boolean isExecutable = false; do { String key = getKey(digest, isExecutable); @@ -724,7 +724,7 @@ void invalidateWrite(Digest digest) { public void put(Blob blob, Runnable onExpiration) throws InterruptedException { String key = getKey(blob.getDigest(), false); try { - log.log(Level.FINE, format("put: %s", key)); + log.log(Level.FINER, format("put: %s", key)); OutputStream out = putImpl( Compressor.Value.IDENTITY, @@ -1050,7 +1050,7 @@ CancellableOutputStream newOutput( String key = getKey(digest, false); final CancellableOutputStream cancellableOut; try { - log.log(Level.FINE, format("getWrite: %s", key)); + log.log(Level.FINER, format("getWrite: %s", key)); cancellableOut = putImpl( compressor, @@ -2140,7 +2140,7 @@ private void fetchDirectory( private void removeFilePath(Path path) throws IOException { if (Files.exists(path)) { if (Files.isDirectory(path)) { - log.log(Level.FINE, "removing existing directory " + path + " for fetch"); + log.log(Level.FINER, "removing existing directory " + path + " for fetch"); Directories.remove(path, fileStore); } else { Files.delete(path); @@ -2169,14 +2169,14 @@ public ListenableFuture putDirectory( // Claim the directory path so no other threads try to create/delete it. Path path = getDirectoryPath(digest); Lock l = locks.acquire(path); - log.log(Level.FINE, format("locking directory %s", path.getFileName())); + log.log(Level.FINER, format("locking directory %s", path.getFileName())); try { l.lockInterruptibly(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return immediateFailedFuture(e); } - log.log(Level.FINE, format("locked directory %s", path.getFileName())); + log.log(Level.FINER, format("locked directory %s", path.getFileName())); // Now that a lock has been claimed, we can proceed to create the directory. ListenableFuture putFuture; @@ -2190,7 +2190,7 @@ public ListenableFuture putDirectory( putFuture.addListener( () -> { l.unlock(); - log.log(Level.FINE, format("directory %s has been unlocked", path.getFileName())); + log.log(Level.FINER, format("directory %s has been unlocked", path.getFileName())); }, service); return putFuture; @@ -2238,7 +2238,7 @@ private boolean directoryEntryExists( private ListenableFuture putDirectorySynchronized( Path path, Digest digest, Map directoriesByDigest, ExecutorService service) throws IOException { - log.log(Level.FINE, format("directory %s has been locked", path.getFileName())); + log.log(Level.FINER, format("directory %s has been locked", path.getFileName())); ListenableFuture expireFuture; synchronized (this) { DirectoryEntry e = directoryStorage.get(digest); @@ -2265,7 +2265,7 @@ private ListenableFuture putDirectorySynchronized( } if (e != null) { - log.log(Level.FINE, format("found existing entry for %s", path.getFileName())); + log.log(Level.FINER, format("found existing entry for %s", path.getFileName())); if (directoryEntryExists(path, e, directoriesByDigest)) { return immediateFuture(path); } @@ -2278,7 +2278,7 @@ private ListenableFuture putDirectorySynchronized( decrementReferencesSynchronized(inputsBuilder.build(), ImmutableList.of()); expireFuture = expireDirectory(digest, service); - log.log(Level.FINE, format("expiring existing entry for %s", path.getFileName())); + log.log(Level.FINER, format("expiring existing entry for %s", path.getFileName())); } } @@ -2300,7 +2300,7 @@ private ListenableFuture putDirectorySynchronized( transformAsync( deindexFuture, result -> { - log.log(Level.FINE, format("expiry complete, fetching %s", path.getFileName())); + log.log(Level.FINER, format("expiry complete, fetching %s", path.getFileName())); ImmutableList.Builder> putFuturesBuilder = ImmutableList.builder(); fetchDirectory( @@ -2374,7 +2374,7 @@ private ListenableFuture putDirectorySynchronized( } } try { - log.log(Level.FINE, "removing directory to roll back " + path); + log.log(Level.FINER, "removing directory to roll back " + path); Directories.remove(path, fileStore); } catch (IOException removeException) { log.log( @@ -2390,7 +2390,8 @@ private ListenableFuture putDirectorySynchronized( return transform( rollbackFuture, (results) -> { - log.log(Level.FINE, format("directory fetch complete, inserting %s", path.getFileName())); + log.log( + Level.FINER, format("directory fetch complete, inserting %s", path.getFileName())); DirectoryEntry e = new DirectoryEntry( // might want to have this treatment ahead of this @@ -2442,13 +2443,13 @@ Path putAndCopy(Digest digest, boolean isExecutable) throws IOException, Interru complete = true; } finally { try { - log.log(Level.FINE, format("closing output stream for %s", DigestUtil.toString(digest))); + log.log(Level.FINER, format("closing output stream for %s", DigestUtil.toString(digest))); if (complete) { out.close(); } else { out.cancel(); } - log.log(Level.FINE, format("output stream closed for %s", DigestUtil.toString(digest))); + log.log(Level.FINER, format("output stream closed for %s", DigestUtil.toString(digest))); } catch (IOException e) { if (Thread.interrupted()) { log.log( @@ -2460,7 +2461,7 @@ Path putAndCopy(Digest digest, boolean isExecutable) throws IOException, Interru throw new InterruptedException(); } else { log.log( - Level.FINE, + Level.FINER, format("failed output stream close for %s", DigestUtil.toString(digest)), e); } @@ -2492,7 +2493,7 @@ private static Exception extractStatusException(IOException e) { private void copyExternalInput(Digest digest, CancellableOutputStream out) throws IOException, InterruptedException { Retrier retrier = new Retrier(Backoff.sequential(5), Retrier.DEFAULT_IS_RETRIABLE); - log.log(Level.FINE, format("downloading %s", DigestUtil.toString(digest))); + log.log(Level.FINER, format("downloading %s", DigestUtil.toString(digest))); try { retrier.execute( () -> { @@ -2513,7 +2514,7 @@ private void copyExternalInput(Digest digest, CancellableOutputStream out) e); // prevent burial by early end of stream during close throw e; } - log.log(Level.FINE, format("download of %s complete", DigestUtil.toString(digest))); + log.log(Level.FINER, format("download of %s complete", DigestUtil.toString(digest))); } @FunctionalInterface @@ -2567,7 +2568,7 @@ private CancellableOutputStream putImpl( if (out == DUPLICATE_OUTPUT_STREAM) { return null; } - log.log(Level.FINE, format("entry %s is missing, downloading and populating", key)); + log.log(Level.FINER, format("entry %s is missing, downloading and populating", key)); return newCancellableOutputStream(out); } @@ -2752,7 +2753,7 @@ private boolean charge(String key, long blobSizeInBytes, AtomicBoolean requiresD return immediateFuture(null); } expiredKeyCounter.inc(); - log.log(Level.INFO, format("expired key %s", expiredKey)); + log.log(Level.FINE, format("expired key %s", expiredKey)); return immediateFuture(fileEntryKey.getDigest()); }, expireService)); @@ -2955,7 +2956,7 @@ void commit() throws IOException { existingEntry = safeStorageInsertion(key, entry); inserted = existingEntry == null; } catch (FileAlreadyExistsException e) { - log.log(Level.FINE, "file already exists for " + key + ", nonexistent entry will fail"); + log.log(Level.FINER, "file already exists for " + key + ", nonexistent entry will fail"); } finally { Files.delete(writePath); if (!inserted) { @@ -2980,20 +2981,20 @@ void commit() throws IOException { } if (existingEntry != null) { - log.log(Level.FINE, "lost the race to insert " + key); + log.log(Level.FINER, "lost the race to insert " + key); if (!referenceIfExists(key)) { // we would lose our accountability and have a presumed reference if we returned throw new IllegalStateException("storage conflict with existing key for " + key); } } else if (writeWinner.get()) { - log.log(Level.FINE, "won the race to insert " + key); + log.log(Level.FINER, "won the race to insert " + key); try { onInsert.run(); } catch (RuntimeException e) { throw new IOException(e); } } else { - log.log(Level.FINE, "did not win the race to insert " + key); + log.log(Level.FINER, "did not win the race to insert " + key); } } }; @@ -3047,7 +3048,7 @@ public boolean incrementReference() { "entry " + key + " has " + referenceCount + " references and is being incremented..."); } log.log( - Level.FINER, + Level.FINEST, "incrementing references to " + key + " from " @@ -3077,7 +3078,7 @@ public boolean decrementReference(Entry header) { "entry " + key + " has 0 references and is being decremented..."); } log.log( - Level.FINER, + Level.FINEST, "decrementing references to " + key + " from " diff --git a/src/main/java/build/buildfarm/common/services/ByteStreamService.java b/src/main/java/build/buildfarm/common/services/ByteStreamService.java index 365a9cec2a..4bb944abff 100644 --- a/src/main/java/build/buildfarm/common/services/ByteStreamService.java +++ b/src/main/java/build/buildfarm/common/services/ByteStreamService.java @@ -342,7 +342,7 @@ public void read(ReadRequest request, StreamObserver responseObser long offset = request.getReadOffset(); long limit = request.getReadLimit(); log.log( - Level.FINER, + Level.FINEST, format("read resource_name=%s offset=%d limit=%d", resourceName, offset, limit)); try { @@ -357,7 +357,7 @@ public void queryWriteStatus( QueryWriteStatusRequest request, StreamObserver responseObserver) { String resourceName = request.getResourceName(); try { - log.log(Level.FINE, format("queryWriteStatus(%s)", resourceName)); + log.log(Level.FINER, format("queryWriteStatus(%s)", resourceName)); Write write = getWrite(resourceName); responseObserver.onNext( QueryWriteStatusResponse.newBuilder() @@ -366,7 +366,7 @@ public void queryWriteStatus( .build()); responseObserver.onCompleted(); log.log( - Level.FINE, + Level.FINER, format( "queryWriteStatus(%s) => committed_size = %d, complete = %s", resourceName, write.getCommittedSize(), write.isComplete())); diff --git a/src/main/java/build/buildfarm/common/services/ContentAddressableStorageService.java b/src/main/java/build/buildfarm/common/services/ContentAddressableStorageService.java index 9395d63fea..6e00e39f67 100644 --- a/src/main/java/build/buildfarm/common/services/ContentAddressableStorageService.java +++ b/src/main/java/build/buildfarm/common/services/ContentAddressableStorageService.java @@ -109,7 +109,7 @@ public void onSuccess(FindMissingBlobsResponse.Builder builder) { long elapsedMicros = stopwatch.elapsed(MICROSECONDS); missingBlobs.observe(request.getBlobDigestsList().size()); log.log( - Level.FINE, + Level.FINER, "FindMissingBlobs(" + instance.getName() + ") for " diff --git a/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java b/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java index 790603db00..483f266e03 100644 --- a/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java +++ b/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java @@ -110,7 +110,7 @@ public synchronized void onNext(WriteRequest request) { Status status = Status.fromThrowable(e); if (errorResponse(status.asException())) { log.log( - status.getCode() == Status.Code.CANCELLED ? Level.FINE : Level.SEVERE, + status.getCode() == Status.Code.CANCELLED ? Level.FINER : Level.SEVERE, format("error writing %s", (name == null ? request.getResourceName() : name)), e); } @@ -160,7 +160,7 @@ synchronized void commitSynchronized(long committedSize) { if (Context.current().isCancelled()) { log.log( - Level.FINER, + Level.FINEST, format("skipped delivering committed_size to %s for cancelled context", name)); } else { try { @@ -182,7 +182,7 @@ synchronized void commitSynchronized(long committedSize) { Status status = Status.fromThrowable(e); if (errorResponse(status.asException())) { log.log( - status.getCode() == Status.Code.CANCELLED ? Level.FINE : Level.SEVERE, + status.getCode() == Status.Code.CANCELLED ? Level.FINER : Level.SEVERE, format( "%s-%s: %s -> %s -> %s: error committing %s", requestMetadata.getToolDetails().getToolName(), @@ -202,7 +202,8 @@ void commitActive(long committedSize) { if (exception.compareAndSet(null, null)) { try { - log.log(Level.FINER, format("delivering committed_size for %s of %d", name, committedSize)); + log.log( + Level.FINEST, format("delivering committed_size for %s of %d", name, committedSize)); responseObserver.onNext(response); responseObserver.onCompleted(); } catch (Exception e) { @@ -221,9 +222,9 @@ private void initialize(WriteRequest request) throws InvalidResourceNameExceptio name = resourceName; try { write = getWrite(resourceName); - if (log.isLoggable(Level.FINER)) { + if (log.isLoggable(Level.FINEST)) { log.log( - Level.FINER, + Level.FINEST, format( "registering callback for %s: committed_size = %d (transient), complete = %s", resourceName, write.getCommittedSize(), write.isComplete())); @@ -365,7 +366,7 @@ private void handleWrite(String resourceName, long offset, ByteString data, bool data = data.substring(skipBytes); } log.log( - Level.FINER, + Level.FINEST, format( "writing %d to %s at %d%s", bytesToWrite, name, offset, finishWrite ? " with finish_write" : "")); @@ -381,7 +382,7 @@ private void handleWrite(String resourceName, long offset, ByteString data, bool @GuardedBy("this") private void close() { - log.log(Level.FINER, format("closing stream due to finishWrite for %s", name)); + log.log(Level.FINEST, format("closing stream due to finishWrite for %s", name)); try { getOutput().close(); } catch (DigestMismatchException e) { @@ -464,11 +465,11 @@ private FeedbackOutputStream getOutput() throws IOException { @Override public void onError(Throwable t) { - log.log(Level.FINE, format("write error for %s", name), t); + log.log(Level.FINER, format("write error for %s", name), t); } @Override public void onCompleted() { - log.log(Level.FINE, format("write completed for %s", name)); + log.log(Level.FINER, format("write completed for %s", name)); } } diff --git a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java index 864c808369..f0a5ff222e 100644 --- a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java +++ b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java @@ -206,7 +206,7 @@ public void visit(String entry) { JsonFormat.parser().merge(entry, executeEntry); visit(executeEntry.build(), entry); } catch (InvalidProtocolBufferException e) { - log.log(Level.FINE, "invalid ExecuteEntry json: " + entry, e); + log.log(Level.FINER, "invalid ExecuteEntry json: " + entry, e); } } } @@ -330,10 +330,10 @@ private void updateWatchers(JedisCluster jedis) { if (!expiringChannels.isEmpty()) { log.log( - Level.FINE, + Level.FINER, format("Scan %d watches, %s, expiresAt: %s", expiringChannels.size(), now, expiresAt)); - log.log(Level.FINE, "Scan prequeue"); + log.log(Level.FINER, "Scan prequeue"); // scan prequeue, pet watches scanPrequeue(jedis, resetChannel); } @@ -342,7 +342,7 @@ private void updateWatchers(JedisCluster jedis) { scanProcessing(jedis, resetChannel, now); if (!expiringChannels.isEmpty()) { - log.log(Level.FINE, "Scan queue"); + log.log(Level.FINER, "Scan queue"); // scan queue, pet watches scanQueue(jedis, resetChannel); } @@ -351,7 +351,7 @@ private void updateWatchers(JedisCluster jedis) { scanDispatching(jedis, resetChannel, now); if (!expiringChannels.isEmpty()) { - log.log(Level.FINE, "Scan dispatched"); + log.log(Level.FINER, "Scan dispatched"); // scan dispatched pet watches scanDispatched(jedis, resetChannel); } @@ -445,7 +445,7 @@ public void updateWatchedIfDone(JedisCluster jedis) { } subscriber.onOperation(operationChannel(operationName), operation, nextExpiresAt(now)); log.log( - Level.FINE, + Level.FINER, format( "operation %s done due to %s", operationName, operation == null ? "null" : "completed")); @@ -537,24 +537,24 @@ public synchronized void stop() throws InterruptedException { if (failsafeOperationThread != null) { failsafeOperationThread.interrupt(); failsafeOperationThread.join(); - log.log(Level.FINE, "failsafeOperationThread has been stopped"); + log.log(Level.FINER, "failsafeOperationThread has been stopped"); } if (operationSubscription != null) { operationSubscription.stop(); if (subscriptionThread != null) { subscriptionThread.join(); } - log.log(Level.FINE, "subscriptionThread has been stopped"); + log.log(Level.FINER, "subscriptionThread has been stopped"); } if (subscriberService != null) { subscriberService.shutdown(); subscriberService.awaitTermination(10, SECONDS); - log.log(Level.FINE, "subscriberService has been stopped"); + log.log(Level.FINER, "subscriberService has been stopped"); } if (client != null) { client.close(); client = null; - log.log(Level.FINE, "client has been closed"); + log.log(Level.FINER, "client has been closed"); } } diff --git a/src/main/java/build/buildfarm/instance/shard/RedisShardSubscriber.java b/src/main/java/build/buildfarm/instance/shard/RedisShardSubscriber.java index 6ecfdc05d4..637be2a383 100644 --- a/src/main/java/build/buildfarm/instance/shard/RedisShardSubscriber.java +++ b/src/main/java/build/buildfarm/instance/shard/RedisShardSubscriber.java @@ -137,7 +137,7 @@ public ListenableFuture watch(String channel, TimedWatcher watcher) { new TimedWatchFuture(watcher) { @Override public void unwatch() { - log.log(Level.FINE, format("unwatching %s", channel)); + log.log(Level.FINER, format("unwatching %s", channel)); RedisShardSubscriber.this.unwatch(channel, this); } }; @@ -199,7 +199,7 @@ private void onOperation( @Nullable Instant expiresAt) { List operationWatchers = watchers.get(channel); boolean observe = operation == null || operation.hasMetadata() || operation.getDone(); - log.log(Level.FINE, format("onOperation %s: %s", channel, operation)); + log.log(Level.FINER, format("onOperation %s: %s", channel, operation)); synchronized (watchers) { ImmutableList.Builder> observers = ImmutableList.builder(); for (TimedWatchFuture watchFuture : operationWatchers) { @@ -215,7 +215,7 @@ private void onOperation( executor.execute( () -> { if (observe) { - log.log(Level.FINE, "observing " + operation); + log.log(Level.FINER, "observing " + operation); observer.accept(operation); } }); diff --git a/src/main/java/build/buildfarm/instance/shard/ShardInstance.java b/src/main/java/build/buildfarm/instance/shard/ShardInstance.java index edbeb168f3..a37e4cb6ad 100644 --- a/src/main/java/build/buildfarm/instance/shard/ShardInstance.java +++ b/src/main/java/build/buildfarm/instance/shard/ShardInstance.java @@ -412,14 +412,14 @@ ListenableFuture iterate() throws IOException, InterruptedException { () -> {}, Deadline.after(5, MINUTES)); try { - log.log(Level.FINE, "queueing " + operationName); + log.log(Level.FINER, "queueing " + operationName); ListenableFuture queueFuture = queue(executeEntry, poller, queueTimeout); addCallback( queueFuture, new FutureCallback() { @Override public void onSuccess(Void result) { - log.log(Level.FINE, "successfully queued " + operationName); + log.log(Level.FINER, "successfully queued " + operationName); // nothing } @@ -433,7 +433,7 @@ public void onFailure(Throwable t) { long operationTransformDispatchUSecs = stopwatch.elapsed(MICROSECONDS) - canQueueUSecs; log.log( - Level.FINE, + Level.FINER, format( "OperationQueuer: Dispatched To Transform %s: %dus in canQueue, %dus in transform dispatch", operationName, canQueueUSecs, operationTransformDispatchUSecs)); @@ -448,7 +448,7 @@ public void onFailure(Throwable t) { @Override public void run() { - log.log(Level.FINE, "OperationQueuer: Running"); + log.log(Level.FINER, "OperationQueuer: Running"); try { while (transformTokensQueue.offer(new Object(), 5, MINUTES)) { stopwatch.start(); @@ -481,7 +481,7 @@ public void run() { } catch (Exception t) { log.log(Level.SEVERE, "OperationQueuer: fatal exception during iteration", t); } finally { - log.log(Level.FINE, "OperationQueuer: Exiting"); + log.log(Level.FINER, "OperationQueuer: Exiting"); } operationQueuer = null; try { @@ -566,7 +566,7 @@ public void stop() throws InterruptedException { return; } stopping = true; - log.log(Level.FINE, format("Instance %s is stopping", getName())); + log.log(Level.FINER, format("Instance %s is stopping", getName())); if (operationQueuer != null) { operationQueuer.stop(); } @@ -602,7 +602,7 @@ public void stop() throws InterruptedException { } actionCacheFetchService.shutdownNow(); workerStubs.invalidateAll(); - log.log(Level.FINE, format("Instance %s has been stopped", getName())); + log.log(Level.FINER, format("Instance %s has been stopped", getName())); stopping = false; stopped = true; } @@ -908,7 +908,7 @@ public void onError(Throwable t) { } else if (status.getCode() == Code.NOT_FOUND) { casMissCounter.inc(); log.log( - configs.getServer().isEnsureOutputsPresent() ? Level.WARNING : Level.FINE, + configs.getServer().isEnsureOutputsPresent() ? Level.WARNING : Level.FINER, worker + " did not contain " + DigestUtil.toString(blobDigest)); // ignore this, the worker will update the backplane eventually } else if (status.getCode() != Code.DEADLINE_EXCEEDED @@ -1022,7 +1022,7 @@ public void getBlob( final ListenableFuture> populatedWorkerListFuture; if (emptyWorkerList) { log.log( - Level.FINE, + Level.FINER, format( "worker list was initially empty for %s, attempting to correct", DigestUtil.toString(blobDigest))); @@ -1038,7 +1038,7 @@ public void getBlob( RequestMetadata.getDefaultInstance()), (foundOnWorkers) -> { log.log( - Level.FINE, + Level.FINER, format( "worker list was corrected for %s to be %s", DigestUtil.toString(blobDigest), foundOnWorkers.toString())); @@ -1068,7 +1068,7 @@ public void onError(Throwable t) { workersList.clear(); final ListenableFuture> workersListFuture; log.log( - Level.FINE, + Level.FINER, format( "worker list was depleted for %s, attempting to correct", DigestUtil.toString(blobDigest))); @@ -1084,7 +1084,7 @@ public void onError(Throwable t) { RequestMetadata.getDefaultInstance()), (foundOnWorkers) -> { log.log( - Level.FINE, + Level.FINER, format( "worker list was corrected after depletion for %s to be %s", DigestUtil.toString(blobDigest), foundOnWorkers.toString())); @@ -1383,7 +1383,7 @@ ListenableFuture expectDirectory( @Override public CompletableFuture apply(Digest digest, Executor executor) { log.log( - Level.FINE, + Level.FINER, format( "transformQueuedOperation(%s): fetching directory %s", reason, DigestUtil.toString(directoryBlobDigest))); @@ -1518,7 +1518,7 @@ private ListenableFuture transformQueuedOperation( expectCommand(commandDigest, requestMetadata), (command) -> { log.log( - Level.FINE, + Level.FINER, format("transformQueuedOperation(%s): fetched command", operationName)); if (command != null) { queuedOperationBuilder.setCommand(command); @@ -2003,7 +2003,7 @@ public ListenableFuture execute( executionSuccess.inc(); log.log( - Level.FINE, + Level.FINER, new StringBuilder() .append("ExecutionSuccess: ") .append(requestMetadata.getToolInvocationId()) @@ -2016,7 +2016,7 @@ public ListenableFuture execute( actionCache.invalidate(DigestUtil.asActionKey(actionDigest)); if (!skipCacheLookup && recentCacheServedExecutions.getIfPresent(requestMetadata) != null) { log.log( - Level.FINE, + Level.FINER, format("Operation %s will have skip_cache_lookup = true due to retry", operationName)); skipCacheLookup = true; } @@ -2241,7 +2241,7 @@ public ListenableFuture queue(ExecuteEntry executeEntry, Poller poller, Du poller.pause(); long checkCacheUSecs = stopwatch.elapsed(MICROSECONDS); log.log( - Level.FINE, + Level.FINER, format( "ShardInstance(%s): checkCache(%s): %sus elapsed", getName(), operation.getName(), checkCacheUSecs)); @@ -2268,7 +2268,7 @@ private ListenableFuture transformAndQueue( Digest actionDigest = metadata.getActionDigest(); SettableFuture queueFuture = SettableFuture.create(); log.log( - Level.FINE, + Level.FINER, format( "ShardInstance(%s): queue(%s): fetching action %s", getName(), operation.getName(), actionDigest.getHash())); @@ -2311,7 +2311,7 @@ private ListenableFuture transformAndQueue( actionFuture, (action) -> { log.log( - Level.FINE, + Level.FINER, format( "ShardInstance(%s): queue(%s): fetched action %s transforming queuedOperation", getName(), operation.getName(), actionDigest.getHash())); @@ -2341,7 +2341,7 @@ private ListenableFuture transformAndQueue( queuedFuture, (profiledQueuedMetadata) -> { log.log( - Level.FINE, + Level.FINER, format( "ShardInstance(%s): queue(%s): queuedOperation %s transformed, validating", getName(), @@ -2363,7 +2363,7 @@ private ListenableFuture transformAndQueue( validatedFuture, (profiledQueuedMetadata) -> { log.log( - Level.FINE, + Level.FINER, format( "ShardInstance(%s): queue(%s): queuedOperation %s validated, uploading", getName(), @@ -2415,7 +2415,7 @@ public void onSuccess(ProfiledQueuedOperationMetadata profiledQueuedMetadata) { long elapsedUSecs = stopwatch.elapsed(MICROSECONDS); long queueUSecs = elapsedUSecs - startQueueUSecs; log.log( - Level.FINE, + Level.FINER, format( "ShardInstance(%s): queue(%s): %dus checkCache, %dus transform, %dus validate, %dus upload, %dus queue, %dus elapsed", getName(), diff --git a/src/main/java/build/buildfarm/instance/shard/Util.java b/src/main/java/build/buildfarm/instance/shard/Util.java index 5e3493d0c6..7070097659 100644 --- a/src/main/java/build/buildfarm/instance/shard/Util.java +++ b/src/main/java/build/buildfarm/instance/shard/Util.java @@ -141,7 +141,7 @@ public void onFailure(Throwable t) { } }; log.log( - Level.FINE, + Level.FINER, format( "scanning through %d workers to find %s", workerSet.size(), DigestUtil.toString(digest))); @@ -184,7 +184,7 @@ static void checkMissingBlobOnInstance( public void onSuccess(Iterable missingDigests) { boolean found = Iterables.isEmpty(missingDigests); log.log( - Level.FINE, + Level.FINER, format( "check missing response for %s to %s was %sfound", DigestUtil.toString(digest), worker, found ? "" : "not ")); @@ -197,7 +197,7 @@ public void onFailure(Throwable t) { Status status = Status.fromThrowable(t); if (status.getCode() == Code.UNAVAILABLE) { log.log( - Level.FINE, + Level.FINER, format( "check missing response for %s to %s was not found for unavailable", DigestUtil.toString(digest), worker)); diff --git a/src/main/java/build/buildfarm/metrics/AbstractMetricsPublisher.java b/src/main/java/build/buildfarm/metrics/AbstractMetricsPublisher.java index 5f9422a421..925f4d95bf 100644 --- a/src/main/java/build/buildfarm/metrics/AbstractMetricsPublisher.java +++ b/src/main/java/build/buildfarm/metrics/AbstractMetricsPublisher.java @@ -172,7 +172,7 @@ protected static String formatRequestMetadataToJson( .usingTypeRegistry(typeRegistry) .omittingInsignificantWhitespace() .print(operationRequestMetadata); - log.log(Level.FINE, "{}", formattedRequestMetadata); + log.log(Level.FINER, "{}", formattedRequestMetadata); return formattedRequestMetadata; } } diff --git a/src/main/java/build/buildfarm/worker/Executor.java b/src/main/java/build/buildfarm/worker/Executor.java index 588d38c208..0416c2354d 100644 --- a/src/main/java/build/buildfarm/worker/Executor.java +++ b/src/main/java/build/buildfarm/worker/Executor.java @@ -199,7 +199,7 @@ private long executePolled( Stopwatch stopwatch) throws InterruptedException { /* execute command */ - log.log(Level.FINE, "Executor: Operation " + operation.getName() + " Executing command"); + log.log(Level.FINER, "Executor: Operation " + operation.getName() + " Executing command"); ActionResult.Builder resultBuilder = operationContext.executeResponse.getResultBuilder(); resultBuilder @@ -291,7 +291,7 @@ private long executePolled( long executeUSecs = stopwatch.elapsed(MICROSECONDS); log.log( - Level.FINE, + Level.FINER, String.format( "Executor::executeCommand(%s): Completed command: exit code %d", operationName, resultBuilder.getExitCode())); @@ -309,7 +309,7 @@ private long executePolled( throw e; } } else { - log.log(Level.FINE, "Executor: Operation " + operationName + " Failed to claim output"); + log.log(Level.FINER, "Executor: Operation " + operationName + " Failed to claim output"); boolean wasInterrupted = Thread.interrupted(); try { putError(); diff --git a/src/main/java/build/buildfarm/worker/InputFetcher.java b/src/main/java/build/buildfarm/worker/InputFetcher.java index 1c99df6a91..7be7a29e96 100644 --- a/src/main/java/build/buildfarm/worker/InputFetcher.java +++ b/src/main/java/build/buildfarm/worker/InputFetcher.java @@ -168,7 +168,7 @@ static String getExecutablePath( @VisibleForTesting long fetchPolled(Stopwatch stopwatch) throws InterruptedException { String operationName = operationContext.queueEntry.getExecuteEntry().getOperationName(); - log.log(Level.FINE, format("fetching inputs: %s", operationName)); + log.log(Level.FINER, format("fetching inputs: %s", operationName)); ExecutedActionMetadata.Builder executedAction = operationContext @@ -278,7 +278,7 @@ private void proceedToOutput(Action action, Command command, Path execDir) } } else { String operationName = operationContext.queueEntry.getExecuteEntry().getOperationName(); - log.log(Level.FINE, "InputFetcher: Operation " + operationName + " Failed to claim output"); + log.log(Level.FINER, "InputFetcher: Operation " + operationName + " Failed to claim output"); owner.error().put(operationContext); } diff --git a/src/main/java/build/buildfarm/worker/Pipeline.java b/src/main/java/build/buildfarm/worker/Pipeline.java index f266875538..da4eaacfb6 100644 --- a/src/main/java/build/buildfarm/worker/Pipeline.java +++ b/src/main/java/build/buildfarm/worker/Pipeline.java @@ -134,7 +134,7 @@ private void join(boolean closeStage) throws InterruptedException { } } if (stageToClose != null && !stageToClose.isClosed()) { - log.log(Level.FINE, "Closing stage at priority " + maxPriority); + log.log(Level.FINER, "Closing stage at priority " + maxPriority); stageToClose.close(); } } @@ -157,7 +157,7 @@ private void join(boolean closeStage) throws InterruptedException { if (!thread.isAlive()) { log.log( - Level.FINE, + Level.FINER, "Stage " + stage.name() + " has exited at priority " diff --git a/src/main/java/build/buildfarm/worker/PipelineStage.java b/src/main/java/build/buildfarm/worker/PipelineStage.java index d3f23d1b2d..7dd1d6d9ee 100644 --- a/src/main/java/build/buildfarm/worker/PipelineStage.java +++ b/src/main/java/build/buildfarm/worker/PipelineStage.java @@ -145,7 +145,7 @@ protected void logStart(String operationName) { } protected void logStart(String operationName, String message) { - getLogger().log(Level.FINE, String.format("%s: %s", logIterateId(operationName), message)); + getLogger().log(Level.FINER, String.format("%s: %s", logIterateId(operationName), message)); } protected void logComplete(String operationName, long usecs, long stallUSecs, boolean success) { @@ -155,7 +155,7 @@ protected void logComplete(String operationName, long usecs, long stallUSecs, bo protected void logComplete(String operationName, long usecs, long stallUSecs, String status) { getLogger() .log( - Level.FINE, + Level.FINER, String.format( "%s: %g ms (%g ms stalled) %s", logIterateId(operationName), usecs / 1000.0f, stallUSecs / 1000.0f, status)); diff --git a/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java b/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java index 96e8f1f218..e6d9826f45 100644 --- a/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java +++ b/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java @@ -373,7 +373,8 @@ public Path createExecDir( ImmutableList.Builder inputFiles = new ImmutableList.Builder<>(); ImmutableList.Builder inputDirectories = new ImmutableList.Builder<>(); - log.log(Level.FINE, "ExecFileSystem::createExecDir(" + operationName + ") calling fetchInputs"); + log.log( + Level.FINER, "ExecFileSystem::createExecDir(" + operationName + ") calling fetchInputs"); Iterable> fetchedFutures = fetchInputs( execDir, @@ -431,7 +432,7 @@ public Path createExecDir( rootInputDirectories.put(execDir, inputDirectories.build()); log.log( - Level.FINE, + Level.FINER, "ExecFileSystem::createExecDir(" + operationName + ") stamping output directories"); boolean stamped = false; try { diff --git a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java index 8b4cb1dd1f..143fa09966 100644 --- a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java +++ b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java @@ -239,12 +239,12 @@ public void resumePoller( } else { operationPollerCounter.inc(); log.log( - Level.INFO, format("%s: poller: Completed Poll for %s: OK", name, operationName)); + Level.FINE, format("%s: poller: Completed Poll for %s: OK", name, operationName)); } return success; }, () -> { - log.log(Level.INFO, format("%s: poller: Deadline expired for %s", name, operationName)); + log.log(Level.FINE, format("%s: poller: Deadline expired for %s", name, operationName)); onFailure.run(); }, deadline); @@ -483,7 +483,7 @@ private void uploadOutputFile( throws IOException, InterruptedException { String outputFile = actionRoot.relativize(outputPath).toString(); if (!Files.exists(outputPath)) { - log.log(Level.FINE, "ReportResultStage: " + outputFile + " does not exist..."); + log.log(Level.FINER, "ReportResultStage: " + outputFile + " does not exist..."); return; } @@ -491,7 +491,7 @@ private void uploadOutputFile( String message = String.format( "ReportResultStage: %s is a directory but it should have been a file", outputPath); - log.log(Level.FINE, message); + log.log(Level.FINER, message); preconditionFailure .addViolationsBuilder() .setType(VIOLATION_TYPE_INVALID) @@ -572,12 +572,12 @@ private void uploadOutputDirectory( throws IOException, InterruptedException { String outputDir = actionRoot.relativize(outputDirPath).toString(); if (!Files.exists(outputDirPath)) { - log.log(Level.FINE, "ReportResultStage: " + outputDir + " does not exist..."); + log.log(Level.FINER, "ReportResultStage: " + outputDir + " does not exist..."); return; } if (!Files.isDirectory(outputDirPath)) { - log.log(Level.FINE, "ReportResultStage: " + outputDir + " is not a directory..."); + log.log(Level.FINER, "ReportResultStage: " + outputDir + " is not a directory..."); preconditionFailure .addViolationsBuilder() .setType(VIOLATION_TYPE_INVALID) @@ -700,7 +700,7 @@ public boolean putOperation(Operation operation) throws IOException, Interrupted boolean success = createBackplaneRetrier().execute(() -> instance.putOperation(operation)); if (success && operation.getDone()) { completedOperations.inc(); - log.log(Level.FINE, "CompletedOperation: " + operation.getName()); + log.log(Level.FINER, "CompletedOperation: " + operation.getName()); } return success; } From 831572372df54c4a7e8539dfd27c75bd7a4d0dac Mon Sep 17 00:00:00 2001 From: Anshuman Mishra Date: Fri, 4 Aug 2023 13:23:58 -0700 Subject: [PATCH 036/311] Fix io_bytes_read metrics for buildfarm:server --- src/main/java/build/buildfarm/instance/shard/ShardInstance.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/build/buildfarm/instance/shard/ShardInstance.java b/src/main/java/build/buildfarm/instance/shard/ShardInstance.java index a37e4cb6ad..883931d2d4 100644 --- a/src/main/java/build/buildfarm/instance/shard/ShardInstance.java +++ b/src/main/java/build/buildfarm/instance/shard/ShardInstance.java @@ -895,7 +895,7 @@ private void fetchBlobFromWorker( public void onNext(ByteString nextChunk) { blobObserver.onNext(nextChunk); received += nextChunk.size(); - ioMetric.observe(received); + ioMetric.observe(nextChunk.size()); } @Override From 77fee77ba7c6484f045e62080cb8e6d93d52cfc8 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Fri, 28 Jul 2023 12:51:17 -0700 Subject: [PATCH 037/311] chore(deps): bump Guava from 31.1-jre to 32.1.1-jre Remediating https://nvd.nist.gov/vuln/detail/CVE-2023-2976 --- defs.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/defs.bzl b/defs.bzl index 65087518d5..5f71245c72 100644 --- a/defs.bzl +++ b/defs.bzl @@ -95,7 +95,7 @@ def buildfarm_init(name = "buildfarm"): "com.google.errorprone:error_prone_annotations:2.9.0", "com.google.errorprone:error_prone_core:0.92", "com.google.guava:failureaccess:1.0.1", - "com.google.guava:guava:31.1-jre", + "com.google.guava:guava:32.1.1-jre", "com.google.j2objc:j2objc-annotations:1.1", "com.google.jimfs:jimfs:1.1", "com.google.protobuf:protobuf-java-util:3.10.0", From b5754e4c5b33c50ddf6d5636e9fb00576283d7be Mon Sep 17 00:00:00 2001 From: Tobias Kongsvik Date: Tue, 8 Aug 2023 08:49:21 +0200 Subject: [PATCH 038/311] Upgrade opentelemetry javaagent to 1.28 --- deps.bzl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deps.bzl b/deps.bzl index 28a66281f4..2b994d33a5 100644 --- a/deps.bzl +++ b/deps.bzl @@ -176,9 +176,9 @@ def buildfarm_dependencies(repository_name = "build_buildfarm"): maybe( http_jar, "opentelemetry", - sha256 = "0523287984978c091be0d22a5c61f0bce8267eeafbbae58c98abaf99c9396832", + sha256 = "eccd069da36031667e5698705a6838d173d527a5affce6cc514a14da9dbf57d7", urls = [ - "https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v1.11.0/opentelemetry-javaagent.jar", + "https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v1.28.0/opentelemetry-javaagent.jar", ], ) From 9e7e633d4e4defd5f0052f9ebe27e4020406afa9 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Thu, 10 Aug 2023 11:16:46 -0700 Subject: [PATCH 039/311] Update platforms Fixes https://github.com/bazelbuild/bazel-buildfarm/issues/1421 --- deps.bzl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deps.bzl b/deps.bzl index 2b994d33a5..cb22b1641f 100644 --- a/deps.bzl +++ b/deps.bzl @@ -13,10 +13,10 @@ def archive_dependencies(third_party): { "name": "platforms", "urls": [ - "https://mirror.bazel.build/github.com/bazelbuild/platforms/releases/download/0.0.6/platforms-0.0.6.tar.gz", - "https://github.com/bazelbuild/platforms/releases/download/0.0.6/platforms-0.0.6.tar.gz", + "https://mirror.bazel.build/github.com/bazelbuild/platforms/releases/download/0.0.7/platforms-0.0.7.tar.gz", + "https://github.com/bazelbuild/platforms/releases/download/0.0.7/platforms-0.0.7.tar.gz", ], - "sha256": "5308fc1d8865406a49427ba24a9ab53087f17f5266a7aabbfc28823f3916e1ca", + "sha256": "3a561c99e7bdbe9173aa653fd579fe849f1d8d67395780ab4770b1f381431d51", }, { "name": "rules_jvm_external", From 18ae72ef484ea453afe60fae368bee4599d7a28d Mon Sep 17 00:00:00 2001 From: amishra-u <119983081+amishra-u@users.noreply.github.com> Date: Fri, 11 Aug 2023 16:37:50 -0700 Subject: [PATCH 040/311] Add download rate metrics for buildfarm:worker (#1418) * Add download metrics for buildfarm:worker * Run formatter * remove static * change IO_METRIC prometheus counter to static --- .../build/buildfarm/worker/shard/ShardWorkerInstance.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/build/buildfarm/worker/shard/ShardWorkerInstance.java b/src/main/java/build/buildfarm/worker/shard/ShardWorkerInstance.java index 04c11d315b..a891af7faa 100644 --- a/src/main/java/build/buildfarm/worker/shard/ShardWorkerInstance.java +++ b/src/main/java/build/buildfarm/worker/shard/ShardWorkerInstance.java @@ -56,6 +56,7 @@ import io.grpc.Status; import io.grpc.Status.Code; import io.grpc.stub.ServerCallStreamObserver; +import io.prometheus.client.Counter; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; @@ -68,6 +69,9 @@ @Log public class ShardWorkerInstance extends AbstractServerInstance { + private static final Counter IO_METRIC = + Counter.build().name("io_bytes_read").help("Read I/O (bytes)").register(); + private final Backplane backplane; public ShardWorkerInstance( @@ -132,6 +136,7 @@ public void getBlob( @Override public void onNext(ByteString data) { blobObserver.onNext(data); + IO_METRIC.inc(data.size()); } void removeBlobLocation() { From 1180a85e231feb99324001e437f1fdaf04634bd5 Mon Sep 17 00:00:00 2001 From: amishra-u <119983081+amishra-u@users.noreply.github.com> Date: Thu, 31 Aug 2023 05:15:44 -0700 Subject: [PATCH 041/311] Add request metadata interceptor to Worker (#1425) --- src/main/java/build/buildfarm/worker/shard/Worker.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/build/buildfarm/worker/shard/Worker.java b/src/main/java/build/buildfarm/worker/shard/Worker.java index da698726de..e1b7acf94c 100644 --- a/src/main/java/build/buildfarm/worker/shard/Worker.java +++ b/src/main/java/build/buildfarm/worker/shard/Worker.java @@ -41,6 +41,7 @@ import build.buildfarm.common.config.GrpcMetrics; import build.buildfarm.common.grpc.Retrier; import build.buildfarm.common.grpc.Retrier.Backoff; +import build.buildfarm.common.grpc.TracingMetadataUtils.ServerHeadersInterceptor; import build.buildfarm.common.services.ByteStreamService; import build.buildfarm.common.services.ContentAddressableStorageService; import build.buildfarm.instance.Instance; @@ -233,6 +234,7 @@ private Server createServer( storage, inputFetchStage, executeActionStage, context, completeStage, backplane)); } GrpcMetrics.handleGrpcMetricIntercepts(serverBuilder, configs.getWorker().getGrpcMetrics()); + serverBuilder.intercept(new ServerHeadersInterceptor()); return serverBuilder.build(); } From 8795c6e0ace4b73473bef4d1ec946d9814e75f24 Mon Sep 17 00:00:00 2001 From: amishra-u <119983081+amishra-u@users.noreply.github.com> Date: Thu, 31 Aug 2023 05:31:16 -0700 Subject: [PATCH 042/311] Separate channel for write api (#1424) * Separate channel for write api * shutdown channel on termination --- .../buildfarm/instance/shard/WorkerStubs.java | 1 + .../buildfarm/instance/stub/StubInstance.java | 26 ++++++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/main/java/build/buildfarm/instance/shard/WorkerStubs.java b/src/main/java/build/buildfarm/instance/shard/WorkerStubs.java index e0015f6fc4..abaf5f71e1 100644 --- a/src/main/java/build/buildfarm/instance/shard/WorkerStubs.java +++ b/src/main/java/build/buildfarm/instance/shard/WorkerStubs.java @@ -57,6 +57,7 @@ private static Instance newStubInstance(String worker, DigestUtil digestUtil, Du worker, digestUtil, createChannel(worker), + createChannel(worker), // separate write channel timeout, newStubRetrier(), newStubRetryService()); diff --git a/src/main/java/build/buildfarm/instance/stub/StubInstance.java b/src/main/java/build/buildfarm/instance/stub/StubInstance.java index dd647a327d..84ff692ab6 100644 --- a/src/main/java/build/buildfarm/instance/stub/StubInstance.java +++ b/src/main/java/build/buildfarm/instance/stub/StubInstance.java @@ -160,6 +160,7 @@ public class StubInstance implements Instance { private final String identifier; private final DigestUtil digestUtil; private final ManagedChannel channel; + private final ManagedChannel writeChannel; private final @Nullable Duration grpcTimeout; private final Retrier retrier; private final @Nullable ListeningScheduledExecutorService retryService; @@ -186,12 +187,24 @@ public StubInstance( this(name, identifier, digestUtil, channel, grpcTimeout, NO_RETRIES, /* retryService=*/ null); } + public StubInstance( + String name, + String identifier, + DigestUtil digestUtil, + ManagedChannel channel, + Duration grpcTimeout, + Retrier retrier, + @Nullable ListeningScheduledExecutorService retryService) { + this(name, identifier, digestUtil, channel, channel, grpcTimeout, retrier, retryService); + } + @SuppressWarnings("NullableProblems") public StubInstance( String name, String identifier, DigestUtil digestUtil, ManagedChannel channel, + ManagedChannel writeChannel, Duration grpcTimeout, Retrier retrier, @Nullable ListeningScheduledExecutorService retryService) { @@ -199,6 +212,7 @@ public StubInstance( this.identifier = identifier; this.digestUtil = digestUtil; this.channel = channel; + this.writeChannel = writeChannel; this.grpcTimeout = grpcTimeout; this.retrier = retrier; this.retryService = retryService; @@ -358,8 +372,14 @@ public void start(String publicName) {} @Override public void stop() throws InterruptedException { isStopped = true; - channel.shutdownNow(); - channel.awaitTermination(0, TimeUnit.SECONDS); + if (!channel.isShutdown()) { + channel.shutdownNow(); + channel.awaitTermination(0, TimeUnit.SECONDS); + } + if (!writeChannel.isShutdown()) { + writeChannel.shutdownNow(); + writeChannel.awaitTermination(0, TimeUnit.SECONDS); + } if (retryService != null && !shutdownAndAwaitTermination(retryService, 10, TimeUnit.SECONDS)) { log.log(Level.SEVERE, format("Could not shut down retry service for %s", identifier)); } @@ -661,7 +681,7 @@ Write getWrite( deadlined(bsBlockingStub).withInterceptors(attachMetadataInterceptor(requestMetadata)), Suppliers.memoize( () -> - ByteStreamGrpc.newStub(channel) + ByteStreamGrpc.newStub(writeChannel) .withInterceptors(attachMetadataInterceptor(requestMetadata))), resourceName, exceptionTranslator, From 0abb176c8130ac82a3f5ef5bc04f2e7d010e4dc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20B=C3=BChler?= Date: Thu, 7 Sep 2023 13:52:34 +0200 Subject: [PATCH 043/311] fix docu CAS config (#1432) --- .../content_addressable_storage.md | 23 ++++++++++--------- _site/docs/configuration/configuration.md | 21 +++++++++-------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/_site/docs/architecture/content_addressable_storage.md b/_site/docs/architecture/content_addressable_storage.md index a8955b4ce3..41b50d9948 100644 --- a/_site/docs/architecture/content_addressable_storage.md +++ b/_site/docs/architecture/content_addressable_storage.md @@ -38,9 +38,9 @@ This is the example presentation of a CAS in the memory instance available [here ``` worker: - cas: - type: MEMORY - maxSizeBytes: 2147483648 # 2 * 1024 * 1024 * 1024 + storages: + - type: MEMORY + maxSizeBytes: 2147483648 # 2 * 1024 * 1024 * 1024 ``` ## GRPC @@ -53,9 +53,11 @@ A grpc config example is available in the alternate instance specification in th server: name: shard worker: - cas: - type: GRPC - target: + storages: + - type: FILESYSTEM + path: "cache" + - type: GRPC + target: ``` ## HTTP/1 @@ -89,11 +91,10 @@ The CASFileCache is also available on MemoryInstance servers, where it can repre ``` worker: - cas: - type: FILESYSTEM - path: "cache" - maxSizeBytes: 2147483648 # 2 * 1024 * 1024 * 1024 - maxEntrySizeBytes: 2147483648 # 2 * 1024 * 1024 * 1024 + storages: + - type: FILESYSTEM + path: "cache" + maxSizeBytes: 2147483648 # 2 * 1024 * 1024 * 1024 ``` CASTest is a standalone tool to load the cache and print status information about it. diff --git a/_site/docs/configuration/configuration.md b/_site/docs/configuration/configuration.md index c6df9b58d3..8ee8d5d55b 100644 --- a/_site/docs/configuration/configuration.md +++ b/_site/docs/configuration/configuration.md @@ -332,20 +332,21 @@ Example: ``` worker: - cas: - type: FILESYSTEM - path: "cache" - maxSizeBytes: 2147483648 # 2 * 1024 * 1024 * 1024 - maxEntrySizeBytes: 2147483648 # 2 * 1024 * 1024 * 1024 - target: + storages: + - type: FILESYSTEM + path: "cache" + maxSizeBytes: 2147483648 # 2 * 1024 * 1024 * 1024 + maxEntrySizeBytes: 2147483648 # 2 * 1024 * 1024 * 1024 + target: ``` ``` worker: - cas: - type: GRPC - instanceName: external-cas - target: "cas.external.com:1234" + storages: + - type: FILESYSTEM + path: "cache" + - type: GRPC + target: "cas.external.com:1234" ``` ### Execution Policies From 882e86fb1516cc62b6dbfbd3712376e612b0e712 Mon Sep 17 00:00:00 2001 From: Dmitriy Shirchenko Date: Wed, 20 Sep 2023 11:35:27 -0700 Subject: [PATCH 044/311] Fix deadlock when handling Write request (#1442) * Fix deadlock by setting a timeout and removing the lock. * remove timeout as its not necessary * lint: delete unused import --- .../build/buildfarm/cas/cfc/CASFileCache.java | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java index a112c37bb2..3897c7268f 100644 --- a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java +++ b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java @@ -861,8 +861,14 @@ Write newWrite(BlobWriteKey key, ListenableFuture future) { Write write = new Write() { CancellableOutputStream out = null; + + @GuardedBy("this") boolean isReset = false; + + @GuardedBy("this") SettableFuture closedFuture = null; + + @GuardedBy("this") long fileCommittedSize = -1; @Override @@ -943,6 +949,11 @@ public synchronized ListenableFuture getOutputFuture( directExecutor()); } + private synchronized void syncCancelled() { + out = null; + isReset = true; + } + @Override public synchronized FeedbackOutputStream getOutput( long deadlineAfter, TimeUnit deadlineAfterUnits, Runnable onReadyHandler) @@ -951,6 +962,9 @@ public synchronized FeedbackOutputStream getOutput( // will block until it is returned via a close. if (closedFuture != null) { try { + while (!closedFuture.isDone()) { + wait(); + } closedFuture.get(); } catch (ExecutionException e) { throw new IOException(e.getCause()); @@ -967,8 +981,7 @@ public synchronized FeedbackOutputStream getOutput( UUID.fromString(key.getIdentifier()), cancelled -> { if (cancelled) { - out = null; - isReset = true; + syncCancelled(); } outClosedFuture.set(null); }, @@ -978,7 +991,11 @@ public synchronized FeedbackOutputStream getOutput( return uniqueOut; } - private void commitOpenState( + private synchronized void syncNotify() { + notify(); + } + + private synchronized void commitOpenState( CancellableOutputStream out, SettableFuture closedFuture) { // transition the Write to an open state, and modify all internal state required // atomically @@ -986,6 +1003,7 @@ private void commitOpenState( this.out = out; this.closedFuture = closedFuture; + closedFuture.addListener(this::syncNotify, directExecutor()); // they will likely write to this, so we can no longer assume isReset. // might want to subscribe to a write event on the stream isReset = false; From 773341ca188cf2e7acc363c322beb3ad46f7b72f Mon Sep 17 00:00:00 2001 From: George Gensure Date: Wed, 20 Sep 2023 14:38:07 -0400 Subject: [PATCH 045/311] Deliver RemoteCasWriter IOExceptions (#1438) Interactions with RemoteCasWriter which declare IOExceptions should throw them exclusively for failures. --- .../buildfarm/worker/shard/RemoteCasWriter.java | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/main/java/build/buildfarm/worker/shard/RemoteCasWriter.java b/src/main/java/build/buildfarm/worker/shard/RemoteCasWriter.java index c7b21bbd0b..8a5bfdb52f 100644 --- a/src/main/java/build/buildfarm/worker/shard/RemoteCasWriter.java +++ b/src/main/java/build/buildfarm/worker/shard/RemoteCasWriter.java @@ -73,7 +73,7 @@ private void insertFileToCasMember(Digest digest, Path file) Throwable cause = e.getCause(); Throwables.throwIfInstanceOf(cause, IOException.class); Throwables.throwIfUnchecked(cause); - throw new RuntimeException(cause); + throw new IOException(cause); } } @@ -90,7 +90,7 @@ private long writeToCasMember(Digest digest, InputStream in) Throwables.throwIfInstanceOf(cause, IOException.class); // prevent a discard of this frame Status status = Status.fromThrowable(cause); - throw status.asRuntimeException(); + throw new IOException(status.asException()); } } @@ -103,25 +103,20 @@ private Write getCasMemberWrite(Digest digest, String workerName) throws IOExcep public void insertBlob(Digest digest, ByteString content) throws IOException, InterruptedException { - insertBlobToCasMember(digest, content); - } - - private void insertBlobToCasMember(Digest digest, ByteString content) - throws IOException, InterruptedException { try (InputStream in = content.newInput()) { retrier.execute(() -> writeToCasMember(digest, in)); } catch (RetryException e) { Throwable cause = e.getCause(); Throwables.throwIfInstanceOf(cause, IOException.class); Throwables.throwIfUnchecked(cause); - throw new RuntimeException(cause); + throw new IOException(cause); } } private String getRandomWorker() throws IOException { synchronized (workerSet) { if (workerSet.isEmpty()) { - throw new RuntimeException("no available workers"); + throw new IOException("no available workers"); } Random rand = new Random(); int index = rand.nextInt(workerSet.size()); From 20d4ae57e5819a529db4a3dae20b06eb3765722c Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Wed, 6 Sep 2023 10:08:47 -0700 Subject: [PATCH 046/311] build: update maven mirrors JCenter is retired. Pick some mirrors from https://repo.maven.apache.org/maven2/.meta/repository-metadata.xml --- defs.bzl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/defs.bzl b/defs.bzl index 5f71245c72..5108852adb 100644 --- a/defs.bzl +++ b/defs.bzl @@ -138,8 +138,8 @@ def buildfarm_init(name = "buildfarm"): ], generate_compat_repositories = True, repositories = [ - "https://repo.maven.apache.org/maven2", - "https://jcenter.bintray.com", + "https://repo1.maven.org/maven2", + "https://mirrors.ibiblio.org/pub/mirrors/maven2", ], ) From a7f1ac2290d56a89a5379dfc4343b86765c3f555 Mon Sep 17 00:00:00 2001 From: shaohui Date: Mon, 28 Aug 2023 07:09:19 +0000 Subject: [PATCH 047/311] Add production-ready helm chart for deploying buildfarm on k8s --- kubernetes/helm-charts/buildfarm/.gitignore | 2 + kubernetes/helm-charts/buildfarm/.helmignore | 23 ++ kubernetes/helm-charts/buildfarm/Chart.yaml | 30 +++ .../helm-charts/buildfarm/templates/NOTES.txt | 22 ++ .../buildfarm/templates/_helpers.tpl | 73 +++++++ .../buildfarm/templates/configmap.yaml | 28 +++ .../templates/server/deployment.yaml | 78 +++++++ .../buildfarm/templates/server/service.yaml | 25 +++ .../templates/server/servicemonitor.yaml | 37 ++++ .../buildfarm/templates/serviceaccount.yaml | 12 + .../templates/shard-worker/autoscaler.yaml | 21 ++ .../templates/shard-worker/service.yaml | 25 +++ .../shard-worker/servicemonitor.yaml | 37 ++++ .../templates/shard-worker/statefulsets.yaml | 110 ++++++++++ .../templates/tests/test-connection.yaml | 15 ++ kubernetes/helm-charts/buildfarm/values.yaml | 206 ++++++++++++++++++ 16 files changed, 744 insertions(+) create mode 100644 kubernetes/helm-charts/buildfarm/.gitignore create mode 100644 kubernetes/helm-charts/buildfarm/.helmignore create mode 100644 kubernetes/helm-charts/buildfarm/Chart.yaml create mode 100644 kubernetes/helm-charts/buildfarm/templates/NOTES.txt create mode 100644 kubernetes/helm-charts/buildfarm/templates/_helpers.tpl create mode 100644 kubernetes/helm-charts/buildfarm/templates/configmap.yaml create mode 100644 kubernetes/helm-charts/buildfarm/templates/server/deployment.yaml create mode 100644 kubernetes/helm-charts/buildfarm/templates/server/service.yaml create mode 100644 kubernetes/helm-charts/buildfarm/templates/server/servicemonitor.yaml create mode 100644 kubernetes/helm-charts/buildfarm/templates/serviceaccount.yaml create mode 100644 kubernetes/helm-charts/buildfarm/templates/shard-worker/autoscaler.yaml create mode 100644 kubernetes/helm-charts/buildfarm/templates/shard-worker/service.yaml create mode 100644 kubernetes/helm-charts/buildfarm/templates/shard-worker/servicemonitor.yaml create mode 100644 kubernetes/helm-charts/buildfarm/templates/shard-worker/statefulsets.yaml create mode 100644 kubernetes/helm-charts/buildfarm/templates/tests/test-connection.yaml create mode 100644 kubernetes/helm-charts/buildfarm/values.yaml diff --git a/kubernetes/helm-charts/buildfarm/.gitignore b/kubernetes/helm-charts/buildfarm/.gitignore new file mode 100644 index 0000000000..8d8946152c --- /dev/null +++ b/kubernetes/helm-charts/buildfarm/.gitignore @@ -0,0 +1,2 @@ +charts +Chart.lock diff --git a/kubernetes/helm-charts/buildfarm/.helmignore b/kubernetes/helm-charts/buildfarm/.helmignore new file mode 100644 index 0000000000..0e8a0eb36f --- /dev/null +++ b/kubernetes/helm-charts/buildfarm/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/kubernetes/helm-charts/buildfarm/Chart.yaml b/kubernetes/helm-charts/buildfarm/Chart.yaml new file mode 100644 index 0000000000..ce443957dd --- /dev/null +++ b/kubernetes/helm-charts/buildfarm/Chart.yaml @@ -0,0 +1,30 @@ +apiVersion: v2 +name: buildfarm +description: A Helm chart for bazel buildfarm + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "v2.5.0" + +dependencies: + - condition: redis.enabled + name: redis + repository: https://charts.helm.sh/stable + version: 10.5.7 \ No newline at end of file diff --git a/kubernetes/helm-charts/buildfarm/templates/NOTES.txt b/kubernetes/helm-charts/buildfarm/templates/NOTES.txt new file mode 100644 index 0000000000..92421375fb --- /dev/null +++ b/kubernetes/helm-charts/buildfarm/templates/NOTES.txt @@ -0,0 +1,22 @@ +1. Get the application URL by running these commands: +{{- if .Values.server.ingress.enabled }} +{{- range $host := .Values.server.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.server.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.server.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "buildfarm.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.server.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "buildfarm.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "buildfarm.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.server.service.port }} +{{- else if contains "ClusterIP" .Values.server.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "buildfarm.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} diff --git a/kubernetes/helm-charts/buildfarm/templates/_helpers.tpl b/kubernetes/helm-charts/buildfarm/templates/_helpers.tpl new file mode 100644 index 0000000000..dffd8587bd --- /dev/null +++ b/kubernetes/helm-charts/buildfarm/templates/_helpers.tpl @@ -0,0 +1,73 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "buildfarm.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "buildfarm.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "buildfarm.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "buildfarm.labels" -}} +helm.sh/chart: {{ include "buildfarm.chart" . }} +{{ include "buildfarm.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "buildfarm.selectorLabels" -}} +app.kubernetes.io/name: {{ include "buildfarm.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "buildfarm.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "buildfarm.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + + +{{/* Checks for `externalRedis` */}} +{{- if .Values.externalRedis.host }} + {{/* check if they are using externalRedis (the default value for `externalRedis.host` is "localhost") */}} + {{- if not (eq .Values.externalRedis.host "localhost") }} + {{- if .Values.redis.enabled }} + {{ required "If `externalRedis.host` is set, then `redis.enabled` should be `false`!" nil }} + {{- end }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/kubernetes/helm-charts/buildfarm/templates/configmap.yaml b/kubernetes/helm-charts/buildfarm/templates/configmap.yaml new file mode 100644 index 0000000000..809d83e049 --- /dev/null +++ b/kubernetes/helm-charts/buildfarm/templates/configmap.yaml @@ -0,0 +1,28 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "buildfarm.fullname" . }}-config +data: + config.yml: |- + {{- range $key, $value := .Values.config }} + {{- if kindIs "map" $value }} + {{- else }} + {{ $key }}: {{ $value }}{{- end }} + {{- end }} + backplane: + {{- if .Values.redis.enabled }} + redisUri: "{{ .Values.redis.scheme }}://{{ printf "%s-redis-master.%s" (include "redis.fullname" .) (.Release.Namespace) }}:{{ "6379" }}" + {{- else }} + redisUri: "{{ .Values.externalRedis.uri }}" + {{- end }} + {{- with .Values.config.backplane }} + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.config.server }} + server: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.config.worker }} + worker: + {{- toYaml . | nindent 6 }} + {{- end }} diff --git a/kubernetes/helm-charts/buildfarm/templates/server/deployment.yaml b/kubernetes/helm-charts/buildfarm/templates/server/deployment.yaml new file mode 100644 index 0000000000..e56261f1fd --- /dev/null +++ b/kubernetes/helm-charts/buildfarm/templates/server/deployment.yaml @@ -0,0 +1,78 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "buildfarm.fullname" . }}-server + labels: + name: {{ include "buildfarm.fullname" . }}-server + {{- include "buildfarm.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.server.replicaCount }} + selector: + matchLabels: + name: {{ include "buildfarm.fullname" . }}-server + {{- include "buildfarm.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + checksum/server-config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + name: {{ include "buildfarm.fullname" . }}-server + {{- include "buildfarm.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "buildfarm.serviceAccountName" . }} + containers: + - name: buildfarm-server + image: "{{ .Values.server.image.repository }}:{{ .Values.server.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.server.image.pullPolicy }} + command: + - bash + - /app/build_buildfarm/buildfarm-server.binary + args: + - /config/config.yml + env: + {{- if .Values.server.extraEnv }} + {{- toYaml .Values.server.extraEnv | nindent 12 }} + {{- end }} + ports: + - containerPort: 8980 + name: "server-comm" + - containerPort: 9090 + name: "metrics" + livenessProbe: + httpGet: + path: / + port: metrics + readinessProbe: + httpGet: + path: / + port: metrics + resources: + {{- toYaml .Values.server.resources | nindent 12 }} + volumeMounts: + - mountPath: /config + name: config + readOnly: true + {{- with .Values.server.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.server.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.server.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + volumes: + - configMap: + defaultMode: 420 + name: {{ include "buildfarm.fullname" . }}-config + name: config diff --git a/kubernetes/helm-charts/buildfarm/templates/server/service.yaml b/kubernetes/helm-charts/buildfarm/templates/server/service.yaml new file mode 100644 index 0000000000..6079f92dc0 --- /dev/null +++ b/kubernetes/helm-charts/buildfarm/templates/server/service.yaml @@ -0,0 +1,25 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "buildfarm.fullname" . }}-server + labels: + name: {{ include "buildfarm.fullname" . }}-server + {{- include "buildfarm.labels" . | nindent 4 }} + {{- with .Values.server.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.server.service.type }} + ports: + - port: {{ .Values.server.service.port }} + targetPort: server-comm + protocol: TCP + name: gprc + - port: 9090 + targetPort: metrics + protocol: TCP + name: metrics + selector: + name: {{ include "buildfarm.fullname" . }}-server + {{- include "buildfarm.selectorLabels" . | nindent 4 }} diff --git a/kubernetes/helm-charts/buildfarm/templates/server/servicemonitor.yaml b/kubernetes/helm-charts/buildfarm/templates/server/servicemonitor.yaml new file mode 100644 index 0000000000..fe8a12b649 --- /dev/null +++ b/kubernetes/helm-charts/buildfarm/templates/server/servicemonitor.yaml @@ -0,0 +1,37 @@ +{{- if .Values.server.serviceMonitor.enabled }} +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "buildfarm.fullname" . }}-server + labels: + {{- include "buildfarm.labels" . | nindent 4 }} +spec: + endpoints: + - port: "metrics" + {{- with .Values.server.serviceMonitor.interval }} + interval: {{ . }} + {{- end }} + {{- with .Values.server.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ . }} + {{- end }} + honorLabels: true + path: {{ .Values.server.serviceMonitor.path }} + scheme: {{ .Values.server.serviceMonitor.scheme }} + {{- with .Values.server.serviceMonitor.relabelings }} + relabelings: + {{- toYaml . | nindent 6 }} + {{- end }} + jobLabel: "{{ .Release.Name }}" + selector: + matchLabels: + name: {{ include "buildfarm.fullname" . }}-server + {{- include "buildfarm.labels" . | nindent 6 }} + namespaceSelector: + matchNames: + - {{ .Release.Namespace }} + {{- with .Values.server.serviceMonitor.targetLabels }} + targetLabels: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/kubernetes/helm-charts/buildfarm/templates/serviceaccount.yaml b/kubernetes/helm-charts/buildfarm/templates/serviceaccount.yaml new file mode 100644 index 0000000000..f28779e3e4 --- /dev/null +++ b/kubernetes/helm-charts/buildfarm/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "buildfarm.serviceAccountName" . }} + labels: + {{- include "buildfarm.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/kubernetes/helm-charts/buildfarm/templates/shard-worker/autoscaler.yaml b/kubernetes/helm-charts/buildfarm/templates/shard-worker/autoscaler.yaml new file mode 100644 index 0000000000..4389c793b6 --- /dev/null +++ b/kubernetes/helm-charts/buildfarm/templates/shard-worker/autoscaler.yaml @@ -0,0 +1,21 @@ +{{- if .Values.shardWorker.autoscaling.enabled -}} +apiVersion: autoscaling/v1 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "buildfarm.fullname" . }}-shard-worker + labels: + name: {{ include "buildfarm.fullname" . }}-shard-worker + {{- include "buildfarm.labels" . | nindent 4 }} + {{- with .Values.shardWorker.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + maxReplicas: {{ .Values.shardWorker.autoscaling.maxReplicas }} + minReplicas: {{ .Values.shardWorker.autoscaling.minReplicas }} + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "buildfarm.fullname" . }}-shard-worker + targetCPUUtilizationPercentage: {{ .Values.shardWorker.autoscaling.targetCPUUtilizationPercentage }} +{{- end }} diff --git a/kubernetes/helm-charts/buildfarm/templates/shard-worker/service.yaml b/kubernetes/helm-charts/buildfarm/templates/shard-worker/service.yaml new file mode 100644 index 0000000000..135756bd5f --- /dev/null +++ b/kubernetes/helm-charts/buildfarm/templates/shard-worker/service.yaml @@ -0,0 +1,25 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "buildfarm.fullname" . }}-shard-worker + labels: + name: {{ include "buildfarm.fullname" . }}-shard-worker + {{- include "buildfarm.labels" . | nindent 4 }} + {{- with .Values.shardWorker.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.shardWorker.service.type }} + ports: + - port: {{ .Values.shardWorker.service.port }} + targetPort: worker-comm + protocol: TCP + name: gprc + - port: 9090 + targetPort: metrics + protocol: TCP + name: metrics + selector: + name: {{ include "buildfarm.fullname" . }}-shard-worker + {{- include "buildfarm.selectorLabels" . | nindent 4 }} diff --git a/kubernetes/helm-charts/buildfarm/templates/shard-worker/servicemonitor.yaml b/kubernetes/helm-charts/buildfarm/templates/shard-worker/servicemonitor.yaml new file mode 100644 index 0000000000..8ff1a59a56 --- /dev/null +++ b/kubernetes/helm-charts/buildfarm/templates/shard-worker/servicemonitor.yaml @@ -0,0 +1,37 @@ +{{- if .Values.shardWorker.serviceMonitor.enabled }} +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "buildfarm.fullname" . }}-shard-worker + labels: + {{- include "buildfarm.labels" . | nindent 4 }} +spec: + endpoints: + - port: "metrics" + {{- with .Values.shardWorker.serviceMonitor.interval }} + interval: {{ . }} + {{- end }} + {{- with .Values.shardWorker.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ . }} + {{- end }} + honorLabels: true + path: {{ .Values.shardWorker.serviceMonitor.path }} + scheme: {{ .Values.shardWorker.serviceMonitor.scheme }} + {{- with .Values.shardWorker.serviceMonitor.relabelings }} + relabelings: + {{- toYaml . | nindent 6 }} + {{- end }} + jobLabel: "{{ .Release.Name }}" + selector: + matchLabels: + name: {{ include "buildfarm.fullname" . }}-shard-worker + {{- include "buildfarm.labels" . | nindent 6 }} + namespaceSelector: + matchNames: + - {{ .Release.Namespace }} + {{- with .Values.shardWorker.serviceMonitor.targetLabels }} + targetLabels: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} diff --git a/kubernetes/helm-charts/buildfarm/templates/shard-worker/statefulsets.yaml b/kubernetes/helm-charts/buildfarm/templates/shard-worker/statefulsets.yaml new file mode 100644 index 0000000000..62706a61ac --- /dev/null +++ b/kubernetes/helm-charts/buildfarm/templates/shard-worker/statefulsets.yaml @@ -0,0 +1,110 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ include "buildfarm.fullname" . }}-shard-worker + labels: + name: {{ include "buildfarm.fullname" . }}-shard-worker + {{- include "buildfarm.labels" . | nindent 4 }} +spec: + serviceName: {{ include "buildfarm.fullname" . }}-shard-worker + {{- if .Values.shardWorker.autoscaling.enabled }} + replicas: {{ .Values.shardWorker.autoscaling.minReplicas }} + {{- else }} + replicas: {{ .Values.shardWorker.replicaCount }} + {{- end }} + selector: + matchLabels: + name: {{ include "buildfarm.fullname" . }}-shard-worker + {{- include "buildfarm.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + checksum/worker-config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + name: {{ include "buildfarm.fullname" . }}-shard-worker + {{- include "buildfarm.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "buildfarm.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: buildfarm-worker + image: "{{ .Values.shardWorker.image.repository }}:{{ .Values.shardWorker.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.shardWorker.image.pullPolicy }} + args: + - /config/config.yml + - --public_name=$(POD_IP):8982 + command: + - bash + - /app/build_buildfarm/buildfarm-shard-worker.binary + env: + - name: POD_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + {{- if .Values.shardWorker.extraEnv }} + {{- toYaml .Values.shardWorker.extraEnv | nindent 12 }} + {{- end }} + ports: + - containerPort: 8981 + name: "worker-comm" + - containerPort: 9090 + name: "metrics" + livenessProbe: + httpGet: + path: / + port: metrics + readinessProbe: + httpGet: + path: / + port: metrics + resources: + {{- toYaml .Values.shardWorker.resources | nindent 12 }} + volumeMounts: + - mountPath: /config + name: config + readOnly: true + - mountPath: /tmp/worker + name: {{ include "buildfarm.fullname" . }}-shard-worker-data + {{- with .Values.extraVolumeMounts }} + {{- tpl (toYaml .) $ | nindent 12 -}} + {{- end }} + {{- with .Values.shardWorker.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.shardWorker.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.shardWorker.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + volumes: + - configMap: + defaultMode: 420 + name: {{ include "buildfarm.fullname" . }}-config + name: config + {{- with .Values.shardWorker.extraVolumes }} + {{- tpl (toYaml .) $ | nindent 8 }} + {{- end }} + volumeClaimTemplates: + - metadata: + name: {{ include "buildfarm.fullname" . }}-shard-worker-data + spec: + accessModes: ["ReadWriteOnce"] + {{- with .Values.shardWorker.storage.class }} + storageClassName: "{{ . }}" + {{- end }} + resources: + requests: + storage: "{{ .Values.shardWorker.storage.size }}" diff --git a/kubernetes/helm-charts/buildfarm/templates/tests/test-connection.yaml b/kubernetes/helm-charts/buildfarm/templates/tests/test-connection.yaml new file mode 100644 index 0000000000..7aea6f1cfe --- /dev/null +++ b/kubernetes/helm-charts/buildfarm/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "buildfarm.fullname" . }}-test-connection" + labels: + {{- include "buildfarm.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: curl + image: appropriate/curl:latest + command: ['curl'] + args: ['--output', '/dev/null', '{{ include "buildfarm.fullname" . }}-server:{{ .Values.server.service.port }}'] + restartPolicy: Never diff --git a/kubernetes/helm-charts/buildfarm/values.yaml b/kubernetes/helm-charts/buildfarm/values.yaml new file mode 100644 index 0000000000..3bb2994b7a --- /dev/null +++ b/kubernetes/helm-charts/buildfarm/values.yaml @@ -0,0 +1,206 @@ +# Default values for buildfarm. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. +nameOverride: "" +fullnameOverride: "" + +imagePullSecrets: [] + +config: + # see: https://github.com/bazelbuild/bazel-buildfarm/blob/main/examples/config.yml + digestFunction: SHA256 + defaultActionTimeout: 600 + maximumActionTimeout: 3600 + maxEntrySizeBytes: "2147483648" # 2 * 1024 * 1024 * 1024 + prometheusPort: 9090 + backplane: + queues: + - name: "cpu" + allowUnmatched: true + properties: + - name: "min-cores" + value: "*" + - name: "max-cores" + value: "*" + server: + name: "shard" + recordBesEvents: true + worker: + port: 8982 + publicName: "localhost:8982" + executeStageWidth: 80 + inputFetchStageWidth: 8 + realInputDirectories: + - "external" + root: "/tmp/worker" + storages: + - type: FILESYSTEM + path: "cache" + maxSizeBytes: 536870912000 # 500 * 1024 * 1024 * 1024 + +server: + image: + repository: bazelbuild/buildfarm-server + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "" + replicaCount: 1 + resources: { } + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + service: + type: ClusterIP + port: 8980 + + ingress: + enabled: false + className: "" + annotations: { } + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: chart-example.local + paths: + - path: / + pathType: ImplementationSpecific + tls: [ ] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + + nodeSelector: {} + tolerations: [] + affinity: {} + extraVolumes: [] + # - name: additionalSecret + # secret: + # secretName: my-secret + # defaultMode: 0600 + + extraVolumeMounts: [] + # - name: customConfig + # mountPath: /mnt/config + # readOnly: true + extraEnv: + - name: JAVABIN + value: "/usr/bin/java" + + serviceMonitor: + ## If true, a ServiceMonitor CRD is created for a prometheus operator + ## https://github.com/coreos/prometheus-operator + ## + enabled: false + path: /metrics + # namespace: monitoring (defaults to use the namespace this chart is deployed to) + labels: {} + interval: 1m + scheme: http + tlsConfig: {} + scrapeTimeout: 30s + relabelings: [] + targetLabels: [] + +shardWorker: + image: + repository: bazelbuild/buildfarm-worker + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "" + replicaCount: 2 + autoscaling: + enabled: true + minReplicas: 2 + maxReplicas: 4 + targetCPUUtilizationPercentage: 50 + + resources: { } + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + storage: + # the storage class for pv, leave empty will using default + class: "" + size: 50Gi + + service: + type: ClusterIP + port: 8982 + + nodeSelector: {} + tolerations: [] + affinity: {} + extraVolumes: [] + # - name: additionalSecret + # secret: + # secretName: my-secret + # defaultMode: 0600 + + extraVolumeMounts: [] + # - name: customConfig + # mountPath: /mnt/config + # readOnly: true + extraEnv: + - name: JAVABIN + value: "/usr/bin/java" + serviceMonitor: + ## If true, a ServiceMonitor CRD is created for a prometheus operator + ## https://github.com/coreos/prometheus-operator + ## + enabled: false + path: /metrics + # namespace: monitoring (defaults to use the namespace this chart is deployed to) + labels: {} + interval: 1m + scheme: http + tlsConfig: {} + scrapeTimeout: 30s + relabelings: [] + targetLabels: [] + +################################### +## DATABASE | Embedded Redis +################################### +redis: + ## - set to `false` if using `externalRedis.*` + ## + enabled: true + scheme: "redis" + ## See more redis configs: https://github.com/bitnami/charts/blob/main/bitnami/redis/README.md + usePassword: false + ## configs for redis cluster mode + ## + cluster: + ## if redis runs in cluster mode + ## + enabled: false + + ## the number of redis slaves + ## + slaveCount: 1 + +externalRedis: + uri: "redis://localhost:6379" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" From dfe9d3da2981624d94390d279ae4aa7c5d3bad4d Mon Sep 17 00:00:00 2001 From: George Gensure Date: Thu, 21 Sep 2023 10:29:22 -0400 Subject: [PATCH 048/311] Update quick_start.md Fixes #1447 --- _site/docs/quick_start.md | 44 ++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/_site/docs/quick_start.md b/_site/docs/quick_start.md index 5383c31199..79b7595bd0 100644 --- a/_site/docs/quick_start.md +++ b/_site/docs/quick_start.md @@ -10,7 +10,7 @@ Here we describe how to use bazel remote caching or remote execution with buildf ## Setup -You can run this quick start on a single computer running nearly any flavor of linux. This computer is the localhost for the rest of the description. +You can run this quick start on a single computer running any flavor of linux that bazel supports. A C++ compiler is used here to demonstrate action execution. This computer is the localhost for the rest of the description. ### Backplane @@ -44,7 +44,7 @@ cc_binary( And an empty WORKSPACE file. -As a test, verify that `bazel run :main` builds your main program and runs it, and prints `Hello, World!`. This will ensure that you have properly installed bazel and a C++ compiler, and have a working target before moving on to remote execution. +As a test, verify that `bazel run :main` builds your main program and runs it, and prints `Hello, World!`. This will ensure that you have properly installed `bazel` and a C++ compiler, and have a working target before moving on to remote caching or remote execution. Download and extract the buildfarm repository. Each command sequence below will have the intended working directory indicated, between the client (workspace running bazel), and buildfarm. @@ -52,25 +52,33 @@ This tutorial assumes that you have a bazel binary in your path and you are in t ## Remote Caching -A Buildfarm server with an instance can be used strictly as an ActionCache and ContentAddressableStorage to improve build performance. This is an example of running a bazel client that will retrieve results if available, and store them if the cache is missed and the execution needs to run locally. +A Buildfarm cluster can be used strictly as an ActionCache (AC) and ContentAddressableStorage (CAS) to improve build performance. This is an example of running a bazel client that will retrieve results if available, otherwise store them on a cache miss after executing locally. Download the buildfarm repository and change into its directory, then: -run `bazelisk run src/main/java/build/buildfarm:buildfarm-server $PWD/examples/config.minimal.yml` + * run `bazel run src/main/java/build/buildfarm:buildfarm-server $PWD/examples/config.minimal.yml` This will wait while the server runs, indicating that it is ready for requests. -From another prompt (i.e. a separate terminal) in your newly created workspace directory from above: +A server alone does not itself store the content of action results. It acts as an endpoint for any number of workers that present storage, so we must also start a single worker. -run `bazel clean` -run `bazel run --remote_cache=grpc://localhost:8980 :main` +From another prompt (i.e. a separate terminal) in the buildfarm repository directory: + + * run `bazel run src/main/java/build/buildfarm:buildfarm-shard-worker $PWD/examples/config.minimal.yml` + +This will also wait while the worker runs, indicating it will be available to store cache content. + +From another prompt in your newly created workspace directory from above: + + * run `bazel clean` + * run `bazel run --remote_cache=grpc://localhost:8980 :main` Why do we clean here? Since we're verifying re-execution and caching, this ensures that we will execute any actions in the `run` step and interact with the remote cache. We should be attempting to retrieve cached results, and then when we miss - since we just started this memory resident server - bazel will upload the results of the execution for later use. There will be no change in the output of this bazel run if everything worked, since bazel does not provide output each time it uploads results. To prove that we have placed something in the action cache, we need to do the following: -run `bazel clean` -run `bazel run --remote_cache=localhost:8980 :main` + * run `bazel clean` + * run `bazel run --remote_cache=localhost:8980 :main` This should now print statistics on the `processes` line that indicate that you've retrieved results from the cache for your actions: @@ -80,20 +88,22 @@ INFO: 2 processes: 2 remote cache hit. ## Remote Execution (and caching) -Now we will use buildfarm for remote execution with a minimal configuration - a single memory instance, with a worker on the localhost that can execute a single process at a time - via a bazel invocation on our workspace. +Now we will use buildfarm for remote execution with a minimal configuration with a worker on the localhost that can execute a single process at a time, via a bazel invocation on our workspace. -First, we should restart the buildfarm server to ensure that we get remote execution (this can also be forced from the client by using `--noremote_accept_cached`). From the buildfarm server prompt and directory: +First, we should restart the buildfarm server, and delete the worker's cas storage to ensure that we get remote execution (this can also be forced from the client by using `--noremote_accept_cached`). From the buildfarm server prompt and directory: -interrupt a running `buildfarm-server` -run `bazelisk run src/main/java/build/buildfarm:buildfarm-server $PWD/examples/config.minimal.yml` + * interrupt the running `buildfarm-server` (i.e. Ctrl-C) + * run `bazel run src/main/java/build/buildfarm:buildfarm-server $PWD/examples/config.minimal.yml` From another prompt in the buildfarm repository directory: -run `bazelisk run src/main/java/build/buildfarm:buildfarm-shard-worker $PWD/examples/config.minimal.yml` + * interrupt the running `buildfarm-shard-worker` (i.e. Ctrl-C) + * recursively remove the worker root directory: from the config.minimal.yml, this will be `rm -fr /tmp/worker` + * run `bazel run src/main/java/build/buildfarm:buildfarm-shard-worker $PWD/examples/config.minimal.yml` From another prompt, in your client workspace: -run `bazel run --remote_executor=grpc://localhost:8980 :main` + * run `bazel run --remote_executor=grpc://localhost:8980 :main` Your build should now print out the following on its `processes` summary line: @@ -117,6 +127,10 @@ To stop the containers, run: ./examples/bf-run stop ``` +## Next Steps + +We've started our worker on the same host as our server, and also the same host on which we built with bazel, but these services can be spread across many machines, per 'remote'. A large number of workers, with a relatively small number of servers (10:1 and 100:1 ratios have been used in practice), consolidating large disks and beefy multicore cpus/gpus on workers, with specialization of what work they perform for bazel builds (or other client work), and specializing servers to have hefty network connections to funnel content traffic. A buildfarm deployment can service hundreds or thousands of developers or CI processes, enabling them to benefit from each others' shared context in the AC/CAS, and the pooled execution of a fleet of worker hosts eager to consume operations and deliver results. + ## Buildfarm Manager You can now easily launch a new Buildfarm cluster locally or in AWS using an open sourced [Buildfarm Manager](https://github.com/80degreeswest/bfmgr). From ed157797fb41f5838d75b1f7e1d9de31cb791412 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Thu, 21 Sep 2023 12:07:55 -0400 Subject: [PATCH 049/311] Permit --prometheus_port to override config Specifying --prometheus_port for either server or worker will: Override the config value if delivered as int > 0, otherwise leave the config value alone. Since prometheusPort as configured <= 0 disables the server, this permits users to specify '0' to override the config with a disable switch. Updated quick_start docs to reflect this extra parameter. --- _site/docs/quick_start.md | 16 +++++----- .../common/config/BuildfarmConfigs.java | 6 ++++ .../common/config/BuildfarmOptions.java | 30 +++++++++++++++++++ .../common/config/ServerOptions.java | 6 +--- .../common/config/ShardWorkerOptions.java | 6 +--- 5 files changed, 47 insertions(+), 17 deletions(-) create mode 100644 src/main/java/build/buildfarm/common/config/BuildfarmOptions.java diff --git a/_site/docs/quick_start.md b/_site/docs/quick_start.md index 79b7595bd0..7af957ee63 100644 --- a/_site/docs/quick_start.md +++ b/_site/docs/quick_start.md @@ -64,8 +64,10 @@ A server alone does not itself store the content of action results. It acts as a From another prompt (i.e. a separate terminal) in the buildfarm repository directory: - * run `bazel run src/main/java/build/buildfarm:buildfarm-shard-worker $PWD/examples/config.minimal.yml` + * run `bazel run src/main/java/build/buildfarm:buildfarm-shard-worker -- --prometheus_port=9091 $PWD/examples/config.minimal.yml` +The `--` option is bazel convention to treat all subsequent arguments as parameters to the running app, like our `--prometheus_port`, instead of interpreting them with `run` +The `--prometheus_port=9091` option allows this worker to run alongside our server, who will have started and logged that it has started a service on port `9090`. You can also turn this option off (with `--` separator), with `--prometheus_option=0` for either server or worker. This will also wait while the worker runs, indicating it will be available to store cache content. From another prompt in your newly created workspace directory from above: @@ -90,16 +92,16 @@ INFO: 2 processes: 2 remote cache hit. Now we will use buildfarm for remote execution with a minimal configuration with a worker on the localhost that can execute a single process at a time, via a bazel invocation on our workspace. -First, we should restart the buildfarm server, and delete the worker's cas storage to ensure that we get remote execution (this can also be forced from the client by using `--noremote_accept_cached`). From the buildfarm server prompt and directory: +First, to clean out the results from the previous cached actions, flush your local redis database: + + * run `redis-cli flushdb` + +Next, we should restart the buildfarm server, and delete the worker's cas storage to ensure that we get remote execution (this can also be forced from the client by using `--noremote_accept_cached`). From the buildfarm server prompt and directory: * interrupt the running `buildfarm-server` (i.e. Ctrl-C) * run `bazel run src/main/java/build/buildfarm:buildfarm-server $PWD/examples/config.minimal.yml` -From another prompt in the buildfarm repository directory: - - * interrupt the running `buildfarm-shard-worker` (i.e. Ctrl-C) - * recursively remove the worker root directory: from the config.minimal.yml, this will be `rm -fr /tmp/worker` - * run `bazel run src/main/java/build/buildfarm:buildfarm-shard-worker $PWD/examples/config.minimal.yml` +You can leave the worker running from the Remote Caching step, it will not require a restart From another prompt, in your client workspace: diff --git a/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java b/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java index 432a11a90a..68106d56c7 100644 --- a/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java +++ b/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java @@ -78,6 +78,9 @@ public static BuildfarmConfigs loadServerConfigs(String[] args) throws Configura if (options.port > 0) { buildfarmConfigs.getServer().setPort(options.port); } + if (options.prometheusPort >= 0) { + buildfarmConfigs.setPrometheusPort(options.prometheusPort); + } adjustServerConfigs(buildfarmConfigs); return buildfarmConfigs; } @@ -94,6 +97,9 @@ public static BuildfarmConfigs loadWorkerConfigs(String[] args) throws Configura if (!Strings.isNullOrEmpty(options.publicName)) { buildfarmConfigs.getWorker().setPublicName(options.publicName); } + if (options.prometheusPort >= 0) { + buildfarmConfigs.setPrometheusPort(options.prometheusPort); + } adjustWorkerConfigs(buildfarmConfigs); return buildfarmConfigs; } diff --git a/src/main/java/build/buildfarm/common/config/BuildfarmOptions.java b/src/main/java/build/buildfarm/common/config/BuildfarmOptions.java new file mode 100644 index 0000000000..defeebbf48 --- /dev/null +++ b/src/main/java/build/buildfarm/common/config/BuildfarmOptions.java @@ -0,0 +1,30 @@ +// Copyright 2023 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package build.buildfarm.common.config; + +import com.google.devtools.common.options.Option; +import com.google.devtools.common.options.OptionsBase; + +/** Command-line options definition for Worker. */ +public class BuildfarmOptions extends OptionsBase { + @Option(name = "help", abbrev = 'h', help = "Prints usage info.", defaultValue = "true") + public boolean help; + + @Option( + name = "prometheus_port", + help = "Port for the prometheus service. '0' will disable prometheus hosting", + defaultValue = "-1") + public int prometheusPort; +} diff --git a/src/main/java/build/buildfarm/common/config/ServerOptions.java b/src/main/java/build/buildfarm/common/config/ServerOptions.java index 5c1e00a0d5..35f47d6d13 100644 --- a/src/main/java/build/buildfarm/common/config/ServerOptions.java +++ b/src/main/java/build/buildfarm/common/config/ServerOptions.java @@ -15,13 +15,9 @@ package build.buildfarm.common.config; import com.google.devtools.common.options.Option; -import com.google.devtools.common.options.OptionsBase; /** Command-line options definition for example server. */ -public class ServerOptions extends OptionsBase { - @Option(name = "help", abbrev = 'h', help = "Prints usage info.", defaultValue = "true") - public boolean help; - +public class ServerOptions extends BuildfarmOptions { @Option(name = "port", abbrev = 'p', help = "Port to use.", defaultValue = "-1") public int port; diff --git a/src/main/java/build/buildfarm/common/config/ShardWorkerOptions.java b/src/main/java/build/buildfarm/common/config/ShardWorkerOptions.java index 7671ae0a4f..c116d31673 100644 --- a/src/main/java/build/buildfarm/common/config/ShardWorkerOptions.java +++ b/src/main/java/build/buildfarm/common/config/ShardWorkerOptions.java @@ -15,13 +15,9 @@ package build.buildfarm.common.config; import com.google.devtools.common.options.Option; -import com.google.devtools.common.options.OptionsBase; /** Command-line options definition for Worker. */ -public class ShardWorkerOptions extends OptionsBase { - @Option(name = "help", abbrev = 'h', help = "Prints usage info.", defaultValue = "true") - public boolean help; - +public class ShardWorkerOptions extends BuildfarmOptions { @Option( name = "root", help = "Root base directory for all work being performed.", From fb7cbd8cce4679c2a48424be92c3c5c51affec8d Mon Sep 17 00:00:00 2001 From: Yuriy Belenitsky Date: Fri, 22 Sep 2023 08:41:32 -0400 Subject: [PATCH 050/311] [metrics] Emit operation_exit_code metric to track execution exit codes (#1444) Co-authored-by: Trevor Hickey --- _site/docs/metrics/metrics.md | 4 ++++ .../buildfarm/metrics/AbstractMetricsPublisher.java | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/_site/docs/metrics/metrics.md b/_site/docs/metrics/metrics.md index 5aa96fe56f..6079b7e9b7 100644 --- a/_site/docs/metrics/metrics.md +++ b/_site/docs/metrics/metrics.md @@ -124,6 +124,10 @@ Gauge for the number of operations in each stage (using a stage_name for each in Gauge for the completed operations status (using a status_code label for each individual GRPC code) +**operation_exit_code** + +Gauge for the completed operations exit code (using a exit_code label for each individual execution exit code) + **operation_worker** Gauge for the number of operations executed on each worker (using a worker_name label for each individual worker) diff --git a/src/main/java/build/buildfarm/metrics/AbstractMetricsPublisher.java b/src/main/java/build/buildfarm/metrics/AbstractMetricsPublisher.java index 925f4d95bf..7dd09b6d0f 100644 --- a/src/main/java/build/buildfarm/metrics/AbstractMetricsPublisher.java +++ b/src/main/java/build/buildfarm/metrics/AbstractMetricsPublisher.java @@ -51,6 +51,13 @@ public abstract class AbstractMetricsPublisher implements MetricsPublisher { .labelNames("worker_name") .help("Operations per worker.") .register(); + + private static final Gauge operationExitCode = + Gauge.build() + .name("operation_exit_code") + .labelNames("exit_code") + .help("Operation execution exit code.") + .register(); private static final Histogram queuedTime = Histogram.build().name("queued_time_ms").help("Queued time in ms.").register(); private static final Histogram outputUploadTime = @@ -97,6 +104,11 @@ protected OperationRequestMetadata populateRequestMetadata( Integer.toString( operationRequestMetadata.getExecuteResponse().getStatus().getCode())) .inc(); + operationExitCode + .labels( + Integer.toString( + operationRequestMetadata.getExecuteResponse().getResult().getExitCode())) + .inc(); if (operationRequestMetadata.getExecuteResponse().hasResult() && operationRequestMetadata.getExecuteResponse().getResult().hasExecutionMetadata()) { operationsPerWorker From a6fe20747ca6f217df84f7cd0432bae0a0dc7fe8 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Thu, 7 Sep 2023 10:48:49 -0700 Subject: [PATCH 051/311] feat(redis): support rediss:// URIs for Redis-SSL Support "rediss://" (extra 's', like https) to indicate Redis-SSL connections. For Redis client identifier, we use the `identifier` passed to RedisShardBackplane. --- .../instance/shard/JedisClusterFactory.java | 27 ++++++++++++++----- .../instance/shard/RedisShardBackplane.java | 2 +- .../build/buildfarm/tools/WorkerProfile.java | 2 +- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/main/java/build/buildfarm/instance/shard/JedisClusterFactory.java b/src/main/java/build/buildfarm/instance/shard/JedisClusterFactory.java index 922558b50b..e3172b01f2 100644 --- a/src/main/java/build/buildfarm/instance/shard/JedisClusterFactory.java +++ b/src/main/java/build/buildfarm/instance/shard/JedisClusterFactory.java @@ -30,6 +30,7 @@ import redis.clients.jedis.JedisPoolConfig; import redis.clients.jedis.ScanParams; import redis.clients.jedis.ScanResult; +import redis.clients.jedis.util.JedisURIHelper; /** * @class JedisClusterFactory @@ -43,15 +44,17 @@ public class JedisClusterFactory { * @brief Create a jedis cluster instance. * @details Use proto configuration to connect to a redis cluster server and provide a jedis * client. - * @param config Configuration for connecting to a redis cluster server. + * @param identifier Redis Client name. * @return An established jedis client used to operate on the redis cluster. * @note Suggested return identifier: jedis. + * @link Redis Client name */ - public static Supplier create() throws ConfigurationException { + public static Supplier create(String identifier) throws ConfigurationException { // null password is required to elicit no auth in jedis String[] redisNodes = configs.getBackplane().getRedisNodes(); if (redisNodes != null && redisNodes.length > 0) { return createJedisClusterFactory( + identifier, list2Set(redisNodes), configs.getBackplane().getTimeout(), configs.getBackplane().getMaxAttempts(), @@ -63,6 +66,7 @@ public static Supplier create() throws ConfigurationException { // support "" as redis password. return createJedisClusterFactory( + identifier, parseUri(configs.getBackplane().getRedisUri()), configs.getBackplane().getTimeout(), configs.getBackplane().getMaxAttempts(), @@ -80,7 +84,7 @@ public static Supplier create() throws ConfigurationException { * @note Suggested return identifier: jedis. */ public static JedisCluster createTest() throws Exception { - JedisCluster redis = JedisClusterFactory.create().get(); + JedisCluster redis = JedisClusterFactory.create("test").get(); // use the client to create an empty redis cluster // this will prevent any persistent data across test runs @@ -151,7 +155,12 @@ private static void deleteExistingKeys(Jedis node) { * @note Suggested return identifier: jedis. */ private static Supplier createJedisClusterFactory( - URI redisUri, int timeout, int maxAttempts, String password, JedisPoolConfig poolConfig) { + String identifier, + URI redisUri, + int timeout, + int maxAttempts, + String password, + JedisPoolConfig poolConfig) { return () -> new JedisCluster( new HostAndPort(redisUri.getHost(), redisUri.getPort()), @@ -159,7 +168,9 @@ private static Supplier createJedisClusterFactory( /* soTimeout=*/ Integer.max(2000, timeout), Integer.max(5, maxAttempts), password, - poolConfig); + identifier, + poolConfig, + JedisURIHelper.isRedisSSLScheme(redisUri)); } /** @@ -174,6 +185,7 @@ private static Supplier createJedisClusterFactory( * @note Suggested return identifier: jedis. */ private static Supplier createJedisClusterFactory( + String identifier, Set redisUrisNodes, int timeout, int maxAttempts, @@ -186,12 +198,13 @@ private static Supplier createJedisClusterFactory( /* soTimeout=*/ Integer.max(2000, timeout), Integer.max(5, maxAttempts), password, - poolConfig); + identifier, + poolConfig, + false); } /** * @brief Create a jedis pool config. * @details Use configuration to build the appropriate jedis pool configuration. - * @param config Configuration for connecting to a redis cluster server. * @return A created jedis pool config. * @note Suggested return identifier: poolConfig. */ diff --git a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java index f0a5ff222e..200929ecbb 100644 --- a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java +++ b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java @@ -152,7 +152,7 @@ public RedisShardBackplane( Function onPublish, Function onComplete) throws ConfigurationException { - this(source, onPublish, onComplete, JedisClusterFactory.create()); + this(source, onPublish, onComplete, JedisClusterFactory.create(source)); } public RedisShardBackplane( diff --git a/src/main/java/build/buildfarm/tools/WorkerProfile.java b/src/main/java/build/buildfarm/tools/WorkerProfile.java index ee36bf035a..69dbb8cdee 100644 --- a/src/main/java/build/buildfarm/tools/WorkerProfile.java +++ b/src/main/java/build/buildfarm/tools/WorkerProfile.java @@ -109,7 +109,7 @@ private static Set getWorkers(String[] args) throws ConfigurationExcepti } catch (IOException e) { System.out.println("Could not parse yml configuration file." + e); } - RedisClient client = new RedisClient(JedisClusterFactory.create().get()); + RedisClient client = new RedisClient(JedisClusterFactory.create("worker-profile").get()); return client.call(jedis -> fetchWorkers(jedis, System.currentTimeMillis())); } From 79eee498c54fc8b67f9368c1f0d54229fdc44e05 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Wed, 20 Sep 2023 12:04:52 -0700 Subject: [PATCH 052/311] chore: make code more readable --- .../build/buildfarm/instance/shard/JedisClusterFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/build/buildfarm/instance/shard/JedisClusterFactory.java b/src/main/java/build/buildfarm/instance/shard/JedisClusterFactory.java index e3172b01f2..5f85da29f6 100644 --- a/src/main/java/build/buildfarm/instance/shard/JedisClusterFactory.java +++ b/src/main/java/build/buildfarm/instance/shard/JedisClusterFactory.java @@ -170,7 +170,7 @@ private static Supplier createJedisClusterFactory( password, identifier, poolConfig, - JedisURIHelper.isRedisSSLScheme(redisUri)); + /* ssl=*/ JedisURIHelper.isRedisSSLScheme(redisUri)); } /** @@ -200,7 +200,7 @@ private static Supplier createJedisClusterFactory( password, identifier, poolConfig, - false); + /* ssl=*/ false); } /** * @brief Create a jedis pool config. From 330566948e437d2c9cf624930a83e24bd54c4992 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Sat, 23 Sep 2023 09:44:48 -0400 Subject: [PATCH 053/311] Update rules_docker dependencies via injection Specify and patch more recent rules_go and bazel_gazelle per upstream patch. Docker images work with recent HEAD releases of bazel as a result. Depends on #1453 resolution to actually build //... Fixes #1440 --- deps.bzl | 19 +++++++++++++++++++ third_party/docker_go_toolchain.patch | 11 +++++++++++ 2 files changed, 30 insertions(+) create mode 100644 third_party/docker_go_toolchain.patch diff --git a/deps.bzl b/deps.bzl index cb22b1641f..c31cf04edd 100644 --- a/deps.bzl +++ b/deps.bzl @@ -106,10 +106,29 @@ def archive_dependencies(third_party): "patch_args": ["-p1"], "patches": ["%s:clang_toolchain.patch" % third_party], }, + + # Used to build release container images { "name": "io_bazel_rules_docker", "sha256": "b1e80761a8a8243d03ebca8845e9cc1ba6c82ce7c5179ce2b295cd36f7e394bf", "urls": ["https://github.com/bazelbuild/rules_docker/releases/download/v0.25.0/rules_docker-v0.25.0.tar.gz"], + "patch_args": ["-p0"], + "patches": ["%s:docker_go_toolchain.patch" % third_party], + }, + + # Updated versions of io_bazel_rules_docker dependencies for bazel compatibility + { + "name": "io_bazel_rules_go", + "sha256": "278b7ff5a826f3dc10f04feaf0b70d48b68748ccd512d7f98bf442077f043fe3", + "urls": [ + "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.41.0/rules_go-v0.41.0.zip", + "https://github.com/bazelbuild/rules_go/releases/download/v0.41.0/rules_go-v0.41.0.zip", + ], + }, + { + "name": "bazel_gazelle", + "sha256": "d3fa66a39028e97d76f9e2db8f1b0c11c099e8e01bf363a923074784e451f809", + "urls": ["https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.33.0/bazel-gazelle-v0.33.0.tar.gz"], }, # Bazel is referenced as a dependency so that buildfarm can access the linux-sandbox as a potential execution wrapper. diff --git a/third_party/docker_go_toolchain.patch b/third_party/docker_go_toolchain.patch new file mode 100644 index 0000000000..3b00ff333c --- /dev/null +++ b/third_party/docker_go_toolchain.patch @@ -0,0 +1,11 @@ +--- repositories/go_repositories.bzl.orig 2023-09-23 08:36:00.148468653 -0400 ++++ repositories/go_repositories.bzl 2023-09-23 08:33:22.502127476 -0400 +@@ -37,7 +37,7 @@ + go_repository_default_config (str, optional): A file used to determine the root of the workspace. + """ + go_rules_dependencies() +- go_register_toolchains() ++ go_register_toolchains("1.21.0") + gazelle_dependencies(go_repository_default_config = go_repository_default_config) + excludes = native.existing_rules().keys() + if "com_github_google_go_containerregistry" not in excludes: From 7f86c47922c995de798946a94cc0eb25c141fdb3 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Tue, 18 Jul 2023 13:58:57 -0400 Subject: [PATCH 054/311] Treat '.' working_directory segment as current Any '.' appearance as a segment should be considered to be the current directory in the search sequence of a working_directory path. --- .../buildfarm/instance/server/AbstractServerInstance.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/build/buildfarm/instance/server/AbstractServerInstance.java b/src/main/java/build/buildfarm/instance/server/AbstractServerInstance.java index 57d827ffa8..d828b7bd89 100644 --- a/src/main/java/build/buildfarm/instance/server/AbstractServerInstance.java +++ b/src/main/java/build/buildfarm/instance/server/AbstractServerInstance.java @@ -1168,6 +1168,9 @@ void validateCommand( } else { Directory directory = directoriesIndex.get(inputRootDigest); for (String segment : workingDirectory.split("/")) { + if (segment.equals(".")) { + continue; + } Directory nextDirectory = directory; // linear for now for (DirectoryNode dirNode : directory.getDirectoriesList()) { From 90439ca36863b9f4971a142733fa9dae895e1500 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Mon, 25 Sep 2023 09:51:24 -0400 Subject: [PATCH 055/311] Remove unused setExecuteResponseBuilder Method setExecuteResponseBuilder is not called in OperationContext --- src/main/java/build/buildfarm/worker/OperationContext.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/build/buildfarm/worker/OperationContext.java b/src/main/java/build/buildfarm/worker/OperationContext.java index e07649d03a..71b1975783 100644 --- a/src/main/java/build/buildfarm/worker/OperationContext.java +++ b/src/main/java/build/buildfarm/worker/OperationContext.java @@ -74,11 +74,6 @@ private Builder( this.queueEntry = queueEntry; } - public Builder setExecuteResponseBuilder(ExecuteResponse.Builder executeResponse) { - this.executeResponse = executeResponse; - return this; - } - public Builder setOperation(Operation operation) { this.operation = operation; return this; From 8cc247f3ccc4b98370eeb0254316090f7bf9b49c Mon Sep 17 00:00:00 2001 From: George Gensure Date: Mon, 17 Jul 2023 15:21:59 -0400 Subject: [PATCH 056/311] Log on write errors --- .../buildfarm/common/services/WriteStreamObserver.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java b/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java index 483f266e03..36cc0595a6 100644 --- a/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java +++ b/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java @@ -291,6 +291,13 @@ private boolean errorResponse(Throwable t) { requestMetadata.getToolInvocationId(), requestMetadata.getActionId(), name)); + } else { + log.log( + Level.WARNING, + format( + "error %s after %d requests and %d bytes at offset %d", + name, requestCount, requestBytes, earliestOffset), + t); } return true; } From f651cdbf7b2203e8cdb5645a1f869589e42f28c3 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Mon, 24 Jul 2023 10:23:54 -0400 Subject: [PATCH 057/311] Use integer ids for Sqlite bidirectional index The cost in size for a single table bidirectional index is vast compared to the use of 3nf integer keys. Experimental estimates offer a decrease in file size of 90%. --- .../cas/cfc/SqliteFileDirectoriesIndex.java | 64 +++++++++++++++---- .../cas/cfc/DirectoriesIndexTest.java | 1 + 2 files changed, 54 insertions(+), 11 deletions(-) diff --git a/src/main/java/build/buildfarm/cas/cfc/SqliteFileDirectoriesIndex.java b/src/main/java/build/buildfarm/cas/cfc/SqliteFileDirectoriesIndex.java index 030c749037..b18b5bd22c 100644 --- a/src/main/java/build/buildfarm/cas/cfc/SqliteFileDirectoriesIndex.java +++ b/src/main/java/build/buildfarm/cas/cfc/SqliteFileDirectoriesIndex.java @@ -57,13 +57,19 @@ private void open() { throw new RuntimeException(e); } + String createDirectoriesSql = + "CREATE TABLE directories (id INTEGER PRIMARY KEY, name VARCHAR UNIQUE)"; + String createFilesSql = "CREATE TABLE files (id INTEGER PRIMARY KEY, name VARCHAR UNIQUE)"; String createEntriesSql = "CREATE TABLE entries (\n" - + " path TEXT NOT NULL,\n" - + " directory TEXT NOT NULL\n" + + " file_id INTEGER NOT NULL REFERENCES files(id) ON DELETE CASCADE,\n" + + " directory_id INTEGER NOT NULL REFERENCES directories(id) ON DELETE CASCADE,\n" + + " PRIMARY KEY (file_id, directory_id)\n" + ")"; try (Statement stmt = conn.createStatement()) { + stmt.execute(createDirectoriesSql); + stmt.execute(createFilesSql); stmt.execute(createEntriesSql); } catch (SQLException e) { throw new RuntimeException(e); @@ -77,11 +83,13 @@ private void open() { public synchronized void start() { open(); - String createPathIndexSql = "CREATE INDEX path_idx ON entries (path)"; - String createDirectoryIndexSql = "CREATE INDEX directory_idx ON entries (directory)"; + String createPathIndexSql = "CREATE INDEX files_name_idx ON entries (file_id)"; + String createDirectoryIndexSql = "CREATE INDEX directory_idx ON entries (directory_id)"; + String enforceForeignKeys = "PRAGMA foreign_keys=ON"; try (Statement stmt = conn.createStatement()) { stmt.execute(createPathIndexSql); stmt.execute(createDirectoryIndexSql); + stmt.execute(enforceForeignKeys); } catch (SQLException e) { throw new RuntimeException(e); } @@ -101,7 +109,8 @@ public void close() { private Set removeEntryDirectories(String entry) { open(); - String selectSql = "SELECT directory FROM entries WHERE path = ?"; + String selectSql = + "SELECT d.name as directory FROM files f INNER JOIN entries e ON f.id = e.file_id INNER JOIN directories d ON d.id = e.directory_id WHERE f.name = ?"; ImmutableSet.Builder directoriesBuilder = ImmutableSet.builder(); try (PreparedStatement selectStatement = conn.prepareStatement(selectSql)) { @@ -116,7 +125,7 @@ private Set removeEntryDirectories(String entry) { } // all directories featuring this entry are now invalid ImmutableSet directories = directoriesBuilder.build(); - String deleteSql = "DELETE FROM entries where directory = ?"; + String deleteSql = "DELETE FROM directories where name = ?"; try (PreparedStatement deleteStatement = conn.prepareStatement(deleteSql)) { conn.setAutoCommit(false); for (Digest directory : directories) { @@ -128,6 +137,14 @@ private Set removeEntryDirectories(String entry) { } catch (SQLException e) { throw new RuntimeException(e); } + // clear out orphaned files + try (Statement orphanStatement = conn.createStatement()) { + String deleteOrphanSql = + "DELETE FROM files WHERE id in (SELECT id FROM files f LEFT JOIN entries e ON f.id = e.file_id WHERE e.file_id IS NULL)"; + orphanStatement.execute(deleteOrphanSql); + } catch (SQLException e) { + throw new RuntimeException(e); + } return directories; } @@ -141,13 +158,37 @@ public synchronized Set removeEntry(String entry) throws IOException { private synchronized void addEntriesDirectory(Set entries, Digest directory) { open(); - String digest = DigestUtil.toString(directory); - String insertSql = "INSERT INTO entries (path, directory) VALUES (?,?)"; - try (PreparedStatement insertStatement = conn.prepareStatement(insertSql)) { + String directoryName = DigestUtil.toString(directory); + String filesInsertSql = "INSERT OR IGNORE INTO files (name) VALUES (?)"; + try (PreparedStatement filesInsertStatement = conn.prepareStatement(filesInsertSql)) { + conn.setAutoCommit(false); + for (String entry : entries) { + filesInsertStatement.setString(1, entry); + filesInsertStatement.addBatch(); + } + filesInsertStatement.executeBatch(); + conn.commit(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + // should be novel directory + String directoriesInsertSql = "INSERT INTO directories (name) VALUES (?)"; + try (PreparedStatement directoriesInsertStatement = + conn.prepareStatement(directoriesInsertSql)) { + conn.setAutoCommit(false); + directoriesInsertStatement.setString(1, directoryName); + directoriesInsertStatement.executeUpdate(); + conn.commit(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + String entriesInsertSql = + "INSERT INTO entries (file_id, directory_id) SELECT f.id, d.id FROM files f, directories d WHERE f.name = ? AND d.name = ?"; + try (PreparedStatement insertStatement = conn.prepareStatement(entriesInsertSql)) { conn.setAutoCommit(false); - insertStatement.setString(2, digest); for (String entry : entries) { insertStatement.setString(1, entry); + insertStatement.setString(2, directoryName); insertStatement.addBatch(); } insertStatement.executeBatch(); @@ -168,8 +209,9 @@ private void removeEntriesDirectory(Digest directory) { open(); String digest = DigestUtil.toString(directory); - String deleteSql = "DELETE FROM entries WHERE directory = ?"; + String deleteSql = "DELETE FROM directories WHERE name = ?"; try (PreparedStatement deleteStatement = conn.prepareStatement(deleteSql)) { + conn.setAutoCommit(true); deleteStatement.setString(1, digest); deleteStatement.executeUpdate(); } catch (SQLException e) { diff --git a/src/test/java/build/buildfarm/cas/cfc/DirectoriesIndexTest.java b/src/test/java/build/buildfarm/cas/cfc/DirectoriesIndexTest.java index 3eec66def7..b4effa2bc8 100644 --- a/src/test/java/build/buildfarm/cas/cfc/DirectoriesIndexTest.java +++ b/src/test/java/build/buildfarm/cas/cfc/DirectoriesIndexTest.java @@ -51,6 +51,7 @@ protected DirectoriesIndexTest(Path root, DirectoriesIndexType type) { } else { throw new IllegalArgumentException("DirectoriesIndex type is not supported."); } + directoriesIndex.start(); } @Before From 9f93972508b907f45c3b06bdbb23186f8b7d5c8f Mon Sep 17 00:00:00 2001 From: Yuriy Belenitsky Date: Fri, 29 Sep 2023 13:47:57 -0400 Subject: [PATCH 058/311] Update graceful shutdown functionality to better handle worker terminations (#1462) --- _site/docs/configuration/configuration.md | 41 +++++----- examples/config.yml | 2 +- .../build/buildfarm/common/config/Admin.java | 2 + .../build/buildfarm/common/config/Worker.java | 1 + .../shard/ShutDownWorkerGracefully.java | 31 ------- .../build/buildfarm/worker/shard/Worker.java | 80 +++++++++---------- 6 files changed, 64 insertions(+), 93 deletions(-) diff --git a/_site/docs/configuration/configuration.md b/_site/docs/configuration/configuration.md index 8ee8d5d55b..cbd286587f 100644 --- a/_site/docs/configuration/configuration.md +++ b/_site/docs/configuration/configuration.md @@ -238,26 +238,27 @@ backplane: ### Worker -| Configuration | Accepted and _Default_ Values | Environment Var | Description | -|----------------------------------|-------------------------------|-------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| port | Integer, _8981_ | | Listening port of the worker | -| publicName | String, _DERIVED:port_ | INSTANCE_NAME | Host:port of the GRPC server, required to be accessible by all servers | -| root | String, _/tmp/worker_ | | Path for all operation content storage | -| inlineContentLimit | Integer, _1048567_ | | Total size in bytes of inline content for action results, output files, stdout, stderr content | -| operationPollPeriod | Integer, _1_ | | Period between poll operations at any stage | -| executeStageWidth | Integer, _0_ | EXECUTION_STAGE_WIDTH | Number of CPU cores available for execution (0 = system available cores) | -| executeStageWidthOffset | Integer, _0_ | | Offset number of CPU cores available for execution (to allow for use by other processes) | -| inputFetchStageWidth | Integer, _0_ | | Number of concurrently available slots to fetch inputs (0 = system calculated based on CPU cores) | -| inputFetchDeadline | Integer, _60_ | | Limit on time (seconds) for input fetch stage to fetch inputs | -| linkInputDirectories | boolean, _true_ | | Use an input directory creation strategy which creates a single directory tree at the highest level containing no output paths of any kind, and symlinks that directory into an action's execroot, saving large amounts of time spent manufacturing the same read-only input hierirchy over multiple actions' executions | -| execOwner | String, _null_ | | Create exec trees containing directories that are owned by this user | -| hexBucketLevels | Integer, _0_ | | Number of levels to create for directory storage by leading byte of the hash (problematic, not recommended) | -| defaultMaxCores | Integer, _0_ | | Constrain all executions to this logical core count unless otherwise specified via min/max-cores (0 = no limit) | -| limitGlobalExecution | boolean, _false_ | | Constrain all executions to a pool of logical cores specified in executeStageWidth | -| onlyMulticoreTests | boolean, _false_ | | Only permit tests to exceed the default coresvalue for their min/max-cores range specification (only works with non-zero defaultMaxCores) | -| allowBringYourOwnContainer | boolean, _false_ | | Enable execution in a custom Docker container | -| errorOperationRemainingResources | boolean, _false_ | | | -| realInputDirectories | List of Strings, _external_ | | A list of paths that will not be subject to the effects of linkInputDirectories setting, may also be used to provide writable directories as input roots for actions which expect to be able to write to an input location and will fail if they cannot | +| Configuration | Accepted and _Default_ Values | Environment Var | Description | +|----------------------------------|-------------------------------|-----------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| port | Integer, _8981_ | | Listening port of the worker | +| publicName | String, _DERIVED:port_ | INSTANCE_NAME | Host:port of the GRPC server, required to be accessible by all servers | +| root | String, _/tmp/worker_ | | Path for all operation content storage | +| inlineContentLimit | Integer, _1048567_ | | Total size in bytes of inline content for action results, output files, stdout, stderr content | +| operationPollPeriod | Integer, _1_ | | Period between poll operations at any stage | +| executeStageWidth | Integer, _0_ | EXECUTION_STAGE_WIDTH | Number of CPU cores available for execution (0 = system available cores) | +| executeStageWidthOffset | Integer, _0_ | | Offset number of CPU cores available for execution (to allow for use by other processes) | +| inputFetchStageWidth | Integer, _0_ | | Number of concurrently available slots to fetch inputs (0 = system calculated based on CPU cores) | +| inputFetchDeadline | Integer, _60_ | | Limit on time (seconds) for input fetch stage to fetch inputs | +| linkInputDirectories | boolean, _true_ | | Use an input directory creation strategy which creates a single directory tree at the highest level containing no output paths of any kind, and symlinks that directory into an action's execroot, saving large amounts of time spent manufacturing the same read-only input hierirchy over multiple actions' executions | +| execOwner | String, _null_ | | Create exec trees containing directories that are owned by this user | +| hexBucketLevels | Integer, _0_ | | Number of levels to create for directory storage by leading byte of the hash (problematic, not recommended) | +| defaultMaxCores | Integer, _0_ | | Constrain all executions to this logical core count unless otherwise specified via min/max-cores (0 = no limit) | +| limitGlobalExecution | boolean, _false_ | | Constrain all executions to a pool of logical cores specified in executeStageWidth | +| onlyMulticoreTests | boolean, _false_ | | Only permit tests to exceed the default coresvalue for their min/max-cores range specification (only works with non-zero defaultMaxCores) | +| allowBringYourOwnContainer | boolean, _false_ | | Enable execution in a custom Docker container | +| errorOperationRemainingResources | boolean, _false_ | | | +| realInputDirectories | List of Strings, _external_ | | A list of paths that will not be subject to the effects of linkInputDirectories setting, may also be used to provide writable directories as input roots for actions which expect to be able to write to an input location and will fail if they cannot | +| gracefulShutdownSeconds | Integer, 0 | | Time in seconds to allow for operations in flight to finish when shutdown signal is received | ``` worker: diff --git a/examples/config.yml b/examples/config.yml index 3c435fccc7..dd165a4d46 100644 --- a/examples/config.yml +++ b/examples/config.yml @@ -38,7 +38,6 @@ server: admin: deploymentEnvironment: AWS clusterEndpoint: "grpc://localhost" - enableGracefulShutdown: false metrics: publisher: LOG logLevel: FINEST @@ -126,6 +125,7 @@ worker: onlyMulticoreTests: false allowBringYourOwnContainer: false errorOperationRemainingResources: false + gracefulShutdownSeconds: 0 sandboxSettings: alwaysUse: false selectForBlockNetwork: false diff --git a/src/main/java/build/buildfarm/common/config/Admin.java b/src/main/java/build/buildfarm/common/config/Admin.java index 07deb4ce70..f4f8168225 100644 --- a/src/main/java/build/buildfarm/common/config/Admin.java +++ b/src/main/java/build/buildfarm/common/config/Admin.java @@ -11,5 +11,7 @@ public enum DEPLOYMENT_ENVIRONMENT { private DEPLOYMENT_ENVIRONMENT deploymentEnvironment; private String clusterEndpoint; + // This configuration is deprecated but is left here for backwards compatibility. Use + // worker:gracefulShutdownSeconds instead. private boolean enableGracefulShutdown; } diff --git a/src/main/java/build/buildfarm/common/config/Worker.java b/src/main/java/build/buildfarm/common/config/Worker.java index 294b70dc2f..4caaff2b02 100644 --- a/src/main/java/build/buildfarm/common/config/Worker.java +++ b/src/main/java/build/buildfarm/common/config/Worker.java @@ -35,6 +35,7 @@ public class Worker { private boolean onlyMulticoreTests = false; private boolean allowBringYourOwnContainer = false; private boolean errorOperationRemainingResources = false; + private int gracefulShutdownSeconds = 0; private ExecutionPolicy[] executionPolicies = {}; private SandboxSettings sandboxSettings = new SandboxSettings(); diff --git a/src/main/java/build/buildfarm/worker/shard/ShutDownWorkerGracefully.java b/src/main/java/build/buildfarm/worker/shard/ShutDownWorkerGracefully.java index 63b1b205cb..711c3cf0d3 100644 --- a/src/main/java/build/buildfarm/worker/shard/ShutDownWorkerGracefully.java +++ b/src/main/java/build/buildfarm/worker/shard/ShutDownWorkerGracefully.java @@ -14,9 +14,6 @@ package build.buildfarm.worker.shard; -import static java.util.logging.Level.WARNING; - -import build.buildfarm.common.config.BuildfarmConfigs; import build.buildfarm.v1test.PrepareWorkerForGracefulShutDownRequest; import build.buildfarm.v1test.PrepareWorkerForGracefulShutDownRequestResults; import build.buildfarm.v1test.ShutDownWorkerGrpc; @@ -26,7 +23,6 @@ @Log public class ShutDownWorkerGracefully extends ShutDownWorkerGrpc.ShutDownWorkerImplBase { - private static BuildfarmConfigs configs = BuildfarmConfigs.getInstance(); private final Worker worker; public ShutDownWorkerGracefully(Worker worker) { @@ -44,33 +40,6 @@ public ShutDownWorkerGracefully(Worker worker) { public void prepareWorkerForGracefulShutdown( PrepareWorkerForGracefulShutDownRequest request, StreamObserver responseObserver) { - String clusterId = configs.getServer().getClusterId(); - String clusterEndpoint = configs.getServer().getAdmin().getClusterEndpoint(); - if (clusterId == null - || clusterId.equals("") - || clusterEndpoint == null - || clusterEndpoint.equals("")) { - String errorMessage = - String.format( - "Current AdminConfig doesn't have cluster_id or cluster_endpoint set, " - + "the worker %s won't be shut down.", - configs.getWorker().getPublicName()); - log.log(WARNING, errorMessage); - responseObserver.onError(new RuntimeException(errorMessage)); - return; - } - - if (!configs.getServer().getAdmin().isEnableGracefulShutdown()) { - String errorMessage = - String.format( - "Current AdminConfig doesn't support shut down worker gracefully, " - + "the worker %s won't be shut down.", - configs.getWorker().getPublicName()); - log.log(WARNING, errorMessage); - responseObserver.onError(new RuntimeException(errorMessage)); - return; - } - try { CompletableFuture.runAsync(worker::prepareWorkerForGracefulShutdown); responseObserver.onNext(PrepareWorkerForGracefulShutDownRequestResults.newBuilder().build()); diff --git a/src/main/java/build/buildfarm/worker/shard/Worker.java b/src/main/java/build/buildfarm/worker/shard/Worker.java index e1b7acf94c..a33dbaad60 100644 --- a/src/main/java/build/buildfarm/worker/shard/Worker.java +++ b/src/main/java/build/buildfarm/worker/shard/Worker.java @@ -27,7 +27,6 @@ import build.bazel.remote.execution.v2.Compressor; import build.bazel.remote.execution.v2.Digest; -import build.buildfarm.admin.aws.AwsAdmin; import build.buildfarm.backplane.Backplane; import build.buildfarm.cas.ContentAddressableStorage; import build.buildfarm.cas.ContentAddressableStorage.Blob; @@ -91,7 +90,6 @@ import javax.annotation.PreDestroy; import javax.naming.ConfigurationException; import lombok.extern.java.Log; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.ComponentScan; @@ -140,52 +138,51 @@ public class Worker { private Pipeline pipeline; private Backplane backplane; private LoadingCache workerStubs; - @Autowired private AwsAdmin awsAdmin; /** - * The method will prepare the worker for graceful shutdown and send out grpc request to disable - * scale in protection when the worker is ready. If unexpected errors happened, it will cancel the - * graceful shutdown progress make the worker available again. + * The method will prepare the worker for graceful shutdown when the worker is ready. Note on + * using stderr here instead of log. By the time this is called in PreDestroy, the log is no + * longer available and is not logging messages. */ public void prepareWorkerForGracefulShutdown() { - inGracefulShutdown = true; - log.log( - Level.INFO, - "The current worker will not be registered again and should be shutdown gracefully!"); - pipeline.stopMatchingOperations(); - int scanRate = 30; // check every 30 seconds - int timeWaited = 0; - int timeOut = 60 * 15; // 15 minutes - - try { - while (!pipeline.isEmpty() && timeWaited < timeOut) { - SECONDS.sleep(scanRate); - timeWaited += scanRate; - log.log(INFO, String.format("Pipeline is still not empty after %d seconds.", timeWaited)); - } - } catch (InterruptedException e) { - log.log(Level.SEVERE, "The worker gracefully shutdown is interrupted: " + e.getMessage()); - } finally { - // make a grpc call to disable scale protection - String clusterEndpoint = configs.getServer().getAdmin().getClusterEndpoint(); - log.log( - INFO, + if (configs.getWorker().getGracefulShutdownSeconds() == 0) { + System.err.println( String.format( - "It took the worker %d seconds to %s", - timeWaited, - pipeline.isEmpty() ? "finish all actions" : "but still cannot finish all actions")); + "Graceful Shutdown is not enabled. Worker is shutting down without finishing executions in progress.")); + } else { + inGracefulShutdown = true; + System.err.println( + "Graceful Shutdown - The current worker will not be registered again and should be shutdown gracefully!"); + pipeline.stopMatchingOperations(); + int scanRate = 30; // check every 30 seconds + int timeWaited = 0; + int timeOut = configs.getWorker().getGracefulShutdownSeconds(); + try { - awsAdmin.disableHostScaleInProtection(clusterEndpoint, configs.getWorker().getPublicName()); - } catch (Exception e) { - log.log( - SEVERE, + if (pipeline.isEmpty()) { + System.err.println("Graceful Shutdown - no work in the pipeline."); + } else { + System.err.println( + String.format("Graceful Shutdown - waiting for executions to finish.")); + } + while (!pipeline.isEmpty() && timeWaited < timeOut) { + SECONDS.sleep(scanRate); + timeWaited += scanRate; + System.err.println( + String.format( + "Graceful Shutdown - Pipeline is still not empty after %d seconds.", timeWaited)); + } + } catch (InterruptedException e) { + System.err.println( + "Graceful Shutdown - The worker gracefully shutdown is interrupted: " + e.getMessage()); + } finally { + System.err.println( String.format( - "gRPC call to AdminService to disable scale in protection failed with exception: %s and stacktrace %s", - e.getMessage(), Arrays.toString(e.getStackTrace()))); - // Gracefully shutdown cannot be performed successfully because of error in - // AdminService side. Under this scenario, the worker has to be added back to the worker - // pool. - inGracefulShutdown = false; + "Graceful Shutdown - It took the worker %d seconds to %s", + timeWaited, + pipeline.isEmpty() + ? "finish all actions" + : "gracefully shutdown but still cannot finish all actions")); } } } @@ -637,6 +634,7 @@ public void start() throws ConfigurationException, InterruptedException, IOExcep @PreDestroy public void stop() throws InterruptedException { System.err.println("*** shutting down gRPC server since JVM is shutting down"); + prepareWorkerForGracefulShutdown(); PrometheusPublisher.stopHttpServer(); boolean interrupted = Thread.interrupted(); if (pipeline != null) { From ec4b82cd488e6a01c3b235210a2fd4090d701105 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Tue, 26 Sep 2023 13:21:25 -0400 Subject: [PATCH 059/311] Manipulate worker set directly in RSB Avoid dependency on subscriber to update state changes when removing workers. This prevents an NPE which will occur invariably when workers are allowably configured with subscribeToBackplane: false. --- .../build/buildfarm/instance/shard/RedisShardBackplane.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java index 200929ecbb..6676accdf3 100644 --- a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java +++ b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java @@ -634,7 +634,7 @@ public boolean removeWorker(String name, String reason) throws IOException { .setRemove(WorkerChange.Remove.newBuilder().setSource(source).setReason(reason).build()) .build(); String workerChangeJson = JsonFormat.printer().print(workerChange); - return subscriber.removeWorker(name) + return storageWorkerSet.remove(name) && client.call( jedis -> removeWorkerAndPublish(jedis, name, workerChangeJson, /* storage=*/ true)); } From c48d600e5a2b69dc42b732bd16f556c9e6b4b49a Mon Sep 17 00:00:00 2001 From: George Gensure Date: Tue, 26 Sep 2023 13:24:53 -0400 Subject: [PATCH 060/311] Remove publishTtlMetric option The individual metric controls for ttl are not necessary either for performance or feature support. Use Files' attributes acquisition mechanism for modified time. --- examples/config.yml | 1 - .../build/buildfarm/cas/cfc/CASFileCache.java | 54 +++++++------------ .../build/buildfarm/common/config/Cas.java | 3 -- .../worker/shard/ShardCASFileCache.java | 2 - .../build/buildfarm/worker/shard/Worker.java | 1 - .../buildfarm/cas/cfc/CASFileCacheTest.java | 3 -- 6 files changed, 20 insertions(+), 44 deletions(-) diff --git a/examples/config.yml b/examples/config.yml index dd165a4d46..6ea0ee1132 100644 --- a/examples/config.yml +++ b/examples/config.yml @@ -112,7 +112,6 @@ worker: hexBucketLevels: 0 execRootCopyFallback: false target: - publishTtlMetric: false executeStageWidth: 1 inputFetchStageWidth: 1 inputFetchDeadline: 60 diff --git a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java index 3897c7268f..6b6e63b4ad 100644 --- a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java +++ b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java @@ -145,7 +145,19 @@ public abstract class CASFileCache implements ContentAddressableStorage { Gauge.build().name("cas_size").help("CAS size.").register(); private static final Gauge casEntryCountMetric = Gauge.build().name("cas_entry_count").help("Number of entries in the CAS.").register(); - private static Histogram casTtl; + private static Histogram casTtl = + Histogram.build() + .name("cas_ttl_s") + .buckets( + 3600, // 1 hour + 21600, // 6 hours + 86400, // 1 day + 345600, // 4 days + 604800, // 1 week + 1210000 // 2 weeks + ) + .help("The amount of time CAS entries live on L1 storage before expiration (seconds)") + .register(); private static final Gauge casCopyFallbackMetric = Gauge.build() @@ -160,7 +172,6 @@ public abstract class CASFileCache implements ContentAddressableStorage { private final EntryPathStrategy entryPathStrategy; private final long maxSizeInBytes; private final long maxEntrySizeInBytes; - private final boolean publishTtlMetric; private final boolean execRootFallback; private final DigestUtil digestUtil; private final ConcurrentMap storage; @@ -306,7 +317,6 @@ public CASFileCache( maxEntrySizeInBytes, config.getHexBucketLevels(), config.isFileDirectoriesIndexInMemory(), - config.isPublishTtlMetric(), config.isExecRootCopyFallback(), digestUtil, expireService, @@ -325,7 +335,6 @@ public CASFileCache( long maxEntrySizeInBytes, int hexBucketLevels, boolean storeFileDirsIndexInMemory, - boolean publishTtlMetric, boolean execRootFallback, DigestUtil digestUtil, ExecutorService expireService, @@ -339,7 +348,6 @@ public CASFileCache( this.root = root; this.maxSizeInBytes = maxSizeInBytes; this.maxEntrySizeInBytes = maxEntrySizeInBytes; - this.publishTtlMetric = publishTtlMetric; this.execRootFallback = execRootFallback; this.digestUtil = digestUtil; this.expireService = expireService; @@ -351,22 +359,6 @@ public CASFileCache( this.delegateSkipLoad = delegateSkipLoad; this.directoriesIndexDbName = directoriesIndexDbName; - if (publishTtlMetric) { - casTtl = - Histogram.build() - .name("cas_ttl_s") - .buckets( - 3600, // 1 hour - 21600, // 6 hours - 86400, // 1 day - 345600, // 4 days - 604800, // 1 week - 1210000 // 2 weeks - ) - .help("The amount of time CAS entries live on L1 storage before expiration (seconds)") - .register(); - } - entryPathStrategy = new HexBucketEntryPathStrategy(root, hexBucketLevels); String directoriesIndexUrl = "jdbc:sqlite:"; @@ -2710,25 +2702,19 @@ private CancellableOutputStream putOrReference( } private void deleteExpiredKey(String key) throws IOException { - // We don't want publishing the metric to delay the deletion of the file. - // We publish the metric only after the file has been deleted. - long createdTime = 0; Path path = getRemovingPath(key); - if (publishTtlMetric) { - createdTime = path.toFile().lastModified(); - } + long createdTimeMs = Files.getLastModifiedTime(path).to(MILLISECONDS); Files.delete(path); - if (publishTtlMetric) { - publishExpirationMetric(createdTime); - } + publishExpirationMetric(createdTimeMs); } - private void publishExpirationMetric(long createdTime) { - long currentTime = new Date().getTime(); - long ttl = currentTime - createdTime; - casTtl.observe(Time.millisecondsToSeconds(ttl)); + private void publishExpirationMetric(long createdTimeMs) { + // TODO introduce ttl clock + long currentTimeMs = new Date().getTime(); + long ttlMs = currentTimeMs - createdTimeMs; + casTtl.observe(Time.millisecondsToSeconds(ttlMs)); } @SuppressWarnings({"ConstantConditions", "ResultOfMethodCallIgnored"}) diff --git a/src/main/java/build/buildfarm/common/config/Cas.java b/src/main/java/build/buildfarm/common/config/Cas.java index 5b16fb2168..93ecdbfaf2 100644 --- a/src/main/java/build/buildfarm/common/config/Cas.java +++ b/src/main/java/build/buildfarm/common/config/Cas.java @@ -30,9 +30,6 @@ public enum TYPE { private String target; private boolean readonly = false; - // Metrics - private boolean publishTtlMetric = false; - public Path getValidPath(Path root) throws ConfigurationException { if (Strings.isNullOrEmpty(path)) { throw new ConfigurationException("Cas cache directory value in config missing"); diff --git a/src/main/java/build/buildfarm/worker/shard/ShardCASFileCache.java b/src/main/java/build/buildfarm/worker/shard/ShardCASFileCache.java index c1a56beb06..b03cbe6f32 100644 --- a/src/main/java/build/buildfarm/worker/shard/ShardCASFileCache.java +++ b/src/main/java/build/buildfarm/worker/shard/ShardCASFileCache.java @@ -38,7 +38,6 @@ class ShardCASFileCache extends CASFileCache { long maxEntrySizeInBytes, int maxBucketLevels, boolean storeFileDirsIndexInMemory, - boolean publishTtlMetric, boolean execRootFallback, DigestUtil digestUtil, ExecutorService expireService, @@ -53,7 +52,6 @@ class ShardCASFileCache extends CASFileCache { maxEntrySizeInBytes, maxBucketLevels, storeFileDirsIndexInMemory, - publishTtlMetric, execRootFallback, digestUtil, expireService, diff --git a/src/main/java/build/buildfarm/worker/shard/Worker.java b/src/main/java/build/buildfarm/worker/shard/Worker.java index a33dbaad60..46f0f083f6 100644 --- a/src/main/java/build/buildfarm/worker/shard/Worker.java +++ b/src/main/java/build/buildfarm/worker/shard/Worker.java @@ -354,7 +354,6 @@ private ContentAddressableStorage createStorage( // delegate level cas.getHexBucketLevels(), cas.isFileDirectoriesIndexInMemory(), - cas.isPublishTtlMetric(), cas.isExecRootCopyFallback(), digestUtil, removeDirectoryService, diff --git a/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java b/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java index 1bd1791999..72e167b4df 100644 --- a/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java +++ b/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java @@ -147,7 +147,6 @@ public void setUp() throws IOException, InterruptedException { /* maxEntrySizeInBytes=*/ 1024, /* hexBucketLevels=*/ 1, storeFileDirsIndexInMemory, - /* publishTtlMetric=*/ false, /* execRootFallback=*/ false, DIGEST_UTIL, expireService, @@ -1111,7 +1110,6 @@ public void copyExternalInputRetries() throws Exception { /* maxEntrySizeInBytes=*/ 1024, /* hexBucketLevels=*/ 1, storeFileDirsIndexInMemory, - /* publishTtlMetric=*/ false, /* execRootFallback=*/ false, DIGEST_UTIL, expireService, @@ -1175,7 +1173,6 @@ public void newInputThrowsNoSuchFileExceptionWithoutDelegate() throws Exception /* maxEntrySizeInBytes=*/ 1024, /* hexBucketLevels=*/ 1, storeFileDirsIndexInMemory, - /* publishTtlMetric=*/ false, /* execRootFallback=*/ false, DIGEST_UTIL, expireService, From 2abad58270b4f89a23a1dacb809cf6ce85d85d43 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Wed, 4 Oct 2023 16:17:38 -0400 Subject: [PATCH 061/311] Config-compatible behavior for publishTtlMetric --- src/main/java/build/buildfarm/common/config/Cas.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/build/buildfarm/common/config/Cas.java b/src/main/java/build/buildfarm/common/config/Cas.java index 93ecdbfaf2..9c671d4958 100644 --- a/src/main/java/build/buildfarm/common/config/Cas.java +++ b/src/main/java/build/buildfarm/common/config/Cas.java @@ -3,7 +3,9 @@ import com.google.common.base.Strings; import java.nio.file.Path; import javax.naming.ConfigurationException; +import lombok.AccessLevel; import lombok.Data; +import lombok.Getter; @Data public class Cas { @@ -30,6 +32,9 @@ public enum TYPE { private String target; private boolean readonly = false; + @Getter(AccessLevel.NONE) + private boolean publishTtlMetric = false; // deprecated + public Path getValidPath(Path root) throws ConfigurationException { if (Strings.isNullOrEmpty(path)) { throw new ConfigurationException("Cas cache directory value in config missing"); From 10189d628c650fea73484a4470038c3a38b64ba6 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Tue, 26 Sep 2023 14:21:10 -0400 Subject: [PATCH 062/311] Correct logging advisements for current Java Java logging definitions must now match java.util.logging.config.file, update these specifications in our README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8dc99874b3..675fe94dbd 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Run via ``` bazelisk run //src/main/java/build/buildfarm:buildfarm-server -- -Ex: bazelisk run //src/main/java/build/buildfarm:buildfarm-server -- --jvm_flag=-Dlogging.config=file:$PWD/examples/logging.properties $PWD/examples/config.minimal.yml +Ex: bazelisk run //src/main/java/build/buildfarm:buildfarm-server -- --jvm_flag=-Djava.util.logging.config.file=$PWD/examples/logging.properties $PWD/examples/config.minimal.yml ``` **`logfile`** has to be in the [standard java util logging format](https://docs.oracle.com/cd/E57471_01/bigData.100/data_processing_bdd/src/rdp_logging_config.html) and passed as a --jvm_flag=-Dlogging.config=file: **`configfile`** has to be in [yaml format](https://bazelbuild.github.io/bazel-buildfarm/docs/configuration). @@ -43,7 +43,7 @@ Run via ``` bazelisk run //src/main/java/build/buildfarm:buildfarm-shard-worker -- -Ex: bazelisk run //src/main/java/build/buildfarm:buildfarm-shard-worker -- --jvm_flag=-Dlogging.config=file:$PWD/examples/logging.properties $PWD/examples/config.minimal.yml +Ex: bazelisk run //src/main/java/build/buildfarm:buildfarm-shard-worker -- --jvm_flag=-Djava.util.logging.config.file=$PWD/examples/logging.properties $PWD/examples/config.minimal.yml ``` **`logfile`** has to be in the [standard java util logging format](https://docs.oracle.com/cd/E57471_01/bigData.100/data_processing_bdd/src/rdp_logging_config.html) and passed as a --jvm_flag=-Dlogging.config=file: @@ -68,13 +68,13 @@ You can use typical Java logging configuration to filter these results and obser An example `logging.properties` file has been provided at [examples/logging.properties](examples/logging.properties) for use as follows: ``` -bazel run //src/main/java/build/buildfarm:buildfarm-server -- --jvm_flag=-Dlogging.config=file:$PWD/examples/logging.properties $PWD/examples/config.minimal.yml +bazel run //src/main/java/build/buildfarm:buildfarm-server -- --jvm_flag=-Djava.util.logging.config.file=$PWD/examples/logging.properties $PWD/examples/config.minimal.yml ``` and ``` -bazel run //src/main/java/build/buildfarm:buildfarm-shard-worker -- --jvm_flag=-Dlogging.config=file:$PWD/examples/logging.properties $PWD/examples/config.minimal.yml +bazel run //src/main/java/build/buildfarm:buildfarm-shard-worker -- --jvm_flag=-Djava.util.logging.config.file=$PWD/examples/logging.properties $PWD/examples/config.minimal.yml ``` To attach a remote debugger, run the executable with the `--debug=` flag. For example: From 0c30cb057e7a9bfb3850c68608c0085fd488ad24 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Tue, 3 Oct 2023 14:44:14 -0400 Subject: [PATCH 063/311] Rename GracefulShutdownTest --- src/main/java/build/buildfarm/tools/BUILD | 6 +++--- .../{GracefulShutdownTest.java => GracefulShutdown.java} | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) rename src/main/java/build/buildfarm/tools/{GracefulShutdownTest.java => GracefulShutdown.java} (93%) diff --git a/src/main/java/build/buildfarm/tools/BUILD b/src/main/java/build/buildfarm/tools/BUILD index 37c6bdb58a..44a4498ef9 100644 --- a/src/main/java/build/buildfarm/tools/BUILD +++ b/src/main/java/build/buildfarm/tools/BUILD @@ -185,9 +185,9 @@ java_binary( ) java_binary( - name = "GracefulShutdownTest", - srcs = ["GracefulShutdownTest.java"], - main_class = "build.buildfarm.tools.GracefulShutdownTest", + name = "GracefulShutdown", + srcs = ["GracefulShutdown.java"], + main_class = "build.buildfarm.tools.GracefulShutdown", visibility = ["//visibility:public"], deps = [ "//src/main/java/build/buildfarm/common/grpc", diff --git a/src/main/java/build/buildfarm/tools/GracefulShutdownTest.java b/src/main/java/build/buildfarm/tools/GracefulShutdown.java similarity index 93% rename from src/main/java/build/buildfarm/tools/GracefulShutdownTest.java rename to src/main/java/build/buildfarm/tools/GracefulShutdown.java index 85ae5ab78d..689edfeff1 100644 --- a/src/main/java/build/buildfarm/tools/GracefulShutdownTest.java +++ b/src/main/java/build/buildfarm/tools/GracefulShutdown.java @@ -23,9 +23,9 @@ import build.buildfarm.v1test.ShutDownWorkerGrpc; import io.grpc.ManagedChannel; -class GracefulShutdownTest { +class GracefulShutdown { /** - * Example command: GracefulShutdownTest ShutDown workerIp buildfarm-endpoint + * Example command: GracefulShutdown ShutDown workerIp buildfarm-endpoint * * @param args */ @@ -48,7 +48,7 @@ private static void shutDownGracefully(String[] args) { } /** - * Example command: GracefulShutdownTest PrepareWorker WorkerIp:port + * Example command: GracefulShutdown PrepareWorker WorkerIp:port * * @param args */ @@ -65,7 +65,7 @@ private static void prepareWorkerForShutDown(String[] args) { } /** - * Example command: GracefulShutdownTest DisableProtection WorkerIp buildfarm_endpoint + * Example command: GracefulShutdown DisableProtection WorkerIp buildfarm_endpoint * * @param args */ From 5a0d8d606ba62d6a801247d9bc52a84761d95a03 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Tue, 3 Oct 2023 14:52:16 -0400 Subject: [PATCH 064/311] Remove WebController --- .../common/config/BuildfarmConfigs.java | 1 - .../build/buildfarm/common/config/WebUI.java | 40 --- src/main/java/build/buildfarm/server/BUILD | 3 - .../buildfarm/server/BuildFarmServer.java | 4 - .../build/buildfarm/server/controllers/BUILD | 46 --- .../server/controllers/WebController.java | 291 ------------------ 6 files changed, 385 deletions(-) delete mode 100644 src/main/java/build/buildfarm/common/config/WebUI.java delete mode 100644 src/main/java/build/buildfarm/server/controllers/BUILD delete mode 100644 src/main/java/build/buildfarm/server/controllers/WebController.java diff --git a/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java b/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java index 68106d56c7..1a15e40803 100644 --- a/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java +++ b/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java @@ -39,7 +39,6 @@ public final class BuildfarmConfigs { private Server server = new Server(); private Backplane backplane = new Backplane(); private Worker worker = new Worker(); - private WebUI ui = new WebUI(); private ExecutionWrappers executionWrappers = new ExecutionWrappers(); private BuildfarmConfigs() {} diff --git a/src/main/java/build/buildfarm/common/config/WebUI.java b/src/main/java/build/buildfarm/common/config/WebUI.java deleted file mode 100644 index 443d210691..0000000000 --- a/src/main/java/build/buildfarm/common/config/WebUI.java +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2023 The Bazel Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package build.buildfarm.common.config; - -import lombok.Data; - -/** - * @class WebUI - * @brief Settings for buildfarm's web UI. - * @details Buildfarm provides a web frontend for developers to introspect builds. - */ -@Data -public class WebUI { - /** - * @field enable - * @brief Whether to enable the web frontend. - * @details When disabled there will be no ports opened or routes available. - */ - public boolean enable = false; - - /** - * @field port - * @brief HTTP port for the web frontend. - * @details 8080 is useful for local testing since port 80 requires sudo. We choose the following - * default since many ports are blocked in upstream CI. - */ - public String port = "8982"; -} diff --git a/src/main/java/build/buildfarm/server/BUILD b/src/main/java/build/buildfarm/server/BUILD index b05d2e5ef7..0d6d396dc8 100644 --- a/src/main/java/build/buildfarm/server/BUILD +++ b/src/main/java/build/buildfarm/server/BUILD @@ -14,7 +14,6 @@ java_library( "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/instance/shard", "//src/main/java/build/buildfarm/metrics/prometheus", - "//src/main/java/build/buildfarm/server/controllers:WebController", "//src/main/java/build/buildfarm/server/services", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "@maven//:com_github_pcj_google_options", @@ -29,10 +28,8 @@ java_library( "@maven//:org_springframework_boot_spring_boot", "@maven//:org_springframework_boot_spring_boot_autoconfigure", "@maven//:org_springframework_boot_spring_boot_starter_thymeleaf", - "@maven//:org_springframework_boot_spring_boot_starter_web", "@maven//:org_springframework_spring_beans", "@maven//:org_springframework_spring_context", "@maven//:org_springframework_spring_core", - "@maven//:org_springframework_spring_web", ], ) diff --git a/src/main/java/build/buildfarm/server/BuildFarmServer.java b/src/main/java/build/buildfarm/server/BuildFarmServer.java index d0d26a6f52..e82928e934 100644 --- a/src/main/java/build/buildfarm/server/BuildFarmServer.java +++ b/src/main/java/build/buildfarm/server/BuildFarmServer.java @@ -29,7 +29,6 @@ import build.buildfarm.instance.Instance; import build.buildfarm.instance.shard.ShardInstance; import build.buildfarm.metrics.prometheus.PrometheusPublisher; -import build.buildfarm.server.controllers.WebController; import build.buildfarm.server.services.ActionCacheService; import build.buildfarm.server.services.AdminService; import build.buildfarm.server.services.CapabilitiesService; @@ -143,7 +142,6 @@ public synchronized void start(ServerBuilder serverBuilder, String publicName checkState(!stopping, "must not call start after stop"); instance.start(publicName); - WebController.setInstance((ShardInstance) instance); server.start(); healthStatusManager.setStatus( @@ -214,8 +212,6 @@ public static void main(String[] args) throws ConfigurationException { // Disable Logback System.setProperty("org.springframework.boot.logging.LoggingSystem", "none"); - springConfig.put("ui.frontend.enable", configs.getUi().isEnable()); - springConfig.put("server.port", configs.getUi().getPort()); app.setDefaultProperties(springConfig); try { diff --git a/src/main/java/build/buildfarm/server/controllers/BUILD b/src/main/java/build/buildfarm/server/controllers/BUILD deleted file mode 100644 index 1e523bcef5..0000000000 --- a/src/main/java/build/buildfarm/server/controllers/BUILD +++ /dev/null @@ -1,46 +0,0 @@ -java_library( - name = "WebController", - srcs = ["WebController.java"], - plugins = ["//src/main/java/build/buildfarm/common:lombok"], - visibility = ["//visibility:public"], - deps = [ - "//src/main/java/build/buildfarm/common", - "//src/main/java/build/buildfarm/common/config", - "//src/main/java/build/buildfarm/common/grpc", - "//src/main/java/build/buildfarm/common/resources", - "//src/main/java/build/buildfarm/common/resources:resource_java_proto", - "//src/main/java/build/buildfarm/common/services", - "//src/main/java/build/buildfarm/instance", - "//src/main/java/build/buildfarm/instance/shard", - "//src/main/java/build/buildfarm/metrics/prometheus", - "//src/main/java/build/buildfarm/operations", - "//src/main/java/build/buildfarm/server/services", - "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "//src/main/protobuf:build_buildfarm_v1test_buildfarm_proto", - "@googleapis//:google_rpc_code_java_proto", - "@googleapis//:google_rpc_error_details_java_proto", - "@googleapis//:google_rpc_error_details_proto", - "@maven//:com_github_pcj_google_options", - "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", - "@maven//:com_google_protobuf_protobuf_java_util", - "@maven//:com_googlecode_json_simple_json_simple", - "@maven//:com_jayway_jsonpath_json_path", - "@maven//:io_grpc_grpc_api", - "@maven//:io_grpc_grpc_core", - "@maven//:io_grpc_grpc_protobuf", - "@maven//:io_grpc_grpc_services", - "@maven//:io_prometheus_simpleclient", - "@maven//:javax_annotation_javax_annotation_api", - "@maven//:org_bouncycastle_bcprov_jdk15on", - "@maven//:org_projectlombok_lombok", - "@maven//:org_springframework_boot_spring_boot", - "@maven//:org_springframework_boot_spring_boot_autoconfigure", - "@maven//:org_springframework_boot_spring_boot_starter_web", - "@maven//:org_springframework_spring_beans", - "@maven//:org_springframework_spring_context", - "@maven//:org_springframework_spring_core", - "@maven//:org_springframework_spring_web", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", - ], -) diff --git a/src/main/java/build/buildfarm/server/controllers/WebController.java b/src/main/java/build/buildfarm/server/controllers/WebController.java deleted file mode 100644 index 5ed5c8250e..0000000000 --- a/src/main/java/build/buildfarm/server/controllers/WebController.java +++ /dev/null @@ -1,291 +0,0 @@ -// Copyright 2023 The Bazel Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package build.buildfarm.server.controllers; - -import build.bazel.remote.execution.v2.ExecuteOperationMetadata; -import build.bazel.remote.execution.v2.ExecuteResponse; -import build.bazel.remote.execution.v2.RequestMetadata; -import build.buildfarm.instance.shard.ShardInstance; -import build.buildfarm.operations.EnrichedOperation; -import build.buildfarm.v1test.CompletedOperationMetadata; -import build.buildfarm.v1test.ExecutingOperationMetadata; -import build.buildfarm.v1test.QueuedOperationMetadata; -import com.google.longrunning.Operation; -import com.google.protobuf.Any; -import com.google.protobuf.Duration; -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Timestamp; -import com.google.protobuf.util.Durations; -import com.google.protobuf.util.JsonFormat; -import com.google.protobuf.util.Timestamps; -import com.google.rpc.PreconditionFailure; -import java.util.Map; -import java.util.Set; -import java.util.logging.Level; -import lombok.extern.java.Log; -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; - -// An HTTP frontend for providing a web UI in buildfarm. Its primarily used by developers so that -// they can introspect their build inovocations. Standalone tools that communicate over GRPC are -// sometimes less accessible. Nonetheless, the APIs should be similar. -// The web frontend can be deployed as part of the servers. However, the controller may also be -// included in other standalone tools if you'd like the frontend decoupled from the servers. -// This controller can provide web content directly through spring boot via thymeleaf. -// The controller also provides raw REST APIs for those wishing to build out their own frontend. -@Log -@Controller -@ConditionalOnProperty("ui.frontend.enable") -public class WebController { - private static ShardInstance instance; - - // Most of the routes require an instance to have their queries fulfilled. - // I wanted to have the instance set in the controller's constructor, but I was having trouble - // doing that with springboot's bean initialization and auto-wiring. - // Particularly because the controller is constructed before the instance is actually created. - // I settled for having the instance static and allowing the server startup to provide the - // instance once ready. - public static void setInstance(ShardInstance instanceIn) { - instance = instanceIn; - } - - // This is typically the starting for a developer looking to introspect their builds. - // When running a bazel client with `--bes_results_url` they will shown this URL route. - // The page is intented to give them a summary of their build invocation and allow them to drill - // down into more details. - @GetMapping("/invocation/{invocationId}") - public String invocation(Model model, @PathVariable String invocationId) { - // We need to look up the user's operations as fast as possible. Scanning all of the stored - // operations and filtering by invocatio ID (i.e. O(n)) does not scale. Instead, the invocation - // ID must be the primary key to their specific list of build operation IDs. We then lookup - // each - // operation by ID (preferably batched). This is technically two backend calls. It could be - // made faster - // at the expense of duplicate information stored in the backend. - Set operationIDs = instance.findOperationsByInvocationId(invocationId); - Iterable> foundOperations = instance.getOperations(operationIDs); - - // Populate the model for the page. - buildInvocationModel(model, invocationId, foundOperations); - - // Render page. - return "invocation"; - } - - private void buildInvocationModel( - Model model, String invocationId, Iterable> foundOperations) { - // Create an array representing table information about all the oprations involved in the - // invocation. - // This is the core content of the page. - JSONArray operationResults = new JSONArray(); - for (Map.Entry entry : foundOperations) { - Operation operation = jsonToOperation(entry.getValue()); - JSONObject obj = new JSONObject(); - obj.put("target", extractTargetId(operation)); - obj.put("mnemonic", extractActionMnemonic(operation)); - obj.put("stage", extractStatus(operation)); - obj.put("duration", extractDuration(operation)); - obj.put("worker", extractWorker(operation)); - - String operationId = entry.getKey(); - String id = operationId.substring(operationId.lastIndexOf('/')).substring(1); - obj.put("operationId", id); - - operationResults.add(obj); - } - - // Populate data to be provided to the frontend. - model.addAttribute("operation", operationResults.toJSONString()); - model.addAttribute("invocationId", String.format("Invocation: %s", invocationId)); - } - - // An operation represents an executed action. - // The operation has a target ID which corresponds to the bazel label what developers are - // typically thinking of when wishing to evaluate their build. - // This page shows them all of the information that we track related to the operation. - @GetMapping("/operation/{operationId}") - public String operation(Model model, @PathVariable String operationId) { - EnrichedOperation result = - instance.findEnrichedOperation(String.format("shard/operations/%s", operationId)); - model.addAttribute("fullOperation", result.asJsonString()); - return "operation"; - } - - // Information about the current deployment. Useful for verifying what is running. - @GetMapping("/info") - public String info(Model model) { - return "info"; - } - - /** - * @brief Convert string json into operation type. - * @details Parses json and returns null if invalid. - * @param json The json to convert to Operation type. - * @return The created operation. - * @note Suggested return identifier: operation. - */ - private static Operation jsonToOperation(String json) { - // create a json parser - JsonFormat.Parser operationParser = - JsonFormat.parser() - .usingTypeRegistry( - JsonFormat.TypeRegistry.newBuilder() - .add(CompletedOperationMetadata.getDescriptor()) - .add(ExecutingOperationMetadata.getDescriptor()) - .add(ExecuteOperationMetadata.getDescriptor()) - .add(QueuedOperationMetadata.getDescriptor()) - .add(PreconditionFailure.getDescriptor()) - .build()) - .ignoringUnknownFields(); - - if (json == null) { - log.log(Level.WARNING, "Operation Json is empty"); - return null; - } - try { - Operation.Builder operationBuilder = Operation.newBuilder(); - operationParser.merge(json, operationBuilder); - return operationBuilder.build(); - } catch (InvalidProtocolBufferException e) { - log.log(Level.WARNING, "InvalidProtocolBufferException while building an operation.", e); - return null; - } - } - - private String extractTargetId(Operation operation) { - return expectRequestMetadata(operation).getTargetId(); - } - - private String extractActionMnemonic(Operation operation) { - return expectRequestMetadata(operation).getActionMnemonic(); - } - - private String extractStatus(Operation operation) { - return String.valueOf(expectExecuteOperationMetadata(operation).getStage()); - } - - private String extractDuration(Operation operation) { - Any result = operation.getResponse(); - try { - Timestamp start = - result - .unpack(ExecuteResponse.class) - .getResult() - .getExecutionMetadata() - .getWorkerStartTimestamp(); - Timestamp end = - result - .unpack(ExecuteResponse.class) - .getResult() - .getExecutionMetadata() - .getWorkerCompletedTimestamp(); - Duration duration = Timestamps.between(start, end); - return Durations.toSecondsAsDouble(duration) + "s"; - } catch (InvalidProtocolBufferException e) { - System.out.println(e.toString()); - return "Unknown"; - } - } - - private String extractWorker(Operation operation) { - Any result = operation.getResponse(); - try { - return result.unpack(ExecuteResponse.class).getResult().getExecutionMetadata().getWorker(); - } catch (InvalidProtocolBufferException e) { - System.out.println(e.toString()); - return "Unknown"; - } - } - - private static ExecuteOperationMetadata expectExecuteOperationMetadata(Operation operation) { - String name = operation.getName(); - Any metadata = operation.getMetadata(); - QueuedOperationMetadata queuedOperationMetadata = maybeQueuedOperationMetadata(name, metadata); - if (queuedOperationMetadata != null) { - return queuedOperationMetadata.getExecuteOperationMetadata(); - } - ExecutingOperationMetadata executingOperationMetadata = - maybeExecutingOperationMetadata(name, metadata); - if (executingOperationMetadata != null) { - return executingOperationMetadata.getExecuteOperationMetadata(); - } - CompletedOperationMetadata completedOperationMetadata = - maybeCompletedOperationMetadata(name, metadata); - if (completedOperationMetadata != null) { - return completedOperationMetadata.getExecuteOperationMetadata(); - } - return ExecuteOperationMetadata.getDefaultInstance(); - } - - private static RequestMetadata expectRequestMetadata(Operation operation) { - String name = operation.getName(); - Any metadata = operation.getMetadata(); - QueuedOperationMetadata queuedOperationMetadata = maybeQueuedOperationMetadata(name, metadata); - if (queuedOperationMetadata != null) { - return queuedOperationMetadata.getRequestMetadata(); - } - ExecutingOperationMetadata executingOperationMetadata = - maybeExecutingOperationMetadata(name, metadata); - if (executingOperationMetadata != null) { - return executingOperationMetadata.getRequestMetadata(); - } - CompletedOperationMetadata completedOperationMetadata = - maybeCompletedOperationMetadata(name, metadata); - if (completedOperationMetadata != null) { - return completedOperationMetadata.getRequestMetadata(); - } - return RequestMetadata.getDefaultInstance(); - } - - private static QueuedOperationMetadata maybeQueuedOperationMetadata(String name, Any metadata) { - if (metadata.is(QueuedOperationMetadata.class)) { - try { - return metadata.unpack(QueuedOperationMetadata.class); - } catch (InvalidProtocolBufferException e) { - log.log(Level.SEVERE, String.format("invalid executing operation metadata %s", name), e); - } - } - return null; - } - - private static ExecutingOperationMetadata maybeExecutingOperationMetadata( - String name, Any metadata) { - if (metadata.is(ExecutingOperationMetadata.class)) { - try { - return metadata.unpack(ExecutingOperationMetadata.class); - } catch (InvalidProtocolBufferException e) { - log.log(Level.SEVERE, String.format("invalid executing operation metadata %s", name), e); - } - } - return null; - } - - private static CompletedOperationMetadata maybeCompletedOperationMetadata( - String name, Any metadata) { - if (metadata.is(CompletedOperationMetadata.class)) { - try { - return metadata.unpack(CompletedOperationMetadata.class); - } catch (InvalidProtocolBufferException e) { - log.log(Level.SEVERE, String.format("invalid completed operation metadata %s", name), e); - } - } - return null; - } -} From fa8dd6fa1c4d138e08333f07c048446aa15a9b33 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Tue, 3 Oct 2023 14:54:06 -0400 Subject: [PATCH 065/311] Interrupt+Join operationQueuer/dispatchMonitor Use interrupt to halt the OperationQueuer. Join on both operationQueuer and dispatchMonitor before instance stop return. --- .../java/build/buildfarm/instance/shard/ShardInstance.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/build/buildfarm/instance/shard/ShardInstance.java b/src/main/java/build/buildfarm/instance/shard/ShardInstance.java index 883931d2d4..bf0c42a8c5 100644 --- a/src/main/java/build/buildfarm/instance/shard/ShardInstance.java +++ b/src/main/java/build/buildfarm/instance/shard/ShardInstance.java @@ -568,10 +568,12 @@ public void stop() throws InterruptedException { stopping = true; log.log(Level.FINER, format("Instance %s is stopping", getName())); if (operationQueuer != null) { - operationQueuer.stop(); + operationQueuer.interrupt(); + operationQueuer.join(); } if (dispatchedMonitor != null) { dispatchedMonitor.interrupt(); + dispatchedMonitor.join(); } if (prometheusMetricsThread != null) { prometheusMetricsThread.interrupt(); From 60093dbe25506302cf3f2c115f98378dc96629b7 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Tue, 3 Oct 2023 15:33:45 -0400 Subject: [PATCH 066/311] Present operationNames by stage Include Match and Report Result stages in output Record the active operationName occupying slots in each of the stages and present them with WorkerProfile Avoid several unnecessary casts with interfaces for operation slot stages. --- src/main/java/build/buildfarm/tools/Cat.java | 3 + .../buildfarm/worker/ExecuteActionStage.java | 4 +- .../buildfarm/worker/InputFetchStage.java | 6 +- .../build/buildfarm/worker/MatchStage.java | 6 +- .../build/buildfarm/worker/PipelineStage.java | 35 ++++-- .../worker/SuperscalarPipelineStage.java | 39 ++++++- .../build/buildfarm/worker/shard/Worker.java | 21 ++-- .../worker/shard/WorkerProfileService.java | 100 +++++++++++------- .../build/buildfarm/v1test/buildfarm.proto | 2 + .../worker/SuperscalarPipelineStageTest.java | 5 + 10 files changed, 155 insertions(+), 66 deletions(-) diff --git a/src/main/java/build/buildfarm/tools/Cat.java b/src/main/java/build/buildfarm/tools/Cat.java index 7c8e561454..bca404b3c1 100644 --- a/src/main/java/build/buildfarm/tools/Cat.java +++ b/src/main/java/build/buildfarm/tools/Cat.java @@ -650,6 +650,9 @@ private static void getWorkerProfile(Instance instance) { private static void printStageInformation(StageInformation stage) { System.out.printf("%s slots configured: %d%n", stage.getName(), stage.getSlotsConfigured()); System.out.printf("%s slots used %d%n", stage.getName(), stage.getSlotsUsed()); + for (String operationName : stage.getOperationNamesList()) { + System.out.printf("%s operation %s\n", stage.getName(), operationName); + } } private static void printOperationTime(OperationTimesBetweenStages time) { diff --git a/src/main/java/build/buildfarm/worker/ExecuteActionStage.java b/src/main/java/build/buildfarm/worker/ExecuteActionStage.java index 6c5e247a8f..f1ad546676 100644 --- a/src/main/java/build/buildfarm/worker/ExecuteActionStage.java +++ b/src/main/java/build/buildfarm/worker/ExecuteActionStage.java @@ -107,7 +107,7 @@ public void releaseExecutor( int slotUsage = removeAndRelease(operationName, claims); executionTime.observe(usecs / 1000.0); executionStallTime.observe(stallUSecs / 1000.0); - logComplete( + complete( operationName, usecs, stallUSecs, @@ -141,7 +141,7 @@ protected void iterate() throws InterruptedException { executors.add(executorThread); int slotUsage = executorClaims.addAndGet(limits.cpu.claimed); executionSlotUsage.set(slotUsage); - logStart(operationContext.operation.getName(), getUsage(slotUsage)); + start(operationContext.operation.getName(), getUsage(slotUsage)); executorThread.start(); } } diff --git a/src/main/java/build/buildfarm/worker/InputFetchStage.java b/src/main/java/build/buildfarm/worker/InputFetchStage.java index 6b0f741fd8..3953ef9595 100644 --- a/src/main/java/build/buildfarm/worker/InputFetchStage.java +++ b/src/main/java/build/buildfarm/worker/InputFetchStage.java @@ -72,13 +72,14 @@ public void releaseInputFetcher( int size = removeAndRelease(operationName); inputFetchTime.observe(usecs / 1000.0); inputFetchStallTime.observe(stallUSecs / 1000.0); - logComplete( + complete( operationName, usecs, stallUSecs, String.format("%s, %s", success ? "Success" : "Failure", getUsage(size))); } + @Override public int getSlotUsage() { return fetchers.size(); } @@ -106,8 +107,7 @@ protected void iterate() throws InterruptedException { fetchers.add(fetcher); int slotUsage = fetchers.size(); inputFetchSlotUsage.set(slotUsage); - logStart( - operationContext.queueEntry.getExecuteEntry().getOperationName(), getUsage(slotUsage)); + start(operationContext.queueEntry.getExecuteEntry().getOperationName(), getUsage(slotUsage)); fetcher.start(); } } diff --git a/src/main/java/build/buildfarm/worker/MatchStage.java b/src/main/java/build/buildfarm/worker/MatchStage.java index e245ee68d6..dc81a2ce31 100644 --- a/src/main/java/build/buildfarm/worker/MatchStage.java +++ b/src/main/java/build/buildfarm/worker/MatchStage.java @@ -103,12 +103,12 @@ public void setOnCancelHandler(Runnable onCancelHandler) { @SuppressWarnings("SameReturnValue") private boolean onOperationPolled() throws InterruptedException { String operationName = operationContext.queueEntry.getExecuteEntry().getOperationName(); - logStart(operationName); + start(operationName); long matchingAtUSecs = stopwatch.elapsed(MICROSECONDS); OperationContext matchedOperationContext = match(operationContext); long matchedInUSecs = stopwatch.elapsed(MICROSECONDS) - matchingAtUSecs; - logComplete(operationName, matchedInUSecs, waitDuration, true); + complete(operationName, matchedInUSecs, waitDuration, true); matchedOperationContext.poller.pause(); try { output.put(matchedOperationContext); @@ -139,7 +139,7 @@ protected void iterate() throws InterruptedException { } MatchOperationListener listener = new MatchOperationListener(operationContext, stopwatch); try { - logStart(); + start(); workerContext.match(listener); } finally { if (!listener.wasMatched()) { diff --git a/src/main/java/build/buildfarm/worker/PipelineStage.java b/src/main/java/build/buildfarm/worker/PipelineStage.java index 7dd1d6d9ee..edad2bb572 100644 --- a/src/main/java/build/buildfarm/worker/PipelineStage.java +++ b/src/main/java/build/buildfarm/worker/PipelineStage.java @@ -19,6 +19,7 @@ import com.google.common.base.Stopwatch; import java.util.logging.Level; import java.util.logging.Logger; +import javax.annotation.Nullable; public abstract class PipelineStage implements Runnable { protected final String name; @@ -30,6 +31,7 @@ public abstract class PipelineStage implements Runnable { private volatile boolean closed = false; private Thread tickThread = null; private boolean tickCancelledFlag = false; + private String operationName = null; PipelineStage( String name, WorkerContext workerContext, PipelineStage output, PipelineStage error) { @@ -39,12 +41,20 @@ public abstract class PipelineStage implements Runnable { this.error = error; } + public String getName() { + return name; + } + private void runInterruptible() throws InterruptedException { while (!output.isClosed() || isClaimed()) { iterate(); } } + public @Nullable String getOperationName() { + return operationName; + } + @Override public void run() { try { @@ -94,7 +104,7 @@ protected void iterate() throws InterruptedException { Stopwatch stopwatch = Stopwatch.createUnstarted(); try { operationContext = take(); - logStart(operationContext.operation.getName()); + start(operationContext.operation.getName()); stopwatch.start(); boolean valid = false; tickThread = Thread.currentThread(); @@ -128,31 +138,34 @@ protected void iterate() throws InterruptedException { } after(operationContext); long usecs = stopwatch.elapsed(MICROSECONDS); - logComplete( - operationContext.operation.getName(), usecs, stallUSecs, nextOperationContext != null); + complete(operationName, usecs, stallUSecs, nextOperationContext != null); + operationName = null; } private String logIterateId(String operationName) { return String.format("%s::iterate(%s)", name, operationName); } - protected void logStart() { - logStart(""); + protected void start() { + start(""); } - protected void logStart(String operationName) { - logStart(operationName, "Starting"); + protected void start(String operationName) { + start(operationName, "Starting"); } - protected void logStart(String operationName, String message) { + protected void start(String operationName, String message) { + // TODO to unary stage + this.operationName = operationName; getLogger().log(Level.FINER, String.format("%s: %s", logIterateId(operationName), message)); } - protected void logComplete(String operationName, long usecs, long stallUSecs, boolean success) { - logComplete(operationName, usecs, stallUSecs, success ? "Success" : "Failed"); + protected void complete(String operationName, long usecs, long stallUSecs, boolean success) { + complete(operationName, usecs, stallUSecs, success ? "Success" : "Failed"); } - protected void logComplete(String operationName, long usecs, long stallUSecs, String status) { + protected void complete(String operationName, long usecs, long stallUSecs, String status) { + this.operationName = operationName; getLogger() .log( Level.FINER, diff --git a/src/main/java/build/buildfarm/worker/SuperscalarPipelineStage.java b/src/main/java/build/buildfarm/worker/SuperscalarPipelineStage.java index 64636d72c2..ed7e610a10 100644 --- a/src/main/java/build/buildfarm/worker/SuperscalarPipelineStage.java +++ b/src/main/java/build/buildfarm/worker/SuperscalarPipelineStage.java @@ -14,17 +14,21 @@ package build.buildfarm.worker; +import java.util.HashSet; +import java.util.Set; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; import java.util.logging.Level; -abstract class SuperscalarPipelineStage extends PipelineStage { +public abstract class SuperscalarPipelineStage extends PipelineStage { protected final int width; @SuppressWarnings("rawtypes") protected final BlockingQueue claims; + protected Set operationNames = new HashSet<>(); + private volatile boolean catastrophic = false; // ensure that only a single claim waits for available slots for core count @@ -46,6 +50,39 @@ public SuperscalarPipelineStage( protected abstract int claimsRequired(OperationContext operationContext); + @Override + public String getOperationName() { + throw new UnsupportedOperationException("use getOperationNames on superscalar stages"); + } + + public int getWidth() { + return width; + } + + public abstract int getSlotUsage(); + + public Iterable getOperationNames() { + synchronized (operationNames) { + return new HashSet(operationNames); + } + } + + @Override + protected void start(String operationName, String message) { + synchronized (operationNames) { + operationNames.add(operationName); + } + super.start(operationName, message); + } + + @Override + protected void complete(String operationName, long usecs, long stallUSecs, String status) { + super.complete(operationName, usecs, stallUSecs, status); + synchronized (operationNames) { + operationNames.remove(operationName); + } + } + synchronized void waitForReleaseOrCatastrophe(BlockingQueue queue) { boolean interrupted = false; while (!catastrophic && isClaimed()) { diff --git a/src/main/java/build/buildfarm/worker/shard/Worker.java b/src/main/java/build/buildfarm/worker/shard/Worker.java index 46f0f083f6..a5affbbaec 100644 --- a/src/main/java/build/buildfarm/worker/shard/Worker.java +++ b/src/main/java/build/buildfarm/worker/shard/Worker.java @@ -57,6 +57,7 @@ import build.buildfarm.worker.PipelineStage; import build.buildfarm.worker.PutOperationStage; import build.buildfarm.worker.ReportResultStage; +import build.buildfarm.worker.SuperscalarPipelineStage; import com.google.common.cache.LoadingCache; import com.google.common.collect.Lists; import com.google.devtools.common.options.OptionsParsingException; @@ -197,7 +198,7 @@ private Operation stripQueuedOperation(Operation operation) { private Server createServer( ServerBuilder serverBuilder, - ContentAddressableStorage storage, + @Nullable CASFileCache storage, Instance instance, Pipeline pipeline, ShardWorkerContext context) { @@ -211,13 +212,13 @@ private Server createServer( // It will use various execution phases for it's profile service. // On the other hand, a worker that is only capable of CAS storage does not need a pipeline. if (configs.getWorker().getCapabilities().isExecution()) { - PipelineStage completeStage = - new PutOperationStage((operation) -> context.deactivate(operation.getName())); + PutOperationStage completeStage = + new PutOperationStage(operation -> context.deactivate(operation.getName())); PipelineStage errorStage = completeStage; /* new ErrorStage(); */ PipelineStage reportResultStage = new ReportResultStage(context, completeStage, errorStage); - PipelineStage executeActionStage = + SuperscalarPipelineStage executeActionStage = new ExecuteActionStage(context, reportResultStage, errorStage); - PipelineStage inputFetchStage = + SuperscalarPipelineStage inputFetchStage = new InputFetchStage(context, executeActionStage, new PutOperationStage(context::requeue)); PipelineStage matchStage = new MatchStage(context, inputFetchStage, errorStage); @@ -228,7 +229,13 @@ private Server createServer( serverBuilder.addService( new WorkerProfileService( - storage, inputFetchStage, executeActionStage, context, completeStage, backplane)); + storage, + matchStage, + inputFetchStage, + executeActionStage, + reportResultStage, + completeStage, + backplane)); } GrpcMetrics.handleGrpcMetricIntercepts(serverBuilder, configs.getWorker().getGrpcMetrics()); serverBuilder.intercept(new ServerHeadersInterceptor()); @@ -608,7 +615,7 @@ public void start() throws ConfigurationException, InterruptedException, IOExcep writer); pipeline = new Pipeline(); - server = createServer(serverBuilder, storage, instance, pipeline, context); + server = createServer(serverBuilder, (CASFileCache) storage, instance, pipeline, context); removeWorker(configs.getWorker().getPublicName()); diff --git a/src/main/java/build/buildfarm/worker/shard/WorkerProfileService.java b/src/main/java/build/buildfarm/worker/shard/WorkerProfileService.java index 6eee990426..f00c57cc3d 100644 --- a/src/main/java/build/buildfarm/worker/shard/WorkerProfileService.java +++ b/src/main/java/build/buildfarm/worker/shard/WorkerProfileService.java @@ -15,7 +15,6 @@ package build.buildfarm.worker.shard; import build.buildfarm.backplane.Backplane; -import build.buildfarm.cas.ContentAddressableStorage; import build.buildfarm.cas.cfc.CASFileCache; import build.buildfarm.v1test.OperationTimesBetweenStages; import build.buildfarm.v1test.StageInformation; @@ -24,67 +23,90 @@ import build.buildfarm.v1test.WorkerProfileGrpc; import build.buildfarm.v1test.WorkerProfileMessage; import build.buildfarm.v1test.WorkerProfileRequest; -import build.buildfarm.worker.ExecuteActionStage; -import build.buildfarm.worker.InputFetchStage; import build.buildfarm.worker.PipelineStage; import build.buildfarm.worker.PutOperationStage; import build.buildfarm.worker.PutOperationStage.OperationStageDurations; -import build.buildfarm.worker.WorkerContext; +import build.buildfarm.worker.SuperscalarPipelineStage; import io.grpc.stub.StreamObserver; import java.io.IOException; +import javax.annotation.Nullable; public class WorkerProfileService extends WorkerProfileGrpc.WorkerProfileImplBase { - private final CASFileCache storage; - private final InputFetchStage inputFetchStage; - private final ExecuteActionStage executeActionStage; - private final WorkerContext context; + private final @Nullable CASFileCache storage; + private final PipelineStage matchStage; + private final SuperscalarPipelineStage inputFetchStage; + private final SuperscalarPipelineStage executeActionStage; + private final PipelineStage reportResultStage; private final PutOperationStage completeStage; private final Backplane backplane; public WorkerProfileService( - ContentAddressableStorage storage, - PipelineStage inputFetchStage, - PipelineStage executeActionStage, - WorkerContext context, - PipelineStage completeStage, + @Nullable CASFileCache storage, + PipelineStage matchStage, + SuperscalarPipelineStage inputFetchStage, + SuperscalarPipelineStage executeActionStage, + PipelineStage reportResultStage, + PutOperationStage completeStage, Backplane backplane) { - this.storage = (CASFileCache) storage; - this.inputFetchStage = (InputFetchStage) inputFetchStage; - this.executeActionStage = (ExecuteActionStage) executeActionStage; - this.context = context; + this.storage = storage; + this.matchStage = matchStage; + this.inputFetchStage = inputFetchStage; + this.executeActionStage = executeActionStage; + this.reportResultStage = reportResultStage; this.completeStage = (PutOperationStage) completeStage; this.backplane = backplane; } + private StageInformation unaryStageInformation(String name, @Nullable String operationName) { + StageInformation.Builder builder = + StageInformation.newBuilder().setName(name).setSlotsConfigured(1); + if (operationName != null) { + builder.setSlotsUsed(1).addOperationNames(operationName); + } + return builder.build(); + } + + private StageInformation superscalarStageInformation(SuperscalarPipelineStage stage) { + return StageInformation.newBuilder() + .setName(stage.getName()) + .setSlotsConfigured(stage.getWidth()) + .setSlotsUsed(stage.getSlotUsage()) + .addAllOperationNames(stage.getOperationNames()) + .build(); + } + @Override public void getWorkerProfile( WorkerProfileRequest request, StreamObserver responseObserver) { // get usage of CASFileCache - WorkerProfileMessage.Builder replyBuilder = - WorkerProfileMessage.newBuilder() - .setCasSize(storage.size()) - .setCasEntryCount(storage.entryCount()) - .setCasMaxSize(storage.maxSize()) - .setCasMaxEntrySize(storage.maxEntrySize()) - .setCasUnreferencedEntryCount(storage.unreferencedEntryCount()) - .setCasDirectoryEntryCount(storage.directoryStorageCount()) - .setCasEvictedEntryCount(storage.getEvictedCount()) - .setCasEvictedEntrySize(storage.getEvictedSize()); + WorkerProfileMessage.Builder replyBuilder = WorkerProfileMessage.newBuilder(); + + // FIXME deliver full local storage chain + if (storage != null) { + replyBuilder + .setCasSize(storage.size()) + .setCasEntryCount(storage.entryCount()) + .setCasMaxSize(storage.maxSize()) + .setCasMaxEntrySize(storage.maxEntrySize()) + .setCasUnreferencedEntryCount(storage.unreferencedEntryCount()) + .setCasDirectoryEntryCount(storage.directoryStorageCount()) + .setCasEvictedEntryCount(storage.getEvictedCount()) + .setCasEvictedEntrySize(storage.getEvictedSize()); + } // get slots configured and used of superscalar stages + // prefer reverse order to avoid double counting if possible + // these stats are not consistent across their sampling and will + // produce: slots that are not consistent with operations, operations + // in multiple stages even in reverse due to claim progress + // in short: this is for monitoring, not for guaranteed consistency checks + String reportResultOperation = reportResultStage.getOperationName(); + String matchOperation = matchStage.getOperationName(); replyBuilder - .addStages( - StageInformation.newBuilder() - .setName("InputFetchStage") - .setSlotsConfigured(context.getInputFetchStageWidth()) - .setSlotsUsed(inputFetchStage.getSlotUsage()) - .build()) - .addStages( - StageInformation.newBuilder() - .setName("ExecuteActionStage") - .setSlotsConfigured(context.getExecuteStageWidth()) - .setSlotsUsed(executeActionStage.getSlotUsage()) - .build()); + .addStages(unaryStageInformation(reportResultStage.getName(), reportResultOperation)) + .addStages(superscalarStageInformation(executeActionStage)) + .addStages(superscalarStageInformation(inputFetchStage)) + .addStages(unaryStageInformation(matchStage.getName(), matchOperation)); // get average time costs on each stage OperationStageDurations[] durations = completeStage.getAverageTimeCostPerStage(); diff --git a/src/main/protobuf/build/buildfarm/v1test/buildfarm.proto b/src/main/protobuf/build/buildfarm/v1test/buildfarm.proto index b4c78b3c03..9632593f11 100644 --- a/src/main/protobuf/build/buildfarm/v1test/buildfarm.proto +++ b/src/main/protobuf/build/buildfarm/v1test/buildfarm.proto @@ -602,6 +602,8 @@ message StageInformation { // number of slots used for this stage int32 slots_used = 3; + + repeated string operation_names = 4; } message WorkerProfileMessage { diff --git a/src/test/java/build/buildfarm/worker/SuperscalarPipelineStageTest.java b/src/test/java/build/buildfarm/worker/SuperscalarPipelineStageTest.java index 60cb0d8be9..3716513102 100644 --- a/src/test/java/build/buildfarm/worker/SuperscalarPipelineStageTest.java +++ b/src/test/java/build/buildfarm/worker/SuperscalarPipelineStageTest.java @@ -72,6 +72,11 @@ protected int claimsRequired(OperationContext operationContext) { boolean isFull() { return claims.size() == width; } + + @Override + public int getSlotUsage() { + return 0; + } } @Test From 9ff8e6448f6ec4c67667b4fbb46c484318354bf4 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Tue, 26 Sep 2023 14:36:58 -0400 Subject: [PATCH 067/311] Remove subscribeToBackplane, adjust failsafe op A shard server is impractical without operation subscription, partition subscription confirmation between servers and workers. The failsafe execution is configuration that is likely not desired on workers. This change removes the failsafe behavior from workers via backplane config, and relegates the setting of failsafe boolean to server config. If the option is restored for workers, it can be added to worker configs so that configs may continue to be shared between workers and servers and retain independent addressability. --- examples/config.yml | 3 +- .../buildfarm/common/config/Backplane.java | 11 ++- .../build/buildfarm/common/config/Server.java | 1 + .../instance/shard/RedisShardBackplane.java | 20 ++++- .../instance/shard/ShardInstance.java | 6 +- .../build/buildfarm/worker/shard/Worker.java | 7 +- .../shard/RedisShardBackplaneTest.java | 83 +++++++++---------- 7 files changed, 79 insertions(+), 52 deletions(-) diff --git a/examples/config.yml b/examples/config.yml index 6ea0ee1132..f426e98547 100644 --- a/examples/config.yml +++ b/examples/config.yml @@ -22,6 +22,7 @@ server: dispatchedMonitorIntervalSeconds: 1 runOperationQueuer: true ensureOutputsPresent: false + runFailsafeOperation: true maxCpu: 0 maxRequeueAttempts: 5 useDenyList: true @@ -70,8 +71,6 @@ backplane: operationChannelPrefix: "OperationChannel" casPrefix: "ContentAddressableStorage" casExpire: 604800 # 1 week - subscribeToBackplane: true - runFailsafeOperation: true maxQueueDepth: 100000 maxPreQueueDepth: 1000000 priorityQueue: false diff --git a/src/main/java/build/buildfarm/common/config/Backplane.java b/src/main/java/build/buildfarm/common/config/Backplane.java index 9dd28c3d22..5c21532ab4 100644 --- a/src/main/java/build/buildfarm/common/config/Backplane.java +++ b/src/main/java/build/buildfarm/common/config/Backplane.java @@ -1,7 +1,9 @@ package build.buildfarm.common.config; import com.google.common.base.Strings; +import lombok.AccessLevel; import lombok.Data; +import lombok.Getter; @Data public class Backplane { @@ -32,8 +34,13 @@ public enum BACKPLANE_TYPE { private String operationChannelPrefix = "OperationChannel"; private String casPrefix = "ContentAddressableStorage"; private int casExpire = 604800; // 1 Week - private boolean subscribeToBackplane = true; - private boolean runFailsafeOperation = true; + + @Getter(AccessLevel.NONE) + private boolean subscribeToBackplane = true; // deprecated + + @Getter(AccessLevel.NONE) + private boolean runFailsafeOperation = true; // deprecated + private int maxQueueDepth = 100000; private int maxPreQueueDepth = 1000000; private boolean priorityQueue = false; diff --git a/src/main/java/build/buildfarm/common/config/Server.java b/src/main/java/build/buildfarm/common/config/Server.java index e169c2575b..9f2899ff60 100644 --- a/src/main/java/build/buildfarm/common/config/Server.java +++ b/src/main/java/build/buildfarm/common/config/Server.java @@ -24,6 +24,7 @@ public enum INSTANCE_TYPE { private String sslPrivateKeyPath = null; private boolean runDispatchedMonitor = true; private int dispatchedMonitorIntervalSeconds = 1; + private boolean runFailsafeOperation = true; private boolean runOperationQueuer = true; private boolean ensureOutputsPresent = false; private int maxRequeueAttempts = 5; diff --git a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java index 6676accdf3..ebb832f5aa 100644 --- a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java +++ b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java @@ -129,6 +129,8 @@ public class RedisShardBackplane implements Backplane { .build()); private final String source; // used in operation change publication + private final boolean subscribeToBackplane; + private final boolean runFailsafeOperation; private final Function onPublish; private final Function onComplete; private final Supplier jedisClusterFactory; @@ -149,18 +151,30 @@ public class RedisShardBackplane implements Backplane { public RedisShardBackplane( String source, + boolean subscribeToBackplane, + boolean runFailsafeOperation, Function onPublish, Function onComplete) throws ConfigurationException { - this(source, onPublish, onComplete, JedisClusterFactory.create(source)); + this( + source, + subscribeToBackplane, + runFailsafeOperation, + onPublish, + onComplete, + JedisClusterFactory.create(source)); } public RedisShardBackplane( String source, + boolean subscribeToBackplane, + boolean runFailsafeOperation, Function onPublish, Function onComplete, Supplier jedisClusterFactory) { this.source = source; + this.subscribeToBackplane = subscribeToBackplane; + this.runFailsafeOperation = runFailsafeOperation; this.onPublish = onPublish; this.onComplete = onComplete; this.jedisClusterFactory = jedisClusterFactory; @@ -519,10 +533,10 @@ public void start(String clientPublicName) throws IOException { // Create containers that make up the backplane state = DistributedStateCreator.create(client); - if (configs.getBackplane().isSubscribeToBackplane()) { + if (subscribeToBackplane) { startSubscriptionThread(); } - if (configs.getBackplane().isRunFailsafeOperation()) { + if (runFailsafeOperation) { startFailsafeOperationThread(); } diff --git a/src/main/java/build/buildfarm/instance/shard/ShardInstance.java b/src/main/java/build/buildfarm/instance/shard/ShardInstance.java index bf0c42a8c5..c1c07b08f0 100644 --- a/src/main/java/build/buildfarm/instance/shard/ShardInstance.java +++ b/src/main/java/build/buildfarm/instance/shard/ShardInstance.java @@ -254,7 +254,11 @@ public class ShardInstance extends AbstractServerInstance { private static Backplane createBackplane(String identifier) throws ConfigurationException { if (configs.getBackplane().getType().equals(SHARD)) { return new RedisShardBackplane( - identifier, ShardInstance::stripOperation, ShardInstance::stripQueuedOperation); + identifier, + /* subscribeToBackplane=*/ true, + configs.getServer().isRunFailsafeOperation(), + ShardInstance::stripOperation, + ShardInstance::stripQueuedOperation); } else { throw new IllegalArgumentException("Shard Backplane not set in config"); } diff --git a/src/main/java/build/buildfarm/worker/shard/Worker.java b/src/main/java/build/buildfarm/worker/shard/Worker.java index a5affbbaec..9a919d9703 100644 --- a/src/main/java/build/buildfarm/worker/shard/Worker.java +++ b/src/main/java/build/buildfarm/worker/shard/Worker.java @@ -546,7 +546,12 @@ public void start() throws ConfigurationException, InterruptedException, IOExcep if (SHARD.equals(configs.getBackplane().getType())) { backplane = - new RedisShardBackplane(identifier, this::stripOperation, this::stripQueuedOperation); + new RedisShardBackplane( + identifier, + /* subscribeToBackplane=*/ false, + /* runFailsafeOperation=*/ false, + this::stripOperation, + this::stripQueuedOperation); backplane.start(configs.getWorker().getPublicName()); } else { throw new IllegalArgumentException("Shard Backplane not set in config"); diff --git a/src/test/java/build/buildfarm/instance/shard/RedisShardBackplaneTest.java b/src/test/java/build/buildfarm/instance/shard/RedisShardBackplaneTest.java index 97d8fb5d0f..16e5bb8fbc 100644 --- a/src/test/java/build/buildfarm/instance/shard/RedisShardBackplaneTest.java +++ b/src/test/java/build/buildfarm/instance/shard/RedisShardBackplaneTest.java @@ -58,7 +58,6 @@ @RunWith(JUnit4.class) public class RedisShardBackplaneTest { - private RedisShardBackplane backplane; private BuildfarmConfigs configs = BuildfarmConfigs.getInstance(); @Mock Supplier mockJedisClusterFactory; @@ -66,12 +65,20 @@ public class RedisShardBackplaneTest { @Before public void setUp() throws IOException { configs.getBackplane().setOperationExpire(10); - configs.getBackplane().setSubscribeToBackplane(false); - configs.getBackplane().setRunFailsafeOperation(false); configs.getBackplane().setQueues(new Queue[] {}); MockitoAnnotations.initMocks(this); } + public RedisShardBackplane createBackplane(String name) { + return new RedisShardBackplane( + name, + /* subscribeToBackplane=*/ false, + /* runFailsafeOperation=*/ false, + o -> o, + o -> o, + mockJedisClusterFactory); + } + @Test public void workersWithInvalidProtobufAreRemoved() throws IOException { JedisCluster jedisCluster = mock(JedisCluster.class); @@ -80,9 +87,7 @@ public void workersWithInvalidProtobufAreRemoved() throws IOException { .thenReturn(ImmutableMap.of("foo", "foo")); when(jedisCluster.hdel(configs.getBackplane().getWorkersHashName() + "_storage", "foo")) .thenReturn(1L); - backplane = - new RedisShardBackplane( - "invalid-protobuf-worker-removed-test", (o) -> o, (o) -> o, mockJedisClusterFactory); + RedisShardBackplane backplane = createBackplane("invalid-protobuf-worker-removed-test"); backplane.start("startTime/test:0000"); assertThat(backplane.getStorageWorkers()).isEmpty(); @@ -99,12 +104,10 @@ public void workersWithInvalidProtobufAreRemoved() throws IOException { assertThat(workerChange.getTypeCase()).isEqualTo(WorkerChange.TypeCase.REMOVE); } - void verifyChangePublished(JedisCluster jedis) throws IOException { + OperationChange verifyChangePublished(String channel, JedisCluster jedis) throws IOException { ArgumentCaptor changeCaptor = ArgumentCaptor.forClass(String.class); - verify(jedis, times(1)).publish(eq(backplane.operationChannel("op")), changeCaptor.capture()); - OperationChange opChange = parseOperationChange(changeCaptor.getValue()); - assertThat(opChange.hasReset()).isTrue(); - assertThat(opChange.getReset().getOperation().getName()).isEqualTo("op"); + verify(jedis, times(1)).publish(eq(channel), changeCaptor.capture()); + return parseOperationChange(changeCaptor.getValue()); } String operationName(String name) { @@ -115,9 +118,7 @@ String operationName(String name) { public void prequeueUpdatesOperationPrequeuesAndPublishes() throws IOException { JedisCluster jedisCluster = mock(JedisCluster.class); when(mockJedisClusterFactory.get()).thenReturn(jedisCluster); - backplane = - new RedisShardBackplane( - "prequeue-operation-test", (o) -> o, (o) -> o, mockJedisClusterFactory); + RedisShardBackplane backplane = createBackplane("prequeue-operation-test"); backplane.start("startTime/test:0000"); final String opName = "op"; @@ -135,32 +136,34 @@ public void prequeueUpdatesOperationPrequeuesAndPublishes() throws IOException { .lpush( configs.getBackplane().getPreQueuedOperationsListName(), JsonFormat.printer().print(executeEntry)); - verifyChangePublished(jedisCluster); + OperationChange opChange = + verifyChangePublished(backplane.operationChannel(opName), jedisCluster); + assertThat(opChange.hasReset()).isTrue(); + assertThat(opChange.getReset().getOperation().getName()).isEqualTo(opName); } @Test public void queuingPublishes() throws IOException { JedisCluster jedisCluster = mock(JedisCluster.class); when(mockJedisClusterFactory.get()).thenReturn(jedisCluster); - backplane = - new RedisShardBackplane( - "requeue-operation-test", (o) -> o, (o) -> o, mockJedisClusterFactory); + RedisShardBackplane backplane = createBackplane("requeue-operation-test"); backplane.start("startTime/test:0000"); final String opName = "op"; backplane.queueing(opName); verify(mockJedisClusterFactory, times(1)).get(); - verifyChangePublished(jedisCluster); + OperationChange opChange = + verifyChangePublished(backplane.operationChannel(opName), jedisCluster); + assertThat(opChange.hasReset()).isTrue(); + assertThat(opChange.getReset().getOperation().getName()).isEqualTo(opName); } @Test public void requeueDispatchedOperationQueuesAndPublishes() throws IOException { JedisCluster jedisCluster = mock(JedisCluster.class); when(mockJedisClusterFactory.get()).thenReturn(jedisCluster); - backplane = - new RedisShardBackplane( - "requeue-operation-test", (o) -> o, (o) -> o, mockJedisClusterFactory); + RedisShardBackplane backplane = createBackplane("requeue-operation-test"); backplane.start("startTime/test:0000"); final String opName = "op"; @@ -180,7 +183,10 @@ public void requeueDispatchedOperationQueuesAndPublishes() throws IOException { .lpush( configs.getBackplane().getQueuedOperationsListName(), JsonFormat.printer().print(queueEntry)); - verifyChangePublished(jedisCluster); + OperationChange opChange = + verifyChangePublished(backplane.operationChannel(opName), jedisCluster); + assertThat(opChange.hasReset()).isTrue(); + assertThat(opChange.getReset().getOperation().getName()).isEqualTo(opName); } @Test @@ -194,9 +200,7 @@ public void dispatchedOperationsShowProperRequeueAmount0to1() // create a backplane JedisCluster jedisCluster = mock(JedisCluster.class); when(mockJedisClusterFactory.get()).thenReturn(jedisCluster); - backplane = - new RedisShardBackplane( - "requeue-operation-test", (o) -> o, (o) -> o, mockJedisClusterFactory); + RedisShardBackplane backplane = createBackplane("requeue-operation-test"); backplane.start("startTime/test:0000"); // ARRANGE @@ -250,9 +254,7 @@ public void dispatchedOperationsShowProperRequeueAmount1to2() // create a backplane JedisCluster jedisCluster = mock(JedisCluster.class); when(mockJedisClusterFactory.get()).thenReturn(jedisCluster); - backplane = - new RedisShardBackplane( - "requeue-operation-test", (o) -> o, (o) -> o, mockJedisClusterFactory); + RedisShardBackplane backplane = createBackplane("requeue-operation-test"); backplane.start("startTime/test:0000"); // Assume the operation queue is already populated from a first re-queue. @@ -298,9 +300,7 @@ public void dispatchedOperationsShowProperRequeueAmount1to2() public void completeOperationUndispatches() throws IOException { JedisCluster jedisCluster = mock(JedisCluster.class); when(mockJedisClusterFactory.get()).thenReturn(jedisCluster); - backplane = - new RedisShardBackplane( - "complete-operation-test", (o) -> o, (o) -> o, mockJedisClusterFactory); + RedisShardBackplane backplane = createBackplane("complete-operation-test"); backplane.start("startTime/test:0000"); final String opName = "op"; @@ -317,9 +317,7 @@ public void completeOperationUndispatches() throws IOException { public void deleteOperationDeletesAndPublishes() throws IOException { JedisCluster jedisCluster = mock(JedisCluster.class); when(mockJedisClusterFactory.get()).thenReturn(jedisCluster); - backplane = - new RedisShardBackplane( - "delete-operation-test", (o) -> o, (o) -> o, mockJedisClusterFactory); + RedisShardBackplane backplane = createBackplane("delete-operation-test"); backplane.start("startTime/test:0000"); final String opName = "op"; @@ -330,7 +328,10 @@ public void deleteOperationDeletesAndPublishes() throws IOException { verify(jedisCluster, times(1)) .hdel(configs.getBackplane().getDispatchedOperationsHashName(), opName); verify(jedisCluster, times(1)).del(operationName(opName)); - verifyChangePublished(jedisCluster); + OperationChange opChange = + verifyChangePublished(backplane.operationChannel(opName), jedisCluster); + assertThat(opChange.hasReset()).isTrue(); + assertThat(opChange.getReset().getOperation().getName()).isEqualTo(opName); } @Test @@ -341,9 +342,7 @@ public void invocationsCanBeBlacklisted() throws IOException { configs.getBackplane().getInvocationBlacklistPrefix() + ":" + toolInvocationId; when(jedisCluster.exists(invocationBlacklistKey)).thenReturn(true); when(mockJedisClusterFactory.get()).thenReturn(jedisCluster); - backplane = - new RedisShardBackplane( - "invocation-blacklist-test", o -> o, o -> o, mockJedisClusterFactory); + RedisShardBackplane backplane = createBackplane("invocation-blacklist-test"); backplane.start("startTime/test:0000"); assertThat( @@ -361,8 +360,7 @@ public void invocationsCanBeBlacklisted() throws IOException { public void testGetWorkersStartTime() throws IOException { JedisCluster jedisCluster = mock(JedisCluster.class); when(mockJedisClusterFactory.get()).thenReturn(jedisCluster); - backplane = - new RedisShardBackplane("workers-starttime-test", o -> o, o -> o, mockJedisClusterFactory); + RedisShardBackplane backplane = createBackplane("workers-starttime-test"); backplane.start("startTime/test:0000"); Set workerNames = ImmutableSet.of("worker1", "worker2", "missing_worker"); @@ -386,8 +384,7 @@ public void testGetWorkersStartTime() throws IOException { public void getDigestInsertTime() throws IOException { JedisCluster jedisCluster = mock(JedisCluster.class); when(mockJedisClusterFactory.get()).thenReturn(jedisCluster); - backplane = - new RedisShardBackplane("digest-inserttime-test", o -> o, o -> o, mockJedisClusterFactory); + RedisShardBackplane backplane = createBackplane("digest-inserttime-test"); backplane.start("startTime/test:0000"); long ttl = 3600L; long expirationInSecs = configs.getBackplane().getCasExpire(); From b21ab2e93a56c74c8071133d4d68675c3527c1b3 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Thu, 28 Sep 2023 16:08:23 -0400 Subject: [PATCH 068/311] Removing AWS/GCP Metrics and Admin controls Internally driven metrics and scaling controls have low, if any, usage rates. Prometheus has largely succeeded independent publication of metrics, and externally driven scaling is the norm. These modules have been incomplete between cloud providers, and for the functional side of AWS, bind us to springboot. Removing them for the sake of reduced dependencies and complexity. --- defs.bzl | 5 - .../java/build/buildfarm/admin/Admin.java | 36 --- src/main/java/build/buildfarm/admin/BUILD | 15 -- .../build/buildfarm/admin/aws/AwsAdmin.java | 243 ----------------- src/main/java/build/buildfarm/admin/aws/BUILD | 29 -- src/main/java/build/buildfarm/admin/gcp/BUILD | 18 -- .../build/buildfarm/admin/gcp/GcpAdmin.java | 57 ---- .../buildfarm/common/config/Metrics.java | 6 +- .../metrics/aws/AwsMetricsPublisher.java | 151 ----------- .../java/build/buildfarm/metrics/aws/BUILD | 22 -- .../java/build/buildfarm/metrics/gcp/BUILD | 16 -- .../metrics/gcp/GcpMetricsPublisher.java | 31 --- .../buildfarm/server/BuildFarmServer.java | 2 - .../server/services/AdminService.java | 254 ------------------ .../build/buildfarm/server/services/BUILD | 5 - .../server/services/ExecutionService.java | 11 +- .../java/build/buildfarm/worker/shard/BUILD | 2 - src/test/java/build/buildfarm/metrics/BUILD | 4 - .../metrics/MetricsPublisherTest.java | 11 +- 19 files changed, 11 insertions(+), 907 deletions(-) delete mode 100644 src/main/java/build/buildfarm/admin/Admin.java delete mode 100644 src/main/java/build/buildfarm/admin/BUILD delete mode 100644 src/main/java/build/buildfarm/admin/aws/AwsAdmin.java delete mode 100644 src/main/java/build/buildfarm/admin/aws/BUILD delete mode 100644 src/main/java/build/buildfarm/admin/gcp/BUILD delete mode 100644 src/main/java/build/buildfarm/admin/gcp/GcpAdmin.java delete mode 100644 src/main/java/build/buildfarm/metrics/aws/AwsMetricsPublisher.java delete mode 100644 src/main/java/build/buildfarm/metrics/aws/BUILD delete mode 100644 src/main/java/build/buildfarm/metrics/gcp/BUILD delete mode 100644 src/main/java/build/buildfarm/metrics/gcp/GcpMetricsPublisher.java delete mode 100644 src/main/java/build/buildfarm/server/services/AdminService.java diff --git a/defs.bzl b/defs.bzl index 5108852adb..993e9d36f4 100644 --- a/defs.bzl +++ b/defs.bzl @@ -43,12 +43,7 @@ IO_GRPC_MODULES = [ ] COM_AWS_MODULES = [ - "autoscaling", - "core", - "ec2", "secretsmanager", - "sns", - "ssm", "s3", ] diff --git a/src/main/java/build/buildfarm/admin/Admin.java b/src/main/java/build/buildfarm/admin/Admin.java deleted file mode 100644 index ca739f2347..0000000000 --- a/src/main/java/build/buildfarm/admin/Admin.java +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2020 The Bazel Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package build.buildfarm.admin; - -import build.buildfarm.v1test.GetHostsResult; - -public interface Admin { - void terminateHost(String hostId); - - void stopContainer(String hostId, String containerName); - - GetHostsResult getHosts(String filter, int ageInMinutes, String status); - - void scaleCluster( - String scaleGroupName, - Integer minHosts, - Integer maxHosts, - Integer targetHosts, - Integer targetReservedHostsPercent); - - void disableHostScaleInProtection(String instanceName); - - void disableHostScaleInProtection(String clusterEndpoint, String instanceIp); -} diff --git a/src/main/java/build/buildfarm/admin/BUILD b/src/main/java/build/buildfarm/admin/BUILD deleted file mode 100644 index a5e481399e..0000000000 --- a/src/main/java/build/buildfarm/admin/BUILD +++ /dev/null @@ -1,15 +0,0 @@ -java_library( - name = "admin", - srcs = glob(["*.java"]), - visibility = ["//visibility:public"], - deps = [ - "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@googleapis//:google_rpc_code_java_proto", - "@googleapis//:google_rpc_error_details_java_proto", - "@googleapis//:google_rpc_status_java_proto", - "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", - "@maven//:com_google_protobuf_protobuf_java_util", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", - ], -) diff --git a/src/main/java/build/buildfarm/admin/aws/AwsAdmin.java b/src/main/java/build/buildfarm/admin/aws/AwsAdmin.java deleted file mode 100644 index f40dd72c95..0000000000 --- a/src/main/java/build/buildfarm/admin/aws/AwsAdmin.java +++ /dev/null @@ -1,243 +0,0 @@ -// Copyright 2020 The Bazel Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package build.buildfarm.admin.aws; - -import static build.buildfarm.common.grpc.Channels.createChannel; - -import build.buildfarm.admin.Admin; -import build.buildfarm.common.config.BuildfarmConfigs; -import build.buildfarm.v1test.AdminGrpc; -import build.buildfarm.v1test.DisableScaleInProtectionRequest; -import build.buildfarm.v1test.GetHostsResult; -import build.buildfarm.v1test.Host; -import com.amazonaws.services.autoscaling.AmazonAutoScaling; -import com.amazonaws.services.autoscaling.AmazonAutoScalingClientBuilder; -import com.amazonaws.services.autoscaling.model.InstancesDistribution; -import com.amazonaws.services.autoscaling.model.MixedInstancesPolicy; -import com.amazonaws.services.autoscaling.model.SetInstanceProtectionRequest; -import com.amazonaws.services.autoscaling.model.SetInstanceProtectionResult; -import com.amazonaws.services.autoscaling.model.UpdateAutoScalingGroupRequest; -import com.amazonaws.services.ec2.AmazonEC2; -import com.amazonaws.services.ec2.AmazonEC2ClientBuilder; -import com.amazonaws.services.ec2.model.DescribeInstancesRequest; -import com.amazonaws.services.ec2.model.DescribeInstancesResult; -import com.amazonaws.services.ec2.model.Filter; -import com.amazonaws.services.ec2.model.Instance; -import com.amazonaws.services.ec2.model.Reservation; -import com.amazonaws.services.ec2.model.Tag; -import com.amazonaws.services.ec2.model.TerminateInstancesRequest; -import com.amazonaws.services.simplesystemsmanagement.AWSSimpleSystemsManagement; -import com.amazonaws.services.simplesystemsmanagement.AWSSimpleSystemsManagementClientBuilder; -import com.amazonaws.services.simplesystemsmanagement.model.SendCommandRequest; -import com.google.protobuf.util.Timestamps; -import io.grpc.ManagedChannel; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.TimeZone; -import java.util.logging.Level; -import lombok.extern.java.Log; -import org.springframework.stereotype.Component; - -@Log -@Component -public class AwsAdmin implements Admin { - private static BuildfarmConfigs configs = BuildfarmConfigs.getInstance(); - private AmazonAutoScaling scale; - private AmazonEC2 ec2; - private AWSSimpleSystemsManagement ssm; - - public AwsAdmin() { - String region = configs.getServer().getCloudRegion(); - if (region != null) { - scale = AmazonAutoScalingClientBuilder.standard().withRegion(region).build(); - ec2 = AmazonEC2ClientBuilder.standard().withRegion(region).build(); - ssm = AWSSimpleSystemsManagementClientBuilder.standard().withRegion(region).build(); - } else { - log.warning("Missing cloudRegion configuration. AWS Admin will not be enabled."); - } - } - - @Override - public void terminateHost(String hostId) { - ec2.terminateInstances(new TerminateInstancesRequest().withInstanceIds(hostId)); - log.log(Level.INFO, String.format("Terminated host: %s", hostId)); - } - - @Override - public void stopContainer(String hostId, String containerName) { - String stopContainerCmd = - "docker ps | grep " + containerName + " | awk '{print $1 }' | xargs -I {} docker stop {}"; - Map> parameters = new HashMap<>(); - parameters.put("commands", Collections.singletonList(stopContainerCmd)); - ssm.sendCommand( - new SendCommandRequest() - .withDocumentName("AWS-RunShellScript") - .withInstanceIds(hostId) - .withParameters(parameters)); - log.log(Level.INFO, String.format("Stopped container: %s on host: %s", containerName, hostId)); - } - - @Override - public GetHostsResult getHosts(String filter, int ageInMinutes, String status) { - GetHostsResult.Builder resultBuilder = GetHostsResult.newBuilder(); - List hosts = new ArrayList<>(); - DescribeInstancesResult instancesResult = - ec2.describeInstances( - new DescribeInstancesRequest() - .withFilters(new Filter().withName("tag-value").withValues(filter))); - long hostNum = 1L; - for (Reservation r : instancesResult.getReservations()) { - for (Instance e : r.getInstances()) { - long uptime = getHostUptimeInMinutes(e.getLaunchTime()); - if (e.getPrivateIpAddress() != null - && uptime > ageInMinutes - && status.equalsIgnoreCase(e.getState().getName())) { - Host.Builder hostBuilder = Host.newBuilder(); - hostBuilder.setHostNum(hostNum++); - hostBuilder.setDnsName(e.getPrivateDnsName()); - hostBuilder.setHostId(e.getInstanceId()); - hostBuilder.setIpAddress(e.getPrivateIpAddress()); - hostBuilder.setLaunchTime(Timestamps.fromMillis(e.getLaunchTime().getTime())); - hostBuilder.setLifecycle( - e.getInstanceLifecycle() != null ? e.getInstanceLifecycle() : "on demand"); - hostBuilder.setNumCores(e.getCpuOptions().getCoreCount()); - hostBuilder.setState(e.getState().getName()); - hostBuilder.setType(e.getInstanceType()); - hostBuilder.setUptimeMinutes(uptime); - hosts.add(hostBuilder.build()); - } - } - } - resultBuilder.addAllHosts(hosts); - resultBuilder.setNumHosts(hosts.size()); - log.log(Level.FINER, String.format("Got %d hosts for filter: %s", hosts.size(), filter)); - return resultBuilder.build(); - } - - @Override - public void scaleCluster( - String scaleGroupName, - Integer minHosts, - Integer maxHosts, - Integer targetHosts, - Integer targetReservedHostsPercent) { - UpdateAutoScalingGroupRequest request = - new UpdateAutoScalingGroupRequest().withAutoScalingGroupName(scaleGroupName); - if (minHosts != null) { - request.setMinSize(minHosts); - } - if (maxHosts != null) { - request.setMaxSize(maxHosts); - } - if (targetHosts != null) { - request.setMaxSize(targetHosts); - } - if (targetReservedHostsPercent != null) { - request.setMixedInstancesPolicy( - new MixedInstancesPolicy() - .withInstancesDistribution( - new InstancesDistribution() - .withOnDemandPercentageAboveBaseCapacity(targetReservedHostsPercent))); - } - scale.updateAutoScalingGroup(request); - log.log(Level.INFO, String.format("Scaled: %s", scaleGroupName)); - } - - private long getHostUptimeInMinutes(Date launchTime) { - Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC")); - return (cal.getTime().getTime() - launchTime.getTime()) / 60000; - } - - /** - * Disable instance scale in protection so that auto scaler can shutdown the instance. - * - * @param privateDnsName the private Dns name of instance (i.e. ip-xx-xxx-xx-xx.ec2.internal) - */ - @Override - public void disableHostScaleInProtection(String privateDnsName) { - // 1 get AutoScalingGroup and InstanceId - Instance workerInstance = getInstanceId(privateDnsName); - if (workerInstance == null) { - String errorMessage = "Cannot find instance with private DNS name " + privateDnsName; - log.log(Level.SEVERE, errorMessage); - throw new RuntimeException(errorMessage); - } - String instanceId = workerInstance.getInstanceId(); - String autoScalingGroup = getTagValue(workerInstance.getTags()); - if (autoScalingGroup == null || autoScalingGroup.length() == 0) { - String errorMessage = - "Cannot find AutoScalingGroup name of worker with private DNS name " + privateDnsName; - log.log(Level.SEVERE, errorMessage); - throw new RuntimeException(errorMessage); - } - - // 2 disable scale in protection of the worker - SetInstanceProtectionRequest disableProtectionRequest = - new SetInstanceProtectionRequest() - .withInstanceIds(instanceId) - .withAutoScalingGroupName(autoScalingGroup) - .withProtectedFromScaleIn(false); - SetInstanceProtectionResult result = scale.setInstanceProtection(disableProtectionRequest); - log.log( - Level.INFO, - String.format( - "Disable protection of host: %s in AutoScalingGroup: %s and get result: %s", - instanceId, autoScalingGroup, result.toString())); - } - - @Override - public void disableHostScaleInProtection(String clusterEndpoint, String instanceIp) { - ManagedChannel channel = null; - try { - channel = createChannel(clusterEndpoint); - AdminGrpc.AdminBlockingStub adminBlockingStub = AdminGrpc.newBlockingStub(channel); - adminBlockingStub.disableScaleInProtection( - DisableScaleInProtectionRequest.newBuilder().setInstanceName(instanceIp).build()); - } finally { - if (channel != null) { - channel.shutdown(); - } - } - } - - private String getTagValue(List tags) { - for (Tag tag : tags) { - if ("aws:autoscaling:groupName".equalsIgnoreCase(tag.getKey())) { - return tag.getValue(); - } - } - return null; - } - - private Instance getInstanceId(String privateDnsName) { - DescribeInstancesRequest describeInstancesRequest = - new DescribeInstancesRequest() - .withFilters(new Filter().withName("private-dns-name").withValues(privateDnsName)); - DescribeInstancesResult instancesResult = ec2.describeInstances(describeInstancesRequest); - for (Reservation r : instancesResult.getReservations()) { - for (Instance e : r.getInstances()) { - if (e.getPrivateDnsName() != null && e.getPrivateDnsName().equals(privateDnsName)) { - return e; - } - } - } - return null; - } -} diff --git a/src/main/java/build/buildfarm/admin/aws/BUILD b/src/main/java/build/buildfarm/admin/aws/BUILD deleted file mode 100644 index a49e431bfd..0000000000 --- a/src/main/java/build/buildfarm/admin/aws/BUILD +++ /dev/null @@ -1,29 +0,0 @@ -java_library( - name = "aws", - srcs = glob(["*.java"]), - plugins = ["//src/main/java/build/buildfarm/common:lombok"], - visibility = ["//visibility:public"], - deps = [ - "//src/main/java/build/buildfarm/admin", - "//src/main/java/build/buildfarm/common/config", - "//src/main/java/build/buildfarm/common/grpc", - "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_grpc", - "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@googleapis//:google_rpc_code_java_proto", - "@googleapis//:google_rpc_error_details_java_proto", - "@googleapis//:google_rpc_status_java_proto", - "@maven//:com_amazonaws_aws_java_sdk_autoscaling", - "@maven//:com_amazonaws_aws_java_sdk_core", - "@maven//:com_amazonaws_aws_java_sdk_ec2", - "@maven//:com_amazonaws_aws_java_sdk_secretsmanager", - "@maven//:com_amazonaws_aws_java_sdk_ssm", - "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java_util", - "@maven//:io_grpc_grpc_api", - "@maven//:org_projectlombok_lombok", - "@maven//:org_springframework_spring_beans", - "@maven//:org_springframework_spring_context", - "@maven//:org_springframework_spring_core", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", - ], -) diff --git a/src/main/java/build/buildfarm/admin/gcp/BUILD b/src/main/java/build/buildfarm/admin/gcp/BUILD deleted file mode 100644 index 3d94b91f3f..0000000000 --- a/src/main/java/build/buildfarm/admin/gcp/BUILD +++ /dev/null @@ -1,18 +0,0 @@ -java_library( - name = "gcp", - srcs = glob(["*.java"]), - visibility = ["//visibility:public"], - deps = [ - "//src/main/java/build/buildfarm/admin", - "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@googleapis//:google_rpc_code_java_proto", - "@googleapis//:google_rpc_error_details_java_proto", - "@googleapis//:google_rpc_status_java_proto", - "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java_util", - "@maven//:org_springframework_spring_beans", - "@maven//:org_springframework_spring_context", - "@maven//:org_springframework_spring_core", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", - ], -) diff --git a/src/main/java/build/buildfarm/admin/gcp/GcpAdmin.java b/src/main/java/build/buildfarm/admin/gcp/GcpAdmin.java deleted file mode 100644 index 34ee9a0163..0000000000 --- a/src/main/java/build/buildfarm/admin/gcp/GcpAdmin.java +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2020 The Bazel Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package build.buildfarm.admin.gcp; - -import build.buildfarm.admin.Admin; -import build.buildfarm.v1test.GetHostsResult; -import org.springframework.stereotype.Component; - -@Component -public class GcpAdmin implements Admin { - @Override - public void terminateHost(String hostId) { - throw new UnsupportedOperationException("Not Implemented."); - } - - @Override - public void stopContainer(String hostId, String containerName) { - throw new UnsupportedOperationException("Not Implemented."); - } - - @Override - public GetHostsResult getHosts(String filter, int ageInMinutes, String status) { - throw new UnsupportedOperationException("Not Implemented."); - } - - @Override - public void scaleCluster( - String scaleGroupName, - Integer minHosts, - Integer maxHosts, - Integer targetHosts, - Integer targetReservedHostsPercent) { - throw new UnsupportedOperationException("Not Implemented."); - } - - @Override - public void disableHostScaleInProtection(String instanceName) { - throw new UnsupportedOperationException("Not Implemented."); - } - - @Override - public void disableHostScaleInProtection(String clusterEndpoint, String instanceIp) { - throw new UnsupportedOperationException("Not Implemented"); - } -} diff --git a/src/main/java/build/buildfarm/common/config/Metrics.java b/src/main/java/build/buildfarm/common/config/Metrics.java index 73a9113d7a..28e065ddbf 100644 --- a/src/main/java/build/buildfarm/common/config/Metrics.java +++ b/src/main/java/build/buildfarm/common/config/Metrics.java @@ -1,6 +1,8 @@ package build.buildfarm.common.config; +import lombok.AccessLevel; import lombok.Data; +import lombok.Getter; @Data public class Metrics { @@ -19,7 +21,9 @@ public enum LOG_LEVEL { FINEST, } - private PUBLISHER publisher = PUBLISHER.LOG; + @Getter(AccessLevel.NONE) + private PUBLISHER publisher = PUBLISHER.LOG; // deprecated + private LOG_LEVEL logLevel = LOG_LEVEL.FINEST; private String topic; private int topicMaxConnections; diff --git a/src/main/java/build/buildfarm/metrics/aws/AwsMetricsPublisher.java b/src/main/java/build/buildfarm/metrics/aws/AwsMetricsPublisher.java deleted file mode 100644 index e0ae2785e0..0000000000 --- a/src/main/java/build/buildfarm/metrics/aws/AwsMetricsPublisher.java +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2020 The Bazel Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package build.buildfarm.metrics.aws; - -import build.bazel.remote.execution.v2.RequestMetadata; -import build.buildfarm.common.config.BuildfarmConfigs; -import build.buildfarm.metrics.AbstractMetricsPublisher; -import com.amazonaws.ClientConfiguration; -import com.amazonaws.auth.AWSCredentials; -import com.amazonaws.auth.AWSStaticCredentialsProvider; -import com.amazonaws.handlers.AsyncHandler; -import com.amazonaws.services.secretsmanager.AWSSecretsManager; -import com.amazonaws.services.secretsmanager.AWSSecretsManagerClientBuilder; -import com.amazonaws.services.secretsmanager.model.GetSecretValueRequest; -import com.amazonaws.services.secretsmanager.model.GetSecretValueResult; -import com.amazonaws.services.sns.AmazonSNSAsync; -import com.amazonaws.services.sns.AmazonSNSAsyncClientBuilder; -import com.amazonaws.services.sns.model.PublishRequest; -import com.amazonaws.services.sns.model.PublishResult; -import com.amazonaws.util.StringUtils; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.longrunning.Operation; -import java.io.IOException; -import java.util.Base64; -import java.util.HashMap; -import java.util.logging.Level; -import lombok.extern.java.Log; - -@Log -public class AwsMetricsPublisher extends AbstractMetricsPublisher { - private static BuildfarmConfigs configs = BuildfarmConfigs.getInstance(); - private static AmazonSNSAsync snsClient; - - private final String snsTopicOperations; - private String accessKeyId = null; - private String secretKey = null; - private final String region; - private final int snsClientMaxConnections; - - public AwsMetricsPublisher() { - super(configs.getServer().getClusterId()); - snsTopicOperations = configs.getServer().getMetrics().getTopic(); - region = configs.getServer().getCloudRegion(); - getAwsSecret(configs.getServer().getMetrics().getSecretName()); - snsClientMaxConnections = configs.getServer().getMetrics().getTopicMaxConnections(); - if (!StringUtils.isNullOrEmpty(snsTopicOperations) - && snsClientMaxConnections > 0 - && !StringUtils.isNullOrEmpty(accessKeyId) - && !StringUtils.isNullOrEmpty(secretKey) - && !StringUtils.isNullOrEmpty(region)) { - snsClient = initSnsClient(); - } - } - - @Override - public void publishRequestMetadata(Operation operation, RequestMetadata requestMetadata) { - try { - if (snsClient != null) { - snsClient.publishAsync( - new PublishRequest( - snsTopicOperations, - formatRequestMetadataToJson(populateRequestMetadata(operation, requestMetadata))), - new AsyncHandler() { - @Override - public void onError(Exception e) { - log.log(Level.WARNING, "Could not publish metrics data to SNS.", e); - } - - @Override - public void onSuccess(PublishRequest request, PublishResult publishResult) {} - }); - } - } catch (Exception e) { - log.log( - Level.WARNING, - String.format("Could not publish request metadata to SNS for %s.", operation.getName()), - e); - } - } - - private AmazonSNSAsync initSnsClient() { - log.log(Level.INFO, "Initializing SNS Client."); - return AmazonSNSAsyncClientBuilder.standard() - .withRegion(region) - .withClientConfiguration( - new ClientConfiguration().withMaxConnections(snsClientMaxConnections)) - .withCredentials( - new AWSStaticCredentialsProvider( - new AWSCredentials() { - @Override - public String getAWSAccessKeyId() { - return accessKeyId; - } - - @Override - public String getAWSSecretKey() { - return secretKey; - } - })) - .build(); - } - - @Override - public void publishMetric(String metricName, Object metricValue) { - throw new UnsupportedOperationException(); - } - - @SuppressWarnings("unchecked") - private void getAwsSecret(String secretName) { - AWSSecretsManager client = AWSSecretsManagerClientBuilder.standard().withRegion(region).build(); - GetSecretValueRequest getSecretValueRequest = - new GetSecretValueRequest().withSecretId(secretName); - GetSecretValueResult getSecretValueResult; - try { - getSecretValueResult = client.getSecretValue(getSecretValueRequest); - } catch (Exception e) { - log.log(Level.SEVERE, String.format("Could not get secret %s from AWS.", secretName)); - return; - } - String secret; - if (getSecretValueResult.getSecretString() != null) { - secret = getSecretValueResult.getSecretString(); - } else { - secret = - new String(Base64.getDecoder().decode(getSecretValueResult.getSecretBinary()).array()); - } - - if (secret != null) { - try { - final ObjectMapper objectMapper = new ObjectMapper(); - final HashMap secretMap = objectMapper.readValue(secret, HashMap.class); - accessKeyId = secretMap.get("access_key"); - secretKey = secretMap.get("secret_key"); - } catch (IOException e) { - log.log(Level.SEVERE, String.format("Could not parse secret %s from AWS", secretName)); - } - } - } -} diff --git a/src/main/java/build/buildfarm/metrics/aws/BUILD b/src/main/java/build/buildfarm/metrics/aws/BUILD deleted file mode 100644 index 51d44ea8c9..0000000000 --- a/src/main/java/build/buildfarm/metrics/aws/BUILD +++ /dev/null @@ -1,22 +0,0 @@ -java_library( - name = "aws", - srcs = glob(["*.java"]), - plugins = ["//src/main/java/build/buildfarm/common:lombok"], - visibility = ["//visibility:public"], - deps = [ - "//src/main/java/build/buildfarm/common/config", - "//src/main/java/build/buildfarm/metrics", - "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@googleapis//:google_rpc_code_java_proto", - "@googleapis//:google_rpc_error_details_java_proto", - "@googleapis//:google_rpc_status_java_proto", - "@maven//:com_amazonaws_aws_java_sdk_core", - "@maven//:com_amazonaws_aws_java_sdk_secretsmanager", - "@maven//:com_amazonaws_aws_java_sdk_sns", - "@maven//:com_fasterxml_jackson_core_jackson_databind", - "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java_util", - "@maven//:org_projectlombok_lombok", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", - ], -) diff --git a/src/main/java/build/buildfarm/metrics/gcp/BUILD b/src/main/java/build/buildfarm/metrics/gcp/BUILD deleted file mode 100644 index 765902b905..0000000000 --- a/src/main/java/build/buildfarm/metrics/gcp/BUILD +++ /dev/null @@ -1,16 +0,0 @@ -java_library( - name = "gcp", - srcs = glob(["*.java"]), - visibility = ["//visibility:public"], - deps = [ - "//src/main/java/build/buildfarm/common/config", - "//src/main/java/build/buildfarm/metrics", - "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@googleapis//:google_rpc_code_java_proto", - "@googleapis//:google_rpc_error_details_java_proto", - "@googleapis//:google_rpc_status_java_proto", - "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java_util", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", - ], -) diff --git a/src/main/java/build/buildfarm/metrics/gcp/GcpMetricsPublisher.java b/src/main/java/build/buildfarm/metrics/gcp/GcpMetricsPublisher.java deleted file mode 100644 index 40a6ddb1f8..0000000000 --- a/src/main/java/build/buildfarm/metrics/gcp/GcpMetricsPublisher.java +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2020 The Bazel Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package build.buildfarm.metrics.gcp; - -import build.buildfarm.common.config.BuildfarmConfigs; -import build.buildfarm.metrics.AbstractMetricsPublisher; - -public class GcpMetricsPublisher extends AbstractMetricsPublisher { - private static BuildfarmConfigs configs = BuildfarmConfigs.getInstance(); - - public GcpMetricsPublisher() { - super(configs.getServer().getClusterId()); - } - - @Override - public void publishMetric(String metricName, Object metricValue) { - throw new UnsupportedOperationException(); - } -} diff --git a/src/main/java/build/buildfarm/server/BuildFarmServer.java b/src/main/java/build/buildfarm/server/BuildFarmServer.java index e82928e934..4ca669d5f1 100644 --- a/src/main/java/build/buildfarm/server/BuildFarmServer.java +++ b/src/main/java/build/buildfarm/server/BuildFarmServer.java @@ -30,7 +30,6 @@ import build.buildfarm.instance.shard.ShardInstance; import build.buildfarm.metrics.prometheus.PrometheusPublisher; import build.buildfarm.server.services.ActionCacheService; -import build.buildfarm.server.services.AdminService; import build.buildfarm.server.services.CapabilitiesService; import build.buildfarm.server.services.ExecutionService; import build.buildfarm.server.services.FetchService; @@ -122,7 +121,6 @@ public synchronized void start(ServerBuilder serverBuilder, String publicName .addService(new ExecutionService(instance, keepaliveScheduler)) .addService(new OperationQueueService(instance)) .addService(new OperationsService(instance)) - .addService(new AdminService(instance)) .addService(new FetchService(instance)) .addService(ProtoReflectionService.newInstance()) .addService(new PublishBuildEventService()) diff --git a/src/main/java/build/buildfarm/server/services/AdminService.java b/src/main/java/build/buildfarm/server/services/AdminService.java deleted file mode 100644 index 94178fbf27..0000000000 --- a/src/main/java/build/buildfarm/server/services/AdminService.java +++ /dev/null @@ -1,254 +0,0 @@ -// Copyright 2020 The Bazel Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package build.buildfarm.server.services; - -import static build.buildfarm.common.grpc.Channels.createChannel; - -import build.buildfarm.admin.Admin; -import build.buildfarm.admin.aws.AwsAdmin; -import build.buildfarm.admin.gcp.GcpAdmin; -import build.buildfarm.common.CasIndexResults; -import build.buildfarm.common.config.BuildfarmConfigs; -import build.buildfarm.instance.Instance; -import build.buildfarm.v1test.AdminGrpc; -import build.buildfarm.v1test.DisableScaleInProtectionRequest; -import build.buildfarm.v1test.DisableScaleInProtectionRequestResults; -import build.buildfarm.v1test.GetClientStartTimeRequest; -import build.buildfarm.v1test.GetClientStartTimeResult; -import build.buildfarm.v1test.GetHostsRequest; -import build.buildfarm.v1test.GetHostsResult; -import build.buildfarm.v1test.PrepareWorkerForGracefulShutDownRequest; -import build.buildfarm.v1test.ReindexCasRequest; -import build.buildfarm.v1test.ReindexCasRequestResults; -import build.buildfarm.v1test.ScaleClusterRequest; -import build.buildfarm.v1test.ShutDownWorkerGracefullyRequest; -import build.buildfarm.v1test.ShutDownWorkerGracefullyRequestResults; -import build.buildfarm.v1test.ShutDownWorkerGrpc; -import build.buildfarm.v1test.StopContainerRequest; -import build.buildfarm.v1test.TerminateHostRequest; -import com.google.rpc.Code; -import com.google.rpc.Status; -import io.grpc.ManagedChannel; -import io.grpc.stub.StreamObserver; -import java.util.logging.Level; -import lombok.extern.java.Log; - -@Log -public class AdminService extends AdminGrpc.AdminImplBase { - private final Admin adminController; - private final Instance instance; - - private static BuildfarmConfigs configs = BuildfarmConfigs.getInstance(); - - public AdminService(Instance instance) { - this.adminController = getAdminController(); - this.instance = instance; - } - - @Override - public void terminateHost(TerminateHostRequest request, StreamObserver responseObserver) { - try { - if (adminController != null) { - adminController.terminateHost(request.getHostId()); - } - responseObserver.onNext(Status.newBuilder().setCode(Code.OK_VALUE).build()); - responseObserver.onCompleted(); - } catch (Exception e) { - log.log(Level.SEVERE, "Could not terminate host.", e); - responseObserver.onError(io.grpc.Status.fromThrowable(e).asException()); - } - } - - @Override - public void stopContainer(StopContainerRequest request, StreamObserver responseObserver) { - try { - if (adminController != null) { - adminController.stopContainer(request.getHostId(), request.getContainerName()); - } - responseObserver.onNext(Status.newBuilder().setCode(Code.OK_VALUE).build()); - responseObserver.onCompleted(); - } catch (Exception e) { - log.log(Level.SEVERE, "Could not stop container.", e); - responseObserver.onError(io.grpc.Status.fromThrowable(e).asException()); - } - } - - @Override - public void getHosts(GetHostsRequest request, StreamObserver responseObserver) { - try { - GetHostsResult result = null; - if (adminController != null) { - result = - adminController.getHosts( - request.getFilter(), request.getAgeInMinutes(), request.getStatus()); - } - responseObserver.onNext(result); - responseObserver.onCompleted(); - } catch (Exception e) { - log.log(Level.SEVERE, "Could not get hosts.", e); - responseObserver.onError(io.grpc.Status.fromThrowable(e).asException()); - } - } - - @Override - public void getClientStartTime( - GetClientStartTimeRequest request, - StreamObserver responseObserver) { - try { - GetClientStartTimeResult result = instance.getClientStartTime(request); - responseObserver.onNext(result); - responseObserver.onCompleted(); - } catch (Exception e) { - log.log( - Level.SEVERE, - String.format("Could not get client start time for %s.", request.getInstanceName()), - e); - responseObserver.onError(io.grpc.Status.fromThrowable(e).asException()); - } - } - - @Override - public void scaleCluster(ScaleClusterRequest request, StreamObserver responseObserver) { - try { - if (adminController != null) { - adminController.scaleCluster( - request.getScaleGroupName(), - request.getMinHosts(), - request.getMaxHosts(), - request.getTargetHosts(), - request.getTargetReservedHostsPercent()); - } - responseObserver.onNext(Status.newBuilder().setCode(Code.OK_VALUE).build()); - responseObserver.onCompleted(); - } catch (Exception e) { - log.log(Level.SEVERE, "Could not scale cluster.", e); - responseObserver.onError(io.grpc.Status.fromThrowable(e).asException()); - } - } - - @Override - public void reindexCas( - ReindexCasRequest request, StreamObserver responseObserver) { - try { - CasIndexResults results = instance.reindexCas(); - log.info(String.format("CAS Indexer Results: %s", results.toMessage())); - responseObserver.onNext( - ReindexCasRequestResults.newBuilder() - .setRemovedHosts(results.removedHosts) - .setRemovedKeys(results.removedKeys) - .setTotalKeys(results.totalKeys) - .build()); - responseObserver.onCompleted(); - } catch (Exception e) { - log.log(Level.SEVERE, "Could not reindex CAS.", e); - responseObserver.onError(io.grpc.Status.fromThrowable(e).asException()); - } - } - - /** - * Server-side implementation of ShutDownWorkerGracefully. This will reroute the request to target - * worker. - * - * @param request ShutDownWorkerGracefullyRequest received through grpc - * @param responseObserver grpc response observer - */ - @Override - public void shutDownWorkerGracefully( - ShutDownWorkerGracefullyRequest request, - StreamObserver responseObserver) { - try { - informWorkerToPrepareForShutdown(request.getWorkerName()); - responseObserver.onNext(ShutDownWorkerGracefullyRequestResults.newBuilder().build()); - responseObserver.onCompleted(); - } catch (Exception e) { - String errorMessage = - String.format( - "Could not inform the worker %s to prepare for graceful shutdown with error %s.", - request.getWorkerName(), e.getMessage()); - log.log(Level.SEVERE, errorMessage); - responseObserver.onError(new Exception(errorMessage)); - } - } - - /** - * Inform a worker to prepare for graceful shutdown. - * - * @param host the host that should be prepared for shutdown. - */ - @SuppressWarnings("ResultOfMethodCallIgnored") - private void informWorkerToPrepareForShutdown(String host) { - ManagedChannel channel = null; - try { - channel = createChannel(host); - ShutDownWorkerGrpc.ShutDownWorkerBlockingStub shutDownWorkerBlockingStub = - ShutDownWorkerGrpc.newBlockingStub(channel); - shutDownWorkerBlockingStub.prepareWorkerForGracefulShutdown( - PrepareWorkerForGracefulShutDownRequest.newBuilder().build()); - } finally { - if (channel != null) { - channel.shutdown(); - } - } - } - - /** - * Server-side implementation of disableScaleInProtection. - * - * @param request grpc request - * @param responseObserver grpc response observer - */ - @Override - public void disableScaleInProtection( - DisableScaleInProtectionRequest request, - StreamObserver responseObserver) { - try { - String hostPrivateIp = trimHostPrivateDns(request.getInstanceName()); - adminController.disableHostScaleInProtection(hostPrivateIp); - responseObserver.onNext(DisableScaleInProtectionRequestResults.newBuilder().build()); - responseObserver.onCompleted(); - } catch (RuntimeException e) { - responseObserver.onError(e); - } - } - - /** - * The private dns get from worker might be suffixed with ":portNumber", which should be trimmed. - * - * @param hostPrivateIp the private dns should be trimmed. - * @return - */ - @SuppressWarnings("JavaDoc") - private String trimHostPrivateDns(String hostPrivateIp) { - String portSeparator = ":"; - if (hostPrivateIp.contains(portSeparator)) { - hostPrivateIp = hostPrivateIp.split(portSeparator)[0]; - } - return hostPrivateIp; - } - - private static Admin getAdminController() { - if (configs.getServer().getAdmin().getDeploymentEnvironment() == null) { - return null; - } - switch (configs.getServer().getAdmin().getDeploymentEnvironment()) { - default: - return null; - case AWS: - return new AwsAdmin(); - case GCP: - return new GcpAdmin(); - } - } -} diff --git a/src/main/java/build/buildfarm/server/services/BUILD b/src/main/java/build/buildfarm/server/services/BUILD index 54b7af993c..6bb44b94f8 100644 --- a/src/main/java/build/buildfarm/server/services/BUILD +++ b/src/main/java/build/buildfarm/server/services/BUILD @@ -4,17 +4,12 @@ java_library( plugins = ["//src/main/java/build/buildfarm/common:lombok"], visibility = ["//visibility:public"], deps = [ - "//src/main/java/build/buildfarm/admin", - "//src/main/java/build/buildfarm/admin/aws", - "//src/main/java/build/buildfarm/admin/gcp", "//src/main/java/build/buildfarm/common", "//src/main/java/build/buildfarm/common/config", "//src/main/java/build/buildfarm/common/grpc", "//src/main/java/build/buildfarm/common/resources:resource_java_proto", "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/metrics", - "//src/main/java/build/buildfarm/metrics/aws", - "//src/main/java/build/buildfarm/metrics/gcp", "//src/main/java/build/buildfarm/metrics/log", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_grpc", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", diff --git a/src/main/java/build/buildfarm/server/services/ExecutionService.java b/src/main/java/build/buildfarm/server/services/ExecutionService.java index 7f46c0bb3c..69799524fb 100644 --- a/src/main/java/build/buildfarm/server/services/ExecutionService.java +++ b/src/main/java/build/buildfarm/server/services/ExecutionService.java @@ -28,8 +28,6 @@ import build.buildfarm.common.grpc.TracingMetadataUtils; import build.buildfarm.instance.Instance; import build.buildfarm.metrics.MetricsPublisher; -import build.buildfarm.metrics.aws.AwsMetricsPublisher; -import build.buildfarm.metrics.gcp.GcpMetricsPublisher; import build.buildfarm.metrics.log.LogMetricsPublisher; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.ListenableFuture; @@ -205,13 +203,6 @@ public void execute(ExecuteRequest request, StreamObserver responseOb } private static MetricsPublisher getMetricsPublisher() { - switch (configs.getServer().getMetrics().getPublisher()) { - default: - return new LogMetricsPublisher(); - case AWS: - return new AwsMetricsPublisher(); - case GCP: - return new GcpMetricsPublisher(); - } + return new LogMetricsPublisher(); } } diff --git a/src/main/java/build/buildfarm/worker/shard/BUILD b/src/main/java/build/buildfarm/worker/shard/BUILD index beeaaae918..120365882b 100644 --- a/src/main/java/build/buildfarm/worker/shard/BUILD +++ b/src/main/java/build/buildfarm/worker/shard/BUILD @@ -4,8 +4,6 @@ java_library( plugins = ["//src/main/java/build/buildfarm/common:lombok"], visibility = ["//visibility:public"], deps = [ - "//src/main/java/build/buildfarm/admin", - "//src/main/java/build/buildfarm/admin/aws", "//src/main/java/build/buildfarm/backplane", "//src/main/java/build/buildfarm/cas", "//src/main/java/build/buildfarm/common", diff --git a/src/test/java/build/buildfarm/metrics/BUILD b/src/test/java/build/buildfarm/metrics/BUILD index 8e5d3cace9..c32955e20d 100644 --- a/src/test/java/build/buildfarm/metrics/BUILD +++ b/src/test/java/build/buildfarm/metrics/BUILD @@ -8,14 +8,10 @@ java_test( "//src/main/java/build/buildfarm/common", "//src/main/java/build/buildfarm/common/config", "//src/main/java/build/buildfarm/metrics", - "//src/main/java/build/buildfarm/metrics/aws", "//src/main/java/build/buildfarm/metrics/log", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", "@googleapis//:google_rpc_error_details_java_proto", - "@maven//:com_amazonaws_aws_java_sdk_core", - "@maven//:com_amazonaws_aws_java_sdk_secretsmanager", - "@maven//:com_amazonaws_aws_java_sdk_sns", "@maven//:com_google_guava_guava", "@maven//:com_google_jimfs_jimfs", "@maven//:com_google_protobuf_protobuf_java", diff --git a/src/test/java/build/buildfarm/metrics/MetricsPublisherTest.java b/src/test/java/build/buildfarm/metrics/MetricsPublisherTest.java index 21c9685efd..f30adb55c6 100644 --- a/src/test/java/build/buildfarm/metrics/MetricsPublisherTest.java +++ b/src/test/java/build/buildfarm/metrics/MetricsPublisherTest.java @@ -22,7 +22,6 @@ import build.bazel.remote.execution.v2.RequestMetadata; import build.buildfarm.common.config.BuildfarmConfigs; import build.buildfarm.common.config.Metrics; -import build.buildfarm.metrics.aws.AwsMetricsPublisher; import build.buildfarm.metrics.log.LogMetricsPublisher; import build.buildfarm.v1test.OperationRequestMetadata; import com.google.longrunning.Operation; @@ -69,7 +68,7 @@ public class MetricsPublisherTest { public void setUp() throws IOException { configs.getServer().setCloudRegion("test"); configs.getServer().setClusterId("buildfarm-test"); - configs.getServer().getMetrics().setPublisher(Metrics.PUBLISHER.AWS); + configs.getServer().getMetrics().setPublisher(Metrics.PUBLISHER.LOG); } @Test @@ -81,7 +80,7 @@ public void publishCompleteMetricsTest() throws InvalidProtocolBufferException { .setMetadata(Any.pack(defaultExecuteOperationMetadata)) .build(); - AwsMetricsPublisher metricsPublisher = new AwsMetricsPublisher(); + LogMetricsPublisher metricsPublisher = new LogMetricsPublisher(); assertThat( AbstractMetricsPublisher.formatRequestMetadataToJson( metricsPublisher.populateRequestMetadata(operation, defaultRequestMetadata))) @@ -110,7 +109,7 @@ public void publishMetricsWithNoExecuteResponseTest() { Operation operation = defaultOperation.toBuilder().setMetadata(Any.pack(defaultExecuteOperationMetadata)).build(); - assertThat(new AwsMetricsPublisher().populateRequestMetadata(operation, defaultRequestMetadata)) + assertThat(new LogMetricsPublisher().populateRequestMetadata(operation, defaultRequestMetadata)) .isNotNull(); } @@ -119,7 +118,7 @@ public void publishMetricsWithNoExecuteOperationMetadataTest() { Operation operation = defaultOperation.toBuilder().setResponse(Any.pack(defaultExecuteResponse)).build(); - assertThat(new AwsMetricsPublisher().populateRequestMetadata(operation, defaultRequestMetadata)) + assertThat(new LogMetricsPublisher().populateRequestMetadata(operation, defaultRequestMetadata)) .isNotNull(); } @@ -135,7 +134,7 @@ public void preconditionFailureTest() { .setMetadata(Any.pack(defaultExecuteOperationMetadata)) .build(); - assertThat(new AwsMetricsPublisher().populateRequestMetadata(operation, defaultRequestMetadata)) + assertThat(new LogMetricsPublisher().populateRequestMetadata(operation, defaultRequestMetadata)) .isNotNull(); } From f97f04816119775bcd52a9becd75c405450c52f4 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Tue, 3 Oct 2023 16:00:15 -0400 Subject: [PATCH 069/311] Remove unused setOnCancelHandler Remove this unused OperationQueue feature which provides no invocations on any use. --- .../buildfarm/instance/MatchListener.java | 3 --- .../server/services/OperationQueueService.java | 18 ++---------------- .../build/buildfarm/worker/MatchStage.java | 5 ----- .../worker/shard/ShardWorkerContext.java | 5 ----- 4 files changed, 2 insertions(+), 29 deletions(-) diff --git a/src/main/java/build/buildfarm/instance/MatchListener.java b/src/main/java/build/buildfarm/instance/MatchListener.java index 46f6dfc000..3da7df90eb 100644 --- a/src/main/java/build/buildfarm/instance/MatchListener.java +++ b/src/main/java/build/buildfarm/instance/MatchListener.java @@ -27,7 +27,4 @@ public interface MatchListener { boolean onEntry(@Nullable QueueEntry queueEntry) throws InterruptedException; void onError(Throwable t); - - // method that should be called when this match is cancelled and no longer valid - void setOnCancelHandler(Runnable onCancelHandler); } diff --git a/src/main/java/build/buildfarm/server/services/OperationQueueService.java b/src/main/java/build/buildfarm/server/services/OperationQueueService.java index 6d3edb8178..11f6501667 100644 --- a/src/main/java/build/buildfarm/server/services/OperationQueueService.java +++ b/src/main/java/build/buildfarm/server/services/OperationQueueService.java @@ -28,9 +28,7 @@ import com.google.rpc.Code; import io.grpc.Status; import io.grpc.StatusRuntimeException; -import io.grpc.stub.ServerCallStreamObserver; import io.grpc.stub.StreamObserver; -import java.util.function.Consumer; public class OperationQueueService extends OperationQueueGrpc.OperationQueueImplBase { private final Instance instance; @@ -43,14 +41,11 @@ private static class OperationQueueMatchListener implements MatchListener { @SuppressWarnings("rawtypes") private final InterruptingPredicate onMatch; - private final Consumer setOnCancelHandler; private static final QueueEntry queueEntry = null; @SuppressWarnings("rawtypes") - OperationQueueMatchListener( - InterruptingPredicate onMatch, Consumer setOnCancelHandler) { + OperationQueueMatchListener(InterruptingPredicate onMatch) { this.onMatch = onMatch; - this.setOnCancelHandler = setOnCancelHandler; } @Override @@ -70,11 +65,6 @@ public void onError(Throwable t) { Throwables.throwIfUnchecked(t); throw new RuntimeException(t); } - - @Override - public void setOnCancelHandler(Runnable onCancelHandler) { - setOnCancelHandler.accept(onCancelHandler); - } } private InterruptingPredicate createOnMatch( @@ -97,14 +87,10 @@ private InterruptingPredicate createOnMatch( @Override public void take(TakeOperationRequest request, StreamObserver responseObserver) { - ServerCallStreamObserver callObserver = - (ServerCallStreamObserver) responseObserver; - try { instance.match( request.getPlatform(), - new OperationQueueMatchListener( - createOnMatch(instance, responseObserver), callObserver::setOnCancelHandler)); + new OperationQueueMatchListener(createOnMatch(instance, responseObserver))); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } diff --git a/src/main/java/build/buildfarm/worker/MatchStage.java b/src/main/java/build/buildfarm/worker/MatchStage.java index dc81a2ce31..663aee3c52 100644 --- a/src/main/java/build/buildfarm/worker/MatchStage.java +++ b/src/main/java/build/buildfarm/worker/MatchStage.java @@ -95,11 +95,6 @@ public void onError(Throwable t) { throw new RuntimeException(t); } - @Override - public void setOnCancelHandler(Runnable onCancelHandler) { - // never called, only blocking stub used - } - @SuppressWarnings("SameReturnValue") private boolean onOperationPolled() throws InterruptedException { String operationName = operationContext.queueEntry.getExecuteEntry().getOperationName(); diff --git a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java index 143fa09966..9f4ee3a29e 100644 --- a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java +++ b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java @@ -350,11 +350,6 @@ public void onError(Throwable t) { Throwables.throwIfUnchecked(t); throw new RuntimeException(t); } - - @Override - public void setOnCancelHandler(Runnable onCancelHandler) { - listener.setOnCancelHandler(onCancelHandler); - } }; while (dedupMatchListener.getMatched()) { try { From c2c15449efddefad5e6bdd11107dbcc1e99f8f7b Mon Sep 17 00:00:00 2001 From: George Gensure Date: Wed, 4 Oct 2023 16:46:57 -0400 Subject: [PATCH 070/311] Update BWoB docs for ensureOutputsPresent --- _site/docs/execution/builds-without-the-bytes.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_site/docs/execution/builds-without-the-bytes.md b/_site/docs/execution/builds-without-the-bytes.md index abda8c86b5..5c49025877 100644 --- a/_site/docs/execution/builds-without-the-bytes.md +++ b/_site/docs/execution/builds-without-the-bytes.md @@ -7,7 +7,7 @@ nav_order: 4 # Builds Without The Bytes -tl;dr: add `--build_request_id=https://host?ENSURE_OUTPUTS_PRESENT=true#$(uuidgen)` to your BWOB bazel invocations. +tl;dr: add `--build_request_id=https://host?ENSURE_OUTPUTS_PRESENT=true#$(uuidgen)`, to your BWOB bazel invocations, or enable `ensureOutputsPresent` in your config to set it globally. As proposed in this [issue](https://github.com/bazelbuild/bazel/issues/6862) and the accompanying document, bazel endeavors to provide a mechanism to be 'content-light' for remote execution, using only content reference addresses to request action execution and construct successively dependent action definitions. @@ -17,4 +17,4 @@ This puts BuildFarm in the uncomfortable position of never being able to expire To combat this, you can provide some metadata to buildfarm that will help to limit (but will not remove the possibility of) failed builds. -Bazel presents a 'correlated_invocations_id' on every request to BuildFarm, including the GetActionResult request, which it uses to retrieve cached results. Since ActionResults are the long tail survivor of actions, being retained for much longer after one executes and produces its content, this represents the most likely position where content may have been removed, and a stale reference might be provided. BuildFarm recognizes this correlated_invocations_id and if it is a URI, can parse its query parameters for behavior control. One such control is ENSURE_OUTPUTS_PRESENT for the GetActionResult request - if this query value is the string "true", BuildFarm will make a silent FindMissingBlobs check for all of the outputs of an ActionResult before responding with it. If any are missing, BuildFarm will instead return code NOT_FOUND, inspiring the client to see a cache miss, and attempt a [remote] execution. \ No newline at end of file +Bazel presents a 'correlated_invocations_id' on every request to BuildFarm, including the GetActionResult request, which it uses to retrieve cached results. Since ActionResults are the long tail survivor of actions, being retained for much longer after one executes and produces its content, this represents the most likely position where content may have been removed, and a stale reference might be provided. BuildFarm recognizes this correlated_invocations_id and if it is a URI, can parse its query parameters for behavior control. One such control is ENSURE_OUTPUTS_PRESENT for the GetActionResult request - if this query value is the string "true", BuildFarm will make a silent FindMissingBlobs check for all of the outputs of an ActionResult before responding with it. If any are missing, BuildFarm will instead return code NOT_FOUND, inspiring the client to see a cache miss, and attempt a [remote] execution. From 09015c9abfd02015ed3fdf88e6a72ec143a83eff Mon Sep 17 00:00:00 2001 From: Yun Peng Date: Fri, 6 Oct 2023 13:34:21 +0000 Subject: [PATCH 071/311] Disable Bzlmod explicitly in .bazelrc --- .bazelrc | 4 ++++ MODULE.bazel | 2 ++ 2 files changed, 6 insertions(+) create mode 100644 MODULE.bazel diff --git a/.bazelrc b/.bazelrc index cfea58ba6a..adbb3c68fd 100644 --- a/.bazelrc +++ b/.bazelrc @@ -14,3 +14,7 @@ test --test_tag_filters=-redis,-integration # Ensure buildfarm is compatible with future versions of bazel. # https://buildkite.com/bazel/bazelisk-plus-incompatible-flags common --incompatible_disallow_empty_glob + +# TODO: migrate all dependencies from WORKSPACE to MODULE.bazel +# https://github.com/bazelbuild/bazel-buildfarm/issues/1479 +common --noenable_bzlmod diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 0000000000..cabbbe697c --- /dev/null +++ b/MODULE.bazel @@ -0,0 +1,2 @@ +# TODO: migrate all dependencies from WORKSPACE to MODULE.bazel +# https://github.com/bazelbuild/bazel-buildfarm/issues/1479 From 1041b57e55cba97d41657b094384a9725c45d5b5 Mon Sep 17 00:00:00 2001 From: Anshuman Mishra Date: Thu, 28 Sep 2023 21:55:15 -0700 Subject: [PATCH 072/311] Log write errors with worker address --- .../buildfarm/common/grpc/StubWriteOutputStream.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/build/buildfarm/common/grpc/StubWriteOutputStream.java b/src/main/java/build/buildfarm/common/grpc/StubWriteOutputStream.java index 26b67f5c6c..4e500398b2 100644 --- a/src/main/java/build/buildfarm/common/grpc/StubWriteOutputStream.java +++ b/src/main/java/build/buildfarm/common/grpc/StubWriteOutputStream.java @@ -227,6 +227,14 @@ public void onNext(WriteResponse response) { @Override public void onError(Throwable t) { + log.log( + WARNING, + format( + "%s: write(%s) on worker %s after %d bytes of content", + Status.fromThrowable(t).getCode().name(), + resourceName, + bsStub.get().getChannel().authority(), + writtenBytes)); writeFuture.setException(exceptionTranslator.apply(t)); } From 30412adf9bcfa72734bd9fb3ac4b13bda397b9d2 Mon Sep 17 00:00:00 2001 From: Yuriy Belenitsky Date: Sun, 8 Oct 2023 08:25:16 -0400 Subject: [PATCH 073/311] Revert "Use integer ids for Sqlite bidirectional index" This reverts commit f651cdbf7b2203e8cdb5645a1f869589e42f28c3. --- .../cas/cfc/SqliteFileDirectoriesIndex.java | 64 ++++--------------- .../cas/cfc/DirectoriesIndexTest.java | 1 - 2 files changed, 11 insertions(+), 54 deletions(-) diff --git a/src/main/java/build/buildfarm/cas/cfc/SqliteFileDirectoriesIndex.java b/src/main/java/build/buildfarm/cas/cfc/SqliteFileDirectoriesIndex.java index b18b5bd22c..030c749037 100644 --- a/src/main/java/build/buildfarm/cas/cfc/SqliteFileDirectoriesIndex.java +++ b/src/main/java/build/buildfarm/cas/cfc/SqliteFileDirectoriesIndex.java @@ -57,19 +57,13 @@ private void open() { throw new RuntimeException(e); } - String createDirectoriesSql = - "CREATE TABLE directories (id INTEGER PRIMARY KEY, name VARCHAR UNIQUE)"; - String createFilesSql = "CREATE TABLE files (id INTEGER PRIMARY KEY, name VARCHAR UNIQUE)"; String createEntriesSql = "CREATE TABLE entries (\n" - + " file_id INTEGER NOT NULL REFERENCES files(id) ON DELETE CASCADE,\n" - + " directory_id INTEGER NOT NULL REFERENCES directories(id) ON DELETE CASCADE,\n" - + " PRIMARY KEY (file_id, directory_id)\n" + + " path TEXT NOT NULL,\n" + + " directory TEXT NOT NULL\n" + ")"; try (Statement stmt = conn.createStatement()) { - stmt.execute(createDirectoriesSql); - stmt.execute(createFilesSql); stmt.execute(createEntriesSql); } catch (SQLException e) { throw new RuntimeException(e); @@ -83,13 +77,11 @@ private void open() { public synchronized void start() { open(); - String createPathIndexSql = "CREATE INDEX files_name_idx ON entries (file_id)"; - String createDirectoryIndexSql = "CREATE INDEX directory_idx ON entries (directory_id)"; - String enforceForeignKeys = "PRAGMA foreign_keys=ON"; + String createPathIndexSql = "CREATE INDEX path_idx ON entries (path)"; + String createDirectoryIndexSql = "CREATE INDEX directory_idx ON entries (directory)"; try (Statement stmt = conn.createStatement()) { stmt.execute(createPathIndexSql); stmt.execute(createDirectoryIndexSql); - stmt.execute(enforceForeignKeys); } catch (SQLException e) { throw new RuntimeException(e); } @@ -109,8 +101,7 @@ public void close() { private Set removeEntryDirectories(String entry) { open(); - String selectSql = - "SELECT d.name as directory FROM files f INNER JOIN entries e ON f.id = e.file_id INNER JOIN directories d ON d.id = e.directory_id WHERE f.name = ?"; + String selectSql = "SELECT directory FROM entries WHERE path = ?"; ImmutableSet.Builder directoriesBuilder = ImmutableSet.builder(); try (PreparedStatement selectStatement = conn.prepareStatement(selectSql)) { @@ -125,7 +116,7 @@ private Set removeEntryDirectories(String entry) { } // all directories featuring this entry are now invalid ImmutableSet directories = directoriesBuilder.build(); - String deleteSql = "DELETE FROM directories where name = ?"; + String deleteSql = "DELETE FROM entries where directory = ?"; try (PreparedStatement deleteStatement = conn.prepareStatement(deleteSql)) { conn.setAutoCommit(false); for (Digest directory : directories) { @@ -137,14 +128,6 @@ private Set removeEntryDirectories(String entry) { } catch (SQLException e) { throw new RuntimeException(e); } - // clear out orphaned files - try (Statement orphanStatement = conn.createStatement()) { - String deleteOrphanSql = - "DELETE FROM files WHERE id in (SELECT id FROM files f LEFT JOIN entries e ON f.id = e.file_id WHERE e.file_id IS NULL)"; - orphanStatement.execute(deleteOrphanSql); - } catch (SQLException e) { - throw new RuntimeException(e); - } return directories; } @@ -158,37 +141,13 @@ public synchronized Set removeEntry(String entry) throws IOException { private synchronized void addEntriesDirectory(Set entries, Digest directory) { open(); - String directoryName = DigestUtil.toString(directory); - String filesInsertSql = "INSERT OR IGNORE INTO files (name) VALUES (?)"; - try (PreparedStatement filesInsertStatement = conn.prepareStatement(filesInsertSql)) { - conn.setAutoCommit(false); - for (String entry : entries) { - filesInsertStatement.setString(1, entry); - filesInsertStatement.addBatch(); - } - filesInsertStatement.executeBatch(); - conn.commit(); - } catch (SQLException e) { - throw new RuntimeException(e); - } - // should be novel directory - String directoriesInsertSql = "INSERT INTO directories (name) VALUES (?)"; - try (PreparedStatement directoriesInsertStatement = - conn.prepareStatement(directoriesInsertSql)) { - conn.setAutoCommit(false); - directoriesInsertStatement.setString(1, directoryName); - directoriesInsertStatement.executeUpdate(); - conn.commit(); - } catch (SQLException e) { - throw new RuntimeException(e); - } - String entriesInsertSql = - "INSERT INTO entries (file_id, directory_id) SELECT f.id, d.id FROM files f, directories d WHERE f.name = ? AND d.name = ?"; - try (PreparedStatement insertStatement = conn.prepareStatement(entriesInsertSql)) { + String digest = DigestUtil.toString(directory); + String insertSql = "INSERT INTO entries (path, directory) VALUES (?,?)"; + try (PreparedStatement insertStatement = conn.prepareStatement(insertSql)) { conn.setAutoCommit(false); + insertStatement.setString(2, digest); for (String entry : entries) { insertStatement.setString(1, entry); - insertStatement.setString(2, directoryName); insertStatement.addBatch(); } insertStatement.executeBatch(); @@ -209,9 +168,8 @@ private void removeEntriesDirectory(Digest directory) { open(); String digest = DigestUtil.toString(directory); - String deleteSql = "DELETE FROM directories WHERE name = ?"; + String deleteSql = "DELETE FROM entries WHERE directory = ?"; try (PreparedStatement deleteStatement = conn.prepareStatement(deleteSql)) { - conn.setAutoCommit(true); deleteStatement.setString(1, digest); deleteStatement.executeUpdate(); } catch (SQLException e) { diff --git a/src/test/java/build/buildfarm/cas/cfc/DirectoriesIndexTest.java b/src/test/java/build/buildfarm/cas/cfc/DirectoriesIndexTest.java index b4effa2bc8..3eec66def7 100644 --- a/src/test/java/build/buildfarm/cas/cfc/DirectoriesIndexTest.java +++ b/src/test/java/build/buildfarm/cas/cfc/DirectoriesIndexTest.java @@ -51,7 +51,6 @@ protected DirectoriesIndexTest(Path root, DirectoriesIndexType type) { } else { throw new IllegalArgumentException("DirectoriesIndex type is not supported."); } - directoriesIndex.start(); } @Before From 83790688c9e589ea35b3526c71ed95899f417633 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Tue, 3 Oct 2023 16:08:51 -0400 Subject: [PATCH 074/311] Common String.format for PipelineStage --- .../java/build/buildfarm/worker/PipelineStage.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/build/buildfarm/worker/PipelineStage.java b/src/main/java/build/buildfarm/worker/PipelineStage.java index edad2bb572..ecc78f8e7e 100644 --- a/src/main/java/build/buildfarm/worker/PipelineStage.java +++ b/src/main/java/build/buildfarm/worker/PipelineStage.java @@ -14,6 +14,7 @@ package build.buildfarm.worker; +import static java.lang.String.format; import static java.util.concurrent.TimeUnit.MICROSECONDS; import com.google.common.base.Stopwatch; @@ -63,8 +64,7 @@ public void run() { // ignore } catch (Exception e) { getLogger() - .log( - Level.SEVERE, String.format("%s::run(): stage terminated due to exception", name), e); + .log(Level.SEVERE, format("%s::run(): stage terminated due to exception", name), e); } finally { boolean wasInterrupted = Thread.interrupted(); try { @@ -143,7 +143,7 @@ protected void iterate() throws InterruptedException { } private String logIterateId(String operationName) { - return String.format("%s::iterate(%s)", name, operationName); + return format("%s::iterate(%s)", name, operationName); } protected void start() { @@ -157,7 +157,7 @@ protected void start(String operationName) { protected void start(String operationName, String message) { // TODO to unary stage this.operationName = operationName; - getLogger().log(Level.FINER, String.format("%s: %s", logIterateId(operationName), message)); + getLogger().log(Level.FINER, format("%s: %s", logIterateId(operationName), message)); } protected void complete(String operationName, long usecs, long stallUSecs, boolean success) { @@ -169,7 +169,7 @@ protected void complete(String operationName, long usecs, long stallUSecs, Strin getLogger() .log( Level.FINER, - String.format( + format( "%s: %g ms (%g ms stalled) %s", logIterateId(operationName), usecs / 1000.0f, stallUSecs / 1000.0f, status)); } From fd20d134497061af3d7bd3e06c209a53a01559ae Mon Sep 17 00:00:00 2001 From: George Gensure Date: Tue, 3 Oct 2023 16:18:10 -0400 Subject: [PATCH 075/311] Cleanup matched logic in SWC listener Continue the loop while we have *not* matched successfully and avoid a confusing inversion in getMatched() --- .../java/build/buildfarm/worker/shard/ShardWorkerContext.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java index 9f4ee3a29e..18ab0d8fe5 100644 --- a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java +++ b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java @@ -313,7 +313,7 @@ public void match(MatchListener listener) throws InterruptedException { @Override public boolean getMatched() { - return !matched; + return matched; } @Override @@ -351,7 +351,7 @@ public void onError(Throwable t) { throw new RuntimeException(t); } }; - while (dedupMatchListener.getMatched()) { + while (!dedupMatchListener.getMatched()) { try { matchInterruptible(dedupMatchListener); } catch (IOException e) { From 632fceb1b02a13f519a1a6ff64a403262bd9b05c Mon Sep 17 00:00:00 2001 From: George Gensure Date: Tue, 3 Oct 2023 16:20:55 -0400 Subject: [PATCH 076/311] Refactor SWC matcher and clarify Nullable Distinguish the valid/unique/propagating methods of entry listening. --- .../buildfarm/worker/shard/ShardWorkerContext.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java index 18ab0d8fe5..d32731879c 100644 --- a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java +++ b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java @@ -92,6 +92,7 @@ import java.util.Map; import java.util.Stack; import java.util.logging.Level; +import javax.annotation.Nullable; import lombok.extern.java.Log; @Log @@ -327,20 +328,28 @@ public void onWaitEnd() { } @Override - public boolean onEntry(QueueEntry queueEntry) throws InterruptedException { + public boolean onEntry(@Nullable QueueEntry queueEntry) throws InterruptedException { if (queueEntry == null) { matched = true; return listener.onEntry(null); } + return onValidEntry(queueEntry); + } + + private boolean onValidEntry(QueueEntry queueEntry) throws InterruptedException { String operationName = queueEntry.getExecuteEntry().getOperationName(); if (activeOperations.putIfAbsent(operationName, queueEntry) != null) { log.log(Level.WARNING, "matched duplicate operation " + operationName); return false; } + return onUniqueEntry(queueEntry); + } + + private boolean onUniqueEntry(QueueEntry queueEntry) throws InterruptedException { matched = true; boolean success = listener.onEntry(queueEntry); if (!success) { - requeue(operationName); + requeue(queueEntry.getExecuteEntry().getOperationName()); } return success; } From 7385c74cf0c711a91d1130fa8f406dcb57a8dc60 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Tue, 3 Oct 2023 16:30:43 -0400 Subject: [PATCH 077/311] Interrupt matchStage to induce prepare shutdown The only signal to a waiting match that will halt its current listen loop for a valid unique operation is an interrupt. --- .../java/build/buildfarm/worker/Pipeline.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/java/build/buildfarm/worker/Pipeline.java b/src/main/java/build/buildfarm/worker/Pipeline.java index da4eaacfb6..6b2d4f2a7d 100644 --- a/src/main/java/build/buildfarm/worker/Pipeline.java +++ b/src/main/java/build/buildfarm/worker/Pipeline.java @@ -61,9 +61,12 @@ public void close() throws InterruptedException { /** Inform MatchStage to stop matching or picking up new Operations from queue. */ public void stopMatchingOperations() { - for (PipelineStage stage : stageClosePriorities.keySet()) { + for (Map.Entry entry : stageThreads.entrySet()) { + PipelineStage stage = entry.getKey(); if (stage instanceof MatchStage) { - ((MatchStage) stage).prepareForGracefulShutdown(); + MatchStage matchStage = (MatchStage) stage; + matchStage.prepareForGracefulShutdown(); + entry.getValue().interrupt(); return; } } @@ -134,15 +137,17 @@ private void join(boolean closeStage) throws InterruptedException { } } if (stageToClose != null && !stageToClose.isClosed()) { - log.log(Level.FINER, "Closing stage at priority " + maxPriority); + log.log(Level.FINER, "Closing stage " + stageToClose + " at priority " + maxPriority); stageToClose.close(); } } + boolean longStageWait = !closeStage; for (Map.Entry stageThread : stageThreads.entrySet()) { PipelineStage stage = stageThread.getKey(); Thread thread = stageThread.getValue(); try { - thread.join(closeStage ? 1 : 1000); + // 0 is wait forever, no instant wait + thread.join(longStageWait ? 1000 : 1); } catch (InterruptedException e) { if (!closeStage) { synchronized (this) { @@ -172,8 +177,8 @@ private void join(boolean closeStage) throws InterruptedException { + stageClosePriorities.get(stage)); thread.interrupt(); } + longStageWait = false; } - closeStage = false; for (PipelineStage stage : inactiveStages) { synchronized (this) { stageThreads.remove(stage); From 79cf64898a11c745834d9eabd6707f64e7acab4c Mon Sep 17 00:00:00 2001 From: George Gensure Date: Tue, 3 Oct 2023 14:52:53 -0400 Subject: [PATCH 078/311] Specify example config with grpc target Distinguish target param with GRPC type storage from FILESYSTEM definition --- examples/config.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/config.yml b/examples/config.yml index f426e98547..901e8ff76d 100644 --- a/examples/config.yml +++ b/examples/config.yml @@ -110,7 +110,8 @@ worker: skipLoad: false hexBucketLevels: 0 execRootCopyFallback: false - target: + #- type: GRPC + # target: "grpc://host:port" executeStageWidth: 1 inputFetchStageWidth: 1 inputFetchDeadline: 60 From d73628b6a6dcaea90f93426ad4d9c203851c9120 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Tue, 3 Oct 2023 16:24:53 -0400 Subject: [PATCH 079/311] Remove SpringBoot usage Reinstate prior usage of LoggingMain for safe shutdown, with added release mechanism for interrupted processes. All invoked shutdowns are graceful, with vastly improved shutdown speed for empty workers waiting for pipeline stages. --- defs.bzl | 20 +-- .../build/buildfarm/common/LoggingMain.java | 28 ++-- src/main/java/build/buildfarm/server/BUILD | 6 - .../buildfarm/server/BuildFarmServer.java | 126 +++++++++------- .../java/build/buildfarm/worker/shard/BUILD | 5 - .../shard/ShutDownWorkerGracefully.java | 3 +- .../build/buildfarm/worker/shard/Worker.java | 139 ++++++++---------- 7 files changed, 145 insertions(+), 182 deletions(-) diff --git a/defs.bzl b/defs.bzl index 993e9d36f4..ec51856484 100644 --- a/defs.bzl +++ b/defs.bzl @@ -43,22 +43,8 @@ IO_GRPC_MODULES = [ ] COM_AWS_MODULES = [ - "secretsmanager", "s3", -] - -ORG_SPRING_MODULES = [ - "spring-beans", - "spring-core", - "spring-context", - "spring-web", -] - -ORG_SPRING_BOOT_MODULES = [ - "spring-boot-autoconfigure", - "spring-boot", - "spring-boot-starter-web", - "spring-boot-starter-thymeleaf", + "secretsmanager", ] def buildfarm_init(name = "buildfarm"): @@ -99,7 +85,6 @@ def buildfarm_init(name = "buildfarm"): "org.slf4j:slf4j-simple:1.7.35", "com.googlecode.json-simple:json-simple:1.1.1", "com.jayway.jsonpath:json-path:2.4.0", - "io.github.lognet:grpc-spring-boot-starter:4.5.4", "org.bouncycastle:bcprov-jdk15on:1.70", "net.jcip:jcip-annotations:1.0", ] + ["io.netty:netty-%s:4.1.94.Final" % module for module in IO_NETTY_MODULES] + @@ -122,9 +107,6 @@ def buildfarm_init(name = "buildfarm"): "org.openjdk.jmh:jmh-core:1.23", "org.openjdk.jmh:jmh-generator-annprocess:1.23", "org.redisson:redisson:3.13.1", - ] + ["org.springframework.boot:%s:2.7.4" % module for module in ORG_SPRING_BOOT_MODULES] + - ["org.springframework:%s:5.3.23" % module for module in ORG_SPRING_MODULES] + - [ "org.threeten:threetenbp:1.3.3", "org.xerial:sqlite-jdbc:3.34.0", "org.jetbrains:annotations:16.0.2", diff --git a/src/main/java/build/buildfarm/common/LoggingMain.java b/src/main/java/build/buildfarm/common/LoggingMain.java index 9a4d9bd2b0..4e60a6286a 100644 --- a/src/main/java/build/buildfarm/common/LoggingMain.java +++ b/src/main/java/build/buildfarm/common/LoggingMain.java @@ -7,24 +7,22 @@ public abstract class LoggingMain { protected abstract void onShutdown() throws InterruptedException; - class ShutdownThread extends Thread { - ShutdownThread(String applicationName) { - super(null, null, applicationName + "-Shutdown", 0); - } - - @Override - public void run() { - try { - LoggingMain.this.onShutdown(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } finally { - WaitingLogManager.release(); - } + private void shutdown() { + try { + onShutdown(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } finally { + WaitingLogManager.release(); } } protected LoggingMain(String applicationName) { - Runtime.getRuntime().addShutdownHook(new ShutdownThread(applicationName)); + Runtime.getRuntime() + .addShutdownHook( + new Thread( + /* group=*/ null, + /* target=*/ this::shutdown, + /* name=*/ applicationName + "-Shutdown")); } } diff --git a/src/main/java/build/buildfarm/server/BUILD b/src/main/java/build/buildfarm/server/BUILD index 0d6d396dc8..eccbf4fda2 100644 --- a/src/main/java/build/buildfarm/server/BUILD +++ b/src/main/java/build/buildfarm/server/BUILD @@ -25,11 +25,5 @@ java_library( "@maven//:javax_annotation_javax_annotation_api", "@maven//:org_bouncycastle_bcprov_jdk15on", "@maven//:org_projectlombok_lombok", - "@maven//:org_springframework_boot_spring_boot", - "@maven//:org_springframework_boot_spring_boot_autoconfigure", - "@maven//:org_springframework_boot_spring_boot_starter_thymeleaf", - "@maven//:org_springframework_spring_beans", - "@maven//:org_springframework_spring_context", - "@maven//:org_springframework_spring_core", ], ) diff --git a/src/main/java/build/buildfarm/server/BuildFarmServer.java b/src/main/java/build/buildfarm/server/BuildFarmServer.java index 4ca669d5f1..c8ae55c83e 100644 --- a/src/main/java/build/buildfarm/server/BuildFarmServer.java +++ b/src/main/java/build/buildfarm/server/BuildFarmServer.java @@ -15,12 +15,13 @@ package build.buildfarm.server; import static build.buildfarm.common.io.Utils.formatIOError; -import static com.google.common.base.Preconditions.checkState; import static com.google.common.util.concurrent.MoreExecutors.shutdownAndAwaitTermination; import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor; import static java.util.logging.Level.SEVERE; +import static java.util.logging.Level.WARNING; import build.buildfarm.common.DigestUtil; +import build.buildfarm.common.LoggingMain; import build.buildfarm.common.config.BuildfarmConfigs; import build.buildfarm.common.config.GrpcMetrics; import build.buildfarm.common.grpc.TracingMetadataUtils.ServerHeadersInterceptor; @@ -36,7 +37,6 @@ import build.buildfarm.server.services.OperationQueueService; import build.buildfarm.server.services.OperationsService; import build.buildfarm.server.services.PublishBuildEventService; -import com.google.devtools.common.options.OptionsParsingException; import io.grpc.ServerBuilder; import io.grpc.ServerInterceptor; import io.grpc.health.v1.HealthCheckResponse.ServingStatus; @@ -47,24 +47,16 @@ import java.io.File; import java.io.IOException; import java.security.Security; -import java.util.HashMap; -import java.util.Map; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; +import java.util.concurrent.atomic.AtomicBoolean; import javax.naming.ConfigurationException; import lombok.extern.java.Log; import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.ComponentScan; @SuppressWarnings("deprecation") @Log -@SpringBootApplication -@ComponentScan("build.buildfarm") -public class BuildFarmServer { +public class BuildFarmServer extends LoggingMain { private static final java.util.logging.Logger nettyLogger = java.util.logging.Logger.getLogger("io.grpc.netty"); private static final Counter healthCheckMetric = @@ -78,8 +70,13 @@ public class BuildFarmServer { private Instance instance; private HealthStatusManager healthStatusManager; private io.grpc.Server server; - private boolean stopping = false; private static BuildfarmConfigs configs = BuildfarmConfigs.getInstance(); + private AtomicBoolean shutdownInitiated = new AtomicBoolean(true); + private AtomicBoolean released = new AtomicBoolean(true); + + BuildFarmServer() { + super("BuildFarmServer"); + } private ShardInstance createInstance() throws IOException, ConfigurationException, InterruptedException { @@ -87,11 +84,13 @@ private ShardInstance createInstance() configs.getServer().getName(), configs.getServer().getSession() + "-" + configs.getServer().getName(), new DigestUtil(configs.getDigestFunction()), - this::stop); + this::initiateShutdown); } public synchronized void start(ServerBuilder serverBuilder, String publicName) throws IOException, ConfigurationException, InterruptedException { + shutdownInitiated.set(false); + released.set(false); instance = createInstance(); healthStatusManager = new HealthStatusManager(); @@ -138,7 +137,6 @@ public synchronized void start(ServerBuilder serverBuilder, String publicName log.info(String.format("%s initialized", configs.getServer().getSession())); - checkState(!stopping, "must not call start after stop"); instance.start(publicName); server.start(); @@ -148,38 +146,69 @@ public synchronized void start(ServerBuilder serverBuilder, String publicName healthCheckMetric.labels("start").inc(); } - @PreDestroy - public void stop() { - synchronized (this) { - if (stopping) { - return; - } - stopping = true; + private synchronized void awaitRelease() throws InterruptedException { + while (!released.get()) { + wait(); } - System.err.println("*** shutting down gRPC server since JVM is shutting down"); + } + + synchronized void stop() throws InterruptedException { + try { + shutdown(); + } finally { + released.set(true); + notify(); + } + } + + private void shutdown() throws InterruptedException { + log.info("*** shutting down gRPC server since JVM is shutting down"); healthStatusManager.setStatus( HealthStatusManager.SERVICE_NAME_ALL_SERVICES, ServingStatus.NOT_SERVING); PrometheusPublisher.stopHttpServer(); healthCheckMetric.labels("stop").inc(); try { - if (server != null) { - server.shutdown(); - } + initiateShutdown(); instance.stop(); - server.awaitTermination(10, TimeUnit.SECONDS); + if (server != null && server.awaitTermination(10, TimeUnit.SECONDS)) { + server = null; + } } catch (InterruptedException e) { if (server != null) { server.shutdownNow(); + server = null; } + throw e; } if (!shutdownAndAwaitTermination(keepaliveScheduler, 10, TimeUnit.SECONDS)) { log.warning("could not shut down keepalive scheduler"); } - System.err.println("*** server shut down"); + log.info("*** server shut down"); + } + + @Override + protected void onShutdown() throws InterruptedException { + initiateShutdown(); + awaitRelease(); } - @PostConstruct - public void init() throws OptionsParsingException { + private void initiateShutdown() { + shutdownInitiated.set(true); + if (server != null) { + server.shutdown(); + } + } + + private void awaitTermination() throws InterruptedException { + while (!shutdownInitiated.get()) { + if (server != null && server.awaitTermination(1, TimeUnit.SECONDS)) { + server = null; + shutdownInitiated.set(true); + } + } + } + + public static void main(String[] args) throws Exception { // Only log severe log messages from Netty. Otherwise it logs warnings that look like this: // // 170714 08:16:28.552:WT 18 [io.grpc.netty.NettyServerHandler.onStreamError] Stream Error @@ -187,35 +216,24 @@ public void init() throws OptionsParsingException { // unknown stream 11369 nettyLogger.setLevel(SEVERE); - try { - start( - ServerBuilder.forPort(configs.getServer().getPort()), - configs.getServer().getPublicName()); - } catch (IOException e) { - System.err.println("error: " + formatIOError(e)); - } catch (InterruptedException e) { - System.err.println("error: interrupted"); - } catch (ConfigurationException e) { - throw new RuntimeException(e); - } - } - - public static void main(String[] args) throws ConfigurationException { configs = BuildfarmConfigs.loadServerConfigs(args); // Configure Spring - SpringApplication app = new SpringApplication(BuildFarmServer.class); - Map springConfig = new HashMap<>(); - - // Disable Logback - System.setProperty("org.springframework.boot.logging.LoggingSystem", "none"); - - app.setDefaultProperties(springConfig); + BuildFarmServer server = new BuildFarmServer(); try { - app.run(args); - } catch (Throwable t) { - log.log(SEVERE, "Error running application", t); + server.start( + ServerBuilder.forPort(configs.getServer().getPort()), + configs.getServer().getPublicName()); + server.awaitTermination(); + } catch (IOException e) { + log.severe("error: " + formatIOError(e)); + } catch (InterruptedException e) { + log.log(WARNING, "interrupted", e); + } catch (Exception e) { + log.log(SEVERE, "Error running application", e); + } finally { + server.stop(); } } } diff --git a/src/main/java/build/buildfarm/worker/shard/BUILD b/src/main/java/build/buildfarm/worker/shard/BUILD index 120365882b..ec48ec5be0 100644 --- a/src/main/java/build/buildfarm/worker/shard/BUILD +++ b/src/main/java/build/buildfarm/worker/shard/BUILD @@ -36,10 +36,5 @@ java_library( "@maven//:io_prometheus_simpleclient", "@maven//:javax_annotation_javax_annotation_api", "@maven//:org_projectlombok_lombok", - "@maven//:org_springframework_boot_spring_boot", - "@maven//:org_springframework_boot_spring_boot_autoconfigure", - "@maven//:org_springframework_spring_beans", - "@maven//:org_springframework_spring_context", - "@maven//:org_springframework_spring_core", ], ) diff --git a/src/main/java/build/buildfarm/worker/shard/ShutDownWorkerGracefully.java b/src/main/java/build/buildfarm/worker/shard/ShutDownWorkerGracefully.java index 711c3cf0d3..7d394c9731 100644 --- a/src/main/java/build/buildfarm/worker/shard/ShutDownWorkerGracefully.java +++ b/src/main/java/build/buildfarm/worker/shard/ShutDownWorkerGracefully.java @@ -18,7 +18,6 @@ import build.buildfarm.v1test.PrepareWorkerForGracefulShutDownRequestResults; import build.buildfarm.v1test.ShutDownWorkerGrpc; import io.grpc.stub.StreamObserver; -import java.util.concurrent.CompletableFuture; import lombok.extern.java.Log; @Log @@ -41,7 +40,7 @@ public void prepareWorkerForGracefulShutdown( PrepareWorkerForGracefulShutDownRequest request, StreamObserver responseObserver) { try { - CompletableFuture.runAsync(worker::prepareWorkerForGracefulShutdown); + worker.initiateShutdown(); responseObserver.onNext(PrepareWorkerForGracefulShutDownRequestResults.newBuilder().build()); responseObserver.onCompleted(); } catch (Exception e) { diff --git a/src/main/java/build/buildfarm/worker/shard/Worker.java b/src/main/java/build/buildfarm/worker/shard/Worker.java index 9a919d9703..084e5df7bf 100644 --- a/src/main/java/build/buildfarm/worker/shard/Worker.java +++ b/src/main/java/build/buildfarm/worker/shard/Worker.java @@ -35,6 +35,7 @@ import build.buildfarm.common.BuildfarmExecutors; import build.buildfarm.common.DigestUtil; import build.buildfarm.common.InputStreamFactory; +import build.buildfarm.common.LoggingMain; import build.buildfarm.common.config.BuildfarmConfigs; import build.buildfarm.common.config.Cas; import build.buildfarm.common.config.GrpcMetrics; @@ -60,7 +61,6 @@ import build.buildfarm.worker.SuperscalarPipelineStage; import com.google.common.cache.LoadingCache; import com.google.common.collect.Lists; -import com.google.devtools.common.options.OptionsParsingException; import com.google.longrunning.Operation; import com.google.protobuf.ByteString; import com.google.protobuf.Duration; @@ -85,20 +85,14 @@ import java.util.UUID; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import javax.annotation.Nullable; -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; import javax.naming.ConfigurationException; import lombok.extern.java.Log; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.ComponentScan; @Log -@SpringBootApplication -@ComponentScan("build.buildfarm") -public class Worker { +public final class Worker extends LoggingMain { private static final java.util.logging.Logger nettyLogger = java.util.logging.Logger.getLogger("io.grpc.netty"); private static final Counter healthCheckMetric = @@ -139,53 +133,10 @@ public class Worker { private Pipeline pipeline; private Backplane backplane; private LoadingCache workerStubs; + private AtomicBoolean released = new AtomicBoolean(true); - /** - * The method will prepare the worker for graceful shutdown when the worker is ready. Note on - * using stderr here instead of log. By the time this is called in PreDestroy, the log is no - * longer available and is not logging messages. - */ - public void prepareWorkerForGracefulShutdown() { - if (configs.getWorker().getGracefulShutdownSeconds() == 0) { - System.err.println( - String.format( - "Graceful Shutdown is not enabled. Worker is shutting down without finishing executions in progress.")); - } else { - inGracefulShutdown = true; - System.err.println( - "Graceful Shutdown - The current worker will not be registered again and should be shutdown gracefully!"); - pipeline.stopMatchingOperations(); - int scanRate = 30; // check every 30 seconds - int timeWaited = 0; - int timeOut = configs.getWorker().getGracefulShutdownSeconds(); - - try { - if (pipeline.isEmpty()) { - System.err.println("Graceful Shutdown - no work in the pipeline."); - } else { - System.err.println( - String.format("Graceful Shutdown - waiting for executions to finish.")); - } - while (!pipeline.isEmpty() && timeWaited < timeOut) { - SECONDS.sleep(scanRate); - timeWaited += scanRate; - System.err.println( - String.format( - "Graceful Shutdown - Pipeline is still not empty after %d seconds.", timeWaited)); - } - } catch (InterruptedException e) { - System.err.println( - "Graceful Shutdown - The worker gracefully shutdown is interrupted: " + e.getMessage()); - } finally { - System.err.println( - String.format( - "Graceful Shutdown - It took the worker %d seconds to %s", - timeWaited, - pipeline.isEmpty() - ? "finish all actions" - : "gracefully shutdown but still cannot finish all actions")); - } - } + private Worker() { + super("BuildFarmShardWorker"); } private Operation stripOperation(Operation operation) { @@ -508,13 +459,6 @@ public void run() { } } catch (InterruptedException e) { // ignore - } finally { - try { - stop(); - } catch (InterruptedException ie) { - log.log(SEVERE, "interrupted while stopping worker", ie); - // ignore - } } } }, @@ -534,6 +478,7 @@ private long loadWorkerStartTimeInMillis() { } public void start() throws ConfigurationException, InterruptedException, IOException { + released.set(false); String session = UUID.randomUUID().toString(); ServerBuilder serverBuilder = ServerBuilder.forPort(configs.getWorker().getPort()); String identifier = "buildfarm-worker-" + configs.getWorker().getPublicName() + "-" + session; @@ -642,10 +587,41 @@ public void start() throws ConfigurationException, InterruptedException, IOExcep log.log(INFO, String.format("%s initialized", identifier)); } - @PreDestroy - public void stop() throws InterruptedException { - System.err.println("*** shutting down gRPC server since JVM is shutting down"); - prepareWorkerForGracefulShutdown(); + @Override + protected void onShutdown() throws InterruptedException { + initiateShutdown(); + awaitRelease(); + } + + private void awaitTermination() throws InterruptedException { + pipeline.join(); + server.awaitTermination(); + } + + public void initiateShutdown() { + pipeline.stopMatchingOperations(); + if (server != null) { + server.shutdown(); + } + } + + private synchronized void awaitRelease() throws InterruptedException { + while (!released.get()) { + wait(); + } + } + + public synchronized void stop() throws InterruptedException { + try { + shutdown(); + } finally { + released.set(true); + notify(); + } + } + + private void shutdown() throws InterruptedException { + log.info("*** shutting down gRPC server since JVM is shutting down"); PrometheusPublisher.stopHttpServer(); boolean interrupted = Thread.interrupted(); if (pipeline != null) { @@ -663,11 +639,12 @@ public void stop() throws InterruptedException { executionSlotsTotal.set(0); inputFetchSlotsTotal.set(0); if (execFileSystem != null) { - log.log(INFO, "Stopping exec filesystem"); + log.info("Stopping exec filesystem"); execFileSystem.stop(); + execFileSystem = null; } if (server != null) { - log.log(INFO, "Shutting down the server"); + log.info("Shutting down the server"); server.shutdown(); try { @@ -678,26 +655,28 @@ public void stop() throws InterruptedException { } finally { server.shutdownNow(); } + server = null; } if (backplane != null) { try { backplane.stop(); + backplane = null; } catch (InterruptedException e) { interrupted = true; } } if (workerStubs != null) { workerStubs.invalidateAll(); + workerStubs = null; } if (interrupted) { Thread.currentThread().interrupt(); throw new InterruptedException(); } - System.err.println("*** server shut down"); + log.info("*** server shut down"); } - @PostConstruct - public void init() throws OptionsParsingException { + public static void main(String[] args) throws Exception { // Only log severe log messages from Netty. Otherwise it logs warnings that look like this: // // 170714 08:16:28.552:WT 18 [io.grpc.netty.NettyServerHandler.onStreamError] Stream Error @@ -705,19 +684,17 @@ public void init() throws OptionsParsingException { // unknown stream 11369 nettyLogger.setLevel(SEVERE); + configs = BuildfarmConfigs.loadWorkerConfigs(args); + Worker worker = new Worker(); try { - start(); + worker.start(); + worker.awaitTermination(); } catch (IOException e) { - System.err.println("error: " + formatIOError(e)); + log.severe(formatIOError(e)); } catch (InterruptedException e) { - System.out.println("error: interrupted"); - } catch (ConfigurationException e) { - throw new RuntimeException(e); + log.log(Level.WARNING, "interrupted", e); + } finally { + worker.stop(); } } - - public static void main(String[] args) throws ConfigurationException { - configs = BuildfarmConfigs.loadWorkerConfigs(args); - SpringApplication.run(Worker.class, args); - } } From 6f88e3424c3b2bb20e381a7358298698c72da559 Mon Sep 17 00:00:00 2001 From: Yuriy Belenitsky Date: Tue, 10 Oct 2023 11:06:01 -0400 Subject: [PATCH 080/311] Enable graceful shutdown for server (#1490) --- _site/docs/configuration/configuration.md | 48 ++++++++++--------- examples/config.yml | 1 + .../build/buildfarm/common/config/Server.java | 1 + .../buildfarm/server/BuildFarmServer.java | 32 +++++++++++++ 4 files changed, 59 insertions(+), 23 deletions(-) diff --git a/_site/docs/configuration/configuration.md b/_site/docs/configuration/configuration.md index cbd286587f..ac74bb3f1e 100644 --- a/_site/docs/configuration/configuration.md +++ b/_site/docs/configuration/configuration.md @@ -51,29 +51,31 @@ worker: ### Server -| Configuration | Accepted and _Default_ Values | Environment Var | Description | -|----------------------------------|-------------------------------|-------------------------|-----------------------------------------------------------------------------------------------------------------------------| -| instanceType | _SHARD_ | | Type of implementation (SHARD is the only one supported) | -| name | String, _shard_ | | Implementation name | -| publicName | String, _DERIVED:port_ | INSTANCE_NAME | Host:port of the GRPC server, required to be accessible by all servers | -| actionCacheReadOnly | boolean, _false_ | | Allow/Deny writing to action cache | -| port | Integer, _8980_ | | Listening port of the GRPC server | -| casWriteTimeout | Integer, _3600_ | | CAS write timeout (seconds) | -| bytestreamTimeout | Integer, _3600_ | | Byte Stream write timeout (seconds) | -| sslCertificatePath | String, _null_ | | Absolute path of the SSL certificate (if TLS used) | -| sslPrivateKeyPath | String, _null_ | | Absolute path of the SSL private key (if TLS used) | -| runDispatchedMonitor | boolean, _true_ | | Enable an agent to monitor the operation store to ensure that dispatched operations with expired worker leases are requeued | -| dispatchedMonitorIntervalSeconds | Integer, _1_ | | Dispatched monitor's lease expiration check interval (seconds) | -| runOperationQueuer | boolean, _true_ | | Aquire execute request entries cooperatively from an arrival queue on the backplane | -| ensureOutputsPresent | boolean, _false_ | | Decide if all outputs are also present in the CAS. If any outputs are missing a cache miss is returned | -| maxCpu | Integer, _0_ | | Maximum number of CPU cores that any min/max-cores property may request (0 = unlimited) | -| maxRequeueAttempts | Integer, _5_ | | Maximum number of requeue attempts for an operation | -| useDenyList | boolean, _true_ | | Allow usage of a deny list when looking up actions and invocations (for cache only it is recommended to disable this check) | -| grpcTimeout | Integer, _3600_ | | GRPC request timeout (seconds) | -| executeKeepaliveAfterSeconds | Integer, _60_ | | Execute keep alive (seconds) | -| recordBesEvents | boolean, _false_ | | Allow recording of BES events | -| clusterId | String, _local_ | | Buildfarm cluster ID | -| cloudRegion | String, _us-east_1_ | | Deployment region in the cloud | +| Configuration | Accepted and _Default_ Values | Environment Var | Description | +|----------------------------------|-------------------------------|-----------------|-----------------------------------------------------------------------------------------------------------------------------| +| instanceType | _SHARD_ | | Type of implementation (SHARD is the only one supported) | +| name | String, _shard_ | | Implementation name | +| publicName | String, _DERIVED:port_ | INSTANCE_NAME | Host:port of the GRPC server, required to be accessible by all servers | +| actionCacheReadOnly | boolean, _false_ | | Allow/Deny writing to action cache | +| port | Integer, _8980_ | | Listening port of the GRPC server | +| casWriteTimeout | Integer, _3600_ | | CAS write timeout (seconds) | +| bytestreamTimeout | Integer, _3600_ | | Byte Stream write timeout (seconds) | +| sslCertificatePath | String, _null_ | | Absolute path of the SSL certificate (if TLS used) | +| sslPrivateKeyPath | String, _null_ | | Absolute path of the SSL private key (if TLS used) | +| runDispatchedMonitor | boolean, _true_ | | Enable an agent to monitor the operation store to ensure that dispatched operations with expired worker leases are requeued | +| dispatchedMonitorIntervalSeconds | Integer, _1_ | | Dispatched monitor's lease expiration check interval (seconds) | +| runOperationQueuer | boolean, _true_ | | Aquire execute request entries cooperatively from an arrival queue on the backplane | +| ensureOutputsPresent | boolean, _false_ | | Decide if all outputs are also present in the CAS. If any outputs are missing a cache miss is returned | +| maxCpu | Integer, _0_ | | Maximum number of CPU cores that any min/max-cores property may request (0 = unlimited) | +| maxRequeueAttempts | Integer, _5_ | | Maximum number of requeue attempts for an operation | +| useDenyList | boolean, _true_ | | Allow usage of a deny list when looking up actions and invocations (for cache only it is recommended to disable this check) | +| grpcTimeout | Integer, _3600_ | | GRPC request timeout (seconds) | +| executeKeepaliveAfterSeconds | Integer, _60_ | | Execute keep alive (seconds) | +| recordBesEvents | boolean, _false_ | | Allow recording of BES events | +| clusterId | String, _local_ | | Buildfarm cluster ID | +| cloudRegion | String, _us-east_1_ | | Deployment region in the cloud | +| gracefulShutdownSeconds | Integer, 0 | | Time in seconds to allow for connections in flight to finish when shutdown signal is received | + Example: diff --git a/examples/config.yml b/examples/config.yml index 901e8ff76d..cdf72f3de7 100644 --- a/examples/config.yml +++ b/examples/config.yml @@ -31,6 +31,7 @@ server: recordBesEvents: false clusterId: local cloudRegion: us-east-1 + gracefulShutdownSeconds: 0 caches: directoryCacheMaxEntries: 10000 commandCacheMaxEntries: 10000 diff --git a/src/main/java/build/buildfarm/common/config/Server.java b/src/main/java/build/buildfarm/common/config/Server.java index 9f2899ff60..0487154c2f 100644 --- a/src/main/java/build/buildfarm/common/config/Server.java +++ b/src/main/java/build/buildfarm/common/config/Server.java @@ -42,6 +42,7 @@ public enum INSTANCE_TYPE { private int maxInboundMetadataSize = 0; private ServerCacheConfigs caches = new ServerCacheConfigs(); private boolean findMissingBlobsViaBackplane = false; + private int gracefulShutdownSeconds = 0; public String getSession() { return String.format("buildfarm-server-%s-%s", getPublicName(), sessionGuid); diff --git a/src/main/java/build/buildfarm/server/BuildFarmServer.java b/src/main/java/build/buildfarm/server/BuildFarmServer.java index c8ae55c83e..a20f4a6f77 100644 --- a/src/main/java/build/buildfarm/server/BuildFarmServer.java +++ b/src/main/java/build/buildfarm/server/BuildFarmServer.java @@ -17,6 +17,7 @@ import static build.buildfarm.common.io.Utils.formatIOError; import static com.google.common.util.concurrent.MoreExecutors.shutdownAndAwaitTermination; import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor; +import static java.util.concurrent.TimeUnit.SECONDS; import static java.util.logging.Level.SEVERE; import static java.util.logging.Level.WARNING; @@ -78,6 +79,36 @@ public class BuildFarmServer extends LoggingMain { super("BuildFarmServer"); } + /** + * The method will prepare the server for graceful shutdown when the server is ready. Current + * implementation waits specified period of time. Future improvements could be to keep track of + * open connections and shutdown when there are not left. Note on using stderr here instead of + * log. By the time this is called in PreDestroy, the log is no longer available and is not + * logging messages. + */ + public void prepareServerForGracefulShutdown() { + if (configs.getServer().getGracefulShutdownSeconds() == 0) { + System.err.println( + String.format("Graceful Shutdown is not enabled. Server is shutting down immediately.")); + } else { + try { + System.err.println( + String.format( + "Graceful Shutdown - Waiting %d to allow connections to drain.", + configs.getServer().getGracefulShutdownSeconds())); + SECONDS.sleep(configs.getServer().getGracefulShutdownSeconds()); + } catch (InterruptedException e) { + System.err.println( + "Graceful Shutdown - The server graceful shutdown is interrupted: " + e.getMessage()); + } finally { + System.err.println( + String.format( + "Graceful Shutdown - It took the server %d seconds to shutdown", + configs.getServer().getGracefulShutdownSeconds())); + } + } + } + private ShardInstance createInstance() throws IOException, ConfigurationException, InterruptedException { return new ShardInstance( @@ -163,6 +194,7 @@ synchronized void stop() throws InterruptedException { private void shutdown() throws InterruptedException { log.info("*** shutting down gRPC server since JVM is shutting down"); + prepareServerForGracefulShutdown(); healthStatusManager.setStatus( HealthStatusManager.SERVICE_NAME_ALL_SERVICES, ServingStatus.NOT_SERVING); PrometheusPublisher.stopHttpServer(); From 81122e7fa455afb1267380cab8658ebedbd8b845 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Fri, 6 Oct 2023 16:00:03 -0700 Subject: [PATCH 081/311] refactor: code cleanup Tiny code cleanup --- .../buildfarm/instance/shard/JedisClusterFactory.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/build/buildfarm/instance/shard/JedisClusterFactory.java b/src/main/java/build/buildfarm/instance/shard/JedisClusterFactory.java index 5f85da29f6..2bfb48ac9e 100644 --- a/src/main/java/build/buildfarm/instance/shard/JedisClusterFactory.java +++ b/src/main/java/build/buildfarm/instance/shard/JedisClusterFactory.java @@ -58,9 +58,7 @@ public static Supplier create(String identifier) throws Configurat list2Set(redisNodes), configs.getBackplane().getTimeout(), configs.getBackplane().getMaxAttempts(), - Strings.isNullOrEmpty(configs.getBackplane().getRedisPassword()) - ? null - : configs.getBackplane().getRedisPassword(), + Strings.emptyToNull(configs.getBackplane().getRedisPassword()), createJedisPoolConfig()); } @@ -70,9 +68,7 @@ public static Supplier create(String identifier) throws Configurat parseUri(configs.getBackplane().getRedisUri()), configs.getBackplane().getTimeout(), configs.getBackplane().getMaxAttempts(), - Strings.isNullOrEmpty(configs.getBackplane().getRedisPassword()) - ? null - : configs.getBackplane().getRedisPassword(), + Strings.emptyToNull(configs.getBackplane().getRedisPassword()), createJedisPoolConfig()); } From ad44854942cab540ebf8c208e16bfe8ecc225c8f Mon Sep 17 00:00:00 2001 From: George Gensure Date: Thu, 22 Jun 2023 09:20:08 -0400 Subject: [PATCH 082/311] Log paths created on putDirectory Will include operation root and inform directory cache effectiveness. --- .../build/buildfarm/cas/cfc/CASFileCache.java | 28 +++++++++++--- .../worker/shard/CFCExecFileSystem.java | 37 ++++++++++--------- .../buildfarm/cas/cfc/CASFileCacheTest.java | 3 +- 3 files changed, 45 insertions(+), 23 deletions(-) diff --git a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java index 6b6e63b4ad..aac1b28994 100644 --- a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java +++ b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java @@ -2173,7 +2173,7 @@ private Directory getDirectoryFromDigest( return directory; } - public ListenableFuture putDirectory( + public ListenableFuture putDirectory( Digest digest, Map directoriesIndex, ExecutorService service) { // Claim lock. // Claim the directory path so no other threads try to create/delete it. @@ -2189,7 +2189,7 @@ public ListenableFuture putDirectory( log.log(Level.FINER, format("locked directory %s", path.getFileName())); // Now that a lock has been claimed, we can proceed to create the directory. - ListenableFuture putFuture; + ListenableFuture putFuture; try { putFuture = putDirectorySynchronized(path, digest, directoriesIndex, service); } catch (IOException e) { @@ -2244,8 +2244,26 @@ private boolean directoryEntryExists( return false; } + public static class PathResult { + private final Path path; + private final boolean missed; + + public PathResult(Path path, boolean missed) { + this.path = path; + this.missed = missed; + } + + public Path getPath() { + return path; + } + + public boolean getMissed() { + return missed; + } + } + @SuppressWarnings("ConstantConditions") - private ListenableFuture putDirectorySynchronized( + private ListenableFuture putDirectorySynchronized( Path path, Digest digest, Map directoriesByDigest, ExecutorService service) throws IOException { log.log(Level.FINER, format("directory %s has been locked", path.getFileName())); @@ -2277,7 +2295,7 @@ private ListenableFuture putDirectorySynchronized( if (e != null) { log.log(Level.FINER, format("found existing entry for %s", path.getFileName())); if (directoryEntryExists(path, e, directoriesByDigest)) { - return immediateFuture(path); + return immediateFuture(new PathResult(path, /* missed=*/ false)); } log.log( Level.SEVERE, @@ -2410,7 +2428,7 @@ private ListenableFuture putDirectorySynchronized( : directoriesByDigest.get(digest), Deadline.after(10, SECONDS)); directoryStorage.put(digest, e); - return path; + return new PathResult(path, /* missed=*/ true); }, service); } diff --git a/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java b/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java index e6d9826f45..74b238b2c6 100644 --- a/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java +++ b/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java @@ -265,6 +265,7 @@ private Iterable> fetchInputs( .map(symlinkNode -> putSymlink(path, symlinkNode)) .collect(ImmutableList.toImmutableList())); + ImmutableList.Builder> linkedDirectories = ImmutableList.builder(); for (DirectoryNode directoryNode : directory.getDirectoriesList()) { Digest digest = directoryNode.getDigest(); String name = directoryNode.getName(); @@ -285,26 +286,23 @@ private Iterable> fetchInputs( onKey, inputDirectories)); } else { - downloads = - concat( - downloads, - ImmutableList.of( - transform( - linkDirectory(dirPath, digest, directoriesIndex), - (result) -> { - // we saw null entries in the built immutable list without synchronization - synchronized (inputDirectories) { - inputDirectories.add(digest); - } - return null; - }, - fetchService))); + linkedDirectories.add( + transform( + linkDirectory(dirPath, digest, directoriesIndex), + (result) -> { + // we saw null entries in the built immutable list without synchronization + synchronized (inputDirectories) { + inputDirectories.add(digest); + } + return null; + }, + fetchService)); } if (Thread.currentThread().isInterrupted()) { break; } } - return downloads; + return concat(downloads, linkedDirectories.build()); } @SuppressWarnings("ConstantConditions") @@ -312,8 +310,13 @@ private ListenableFuture linkDirectory( Path execPath, Digest digest, Map directoriesIndex) { return transformAsync( fileCache.putDirectory(digest, directoriesIndex, fetchService), - (cachePath) -> { - Files.createSymbolicLink(execPath, cachePath); + pathResult -> { + Path path = pathResult.getPath(); + if (pathResult.getMissed()) { + log.fine( + String.format("putDirectory(%s, %s) created", path, DigestUtil.toString(digest))); + } + Files.createSymbolicLink(execPath, path); return immediateFuture(null); }, fetchService); diff --git a/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java b/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java index 72e167b4df..a3d406e232 100644 --- a/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java +++ b/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java @@ -240,7 +240,8 @@ public void putDirectoryCreatesTree() throws IOException, InterruptedException { subdirDigest, subDirectory); Path dirPath = getInterruptiblyOrIOException( - fileCache.putDirectory(dirDigest, directoriesIndex, putService)); + fileCache.putDirectory(dirDigest, directoriesIndex, putService)) + .getPath(); assertThat(Files.isDirectory(dirPath)).isTrue(); assertThat(Files.exists(dirPath.resolve("file"))).isTrue(); assertThat(Files.isDirectory(dirPath.resolve("subdir"))).isTrue(); From b31ffedb5528c0f0fb2930473f802641f390a3d2 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Fri, 7 Jul 2023 01:49:58 -0400 Subject: [PATCH 083/311] Permit regex realInputDirectories Selecting realInputDirectories by regex permits flexible patterns that can yield drastic improvements in directory reuse for specialized deployments. runfiles in particular are hazardous expansions of nearly-execroot in the case of bazel. Care must be taken to match directories exclusively. The entire input tree is traversed for matches against expanded paths under the root, to allow for nested selection. Each match thus costs the number of input directories. Counterintuitively, OutputFiles are augmented to avoid the recursive check for OutputDirectories which only applies to actual reported results, resulting in a path match when creating the exec root. Regex style is java.util.Pattern, and must match the full input directory. --- .../worker/shard/CFCExecFileSystem.java | 81 +++++++++++++------ 1 file changed, 58 insertions(+), 23 deletions(-) diff --git a/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java b/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java index 74b238b2c6..70a4acbb04 100644 --- a/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java +++ b/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java @@ -19,7 +19,6 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import static com.google.common.collect.Iterables.concat; -import static com.google.common.collect.Iterables.filter; import static com.google.common.util.concurrent.Futures.allAsList; import static com.google.common.util.concurrent.Futures.catchingAsync; import static com.google.common.util.concurrent.Futures.immediateFailedFuture; @@ -48,7 +47,7 @@ import build.buildfarm.worker.ExecDirException.ViolationException; import build.buildfarm.worker.OutputDirectory; import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; +import com.google.common.collect.Iterables; import com.google.common.util.concurrent.ListenableFuture; import java.io.IOException; import java.io.InputStream; @@ -56,14 +55,16 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.attribute.UserPrincipal; -import java.util.Collections; +import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Stack; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.function.Consumer; import java.util.logging.Level; +import java.util.regex.Pattern; import javax.annotation.Nullable; import lombok.extern.java.Log; @@ -77,7 +78,7 @@ class CFCExecFileSystem implements ExecFileSystem { private final boolean linkInputDirectories; // override the symlinking above for a set of matching paths - private final Iterable realInputDirectories; + private final Iterable realInputDirectories; private final Map> rootInputFiles = new ConcurrentHashMap<>(); private final Map> rootInputDirectories = new ConcurrentHashMap<>(); @@ -98,7 +99,9 @@ class CFCExecFileSystem implements ExecFileSystem { this.fileCache = fileCache; this.owner = owner; this.linkInputDirectories = linkInputDirectories; - this.realInputDirectories = realInputDirectories; + this.realInputDirectories = + Iterables.transform( + realInputDirectories, realInputDirectory -> Pattern.compile(realInputDirectory)); this.removeDirectoryService = removeDirectoryService; this.accessRecorder = accessRecorder; } @@ -328,28 +331,61 @@ private static void checkExecErrors(Path path, List errors) throws Ex } } - private static boolean treeContainsPath( - String directoryPath, Map directoriesIndex, Digest rootDigest) { - Directory directory = directoriesIndex.get(rootDigest); - for (String name : directoryPath.split("/")) { - List subdirs = directory.getDirectoriesList(); - int index = Collections.binarySearch(Lists.transform(subdirs, DirectoryNode::getName), name); - if (index < 0) { - return false; + private static Iterator directoriesIterator( + Digest digest, Map directoriesIndex) { + Directory root = directoriesIndex.get(digest); + return new Iterator() { + boolean atEnd = root.getDirectoriesCount() == 0; + Stack path = new Stack<>(); + Stack> route = new Stack<>(); + Iterator current = root.getDirectoriesList().iterator(); + + @Override + public boolean hasNext() { + return !atEnd; } - directory = directoriesIndex.get(subdirs.get(index).getDigest()); - } - return true; + + @Override + public String next() { + String nextPath; + DirectoryNode next = current.next(); + String name = next.getName(); + path.push(name); + nextPath = String.join("/", path); + Digest digest = next.getDigest(); + if (digest.getSizeBytes() != 0) { + route.push(current); + current = directoriesIndex.get(digest).getDirectoriesList().iterator(); + } else { + path.pop(); + } + while (!current.hasNext() && !route.isEmpty()) { + current = route.pop(); + path.pop(); + } + atEnd = !current.hasNext(); + return nextPath; + } + }; } private Iterable realDirectories( Map directoriesIndex, Digest rootDigest) { // skip this search if all the directories are real if (linkInputDirectories) { - // somewhat inefficient, but would need many overrides to be painful - return filter( - realInputDirectories, - realInputDirectory -> treeContainsPath(realInputDirectory, directoriesIndex, rootDigest)); + ImmutableList.Builder builder = ImmutableList.builder(); + + Iterator dirs = directoriesIterator(rootDigest, directoriesIndex); + while (dirs.hasNext()) { + String dir = dirs.next(); + for (Pattern pattern : realInputDirectories) { + if (pattern.matcher(dir).matches()) { + builder.add(dir); + } + } + } + + return builder.build(); } return ImmutableList.of(); } @@ -361,10 +397,9 @@ public Path createExecDir( Digest inputRootDigest = action.getInputRootDigest(); OutputDirectory outputDirectory = OutputDirectory.parse( - command.getOutputFilesList(), concat( - command.getOutputDirectoriesList(), - realDirectories(directoriesIndex, inputRootDigest)), + command.getOutputFilesList(), realDirectories(directoriesIndex, inputRootDigest)), + command.getOutputDirectoriesList(), command.getEnvironmentVariablesList()); Path execDir = root.resolve(operationName); From 1dec6848e4141c714b0f854a94fbee3693da2a37 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Fri, 7 Jul 2023 02:08:18 -0400 Subject: [PATCH 084/311] Log execPath rather than the cache dir path This will include the path to the missed directory and the operation which required it. --- .../java/build/buildfarm/worker/shard/CFCExecFileSystem.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java b/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java index 70a4acbb04..2944f30d0d 100644 --- a/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java +++ b/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java @@ -317,7 +317,8 @@ private ListenableFuture linkDirectory( Path path = pathResult.getPath(); if (pathResult.getMissed()) { log.fine( - String.format("putDirectory(%s, %s) created", path, DigestUtil.toString(digest))); + String.format( + "putDirectory(%s, %s) created", execPath, DigestUtil.toString(digest))); } Files.createSymbolicLink(execPath, path); return immediateFuture(null); From 6af857ad318180ee9bd574429990e774d780f1c7 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Fri, 7 Jul 2023 11:14:30 -0400 Subject: [PATCH 085/311] Shore up OutputDirectory for silence on duplicates Prevent adding duplicate realInputDirectories matches --- src/main/java/build/buildfarm/worker/OutputDirectory.java | 5 +++++ .../java/build/buildfarm/worker/shard/CFCExecFileSystem.java | 1 + 2 files changed, 6 insertions(+) diff --git a/src/main/java/build/buildfarm/worker/OutputDirectory.java b/src/main/java/build/buildfarm/worker/OutputDirectory.java index 6245553803..caf77b273e 100644 --- a/src/main/java/build/buildfarm/worker/OutputDirectory.java +++ b/src/main/java/build/buildfarm/worker/OutputDirectory.java @@ -161,10 +161,15 @@ private static OutputDirectory parseDirectories(Iterable o Iterables.addAll(sortedOutputDirs, outputDirs); Collections.sort(sortedOutputDirs); + String currentOutputDir = ""; Builder currentBuilder = builder; String prefix = "/"; for (OutputDirectoryEntry entry : sortedOutputDirs) { String outputDir = entry.outputDirectory; + if (outputDir == currentOutputDir) { + continue; + } + currentOutputDir = outputDir; while (!outputDir.startsWith(prefix)) { currentBuilder = stack.pop(); int upPathSeparatorIndex = prefix.lastIndexOf('/', prefix.length() - 2); diff --git a/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java b/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java index 2944f30d0d..d73b977916 100644 --- a/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java +++ b/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java @@ -382,6 +382,7 @@ private Iterable realDirectories( for (Pattern pattern : realInputDirectories) { if (pattern.matcher(dir).matches()) { builder.add(dir); + break; // avoid adding the same directory twice } } } From 71a928c73f7ba69f7533d13821de0d9bf72c36d9 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Fri, 7 Jul 2023 16:31:06 -0400 Subject: [PATCH 086/311] Trigger realInputDirectories to have empty files Ensure that the last leg of the execution presents a directory, rather than the parent, per OutputDirectory's stamping. --- .../java/build/buildfarm/worker/shard/CFCExecFileSystem.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java b/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java index d73b977916..94c232a942 100644 --- a/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java +++ b/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java @@ -381,7 +381,7 @@ private Iterable realDirectories( String dir = dirs.next(); for (Pattern pattern : realInputDirectories) { if (pattern.matcher(dir).matches()) { - builder.add(dir); + builder.add(dir + "/"); break; // avoid adding the same directory twice } } From f8017bd9aaa513dc0f91d52b18d06e2a6379d410 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Sat, 8 Jul 2023 10:02:43 -0400 Subject: [PATCH 087/311] Switch to positive check for linkInputDirectories --- examples/config.yml | 4 +- .../build/buildfarm/common/config/Worker.java | 2 +- .../worker/shard/CFCExecFileSystem.java | 39 ++++++++++++------- .../build/buildfarm/worker/shard/Worker.java | 2 +- 4 files changed, 29 insertions(+), 18 deletions(-) diff --git a/examples/config.yml b/examples/config.yml index cdf72f3de7..bce19a3d60 100644 --- a/examples/config.yml +++ b/examples/config.yml @@ -117,8 +117,8 @@ worker: inputFetchStageWidth: 1 inputFetchDeadline: 60 linkInputDirectories: true - realInputDirectories: - - "external" + linkedInputDirectories: + - "(?!external)[^/]+" execOwner: defaultMaxCores: 0 limitGlobalExecution: false diff --git a/src/main/java/build/buildfarm/common/config/Worker.java b/src/main/java/build/buildfarm/common/config/Worker.java index 4caaff2b02..1661df9bfe 100644 --- a/src/main/java/build/buildfarm/common/config/Worker.java +++ b/src/main/java/build/buildfarm/common/config/Worker.java @@ -28,7 +28,7 @@ public class Worker { private int inputFetchStageWidth = 0; private int inputFetchDeadline = 60; private boolean linkInputDirectories = true; - private List realInputDirectories = Arrays.asList("external"); + private List linkedInputDirectories = Arrays.asList("(?!external)[^/]+"); private String execOwner; private int defaultMaxCores = 0; private boolean limitGlobalExecution = false; diff --git a/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java b/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java index 94c232a942..041868f69c 100644 --- a/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java +++ b/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java @@ -47,6 +47,7 @@ import build.buildfarm.worker.ExecDirException.ViolationException; import build.buildfarm.worker.OutputDirectory; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.util.concurrent.ListenableFuture; import java.io.IOException; @@ -58,6 +59,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.Stack; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; @@ -77,8 +79,8 @@ class CFCExecFileSystem implements ExecFileSystem { // perform first-available non-output symlinking and retain directories in cache private final boolean linkInputDirectories; - // override the symlinking above for a set of matching paths - private final Iterable realInputDirectories; + // indicate symlinking above for a set of matching paths + private final Iterable linkedInputDirectories; private final Map> rootInputFiles = new ConcurrentHashMap<>(); private final Map> rootInputDirectories = new ConcurrentHashMap<>(); @@ -92,16 +94,16 @@ class CFCExecFileSystem implements ExecFileSystem { CASFileCache fileCache, @Nullable UserPrincipal owner, boolean linkInputDirectories, - Iterable realInputDirectories, + Iterable linkedInputDirectories, ExecutorService removeDirectoryService, ExecutorService accessRecorder) { this.root = root; this.fileCache = fileCache; this.owner = owner; this.linkInputDirectories = linkInputDirectories; - this.realInputDirectories = + this.linkedInputDirectories = Iterables.transform( - realInputDirectories, realInputDirectory -> Pattern.compile(realInputDirectory)); + linkedInputDirectories, realInputDirectory -> Pattern.compile(realInputDirectory)); this.removeDirectoryService = removeDirectoryService; this.accessRecorder = accessRecorder; } @@ -239,6 +241,7 @@ private Iterable> fetchInputs( Digest directoryDigest, Map directoriesIndex, OutputDirectory outputDirectory, + Set linkedInputDirectories, Consumer onKey, ImmutableList.Builder inputDirectories) throws IOException { @@ -275,7 +278,9 @@ private Iterable> fetchInputs( OutputDirectory childOutputDirectory = outputDirectory != null ? outputDirectory.getChild(name) : null; Path dirPath = path.resolve(name); - if (childOutputDirectory != null || !linkInputDirectories) { + if (childOutputDirectory != null + || !linkInputDirectories + || !linkedInputDirectories.contains(dirPath)) { Files.createDirectories(dirPath); downloads = concat( @@ -286,6 +291,7 @@ private Iterable> fetchInputs( digest, directoriesIndex, childOutputDirectory, + linkedInputDirectories, onKey, inputDirectories)); } else { @@ -370,26 +376,25 @@ public String next() { }; } - private Iterable realDirectories( + private Set linkedDirectories( Map directoriesIndex, Digest rootDigest) { // skip this search if all the directories are real if (linkInputDirectories) { - ImmutableList.Builder builder = ImmutableList.builder(); + ImmutableSet.Builder builder = ImmutableSet.builder(); Iterator dirs = directoriesIterator(rootDigest, directoriesIndex); while (dirs.hasNext()) { String dir = dirs.next(); - for (Pattern pattern : realInputDirectories) { + for (Pattern pattern : linkedInputDirectories) { if (pattern.matcher(dir).matches()) { - builder.add(dir + "/"); + builder.add(dir); break; // avoid adding the same directory twice } } } - return builder.build(); } - return ImmutableList.of(); + return ImmutableSet.of(); } @Override @@ -399,8 +404,7 @@ public Path createExecDir( Digest inputRootDigest = action.getInputRootDigest(); OutputDirectory outputDirectory = OutputDirectory.parse( - concat( - command.getOutputFilesList(), realDirectories(directoriesIndex, inputRootDigest)), + command.getOutputFilesList(), command.getOutputDirectoriesList(), command.getEnvironmentVariablesList()); @@ -413,6 +417,12 @@ public Path createExecDir( ImmutableList.Builder inputFiles = new ImmutableList.Builder<>(); ImmutableList.Builder inputDirectories = new ImmutableList.Builder<>(); + Set linkedInputDirectories = + ImmutableSet.copyOf( + Iterables.transform( + linkedDirectories(directoriesIndex, inputRootDigest), + path -> execDir.resolve(path))); // does this work on windows with / separators? + log.log( Level.FINER, "ExecFileSystem::createExecDir(" + operationName + ") calling fetchInputs"); Iterable> fetchedFutures = @@ -422,6 +432,7 @@ public Path createExecDir( inputRootDigest, directoriesIndex, outputDirectory, + linkedInputDirectories, key -> { synchronized (inputFiles) { inputFiles.add(key); diff --git a/src/main/java/build/buildfarm/worker/shard/Worker.java b/src/main/java/build/buildfarm/worker/shard/Worker.java index 084e5df7bf..153df1a371 100644 --- a/src/main/java/build/buildfarm/worker/shard/Worker.java +++ b/src/main/java/build/buildfarm/worker/shard/Worker.java @@ -333,7 +333,7 @@ private ExecFileSystem createCFCExecFileSystem( fileCache, owner, configs.getWorker().isLinkInputDirectories(), - configs.getWorker().getRealInputDirectories(), + configs.getWorker().getLinkedInputDirectories(), removeDirectoryService, accessRecorder /* deadlineAfter=*/ From 5d88e544e54d028c6b7af485aba5bac5b32b11c4 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Thu, 12 Oct 2023 10:48:23 -0700 Subject: [PATCH 088/311] docs(configuration): document --prometheus_port CLI argument --- _site/docs/configuration/configuration.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/_site/docs/configuration/configuration.md b/_site/docs/configuration/configuration.md index ac74bb3f1e..21956e7b3d 100644 --- a/_site/docs/configuration/configuration.md +++ b/_site/docs/configuration/configuration.md @@ -28,13 +28,13 @@ For an example config containing all of the configuration values, see `examples/ ### Common -| Configuration | Accepted and _Default_ Values | Description | -|----------------------|-------------------------------|---------------------------------------------------| -| digestFunction | _SHA256_, SHA1 | Digest function for this implementation | -| defaultActionTimeout | Integer, _600_ | Default timeout value for an action (seconds) | -| maximumActionTimeout | Integer, _3600_ | Maximum allowed action timeout (seconds) | -| maxEntrySizeBytes | Long, _2147483648_ | Maximum size of a single blob accepted (bytes) | -| prometheusPort | Integer, _9090_ | Listening port of the Prometheus metrics endpoint | +| Configuration | Accepted and _Default_ Values | Command Line Argument | Description | +|----------------------|-------------------------------|-----------------------|---------------------------------------------------| +| digestFunction | _SHA256_, SHA1 | | Digest function for this implementation | +| defaultActionTimeout | Integer, _600_ | | Default timeout value for an action (seconds) | +| maximumActionTimeout | Integer, _3600_ | | Maximum allowed action timeout (seconds) | +| maxEntrySizeBytes | Long, _2147483648_ | | Maximum size of a single blob accepted (bytes) | +| prometheusPort | Integer, _9090_ | --prometheus_port | Listening port of the Prometheus metrics endpoint | Example: From 21448c3954ff70268c9a8e21871c0fdd7f44767a Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Thu, 12 Oct 2023 10:48:54 -0700 Subject: [PATCH 089/311] docs(configuration): readability and typos --- _site/docs/configuration/configuration.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/_site/docs/configuration/configuration.md b/_site/docs/configuration/configuration.md index 21956e7b3d..9a806ef336 100644 --- a/_site/docs/configuration/configuration.md +++ b/_site/docs/configuration/configuration.md @@ -21,8 +21,8 @@ worker: publicName: "localhost:8981" ``` -The configuration can be provided to the server and worker as a CLI argument or through the env variable `CONFIG_PATH` -For an example config containing all of the configuration values, see `examples/config.yml`. +The configuration can be provided to the server and worker as a CLI argument or through the environment variable `CONFIG_PATH` +For an example configuration containing all of the configuration values, see `examples/config.yml`. ## All Configurations @@ -64,7 +64,7 @@ worker: | sslPrivateKeyPath | String, _null_ | | Absolute path of the SSL private key (if TLS used) | | runDispatchedMonitor | boolean, _true_ | | Enable an agent to monitor the operation store to ensure that dispatched operations with expired worker leases are requeued | | dispatchedMonitorIntervalSeconds | Integer, _1_ | | Dispatched monitor's lease expiration check interval (seconds) | -| runOperationQueuer | boolean, _true_ | | Aquire execute request entries cooperatively from an arrival queue on the backplane | +| runOperationQueuer | boolean, _true_ | | Acquire execute request entries cooperatively from an arrival queue on the backplane | | ensureOutputsPresent | boolean, _false_ | | Decide if all outputs are also present in the CAS. If any outputs are missing a cache miss is returned | | maxCpu | Integer, _0_ | | Maximum number of CPU cores that any min/max-cores property may request (0 = unlimited) | | maxRequeueAttempts | Integer, _5_ | | Maximum number of requeue attempts for an operation | From 461cc5a637d9b5617534dbc39b02e78b9a042312 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Thu, 12 Oct 2023 10:49:21 -0700 Subject: [PATCH 090/311] style(configuration.md): table formatting --- _site/docs/configuration/configuration.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/_site/docs/configuration/configuration.md b/_site/docs/configuration/configuration.md index 9a806ef336..2c08e8598e 100644 --- a/_site/docs/configuration/configuration.md +++ b/_site/docs/configuration/configuration.md @@ -105,12 +105,12 @@ server: ### Server Caches -| Configuration | Accepted and _Default_ Values | Description | -|--------------------------|-------------------------------|--------------------------------------------------------| -| directoryCacheMaxEntries | Long, _64 * 1024_ | The max number of entries that the directory cache will hold. | -| commandCacheMaxEntries | Long, _64 * 1024_ | The max number of entries that the command cache will hold. | -| digestToActionCacheMaxEntries | Long, _64 * 1024_ | The max number of entries that the digest-to-action cache will hold. | -| recentServedExecutionsCacheMaxEntries | Long, _64 * 1024_ | The max number of entries that the executions cache will hold. | +| Configuration | Accepted and _Default_ Values | Description | +|---------------------------------------|-------------------------------|----------------------------------------------------------------------| +| directoryCacheMaxEntries | Long, _64 * 1024_ | The max number of entries that the directory cache will hold. | +| commandCacheMaxEntries | Long, _64 * 1024_ | The max number of entries that the command cache will hold. | +| digestToActionCacheMaxEntries | Long, _64 * 1024_ | The max number of entries that the digest-to-action cache will hold. | +| recentServedExecutionsCacheMaxEntries | Long, _64 * 1024_ | The max number of entries that the executions cache will hold. | Example: From b74531c7c6dd74a83ccb1d07c4b8ce9ba8d66d4d Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Fri, 6 Oct 2023 16:01:26 -0700 Subject: [PATCH 091/311] feat: support --redis_uri command line option Support a `--redis_uri` command line option for start-up. --- .../build/buildfarm/common/config/BuildfarmConfigs.java | 6 ++++++ .../build/buildfarm/common/config/BuildfarmOptions.java | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java b/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java index 1a15e40803..444d25a13d 100644 --- a/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java +++ b/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java @@ -80,6 +80,9 @@ public static BuildfarmConfigs loadServerConfigs(String[] args) throws Configura if (options.prometheusPort >= 0) { buildfarmConfigs.setPrometheusPort(options.prometheusPort); } + if (!Strings.isNullOrEmpty(options.redisUri)) { + buildfarmConfigs.getBackplane().setRedisUri(options.redisUri); + } adjustServerConfigs(buildfarmConfigs); return buildfarmConfigs; } @@ -99,6 +102,9 @@ public static BuildfarmConfigs loadWorkerConfigs(String[] args) throws Configura if (options.prometheusPort >= 0) { buildfarmConfigs.setPrometheusPort(options.prometheusPort); } + if (!Strings.isNullOrEmpty(options.redisUri)) { + buildfarmConfigs.getBackplane().setRedisUri(options.redisUri); + } adjustWorkerConfigs(buildfarmConfigs); return buildfarmConfigs; } diff --git a/src/main/java/build/buildfarm/common/config/BuildfarmOptions.java b/src/main/java/build/buildfarm/common/config/BuildfarmOptions.java index defeebbf48..1dbe0c7f98 100644 --- a/src/main/java/build/buildfarm/common/config/BuildfarmOptions.java +++ b/src/main/java/build/buildfarm/common/config/BuildfarmOptions.java @@ -27,4 +27,10 @@ public class BuildfarmOptions extends OptionsBase { help = "Port for the prometheus service. '0' will disable prometheus hosting", defaultValue = "-1") public int prometheusPort; + + @Option( + name = "redis_uri", + help = "URI for Redis connection. Use 'redis://' or 'rediss://' for the scheme", + defaultValue = "") + public String redisUri; } From d860b277f891222dd83a0cc746a193863e60d715 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Thu, 12 Oct 2023 10:46:17 -0700 Subject: [PATCH 092/311] docs(configuration): document the --redis_uri command line options also fixed some spelling typos. --- _site/docs/configuration/configuration.md | 70 +++++++++++------------ 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/_site/docs/configuration/configuration.md b/_site/docs/configuration/configuration.md index 2c08e8598e..ae913adf88 100644 --- a/_site/docs/configuration/configuration.md +++ b/_site/docs/configuration/configuration.md @@ -169,41 +169,41 @@ server: ### Redis Backplane -| Configuration | Accepted and _Default_ Values | Environment Var | Description | -|------------------------------|------------------------------------------|-----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| type | _SHARD_ | | Type of backplane. Currently, the only implemntation is SHARD utilizing Redis | -| redisUri | String, redis://localhost:6379 | REDIS_URI | Redis cluster endpoint. This must be a single URI | -| redisPassword | String, _null_ | | Redis password, if applicable | -| redisNodes | List of Strings, _null_ | | List of individual Redis nodes, if applicable | -| jedisPoolMaxTotal | Integer, _4000_ | | The size of the Redis connection pool | -| workersHashName | String, _Workers_ | | Redis key used to store a hash of registered workers | -| workerChannel | String, _WorkerChannel_ | | Redis pubsub channel key where changes of the cluster membership are announced | -| actionCachePrefix | String, _ActionCache_ | | Redis key prefix for all ActionCache entries | -| actionCacheExpire | Integer, _2419200_ | | The TTL maintained for ActionCache entries, not refreshed on getActionResult hit | -| actionBlacklistPrefix | String, _ActionBlacklist_ | | Redis key prefix for all blacklisted actions, which are rejected | -| actionBlacklistExpire | Integer, _3600_ | | The TTL maintained for action blacklist entries | -| invocationBlacklistPrefix | String, _InvocationBlacklist_ | | Redis key prefix for blacklisted invocations, suffixed with a a tool invocation ID | -| operationPrefix | String, _Operation_ | | Redis key prefix for all operations, suffixed wtih the operation's name | -| operationExpire | Integer, _604800_ | | The TTL maintained for all operations, updated on each modification | -| preQueuedOperationsListName | String, _{Arrival}:PreQueuedOperations_ | | Redis key used to store a list of ExecuteEntry awaiting transformation into QueryEntry | -| processingListName | String, _{Arrival}:ProcessingOperations_ | | Redis key of a list used to ensure reliable processing of arrival queue etries with operation watch monitoring | -| processingPrefix | String, _Processing_ | | Redis key prefix for operations which are being dequeued from the arrival queue | -| processingTimeoutMillis | Integer, _20000_ | | Delay (in ms) used to populate processing operation entries | -| queuedOperationsListName | String, _{Execution}:QueuedOperations_ | | Redis key used to store a list of QueueEntry awaiting execution by workers | -| dispatchingPrefix | String, _Dispatching_ | | Redis key prefix for operations which are being dequeued from the ready to run queue | -| dispatchingTimeoutMillis | Integer, _10000_ | | Delay (in ms) used to populate dispatching operation entries | -| dispatchedOperationsHashName | String, _DispatchedOperations_ | | Redis key of a hash of operation names to the worker lease for its execution, which are monitored by the dispatched monitor | -| operationChannelPrefix | String, _OperationChannel_ | | Redis pubsub channel prefix suffixed by an operation name | -| casPrefix | String, _ContentAddressableStorage_ | | Redis key prefix suffixed with a blob digest that maps to a set of workers with that blob's availability | -| casExpire | Integer, _604800_ | | The TTL maintained for CAS entries, which is not refreshed on any read access of the blob | -| subscribeToBackplane | boolean, _true_ | | Enable an agent of the backplane client which subscribes to worker channel and operation channel events. If disabled, responsiveness of watchers and CAS are reduced | -| runFailsafeOperation | boolean, _true_ | | Enable an agent in the backplane client which monitors watched operations and ensures they are in a known maintained, or expirable state | -| maxQueueDepth | Integer, _100000_ | | Maximum length that the ready to run queue is allowed to reach to control an arrival flow for execution | -| maxPreQueueDepth | Integer, _1000000_ | | Maximum lengh that the arrival queue is allowed to reach to control load on the Redis cluster | -| priorityQueue | boolean, _false_ | | Priority queue type allows prioritizing operations based on Bazel's --remote_execution_priority= flag | -| timeout | Integer, _10000_ | | Default timeout | -| maxAttempts | Integer, _20_ | | Maximum number of execution attempts | -| cacheCas | boolean, _false_ | | | +| Configuration | Accepted and _Default_ Values | Environment Var | Command Line Argument | Description | +|------------------------------|------------------------------------------|-----------------|-----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| type | _SHARD_ | | | Type of backplane. Currently, the only implementation is SHARD utilizing Redis | +| redisUri | String, redis://localhost:6379 | REDIS_URI | --redis_uri | Redis cluster endpoint. This must be a single URI | +| redisPassword | String, _null_ | | | Redis password, if applicable | +| redisNodes | List of Strings, _null_ | | | List of individual Redis nodes, if applicable | +| jedisPoolMaxTotal | Integer, _4000_ | | | The size of the Redis connection pool | +| workersHashName | String, _Workers_ | | | Redis key used to store a hash of registered workers | +| workerChannel | String, _WorkerChannel_ | | | Redis pubsub channel key where changes of the cluster membership are announced | +| actionCachePrefix | String, _ActionCache_ | | | Redis key prefix for all ActionCache entries | +| actionCacheExpire | Integer, _2419200_ | | | The TTL maintained for ActionCache entries, not refreshed on getActionResult hit | +| actionBlacklistPrefix | String, _ActionBlacklist_ | | | Redis key prefix for all blacklisted actions, which are rejected | +| actionBlacklistExpire | Integer, _3600_ | | | The TTL maintained for action blacklist entries | +| invocationBlacklistPrefix | String, _InvocationBlacklist_ | | | Redis key prefix for blacklisted invocations, suffixed with a a tool invocation ID | +| operationPrefix | String, _Operation_ | | | Redis key prefix for all operations, suffixed with the operation's name | +| operationExpire | Integer, _604800_ | | | The TTL maintained for all operations, updated on each modification | +| preQueuedOperationsListName | String, _{Arrival}:PreQueuedOperations_ | | | Redis key used to store a list of ExecuteEntry awaiting transformation into QueryEntry | +| processingListName | String, _{Arrival}:ProcessingOperations_ | | | Redis key of a list used to ensure reliable processing of arrival queue entries with operation watch monitoring | +| processingPrefix | String, _Processing_ | | | Redis key prefix for operations which are being dequeued from the arrival queue | +| processingTimeoutMillis | Integer, _20000_ | | | Delay (in ms) used to populate processing operation entries | +| queuedOperationsListName | String, _{Execution}:QueuedOperations_ | | | Redis key used to store a list of QueueEntry awaiting execution by workers | +| dispatchingPrefix | String, _Dispatching_ | | | Redis key prefix for operations which are being dequeued from the ready to run queue | +| dispatchingTimeoutMillis | Integer, _10000_ | | | Delay (in ms) used to populate dispatching operation entries | +| dispatchedOperationsHashName | String, _DispatchedOperations_ | | | Redis key of a hash of operation names to the worker lease for its execution, which are monitored by the dispatched monitor | +| operationChannelPrefix | String, _OperationChannel_ | | | Redis pubsub channel prefix suffixed by an operation name | +| casPrefix | String, _ContentAddressableStorage_ | | | Redis key prefix suffixed with a blob digest that maps to a set of workers with that blob's availability | +| casExpire | Integer, _604800_ | | | The TTL maintained for CAS entries, which is not refreshed on any read access of the blob | +| subscribeToBackplane | boolean, _true_ | | | Enable an agent of the backplane client which subscribes to worker channel and operation channel events. If disabled, responsiveness of watchers and CAS are reduced | +| runFailsafeOperation | boolean, _true_ | | | Enable an agent in the backplane client which monitors watched operations and ensures they are in a known maintained, or expirable state | +| maxQueueDepth | Integer, _100000_ | | | Maximum length that the ready to run queue is allowed to reach to control an arrival flow for execution | +| maxPreQueueDepth | Integer, _1000000_ | | | Maximum lengh that the arrival queue is allowed to reach to control load on the Redis cluster | +| priorityQueue | boolean, _false_ | | | Priority queue type allows prioritizing operations based on Bazel's --remote_execution_priority= flag | +| timeout | Integer, _10000_ | | | Default timeout | +| maxAttempts | Integer, _20_ | | | Maximum number of execution attempts | +| cacheCas | boolean, _false_ | | | | Example: From 10bf1398bfecc13804b865ffde0b0e9613c80c23 Mon Sep 17 00:00:00 2001 From: Jorge Pinto Sousa Date: Wed, 11 Oct 2023 16:28:41 +0200 Subject: [PATCH 093/311] Example should use `container_image` instead of `java_image` --- _site/docs/execution/environment.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_site/docs/execution/environment.md b/_site/docs/execution/environment.md index 4a17aabe6b..d2cbca0b51 100644 --- a/_site/docs/execution/environment.md +++ b/_site/docs/execution/environment.md @@ -116,7 +116,7 @@ Next we will create a BUILD file to create our target image. We will use the sha ``` load("@io_bazel_rules_docker//container:container.bzl", "container_image") -java_image( +container_image( name = "buildfarm-shard-worker-ubuntu20-java14", base = "@ubuntu20_java14_image_base//image", files = [ From 9d4c86c8021804aeb5f8723b4faf914963a95386 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Thu, 21 Sep 2023 22:16:27 -0700 Subject: [PATCH 094/311] chore: bump rules_jvm_external Bumping 4.2 -> 5.3 --- deps.bzl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deps.bzl b/deps.bzl index c31cf04edd..833fe1447e 100644 --- a/deps.bzl +++ b/deps.bzl @@ -5,8 +5,8 @@ buildfarm dependencies that can be imported into other WORKSPACE files load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive", "http_file", "http_jar") load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") -RULES_JVM_EXTERNAL_TAG = "4.2" -RULES_JVM_EXTERNAL_SHA = "cd1a77b7b02e8e008439ca76fd34f5b07aecb8c752961f9640dea15e9e5ba1ca" +RULES_JVM_EXTERNAL_TAG = "5.3" +RULES_JVM_EXTERNAL_SHA = "d31e369b854322ca5098ea12c69d7175ded971435e55c18dd9dd5f29cc5249ac" def archive_dependencies(third_party): return [ @@ -22,7 +22,7 @@ def archive_dependencies(third_party): "name": "rules_jvm_external", "strip_prefix": "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG, "sha256": RULES_JVM_EXTERNAL_SHA, - "url": "https://github.com/bazelbuild/rules_jvm_external/archive/%s.zip" % RULES_JVM_EXTERNAL_TAG, + "url": "https://github.com/bazelbuild/rules_jvm_external/releases/download/%s/rules_jvm_external-%s.tar.gz" % (RULES_JVM_EXTERNAL_TAG, RULES_JVM_EXTERNAL_TAG), }, # Kubernetes rules. Useful for local development with tilt. From 5bc4564590eba4585676ef411f093423ee6b1b19 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Thu, 21 Sep 2023 22:26:06 -0700 Subject: [PATCH 095/311] chore: bump rules_cc Bump fro 0.0.6 -> 0.0.9 --- deps.bzl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deps.bzl b/deps.bzl index 833fe1447e..f802fb27e7 100644 --- a/deps.bzl +++ b/deps.bzl @@ -92,9 +92,9 @@ def archive_dependencies(third_party): }, { "name": "rules_cc", - "sha256": "3d9e271e2876ba42e114c9b9bc51454e379cbf0ec9ef9d40e2ae4cec61a31b40", - "strip_prefix": "rules_cc-0.0.6", - "url": "https://github.com/bazelbuild/rules_cc/releases/download/0.0.6/rules_cc-0.0.6.tar.gz", + "sha256": "2037875b9a4456dce4a79d112a8ae885bbc4aad968e6587dca6e64f3a0900cdf", + "strip_prefix": "rules_cc-0.0.9", + "url": "https://github.com/bazelbuild/rules_cc/releases/download/0.0.9/rules_cc-0.0.9.tar.gz", }, # Used to format proto files From edf2211c086b839aa1bb1957245febc681685e2e Mon Sep 17 00:00:00 2001 From: Trevor Hickey Date: Mon, 16 Oct 2023 23:54:31 -0400 Subject: [PATCH 096/311] Implement local resources for workers (#1282) --- _site/docs/contribute/design-documents.md | 3 +- .../buildfarm/common/config/Backplane.java | 15 +- .../common/config/LimitedResource.java | 43 ++++ .../build/buildfarm/common/config/Worker.java | 6 + .../common/redis/BalancedRedisQueue.java | 11 + .../instance/shard/OperationQueue.java | 84 +++++++- src/main/java/build/buildfarm/worker/BUILD | 1 + .../worker/DequeueMatchEvaluator.java | 37 ++-- .../java/build/buildfarm/worker/Executor.java | 3 + .../build/buildfarm/worker/WorkerContext.java | 2 + .../build/buildfarm/worker/resources/BUILD | 1 + .../worker/resources/LocalResourceSet.java | 37 ++++ .../resources/LocalResourceSetMetrics.java | 46 +++++ .../resources/LocalResourceSetUtils.java | 120 +++++++++++ .../worker/shard/ShardWorkerContext.java | 22 +- .../build/buildfarm/worker/shard/Worker.java | 2 + .../common/config/GrpcMetricsTest.java | 1 - .../java/build/buildfarm/instance/shard/BUILD | 192 +++++++++++++++++- .../shard/RedisShardBackplaneTest.java | 6 +- .../instance/shard/ShardInstanceTest.java | 1 - .../worker/DequeueMatchEvaluatorTest.java | 168 ++++++++++++++- .../buildfarm/worker/StubWorkerContext.java | 5 + .../java/build/buildfarm/worker/shard/BUILD | 1 + .../worker/shard/ShardWorkerContextTest.java | 2 + 24 files changed, 759 insertions(+), 50 deletions(-) create mode 100644 src/main/java/build/buildfarm/common/config/LimitedResource.java create mode 100644 src/main/java/build/buildfarm/worker/resources/LocalResourceSet.java create mode 100644 src/main/java/build/buildfarm/worker/resources/LocalResourceSetMetrics.java create mode 100644 src/main/java/build/buildfarm/worker/resources/LocalResourceSetUtils.java diff --git a/_site/docs/contribute/design-documents.md b/_site/docs/contribute/design-documents.md index f7b1c0b80d..ea608696f3 100644 --- a/_site/docs/contribute/design-documents.md +++ b/_site/docs/contribute/design-documents.md @@ -5,4 +5,5 @@ parent: Contribute nav_order: 2 --- -[Infinite Cache (Storage Workers)](https://docs.google.com/document/d/1IQQbWPzjSluDL25FZ9ADtNIOT90PLijQGIAC4RbwMjY/edit?usp=sharing) \ No newline at end of file +[Infinite Cache (Storage Workers)](https://docs.google.com/document/d/1IQQbWPzjSluDL25FZ9ADtNIOT90PLijQGIAC4RbwMjY/edit?usp=sharing) +[Local and Global Resources](https://docs.google.com/document/d/1u0TkmVmdMS53PWR1hgh-a_cj3NmQYE0Favv9aGFfQZs/edit?usp=sharing) \ No newline at end of file diff --git a/src/main/java/build/buildfarm/common/config/Backplane.java b/src/main/java/build/buildfarm/common/config/Backplane.java index 5c21532ab4..cc15a6028a 100644 --- a/src/main/java/build/buildfarm/common/config/Backplane.java +++ b/src/main/java/build/buildfarm/common/config/Backplane.java @@ -1,6 +1,7 @@ package build.buildfarm.common.config; -import com.google.common.base.Strings; +import java.util.ArrayList; +import java.util.List; import lombok.AccessLevel; import lombok.Data; import lombok.Getter; @@ -52,13 +53,7 @@ public enum BACKPLANE_TYPE { private boolean cacheCas = false; private long priorityPollIntervalMillis = 100; - public String getRedisUri() { - // use environment override (useful for containerized deployment) - if (!Strings.isNullOrEmpty(System.getenv("REDIS_URI"))) { - return System.getenv("REDIS_URI"); - } - - // use configured value - return redisUri; - } + // These limited resources are shared across all workers. + // An example would be a limited number of seats to a license server. + private List resources = new ArrayList<>(); } diff --git a/src/main/java/build/buildfarm/common/config/LimitedResource.java b/src/main/java/build/buildfarm/common/config/LimitedResource.java new file mode 100644 index 0000000000..f3b09ff621 --- /dev/null +++ b/src/main/java/build/buildfarm/common/config/LimitedResource.java @@ -0,0 +1,43 @@ +// Copyright 2023 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package build.buildfarm.common.config; + +import lombok.Data; + +/** + * @class Limited Resource + * @brief A fixed amount of a specific resource. + * @details We define a limited resource as a counting semaphore whose configuration contains a name + * and a count representing a physical or logical group of units obtained by executors as a + * precondition to fulfill a long running operation. These units are released upon the + * operation's completion. The resource is requested by the action's platform properties. + */ +@Data +public class LimitedResource { + /** + * @field name + * @brief The name of the resource. + * @details This should correspond to the platform property's key name: + * resources:: + */ + public String name; + + /** + * @field amount + * @brief The total amount of the resource that's available for use during execution. + * @details As a counting semaphore, this amount becomes the limit. + */ + public int amount = 1; +} diff --git a/src/main/java/build/buildfarm/common/config/Worker.java b/src/main/java/build/buildfarm/common/config/Worker.java index 1661df9bfe..e987c1e370 100644 --- a/src/main/java/build/buildfarm/common/config/Worker.java +++ b/src/main/java/build/buildfarm/common/config/Worker.java @@ -5,6 +5,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.naming.ConfigurationException; @@ -39,6 +40,11 @@ public class Worker { private ExecutionPolicy[] executionPolicies = {}; private SandboxSettings sandboxSettings = new SandboxSettings(); + // These limited resources are only for the individual worker. + // An example would be hardware resources such as GPUs. + // If you want GPU actions to run exclusively, define a single GPU resource. + private List resources = new ArrayList<>(); + public ExecutionPolicy[] getExecutionPolicies() { if (executionPolicies != null) { return executionPolicies; diff --git a/src/main/java/build/buildfarm/common/redis/BalancedRedisQueue.java b/src/main/java/build/buildfarm/common/redis/BalancedRedisQueue.java index 52f937c8ed..9123f5eaf9 100644 --- a/src/main/java/build/buildfarm/common/redis/BalancedRedisQueue.java +++ b/src/main/java/build/buildfarm/common/redis/BalancedRedisQueue.java @@ -236,6 +236,17 @@ public String dequeue(JedisCluster jedis) throws InterruptedException { } } + /** + * @brief Pop element into internal dequeue and return value. + * @details Null is returned if the queue is empty. + * @return The value of the transfered element. null if queue is empty or thread was interrupted. + * @note Suggested return identifier: val. + */ + public String nonBlockingDequeue(JedisCluster jedis) throws InterruptedException { + QueueInterface queue = queues.get(roundRobinPopIndex()); + return queue.nonBlockingDequeue(jedis); + } + /** * @brief Get the current pop queue. * @details Get the queue that the balanced queue intends to pop from next. diff --git a/src/main/java/build/buildfarm/instance/shard/OperationQueue.java b/src/main/java/build/buildfarm/instance/shard/OperationQueue.java index 64f1f2befa..78dd77c769 100644 --- a/src/main/java/build/buildfarm/instance/shard/OperationQueue.java +++ b/src/main/java/build/buildfarm/instance/shard/OperationQueue.java @@ -24,6 +24,7 @@ import com.google.common.collect.SetMultimap; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; import redis.clients.jedis.JedisCluster; /** @@ -48,6 +49,14 @@ public class OperationQueue { */ private final List queues; + /** + * @field currentDequeueIndex + * @brief The current queue index to dequeue from. + * @details Used in a round-robin fashion to ensure an even distribution of dequeues across + * matched queues. + */ + private int currentDequeueIndex = 0; + /** * @brief Constructor. * @details Construct the operation queue with various provisioned redis queues. @@ -186,8 +195,18 @@ public void push( */ public String dequeue(JedisCluster jedis, List provisions) throws InterruptedException { - BalancedRedisQueue queue = chooseEligibleQueue(provisions); - return queue.dequeue(jedis); + // Select all matched queues, and attempt dequeuing via round-robin. + List queues = chooseEligibleQueues(provisions); + int index = roundRobinPopIndex(queues); + String value = queues.get(index).nonBlockingDequeue(jedis); + + // Keep iterating over matched queues until we find one that is non-empty and provides a + // dequeued value. + while (value == null) { + index = roundRobinPopIndex(queues); + value = queues.get(index).nonBlockingDequeue(jedis); + } + return value; } /** @@ -270,6 +289,39 @@ private BalancedRedisQueue chooseEligibleQueue(List provision } } + throwNoEligibleQueueException(provisions); + return null; + } + + /** + * @brief Choose an eligible queues based on given properties. + * @details We use the platform execution properties of a queue entry to determine the appropriate + * queues. If there no eligible queues, an exception is thrown. + * @param provisions Provisions to check that requirements are met. + * @return The chosen queues. + * @note Suggested return identifier: queues. + */ + private List chooseEligibleQueues(List provisions) { + List eligibleQueues = + queues.stream() + .filter(provisionedQueue -> provisionedQueue.isEligible(toMultimap(provisions))) + .map(provisionedQueue -> provisionedQueue.queue()) + .collect(Collectors.toList()); + + if (eligibleQueues.isEmpty()) { + throwNoEligibleQueueException(provisions); + } + + return eligibleQueues; + } + + /** + * @brief Throw an exception that explains why there are no eligible queues. + * @details This function should only be called, when there were no matched queues. + * @param provisions Provisions to check that requirements are met. + * @return no return. + */ + private void throwNoEligibleQueueException(List provisions) { // At this point, we were unable to match an action to an eligible queue. // We will build an error explaining why the matching failed. This will help user's properly // configure their queue or adjust the execution_properties of their actions. @@ -286,6 +338,34 @@ private BalancedRedisQueue chooseEligibleQueue(List provision + eligibilityResults); } + /** + * @brief Get the current queue index for round-robin dequeues. + * @details Adjusts the round-robin index for next call. + * @param matchedQueues The queues to round robin. + * @return The current round-robin index. + * @note Suggested return identifier: queueIndex. + */ + private int roundRobinPopIndex(List matchedQueues) { + int currentIndex = currentDequeueIndex; + currentDequeueIndex = nextQueueInRoundRobin(currentDequeueIndex, matchedQueues); + return currentIndex; + } + + /** + * @brief Get the next queue in the round robin. + * @details If we are currently on the last queue it becomes the first queue. + * @param index Current queue index. + * @param matchedQueues The queues to round robin. + * @return And adjusted val based on the current queue index. + * @note Suggested return identifier: adjustedCurrentQueue. + */ + private int nextQueueInRoundRobin(int index, List matchedQueues) { + if (index >= matchedQueues.size() - 1) { + return 0; + } + return index + 1; + } + /** * @brief Convert proto provisions into java multimap. * @details This conversion is done to more easily check if a key/value exists in the provisions. diff --git a/src/main/java/build/buildfarm/worker/BUILD b/src/main/java/build/buildfarm/worker/BUILD index c25b9e74d6..e24b50d731 100644 --- a/src/main/java/build/buildfarm/worker/BUILD +++ b/src/main/java/build/buildfarm/worker/BUILD @@ -36,6 +36,7 @@ java_library( "@maven//:io_grpc_grpc_stub", "@maven//:io_prometheus_simpleclient", "@maven//:org_apache_commons_commons_compress", + "@maven//:org_apache_commons_commons_lang3", "@maven//:org_jetbrains_annotations", "@maven//:org_projectlombok_lombok", ], diff --git a/src/main/java/build/buildfarm/worker/DequeueMatchEvaluator.java b/src/main/java/build/buildfarm/worker/DequeueMatchEvaluator.java index c3c4c1dfc9..3536ed6bac 100644 --- a/src/main/java/build/buildfarm/worker/DequeueMatchEvaluator.java +++ b/src/main/java/build/buildfarm/worker/DequeueMatchEvaluator.java @@ -14,11 +14,12 @@ package build.buildfarm.worker; -import build.bazel.remote.execution.v2.Command; import build.bazel.remote.execution.v2.Platform; import build.buildfarm.common.ExecutionProperties; import build.buildfarm.common.config.BuildfarmConfigs; import build.buildfarm.v1test.QueueEntry; +import build.buildfarm.worker.resources.LocalResourceSet; +import build.buildfarm.worker.resources.LocalResourceSetUtils; import com.google.common.collect.Iterables; import com.google.common.collect.SetMultimap; import org.jetbrains.annotations.NotNull; @@ -45,6 +46,7 @@ public class DequeueMatchEvaluator { * @brief Decide whether the worker should keep the operation or put it back on the queue. * @details Compares the platform properties of the worker to the operation's platform properties. * @param workerProvisions The provisions of the worker. + * @param resourceSet The limited resources that the worker has available. * @param queueEntry An entry recently removed from the queue. * @return Whether or not the worker should accept or reject the queue entry. * @note Overloaded. @@ -53,24 +55,10 @@ public class DequeueMatchEvaluator { @SuppressWarnings("NullableProblems") @NotNull public static boolean shouldKeepOperation( - SetMultimap workerProvisions, QueueEntry queueEntry) { - return shouldKeepViaPlatform(workerProvisions, queueEntry.getPlatform()); - } - - /** - * @brief Decide whether the worker should keep the operation or put it back on the queue. - * @details Compares the platform properties of the worker to the operation's platform properties. - * @param workerProvisions The provisions of the worker. - * @param command A command to evaluate. - * @return Whether or not the worker should accept or reject the queue entry. - * @note Overloaded. - * @note Suggested return identifier: shouldKeepOperation. - */ - @SuppressWarnings("NullableProblems") - @NotNull - public static boolean shouldKeepOperation( - SetMultimap workerProvisions, Command command) { - return shouldKeepViaPlatform(workerProvisions, command.getPlatform()); + SetMultimap workerProvisions, + LocalResourceSet resourceSet, + QueueEntry queueEntry) { + return shouldKeepViaPlatform(workerProvisions, resourceSet, queueEntry.getPlatform()); } /** @@ -79,6 +67,7 @@ public static boolean shouldKeepOperation( * @details Compares the platform properties of the worker to the platform properties of the * operation. * @param workerProvisions The provisions of the worker. + * @param resourceSet The limited resources that the worker has available. * @param platform The platforms of operation. * @return Whether or not the worker should accept or reject the operation. * @note Suggested return identifier: shouldKeepOperation. @@ -86,9 +75,15 @@ public static boolean shouldKeepOperation( @SuppressWarnings("NullableProblems") @NotNull private static boolean shouldKeepViaPlatform( - SetMultimap workerProvisions, Platform platform) { - // attempt to execute everything the worker gets off the queue. + SetMultimap workerProvisions, + LocalResourceSet resourceSet, + Platform platform) { + // attempt to execute everything the worker gets off the queue, + // provided there is enough resources to do so. // this is a recommended configuration. + if (!LocalResourceSetUtils.claimResources(platform, resourceSet)) { + return false; + } if (configs.getWorker().getDequeueMatchSettings().isAcceptEverything()) { return true; } diff --git a/src/main/java/build/buildfarm/worker/Executor.java b/src/main/java/build/buildfarm/worker/Executor.java index 0416c2354d..f4776a6f00 100644 --- a/src/main/java/build/buildfarm/worker/Executor.java +++ b/src/main/java/build/buildfarm/worker/Executor.java @@ -359,6 +359,9 @@ public void run(ResourceLimits limits) { } finally { boolean wasInterrupted = Thread.interrupted(); try { + // Now that the execution has finished we can return any of the claims against local + // resources. + workerContext.returnLocalResources(operationContext.queueEntry); owner.releaseExecutor( operationName, limits.cpu.claimed, diff --git a/src/main/java/build/buildfarm/worker/WorkerContext.java b/src/main/java/build/buildfarm/worker/WorkerContext.java index 873ad1b938..70060acea1 100644 --- a/src/main/java/build/buildfarm/worker/WorkerContext.java +++ b/src/main/java/build/buildfarm/worker/WorkerContext.java @@ -130,4 +130,6 @@ IOResource limitExecution( int commandExecutionClaims(Command command); ResourceLimits commandExecutionSettings(Command command); + + void returnLocalResources(QueueEntry queueEntry); } diff --git a/src/main/java/build/buildfarm/worker/resources/BUILD b/src/main/java/build/buildfarm/worker/resources/BUILD index ac2d69179b..36a4dc3d34 100644 --- a/src/main/java/build/buildfarm/worker/resources/BUILD +++ b/src/main/java/build/buildfarm/worker/resources/BUILD @@ -8,6 +8,7 @@ java_library( "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_googlecode_json_simple_json_simple", + "@maven//:io_prometheus_simpleclient", "@maven//:org_apache_commons_commons_lang3", ], ) diff --git a/src/main/java/build/buildfarm/worker/resources/LocalResourceSet.java b/src/main/java/build/buildfarm/worker/resources/LocalResourceSet.java new file mode 100644 index 0000000000..97d64fe9b1 --- /dev/null +++ b/src/main/java/build/buildfarm/worker/resources/LocalResourceSet.java @@ -0,0 +1,37 @@ +// Copyright 2023 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package build.buildfarm.worker.resources; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Semaphore; + +/** + * @class Local Resource Set + * @brief A fixed amount of a specific resource. + * @details We define limited resources as a counting semaphores whose configuration contains a name + * and a count representing a physical or logical group of units obtained by executors as a + * precondition to fulfill a long running operation. These units are released upon the + * operation's completion. The resource is requested by the action's platform properties. These + * resources are specific to the individual worker. + */ +public class LocalResourceSet { + /** + * @field resources + * @brief A set containing resource semaphores organized by name. + * @details Key is name, and value is current usage amount. + */ + public Map resources = new HashMap<>(); +} diff --git a/src/main/java/build/buildfarm/worker/resources/LocalResourceSetMetrics.java b/src/main/java/build/buildfarm/worker/resources/LocalResourceSetMetrics.java new file mode 100644 index 0000000000..787a7840e5 --- /dev/null +++ b/src/main/java/build/buildfarm/worker/resources/LocalResourceSetMetrics.java @@ -0,0 +1,46 @@ +// Copyright 2020 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package build.buildfarm.worker.resources; + +import io.prometheus.client.Gauge; + +/** + * @class LocalResourceSetMetrics + * @brief Tracks metrics related to a worker's limited local resources. + * @details Answers how many resources exist, how many are claimed, and by how many requesters. + */ +public class LocalResourceSetMetrics { + public static final Gauge resourceUsageMetric = + Gauge.build() + .name("local_resource_usage") + .labelNames("resource_name") + .help("The number of claims for each resource currently being used for execution") + .register(); + + public static final Gauge resourceTotalMetric = + Gauge.build() + .name("local_resource_total") + .labelNames("resource_name") + .help("The total number of claims exist for a particular resource") + .register(); + + public static final Gauge requestersMetric = + Gauge.build() + .name("local_resource_requesters") + .labelNames("resource_name") + .help( + "Tracks how many actions have requested local resources. This can help determine if resources are being hogged by some actions.") + .register(); +} diff --git a/src/main/java/build/buildfarm/worker/resources/LocalResourceSetUtils.java b/src/main/java/build/buildfarm/worker/resources/LocalResourceSetUtils.java new file mode 100644 index 0000000000..e8a1e56131 --- /dev/null +++ b/src/main/java/build/buildfarm/worker/resources/LocalResourceSetUtils.java @@ -0,0 +1,120 @@ +// Copyright 2020 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package build.buildfarm.worker.resources; + +import build.bazel.remote.execution.v2.Platform; +import build.buildfarm.common.config.LimitedResource; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Semaphore; +import org.apache.commons.lang3.StringUtils; + +/** + * @class LocalResourceSetUtils + * @brief Utilities for working with the worker's set of local limited resources. + * @details The methods help with allocation / de-allocation of claims, as well as metrics printing. + */ +public class LocalResourceSetUtils { + private static final LocalResourceSetMetrics metrics = new LocalResourceSetMetrics(); + + public static LocalResourceSet create(List resources) { + LocalResourceSet resourceSet = new LocalResourceSet(); + for (LimitedResource resource : resources) { + resourceSet.resources.put(resource.getName(), new Semaphore(resource.getAmount())); + metrics.resourceTotalMetric.labels(resource.getName()).set(resource.getAmount()); + } + return resourceSet; + } + + public static boolean claimResources(Platform platform, LocalResourceSet resourceSet) { + List> claimed = new ArrayList<>(); + + boolean allClaimed = true; + for (Platform.Property property : platform.getPropertiesList()) { + // Skip properties that are not requesting a limited resource. + String resourceName = getResourceName(property); + Semaphore resource = resourceSet.resources.get(resourceName); + if (resource == null) { + continue; + } + + // Attempt to claim. If claiming fails, we must return all other claims. + int requestAmount = getResourceRequestAmount(property); + boolean wasAcquired = semaphoreAquire(resource, resourceName, requestAmount); + if (wasAcquired) { + claimed.add(new AbstractMap.SimpleEntry<>(resourceName, requestAmount)); + } else { + allClaimed = false; + break; + } + } + + // cleanup remaining resources if they were not all claimed. + if (!allClaimed) { + for (Map.Entry claim : claimed) { + semaphoreRelease( + resourceSet.resources.get(claim.getKey()), claim.getKey(), claim.getValue()); + } + } + + return allClaimed; + } + + public static void releaseClaims(Platform platform, LocalResourceSet resourceSet) { + for (Platform.Property property : platform.getPropertiesList()) { + String resourceName = getResourceName(property); + Semaphore resource = resourceSet.resources.get(resourceName); + if (resource == null) { + continue; + } + int requestAmount = getResourceRequestAmount(property); + semaphoreRelease(resource, resourceName, requestAmount); + } + } + + private static boolean semaphoreAquire(Semaphore resource, String resourceName, int amount) { + boolean wasAcquired = resource.tryAcquire(amount); + if (wasAcquired) { + metrics.resourceUsageMetric.labels(resourceName).inc(amount); + } + metrics.requestersMetric.labels(resourceName).inc(); + return wasAcquired; + } + + private static void semaphoreRelease(Semaphore resource, String resourceName, int amount) { + resource.release(amount); + metrics.resourceUsageMetric.labels(resourceName).dec(amount); + metrics.requestersMetric.labels(resourceName).dec(); + } + + private static int getResourceRequestAmount(Platform.Property property) { + // We support resource values that are not numbers and interpret them as a request for 1 + // resource. For example "gpu:RTX-4090" is equivalent to resource:gpu:1". + try { + return Integer.parseInt(property.getValue()); + } catch (NumberFormatException e) { + return 1; + } + } + + private static String getResourceName(Platform.Property property) { + // We match to keys whether they are prefixed "resource:" or not. + // "resource:gpu:1" requests the gpu resource in the same way that "gpu:1" does. + // The prefix originates from bazel's syntax for the --extra_resources flag. + return StringUtils.removeStart(property.getName(), "resource:"); + } +} diff --git a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java index d32731879c..c844f53963 100644 --- a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java +++ b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java @@ -60,6 +60,8 @@ import build.buildfarm.worker.cgroup.Cpu; import build.buildfarm.worker.cgroup.Group; import build.buildfarm.worker.cgroup.Mem; +import build.buildfarm.worker.resources.LocalResourceSet; +import build.buildfarm.worker.resources.LocalResourceSetUtils; import build.buildfarm.worker.resources.ResourceDecider; import build.buildfarm.worker.resources.ResourceLimits; import com.google.common.annotations.VisibleForTesting; @@ -129,6 +131,7 @@ class ShardWorkerContext implements WorkerContext { private final Group operationsGroup = executionsGroup.getChild("operations"); private final CasWriter writer; private final boolean errorOperationRemainingResources; + private final LocalResourceSet resourceSet; static SetMultimap getMatchProvisions( Iterable policies, int executeStageWidth) { @@ -162,6 +165,7 @@ static SetMultimap getMatchProvisions( boolean onlyMulticoreTests, boolean allowBringYourOwnContainer, boolean errorOperationRemainingResources, + LocalResourceSet resourceSet, CasWriter writer) { this.name = name; this.matchProvisions = getMatchProvisions(policies, executeStageWidth); @@ -182,6 +186,7 @@ static SetMultimap getMatchProvisions( this.onlyMulticoreTests = onlyMulticoreTests; this.allowBringYourOwnContainer = allowBringYourOwnContainer; this.errorOperationRemainingResources = errorOperationRemainingResources; + this.resourceSet = resourceSet; this.writer = writer; } @@ -273,6 +278,12 @@ public QueuedOperation getQueuedOperation(QueueEntry queueEntry) @SuppressWarnings("ConstantConditions") private void matchInterruptible(MatchListener listener) throws IOException, InterruptedException { + QueueEntry queueEntry = takeEntryOffOperationQueue(listener); + decideWhetherToKeepOperation(queueEntry, listener); + } + + private QueueEntry takeEntryOffOperationQueue(MatchListener listener) + throws IOException, InterruptedException { listener.onWaitStart(); QueueEntry queueEntry = null; try { @@ -294,9 +305,13 @@ private void matchInterruptible(MatchListener listener) throws IOException, Inte // transient backplane errors will propagate a null queueEntry } listener.onWaitEnd(); + return queueEntry; + } + private void decideWhetherToKeepOperation(QueueEntry queueEntry, MatchListener listener) + throws IOException, InterruptedException { if (queueEntry == null - || DequeueMatchEvaluator.shouldKeepOperation(matchProvisions, queueEntry)) { + || DequeueMatchEvaluator.shouldKeepOperation(matchProvisions, resourceSet, queueEntry)) { listener.onEntry(queueEntry); } else { backplane.rejectOperation(queueEntry); @@ -306,6 +321,11 @@ private void matchInterruptible(MatchListener listener) throws IOException, Inte } } + @Override + public void returnLocalResources(QueueEntry queueEntry) { + LocalResourceSetUtils.releaseClaims(queueEntry.getPlatform(), resourceSet); + } + @Override public void match(MatchListener listener) throws InterruptedException { RetryingMatchListener dedupMatchListener = diff --git a/src/main/java/build/buildfarm/worker/shard/Worker.java b/src/main/java/build/buildfarm/worker/shard/Worker.java index 153df1a371..7a0d4a60ed 100644 --- a/src/main/java/build/buildfarm/worker/shard/Worker.java +++ b/src/main/java/build/buildfarm/worker/shard/Worker.java @@ -59,6 +59,7 @@ import build.buildfarm.worker.PutOperationStage; import build.buildfarm.worker.ReportResultStage; import build.buildfarm.worker.SuperscalarPipelineStage; +import build.buildfarm.worker.resources.LocalResourceSetUtils; import com.google.common.cache.LoadingCache; import com.google.common.collect.Lists; import com.google.longrunning.Operation; @@ -562,6 +563,7 @@ public void start() throws ConfigurationException, InterruptedException, IOExcep configs.getWorker().isOnlyMulticoreTests(), configs.getWorker().isAllowBringYourOwnContainer(), configs.getWorker().isErrorOperationRemainingResources(), + LocalResourceSetUtils.create(configs.getWorker().getResources()), writer); pipeline = new Pipeline(); diff --git a/src/test/java/build/buildfarm/common/config/GrpcMetricsTest.java b/src/test/java/build/buildfarm/common/config/GrpcMetricsTest.java index 5301b82608..547f81b2ca 100644 --- a/src/test/java/build/buildfarm/common/config/GrpcMetricsTest.java +++ b/src/test/java/build/buildfarm/common/config/GrpcMetricsTest.java @@ -30,7 +30,6 @@ public void testHandleGrpcMetricIntercepts_withLatencyBucket() { grpcMetrics.setEnabled(true); grpcMetrics.setProvideLatencyHistograms(true); grpcMetrics.setLatencyBuckets(new double[] {1, 2, 3}); - GrpcMetrics.handleGrpcMetricIntercepts(serverBuilder, grpcMetrics); verify(serverBuilder, times(1)).intercept(any(MonitoringServerInterceptor.class)); } diff --git a/src/test/java/build/buildfarm/instance/shard/BUILD b/src/test/java/build/buildfarm/instance/shard/BUILD index 6a501a1b68..cd0ae18d24 100644 --- a/src/test/java/build/buildfarm/instance/shard/BUILD +++ b/src/test/java/build/buildfarm/instance/shard/BUILD @@ -1,7 +1,195 @@ java_test( - name = "tests", + name = "DispatchedMonitorTest", size = "small", - srcs = glob(["*.java"]), + srcs = [ + "DispatchedMonitorTest.java", + "UnobservableWatcher.java", + ], + data = ["//examples:example_configs"], + test_class = "build.buildfarm.AllTests", + deps = [ + "//src/main/java/build/buildfarm/actioncache", + "//src/main/java/build/buildfarm/backplane", + "//src/main/java/build/buildfarm/common", + "//src/main/java/build/buildfarm/common/config", + "//src/main/java/build/buildfarm/instance", + "//src/main/java/build/buildfarm/instance/server", + "//src/main/java/build/buildfarm/instance/shard", + "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", + "//src/test/java/build/buildfarm:test_runner", + "//third_party/jedis", + "@googleapis//:google_longrunning_operations_java_proto", + "@googleapis//:google_rpc_code_java_proto", + "@googleapis//:google_rpc_error_details_java_proto", + "@maven//:com_github_ben_manes_caffeine_caffeine", + "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", + "@maven//:com_google_protobuf_protobuf_java_util", + "@maven//:com_google_truth_truth", + "@maven//:io_grpc_grpc_api", + "@maven//:io_grpc_grpc_core", + "@maven//:io_grpc_grpc_protobuf", + "@maven//:io_grpc_grpc_stub", + "@maven//:org_mockito_mockito_core", + "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", + ], +) + +java_test( + name = "RedisShardBackplaneTest", + size = "small", + srcs = [ + "RedisShardBackplaneTest.java", + "UnobservableWatcher.java", + ], + data = ["//examples:example_configs"], + test_class = "build.buildfarm.AllTests", + deps = [ + "//src/main/java/build/buildfarm/actioncache", + "//src/main/java/build/buildfarm/backplane", + "//src/main/java/build/buildfarm/common", + "//src/main/java/build/buildfarm/common/config", + "//src/main/java/build/buildfarm/instance", + "//src/main/java/build/buildfarm/instance/server", + "//src/main/java/build/buildfarm/instance/shard", + "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", + "//src/test/java/build/buildfarm:test_runner", + "//third_party/jedis", + "@googleapis//:google_longrunning_operations_java_proto", + "@googleapis//:google_rpc_code_java_proto", + "@googleapis//:google_rpc_error_details_java_proto", + "@maven//:com_github_ben_manes_caffeine_caffeine", + "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", + "@maven//:com_google_protobuf_protobuf_java_util", + "@maven//:com_google_truth_truth", + "@maven//:io_grpc_grpc_api", + "@maven//:io_grpc_grpc_core", + "@maven//:io_grpc_grpc_protobuf", + "@maven//:io_grpc_grpc_stub", + "@maven//:org_mockito_mockito_core", + "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", + ], +) + +java_test( + name = "RedisShardSubscriberTest", + size = "small", + srcs = [ + "RedisShardSubscriberTest.java", + "UnobservableWatcher.java", + ], + data = ["//examples:example_configs"], + test_class = "build.buildfarm.AllTests", + deps = [ + "//src/main/java/build/buildfarm/actioncache", + "//src/main/java/build/buildfarm/backplane", + "//src/main/java/build/buildfarm/common", + "//src/main/java/build/buildfarm/common/config", + "//src/main/java/build/buildfarm/instance", + "//src/main/java/build/buildfarm/instance/server", + "//src/main/java/build/buildfarm/instance/shard", + "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", + "//src/test/java/build/buildfarm:test_runner", + "//third_party/jedis", + "@googleapis//:google_longrunning_operations_java_proto", + "@googleapis//:google_rpc_code_java_proto", + "@googleapis//:google_rpc_error_details_java_proto", + "@maven//:com_github_ben_manes_caffeine_caffeine", + "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", + "@maven//:com_google_protobuf_protobuf_java_util", + "@maven//:com_google_truth_truth", + "@maven//:io_grpc_grpc_api", + "@maven//:io_grpc_grpc_core", + "@maven//:io_grpc_grpc_protobuf", + "@maven//:io_grpc_grpc_stub", + "@maven//:org_mockito_mockito_core", + "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", + ], +) + +java_test( + name = "ShardInstanceTest", + size = "small", + srcs = [ + "ShardInstanceTest.java", + "UnobservableWatcher.java", + ], + data = ["//examples:example_configs"], + test_class = "build.buildfarm.AllTests", + deps = [ + "//src/main/java/build/buildfarm/actioncache", + "//src/main/java/build/buildfarm/backplane", + "//src/main/java/build/buildfarm/common", + "//src/main/java/build/buildfarm/common/config", + "//src/main/java/build/buildfarm/instance", + "//src/main/java/build/buildfarm/instance/server", + "//src/main/java/build/buildfarm/instance/shard", + "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", + "//src/test/java/build/buildfarm:test_runner", + "//third_party/jedis", + "@googleapis//:google_longrunning_operations_java_proto", + "@googleapis//:google_rpc_code_java_proto", + "@googleapis//:google_rpc_error_details_java_proto", + "@maven//:com_github_ben_manes_caffeine_caffeine", + "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", + "@maven//:com_google_protobuf_protobuf_java_util", + "@maven//:com_google_truth_truth", + "@maven//:io_grpc_grpc_api", + "@maven//:io_grpc_grpc_core", + "@maven//:io_grpc_grpc_protobuf", + "@maven//:io_grpc_grpc_stub", + "@maven//:org_mockito_mockito_core", + "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", + ], +) + +java_test( + name = "TimedWatcherTest", + size = "small", + srcs = [ + "TimedWatcherTest.java", + "UnobservableWatcher.java", + ], + data = ["//examples:example_configs"], + test_class = "build.buildfarm.AllTests", + deps = [ + "//src/main/java/build/buildfarm/actioncache", + "//src/main/java/build/buildfarm/backplane", + "//src/main/java/build/buildfarm/common", + "//src/main/java/build/buildfarm/common/config", + "//src/main/java/build/buildfarm/instance", + "//src/main/java/build/buildfarm/instance/server", + "//src/main/java/build/buildfarm/instance/shard", + "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", + "//src/test/java/build/buildfarm:test_runner", + "//third_party/jedis", + "@googleapis//:google_longrunning_operations_java_proto", + "@googleapis//:google_rpc_code_java_proto", + "@googleapis//:google_rpc_error_details_java_proto", + "@maven//:com_github_ben_manes_caffeine_caffeine", + "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", + "@maven//:com_google_protobuf_protobuf_java_util", + "@maven//:com_google_truth_truth", + "@maven//:io_grpc_grpc_api", + "@maven//:io_grpc_grpc_core", + "@maven//:io_grpc_grpc_protobuf", + "@maven//:io_grpc_grpc_stub", + "@maven//:org_mockito_mockito_core", + "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", + ], +) + +java_test( + name = "UtilTest", + size = "small", + srcs = [ + "UnobservableWatcher.java", + "UtilTest.java", + ], data = ["//examples:example_configs"], test_class = "build.buildfarm.AllTests", deps = [ diff --git a/src/test/java/build/buildfarm/instance/shard/RedisShardBackplaneTest.java b/src/test/java/build/buildfarm/instance/shard/RedisShardBackplaneTest.java index 16e5bb8fbc..3772459cf7 100644 --- a/src/test/java/build/buildfarm/instance/shard/RedisShardBackplaneTest.java +++ b/src/test/java/build/buildfarm/instance/shard/RedisShardBackplaneTest.java @@ -213,8 +213,7 @@ public void dispatchedOperationsShowProperRequeueAmount0to1() .setRequeueAttempts(STARTING_REQUEUE_AMOUNT) .build(); String queueEntryJson = JsonFormat.printer().print(queueEntry); - when(jedisCluster.brpoplpush(any(String.class), any(String.class), any(Integer.class))) - .thenReturn(queueEntryJson); + when(jedisCluster.rpoplpush(any(String.class), any(String.class))).thenReturn(queueEntryJson); // PRE-ASSERT when(jedisCluster.hsetnx(any(String.class), any(String.class), any(String.class))) @@ -266,8 +265,7 @@ public void dispatchedOperationsShowProperRequeueAmount1to2() .setRequeueAttempts(STARTING_REQUEUE_AMOUNT) .build(); String queueEntryJson = JsonFormat.printer().print(queueEntry); - when(jedisCluster.brpoplpush(any(String.class), any(String.class), any(Integer.class))) - .thenReturn(queueEntryJson); + when(jedisCluster.rpoplpush(any(String.class), any(String.class))).thenReturn(queueEntryJson); // PRE-ASSERT when(jedisCluster.hsetnx(any(String.class), any(String.class), any(String.class))) diff --git a/src/test/java/build/buildfarm/instance/shard/ShardInstanceTest.java b/src/test/java/build/buildfarm/instance/shard/ShardInstanceTest.java index 1fdb7fc460..aa1adc5d3d 100644 --- a/src/test/java/build/buildfarm/instance/shard/ShardInstanceTest.java +++ b/src/test/java/build/buildfarm/instance/shard/ShardInstanceTest.java @@ -1052,7 +1052,6 @@ public void containsBlobReflectsWorkerWithUnknownSize() throws Exception { @Test public void findMissingBlobsTest_ViaBackPlane() throws Exception { - Set activeWorkers = ImmutableSet.of("worker1", "worker2", "worker3"); Set expiredWorkers = ImmutableSet.of("workerX", "workerY", "workerZ"); Set imposterWorkers = ImmutableSet.of("imposter1", "imposter2", "imposter3"); diff --git a/src/test/java/build/buildfarm/worker/DequeueMatchEvaluatorTest.java b/src/test/java/build/buildfarm/worker/DequeueMatchEvaluatorTest.java index bc7acd00a4..47f25cdf79 100644 --- a/src/test/java/build/buildfarm/worker/DequeueMatchEvaluatorTest.java +++ b/src/test/java/build/buildfarm/worker/DequeueMatchEvaluatorTest.java @@ -19,8 +19,10 @@ import build.bazel.remote.execution.v2.Platform; import build.buildfarm.common.config.BuildfarmConfigs; import build.buildfarm.v1test.QueueEntry; +import build.buildfarm.worker.resources.LocalResourceSet; import com.google.common.collect.HashMultimap; import com.google.common.collect.SetMultimap; +import java.util.concurrent.Semaphore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -52,10 +54,12 @@ public class DequeueMatchEvaluatorTest { public void shouldKeepOperationKeepEmptyQueueEntry() throws Exception { // ARRANGE SetMultimap workerProvisions = HashMultimap.create(); + LocalResourceSet resourceSet = new LocalResourceSet(); QueueEntry entry = QueueEntry.newBuilder().setPlatform(Platform.newBuilder()).build(); // ACT - boolean shouldKeep = DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, entry); + boolean shouldKeep = + DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); // ASSERT assertThat(shouldKeep).isTrue(); @@ -70,6 +74,7 @@ public void shouldKeepOperationKeepEmptyQueueEntry() throws Exception { public void shouldKeepOperationValidMinCoresQueueEntry() throws Exception { // ARRANGE SetMultimap workerProvisions = HashMultimap.create(); + LocalResourceSet resourceSet = new LocalResourceSet(); workerProvisions.put("cores", "11"); QueueEntry entry = @@ -81,7 +86,8 @@ public void shouldKeepOperationValidMinCoresQueueEntry() throws Exception { .build(); // ACT - boolean shouldKeep = DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, entry); + boolean shouldKeep = + DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); // ASSERT // the worker accepts because it has more cores than the min-cores requested @@ -98,6 +104,7 @@ public void shouldKeepOperationInvalidMinCoresQueueEntry() throws Exception { // ARRANGE configs.getWorker().getDequeueMatchSettings().setAcceptEverything(false); SetMultimap workerProvisions = HashMultimap.create(); + LocalResourceSet resourceSet = new LocalResourceSet(); workerProvisions.put("cores", "10"); QueueEntry entry = @@ -109,7 +116,8 @@ public void shouldKeepOperationInvalidMinCoresQueueEntry() throws Exception { .build(); // ACT - boolean shouldKeep = DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, entry); + boolean shouldKeep = + DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); // ASSERT // the worker rejects because it has less cores than the min-cores requested @@ -123,6 +131,7 @@ public void shouldKeepOperationInvalidMinCoresQueueEntry() throws Exception { public void shouldKeepOperationMaxCoresDoNotInfluenceAcceptance() throws Exception { // ARRANGE SetMultimap workerProvisions = HashMultimap.create(); + LocalResourceSet resourceSet = new LocalResourceSet(); workerProvisions.put("cores", "10"); QueueEntry entry = @@ -136,7 +145,8 @@ public void shouldKeepOperationMaxCoresDoNotInfluenceAcceptance() throws Excepti .build(); // ACT - boolean shouldKeep = DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, entry); + boolean shouldKeep = + DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); // ASSERT // the worker accepts because it has the same cores as the min-cores requested @@ -153,6 +163,7 @@ public void shouldKeepOperationUnmatchedPropertiesRejectionAcceptance() throws E configs.getWorker().getDequeueMatchSettings().setAcceptEverything(false); configs.getWorker().getDequeueMatchSettings().setAllowUnmatched(false); SetMultimap workerProvisions = HashMultimap.create(); + LocalResourceSet resourceSet = new LocalResourceSet(); QueueEntry entry = QueueEntry.newBuilder() @@ -163,7 +174,8 @@ public void shouldKeepOperationUnmatchedPropertiesRejectionAcceptance() throws E .build(); // ACT - boolean shouldKeep = DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, entry); + boolean shouldKeep = + DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); // ASSERT assertThat(shouldKeep).isFalse(); @@ -172,7 +184,7 @@ public void shouldKeepOperationUnmatchedPropertiesRejectionAcceptance() throws E configs.getWorker().getDequeueMatchSettings().setAcceptEverything(true); // ACT - shouldKeep = DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, entry); + shouldKeep = DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); // ASSERT assertThat(shouldKeep).isTrue(); @@ -181,9 +193,151 @@ public void shouldKeepOperationUnmatchedPropertiesRejectionAcceptance() throws E configs.getWorker().getDequeueMatchSettings().setAllowUnmatched(true); // ACT - shouldKeep = DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, entry); + shouldKeep = DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); // ASSERT assertThat(shouldKeep).isTrue(); } + + // Function under test: shouldKeepOperation + // Reason for testing: the local resource should be claimed + // Failure explanation: semaphore claim did not work as expected. + @Test + public void shouldKeepOperationClaimsResource() throws Exception { + // ARRANGE + configs.getWorker().getDequeueMatchSettings().setAcceptEverything(true); + configs.getWorker().getDequeueMatchSettings().setAllowUnmatched(true); + SetMultimap workerProvisions = HashMultimap.create(); + LocalResourceSet resourceSet = new LocalResourceSet(); + resourceSet.resources.put("FOO", new Semaphore(1)); + + QueueEntry entry = + QueueEntry.newBuilder() + .setPlatform( + Platform.newBuilder() + .addProperties( + Platform.Property.newBuilder().setName("resource:FOO").setValue("1"))) + .build(); + + // PRE-ASSERT + assertThat(resourceSet.resources.get("FOO").availablePermits()).isEqualTo(1); + + // ACT + boolean shouldKeep = + DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + + // ASSERT + // the worker accepts because the resource is available. + assertThat(shouldKeep).isTrue(); + assertThat(resourceSet.resources.get("FOO").availablePermits()).isEqualTo(0); + + // ACT + shouldKeep = DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + + // ASSERT + // the worker rejects because there are no resources left. + assertThat(shouldKeep).isFalse(); + assertThat(resourceSet.resources.get("FOO").availablePermits()).isEqualTo(0); + } + + // Function under test: shouldKeepOperation + // Reason for testing: the local resources should be claimed + // Failure explanation: semaphore claim did not work as expected. + @Test + public void shouldKeepOperationClaimsMultipleResource() throws Exception { + // ARRANGE + configs.getWorker().getDequeueMatchSettings().setAcceptEverything(true); + configs.getWorker().getDequeueMatchSettings().setAllowUnmatched(true); + SetMultimap workerProvisions = HashMultimap.create(); + LocalResourceSet resourceSet = new LocalResourceSet(); + resourceSet.resources.put("FOO", new Semaphore(2)); + resourceSet.resources.put("BAR", new Semaphore(4)); + + QueueEntry entry = + QueueEntry.newBuilder() + .setPlatform( + Platform.newBuilder() + .addProperties( + Platform.Property.newBuilder().setName("resource:FOO").setValue("1")) + .addProperties( + Platform.Property.newBuilder().setName("resource:BAR").setValue("2"))) + .build(); + + // PRE-ASSERT + assertThat(resourceSet.resources.get("FOO").availablePermits()).isEqualTo(2); + assertThat(resourceSet.resources.get("BAR").availablePermits()).isEqualTo(4); + + // ACT + boolean shouldKeep = + DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + + // ASSERT + // the worker accepts because the resource is available. + assertThat(shouldKeep).isTrue(); + assertThat(resourceSet.resources.get("FOO").availablePermits()).isEqualTo(1); + assertThat(resourceSet.resources.get("BAR").availablePermits()).isEqualTo(2); + + // ACT + shouldKeep = DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + + // ASSERT + // the worker accepts because the resource is available. + assertThat(shouldKeep).isTrue(); + assertThat(resourceSet.resources.get("FOO").availablePermits()).isEqualTo(0); + assertThat(resourceSet.resources.get("BAR").availablePermits()).isEqualTo(0); + + // ACT + shouldKeep = DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + + // ASSERT + // the worker rejects because there are no resources left. + assertThat(shouldKeep).isFalse(); + assertThat(resourceSet.resources.get("FOO").availablePermits()).isEqualTo(0); + assertThat(resourceSet.resources.get("BAR").availablePermits()).isEqualTo(0); + } + + // Function under test: shouldKeepOperation + // Reason for testing: the local resources should fail to claim, and the existing amount should be + // the same. + // Failure explanation: semaphore claim did not work as expected. + @Test + public void shouldKeepOperationFailsToClaimSameAmountRemains() throws Exception { + // ARRANGE + configs.getWorker().getDequeueMatchSettings().setAcceptEverything(true); + configs.getWorker().getDequeueMatchSettings().setAllowUnmatched(true); + SetMultimap workerProvisions = HashMultimap.create(); + LocalResourceSet resourceSet = new LocalResourceSet(); + resourceSet.resources.put("FOO", new Semaphore(50)); + resourceSet.resources.put("BAR", new Semaphore(100)); + resourceSet.resources.put("BAZ", new Semaphore(200)); + + QueueEntry entry = + QueueEntry.newBuilder() + .setPlatform( + Platform.newBuilder() + .addProperties( + Platform.Property.newBuilder().setName("resource:FOO").setValue("20")) + .addProperties( + Platform.Property.newBuilder().setName("resource:BAR").setValue("101")) + .addProperties( + Platform.Property.newBuilder().setName("resource:BAZ").setValue("20"))) + .build(); + + // PRE-ASSERT + assertThat(resourceSet.resources.get("FOO").availablePermits()).isEqualTo(50); + assertThat(resourceSet.resources.get("BAR").availablePermits()).isEqualTo(100); + assertThat(resourceSet.resources.get("BAZ").availablePermits()).isEqualTo(200); + + // ACT + boolean shouldKeep = + DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + + // ASSERT + // the worker rejects because there are no resources left. + // The same amount are returned. + assertThat(shouldKeep).isFalse(); + assertThat(resourceSet.resources.get("FOO").availablePermits()).isEqualTo(50); + assertThat(resourceSet.resources.get("BAR").availablePermits()).isEqualTo(100); + assertThat(resourceSet.resources.get("BAZ").availablePermits()).isEqualTo(200); + } } diff --git a/src/test/java/build/buildfarm/worker/StubWorkerContext.java b/src/test/java/build/buildfarm/worker/StubWorkerContext.java index d288d67a6f..7ccf1182d3 100644 --- a/src/test/java/build/buildfarm/worker/StubWorkerContext.java +++ b/src/test/java/build/buildfarm/worker/StubWorkerContext.java @@ -222,4 +222,9 @@ public ResourceLimits commandExecutionSettings(Command command) { public boolean shouldErrorOperationOnRemainingResources() { throw new UnsupportedOperationException(); } + + @Override + public void returnLocalResources(QueueEntry queueEntry) { + throw new UnsupportedOperationException(); + } } diff --git a/src/test/java/build/buildfarm/worker/shard/BUILD b/src/test/java/build/buildfarm/worker/shard/BUILD index b8a7b31ec6..c254e41fa4 100644 --- a/src/test/java/build/buildfarm/worker/shard/BUILD +++ b/src/test/java/build/buildfarm/worker/shard/BUILD @@ -11,6 +11,7 @@ java_test( "//src/main/java/build/buildfarm/common/config", "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/worker", + "//src/main/java/build/buildfarm/worker/resources", "//src/main/java/build/buildfarm/worker/shard", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", diff --git a/src/test/java/build/buildfarm/worker/shard/ShardWorkerContextTest.java b/src/test/java/build/buildfarm/worker/shard/ShardWorkerContextTest.java index dd584c49af..c24e681abb 100644 --- a/src/test/java/build/buildfarm/worker/shard/ShardWorkerContextTest.java +++ b/src/test/java/build/buildfarm/worker/shard/ShardWorkerContextTest.java @@ -35,6 +35,7 @@ import build.buildfarm.instance.MatchListener; import build.buildfarm.v1test.QueueEntry; import build.buildfarm.worker.WorkerContext; +import build.buildfarm.worker.resources.LocalResourceSet; import com.google.common.collect.ImmutableList; import com.google.protobuf.Duration; import java.util.ArrayList; @@ -105,6 +106,7 @@ WorkerContext createTestContext(Iterable policies) { /* onlyMulticoreTests=*/ false, /* allowBringYourOwnContainer=*/ false, /* errorOperationRemainingResources=*/ false, + /* resourceSet=*/ new LocalResourceSet(), writer); } From 97e3b90c263a27b6e08713d2455a590f7f47405c Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Mon, 16 Oct 2023 11:34:32 -0700 Subject: [PATCH 097/311] build: override grpc dependencies with our dependencies Don't get transitive grpc dependencies, use the ones from our `maven_install(...)` --- defs.bzl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/defs.bzl b/defs.bzl index ec51856484..869fdd2da7 100644 --- a/defs.bzl +++ b/defs.bzl @@ -8,7 +8,7 @@ load( "@io_bazel_rules_docker//repositories:repositories.bzl", container_repositories = "repositories", ) -load("@io_grpc_grpc_java//:repositories.bzl", "grpc_java_repositories") +load("@io_grpc_grpc_java//:repositories.bzl", "grpc_java_repositories", "IO_GRPC_GRPC_JAVA_OVERRIDE_TARGETS") load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") load("@com_grail_bazel_toolchain//toolchain:rules.bzl", "llvm_toolchain") load("@io_bazel_rules_k8s//k8s:k8s.bzl", "k8s_repositories") @@ -114,6 +114,7 @@ def buildfarm_init(name = "buildfarm"): "org.projectlombok:lombok:1.18.24", ], generate_compat_repositories = True, + override_targets = IO_GRPC_GRPC_JAVA_OVERRIDE_TARGETS, repositories = [ "https://repo1.maven.org/maven2", "https://mirrors.ibiblio.org/pub/mirrors/maven2", From 96f239d5131b17c32d07a46bb583b487472e5d1c Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Mon, 16 Oct 2023 11:35:25 -0700 Subject: [PATCH 098/311] chore(deps): bump protobuf runtime to 3.19.1 --- defs.bzl | 4 ++-- deps.bzl | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/defs.bzl b/defs.bzl index 869fdd2da7..ad8d07ced8 100644 --- a/defs.bzl +++ b/defs.bzl @@ -79,8 +79,8 @@ def buildfarm_init(name = "buildfarm"): "com.google.guava:guava:32.1.1-jre", "com.google.j2objc:j2objc-annotations:1.1", "com.google.jimfs:jimfs:1.1", - "com.google.protobuf:protobuf-java-util:3.10.0", - "com.google.protobuf:protobuf-java:3.10.0", + "com.google.protobuf:protobuf-java-util:3.19.1", + "com.google.protobuf:protobuf-java:3.19.1", "com.google.truth:truth:0.44", "org.slf4j:slf4j-simple:1.7.35", "com.googlecode.json-simple:json-simple:1.1.1", diff --git a/deps.bzl b/deps.bzl index f802fb27e7..e2d2609acf 100644 --- a/deps.bzl +++ b/deps.bzl @@ -36,9 +36,9 @@ def archive_dependencies(third_party): # Needed for "well-known protos" and @com_google_protobuf//:protoc. { "name": "com_google_protobuf", - "sha256": "dd513a79c7d7e45cbaeaf7655289f78fd6b806e52dbbd7018ef4e3cf5cff697a", - "strip_prefix": "protobuf-3.15.8", - "urls": ["https://github.com/protocolbuffers/protobuf/archive/v3.15.8.zip"], + "sha256": "25f1292d4ea6666f460a2a30038eef121e6c3937ae0f61d610611dfb14b0bd32", + "strip_prefix": "protobuf-3.19.1", + "urls": ["https://github.com/protocolbuffers/protobuf/archive/v3.19.1.zip"], }, { "name": "com_github_bazelbuild_buildtools", From af3f34e143c263f10139a9eee6262fb190bdddb9 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Mon, 16 Oct 2023 11:36:21 -0700 Subject: [PATCH 099/311] chore(deps) add transitive dependencies --- src/main/java/build/buildfarm/server/BUILD | 2 ++ src/main/java/build/buildfarm/worker/shard/BUILD | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/main/java/build/buildfarm/server/BUILD b/src/main/java/build/buildfarm/server/BUILD index eccbf4fda2..7244807f8a 100644 --- a/src/main/java/build/buildfarm/server/BUILD +++ b/src/main/java/build/buildfarm/server/BUILD @@ -16,6 +16,8 @@ java_library( "//src/main/java/build/buildfarm/metrics/prometheus", "//src/main/java/build/buildfarm/server/services", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", + "@io_grpc_grpc_proto//:health_proto", + "@io_grpc_grpc_proto//:health_java_proto", "@maven//:com_github_pcj_google_options", "@maven//:com_google_guava_guava", "@maven//:io_grpc_grpc_api", diff --git a/src/main/java/build/buildfarm/worker/shard/BUILD b/src/main/java/build/buildfarm/worker/shard/BUILD index ec48ec5be0..4458d61821 100644 --- a/src/main/java/build/buildfarm/worker/shard/BUILD +++ b/src/main/java/build/buildfarm/worker/shard/BUILD @@ -20,6 +20,8 @@ java_library( "//src/main/java/build/buildfarm/worker/resources", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_grpc", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", + "@io_grpc_grpc_proto//:health_java_proto", + "@io_grpc_grpc_proto//:health_proto", "@googleapis//:google_rpc_error_details_java_proto", "@maven//:com_github_ben_manes_caffeine_caffeine", "@maven//:com_github_pcj_google_options", From 380f8a1bec163adffc7e0c883abf7f5a160a80ac Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Mon, 16 Oct 2023 11:36:33 -0700 Subject: [PATCH 100/311] feat: add Proto reflection service to shard worker To aid connection troubleshooting --- src/main/java/build/buildfarm/worker/shard/Worker.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/build/buildfarm/worker/shard/Worker.java b/src/main/java/build/buildfarm/worker/shard/Worker.java index 7a0d4a60ed..038097de7f 100644 --- a/src/main/java/build/buildfarm/worker/shard/Worker.java +++ b/src/main/java/build/buildfarm/worker/shard/Worker.java @@ -70,6 +70,7 @@ import io.grpc.Status; import io.grpc.Status.Code; import io.grpc.health.v1.HealthCheckResponse.ServingStatus; +import io.grpc.protobuf.services.ProtoReflectionService; import io.grpc.services.HealthStatusManager; import io.prometheus.client.Counter; import io.prometheus.client.Gauge; @@ -158,6 +159,7 @@ private Server createServer( serverBuilder.addService(new ContentAddressableStorageService(instance)); serverBuilder.addService(new ByteStreamService(instance)); serverBuilder.addService(new ShutDownWorkerGracefully(this)); + serverBuilder.addService(ProtoReflectionService.newInstance()); // We will build a worker's server based on it's capabilities. // A worker that is capable of execution will construct an execution pipeline. From 7e7979d037294d1896ed6ae53d8a966e97ffc609 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Mon, 16 Oct 2023 11:55:18 -0700 Subject: [PATCH 101/311] fixup! build: override grpc dependencies with our dependencies --- defs.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/defs.bzl b/defs.bzl index ad8d07ced8..5b0e4f640c 100644 --- a/defs.bzl +++ b/defs.bzl @@ -8,7 +8,7 @@ load( "@io_bazel_rules_docker//repositories:repositories.bzl", container_repositories = "repositories", ) -load("@io_grpc_grpc_java//:repositories.bzl", "grpc_java_repositories", "IO_GRPC_GRPC_JAVA_OVERRIDE_TARGETS") +load("@io_grpc_grpc_java//:repositories.bzl", "IO_GRPC_GRPC_JAVA_OVERRIDE_TARGETS", "grpc_java_repositories") load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") load("@com_grail_bazel_toolchain//toolchain:rules.bzl", "llvm_toolchain") load("@io_bazel_rules_k8s//k8s:k8s.bzl", "k8s_repositories") From 1f9d01fa70f1ecc419c9fca62f5602e5400d66c6 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Mon, 16 Oct 2023 11:55:29 -0700 Subject: [PATCH 102/311] fixup! chore(deps) add transitive dependencies --- src/main/java/build/buildfarm/server/BUILD | 2 +- src/main/java/build/buildfarm/worker/shard/BUILD | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/build/buildfarm/server/BUILD b/src/main/java/build/buildfarm/server/BUILD index 7244807f8a..2cd750a4ff 100644 --- a/src/main/java/build/buildfarm/server/BUILD +++ b/src/main/java/build/buildfarm/server/BUILD @@ -16,8 +16,8 @@ java_library( "//src/main/java/build/buildfarm/metrics/prometheus", "//src/main/java/build/buildfarm/server/services", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@io_grpc_grpc_proto//:health_proto", "@io_grpc_grpc_proto//:health_java_proto", + "@io_grpc_grpc_proto//:health_proto", "@maven//:com_github_pcj_google_options", "@maven//:com_google_guava_guava", "@maven//:io_grpc_grpc_api", diff --git a/src/main/java/build/buildfarm/worker/shard/BUILD b/src/main/java/build/buildfarm/worker/shard/BUILD index 4458d61821..b62e4369de 100644 --- a/src/main/java/build/buildfarm/worker/shard/BUILD +++ b/src/main/java/build/buildfarm/worker/shard/BUILD @@ -20,9 +20,9 @@ java_library( "//src/main/java/build/buildfarm/worker/resources", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_grpc", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", + "@googleapis//:google_rpc_error_details_java_proto", "@io_grpc_grpc_proto//:health_java_proto", "@io_grpc_grpc_proto//:health_proto", - "@googleapis//:google_rpc_error_details_java_proto", "@maven//:com_github_ben_manes_caffeine_caffeine", "@maven//:com_github_pcj_google_options", "@maven//:com_google_code_findbugs_jsr305", From 578589fe6dfe075bbb92eb68b4235ed7a335afb0 Mon Sep 17 00:00:00 2001 From: amishra-u <119983081+amishra-u@users.noreply.github.com> Date: Tue, 24 Oct 2023 11:00:14 -0700 Subject: [PATCH 103/311] Bug: Fix Blocked thread in WriteStreamObserver Caused by CASFile Write (#1486) * Add unit test * Signal Write on complete --- .../build/buildfarm/cas/cfc/CASFileCache.java | 3 + .../buildfarm/cas/cfc/CASFileCacheTest.java | 113 ++++++++++++++++++ 2 files changed, 116 insertions(+) diff --git a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java index aac1b28994..21c90e5fee 100644 --- a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java +++ b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java @@ -878,6 +878,9 @@ public synchronized void reset() { + key.getIdentifier(), e); } finally { + if (closedFuture != null) { + closedFuture.set(null); + } isReset = true; } } diff --git a/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java b/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java index a3d406e232..caaab02b35 100644 --- a/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java +++ b/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java @@ -19,8 +19,11 @@ import static com.google.common.truth.Truth.assertThat; import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static com.google.common.util.concurrent.MoreExecutors.shutdownAndAwaitTermination; +import static java.lang.Thread.State.TERMINATED; +import static java.lang.Thread.State.WAITING; import static java.util.concurrent.Executors.newSingleThreadExecutor; import static java.util.concurrent.TimeUnit.MICROSECONDS; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.Assert.fail; import static org.mockito.Mockito.any; @@ -58,6 +61,7 @@ import com.google.common.collect.Maps; import com.google.common.jimfs.Configuration; import com.google.common.jimfs.Jimfs; +import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; @@ -77,6 +81,7 @@ import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.CyclicBarrier; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; @@ -1207,6 +1212,114 @@ protected InputStream newExternalInput( assertThat(expected).isNotNull(); } + @Test + public void testConcurrentWrites() throws Exception { + ByteString blob = ByteString.copyFromUtf8("concurrent write"); + Digest digest = DIGEST_UTIL.compute(blob); + UUID uuid = UUID.randomUUID(); + // The same instance of Write will be passed to both the threads, so that the both threads + // try to get same output stream. + Write write = + fileCache.getWrite( + Compressor.Value.IDENTITY, digest, uuid, RequestMetadata.getDefaultInstance()); + + CyclicBarrier barrier = new CyclicBarrier(3); + + Thread write1 = + new Thread( + () -> { + try { + ConcurrentWriteStreamObserver writeStreamObserver = + new ConcurrentWriteStreamObserver(write); + writeStreamObserver.registerCallback(); + barrier.await(); // let both the threads get same write stream. + writeStreamObserver.ownStream(); // let other thread get the ownership of stream + writeStreamObserver.write(blob); + writeStreamObserver.close(); + } catch (Exception e) { + // do nothing + } + }, + "FirstRequest"); + Thread write2 = + new Thread( + () -> { + try { + ConcurrentWriteStreamObserver writeStreamObserver = + new ConcurrentWriteStreamObserver(write); + writeStreamObserver.registerCallback(); + writeStreamObserver.ownStream(); // this thread will get the ownership of stream + barrier.await(); // let both the threads get same write stream. + while (write1.getState() != WAITING) ; // wait for first request to go in wait state + writeStreamObserver.write(blob); + writeStreamObserver.close(); + } catch (Exception e) { + // do nothing + } + }, + "SecondRequest"); + write1.start(); + write2.start(); + barrier.await(); // let both the requests reach the critical section + + // Wait for each write operation to complete, allowing a maximum of 100ms per write. + // Note: A 100ms wait time allowed 1000 * 8 successful test runs. + // In certain scenario, even this wait time may not be enough and test still be called flaky. + // But setting wait time 0 may cause test to wait forever (if there is issue in code) and the + // build might fail with timeout error. + write1.join(100); + write2.join(100); + + assertThat(write1.getState()).isEqualTo(TERMINATED); + assertThat(write2.getState()).isEqualTo(TERMINATED); + } + + static class ConcurrentWriteStreamObserver { + Write write; + FeedbackOutputStream out; + + ConcurrentWriteStreamObserver(Write write) { + this.write = write; + } + + void registerCallback() { + Futures.addCallback( + write.getFuture(), + new FutureCallback() { + @Override + public void onSuccess(Long committedSize) { + commit(); + } + + @Override + public void onFailure(Throwable t) { + // do nothing + } + }, + directExecutor()); + } + + synchronized void ownStream() throws Exception { + this.out = write.getOutput(10, MILLISECONDS, () -> {}); + } + /** + * Request 1 may invoke this method for request 2 or vice-versa via callback on + * write.getFuture(). Synchronization is necessary to prevent conflicts when this method is + * called simultaneously by different threads. + */ + synchronized void commit() { + // critical section + } + + void write(ByteString data) throws IOException { + data.writeTo(out); + } + + void close() throws IOException { + out.close(); + } + } + @RunWith(JUnit4.class) public static class NativeFileDirsIndexInMemoryCASFileCacheTest extends CASFileCacheTest { public NativeFileDirsIndexInMemoryCASFileCacheTest() throws IOException { From dfa5937090d36e7d39fae577c978412367b71c6c Mon Sep 17 00:00:00 2001 From: Stefano Baghino Date: Tue, 24 Oct 2023 21:38:09 +0200 Subject: [PATCH 104/311] Pin the Java toolchain to `remotejdk_17` (#1509) Closes #1508 Cleanups: - remove the unused `ubuntu-bionic` base image - replace `ubuntu-jammy:jammy-java11-gcc` with `ubuntu-mantic:mantic-java17-gcc` - replace `amazoncorretto:19` with `ubuntu-mantic:mantic-java17-gcc` - swap inverted log file names in a file --- .bazelci/run_server_test.sh | 4 ++-- .bazelrc | 6 +++++ BUILD | 6 ++--- images.bzl | 22 +++---------------- jvm_flags.bzl | 10 +++++++-- .../common/processes/JavaProcessWrapper.java | 6 ++++- .../bazel/processes/PersistentWorkerTest.java | 3 ++- src/main/java/build/buildfarm/BUILD | 6 ++--- src/test/java/build/buildfarm/cas/BUILD | 4 ++-- src/test/java/build/buildfarm/common/BUILD | 4 ++-- 10 files changed, 36 insertions(+), 35 deletions(-) diff --git a/.bazelci/run_server_test.sh b/.bazelci/run_server_test.sh index 21b6d70389..54e4658b16 100755 --- a/.bazelci/run_server_test.sh +++ b/.bazelci/run_server_test.sh @@ -8,11 +8,11 @@ bazel build //src/main/java/build/buildfarm:buildfarm-shard-worker bazel build //src/main/java/build/buildfarm:buildfarm-server # Start a single worker -bazel run //src/main/java/build/buildfarm:buildfarm-shard-worker $(pwd)/examples/config.minimal.yml > server.log 2>&1 & +bazel run //src/main/java/build/buildfarm:buildfarm-shard-worker $(pwd)/examples/config.minimal.yml > worker.log 2>&1 & echo "Started buildfarm-shard-worker..." # Start a single server -bazel run //src/main/java/build/buildfarm:buildfarm-server $(pwd)/examples/config.minimal.yml > worker.log 2>&1 & +bazel run //src/main/java/build/buildfarm:buildfarm-server $(pwd)/examples/config.minimal.yml > server.log 2>&1 & echo "Started buildfarm-server..." echo "Wait for startup to finish..." diff --git a/.bazelrc b/.bazelrc index adbb3c68fd..c3caf4d8fb 100644 --- a/.bazelrc +++ b/.bazelrc @@ -1,3 +1,9 @@ +build --java_language_version=17 +build --java_runtime_version=remotejdk_17 + +build --tool_java_language_version=17 +build --tool_java_runtime_version=remotejdk_17 + common --enable_platform_specific_config build:fuse --define=fuse=true diff --git a/BUILD b/BUILD index f552ea9d7b..eb773e1a16 100644 --- a/BUILD +++ b/BUILD @@ -120,7 +120,7 @@ sh_binary( java_image( name = "buildfarm-server", args = ["/app/build_buildfarm/examples/config.minimal.yml"], - base = "@amazon_corretto_java_image_base//image", + base = "@ubuntu-mantic//image", classpath_resources = [ "//src/main/java/build/buildfarm:configs", ], @@ -148,14 +148,14 @@ oss_audit( # Download cgroup-tools so that the worker is able to restrict actions via control groups. download_pkgs( name = "worker_pkgs", - image_tar = "@ubuntu-jammy//image", + image_tar = "@ubuntu-mantic//image", packages = ["cgroup-tools"], tags = ["container"], ) install_pkgs( name = "worker_pkgs_image", - image_tar = "@ubuntu-jammy//image", + image_tar = "@ubuntu-mantic//image", installables_tar = ":worker_pkgs.tar", installation_cleanup_commands = "rm -rf /var/lib/apt/lists/*", output_image_name = "worker_pkgs_image", diff --git a/images.bzl b/images.bzl index 9ab0a8b0b7..939a752ed5 100644 --- a/images.bzl +++ b/images.bzl @@ -27,25 +27,9 @@ def buildfarm_images(): ) container_pull( - name = "ubuntu-bionic", - digest = "sha256:4bc527c7a288da405f2041928c63d0a6479a120ad63461c2f124c944def54be2", + name = "ubuntu-mantic", + digest = "sha256:1419bba15470a95242e917b3abcd8981ae36707b99df5ac705e1eee4d920c51c", registry = "index.docker.io", repository = "bazelbuild/buildfarm-worker-base", - tag = "bionic-java11-gcc", - ) - - container_pull( - name = "ubuntu-jammy", - digest = "sha256:da847ee259ebe7f00631a2f0146d9add60ff0f94b031a2e522ce94c78b1335c2", - registry = "index.docker.io", - repository = "bazelbuild/buildfarm-worker-base", - tag = "jammy-java11-gcc", - ) - - container_pull( - name = "amazon_corretto_java_image_base", - registry = "index.docker.io", - repository = "amazoncorretto", - tag = "19", - digest = "sha256:81d0df4412140416b27211c999e1f3c4565ae89a5cd92889475d20af422ba507", + tag = "mantic-java17-gcc", ) diff --git a/jvm_flags.bzl b/jvm_flags.bzl index 363f161465..440e0718aa 100644 --- a/jvm_flags.bzl +++ b/jvm_flags.bzl @@ -54,6 +54,12 @@ def ensure_accurate_metadata(): "//config:windows": ["-Dsun.nio.fs.ensureAccurateMetadata=true"], }) +def add_opens_sun_nio_fs(): + return select({ + "//conditions:default": [], + "//config:windows": ["--add-opens java.base/sun.nio.fs=ALL-UNNAMED"], + }) + def server_telemetry(): return select({ "//config:open_telemetry": SERVER_TELEMETRY_JVM_FLAGS, @@ -67,7 +73,7 @@ def worker_telemetry(): }) def server_jvm_flags(): - return RECOMMENDED_JVM_FLAGS + DEFAULT_LOGGING_CONFIG + ensure_accurate_metadata() + server_telemetry() + return RECOMMENDED_JVM_FLAGS + DEFAULT_LOGGING_CONFIG + ensure_accurate_metadata() + add_opens_sun_nio_fs() + server_telemetry() def worker_jvm_flags(): - return RECOMMENDED_JVM_FLAGS + DEFAULT_LOGGING_CONFIG + ensure_accurate_metadata() + worker_telemetry() + return RECOMMENDED_JVM_FLAGS + DEFAULT_LOGGING_CONFIG + ensure_accurate_metadata() + add_opens_sun_nio_fs() + worker_telemetry() diff --git a/persistentworkers/src/main/java/persistent/common/processes/JavaProcessWrapper.java b/persistentworkers/src/main/java/persistent/common/processes/JavaProcessWrapper.java index a27b6a9e99..89f2e6a5be 100644 --- a/persistentworkers/src/main/java/persistent/common/processes/JavaProcessWrapper.java +++ b/persistentworkers/src/main/java/persistent/common/processes/JavaProcessWrapper.java @@ -10,12 +10,16 @@ public class JavaProcessWrapper extends ProcessWrapper { + // Get the path of the JVM from the current process to avoid breaking the Bazel sandbox + public static final String CURRENT_JVM_COMMAND = + ProcessHandle.current().info().command().orElseThrow(() -> new RuntimeException("Unable to retrieve the path of the running JVM")); + public JavaProcessWrapper( Path workDir, String classPath, String fullClassName, String[] args ) throws IOException { super(workDir, cmdArgs( new String[]{ - "java", + CURRENT_JVM_COMMAND, "-cp", classPath, fullClassName diff --git a/persistentworkers/src/test/java/persistent/bazel/processes/PersistentWorkerTest.java b/persistentworkers/src/test/java/persistent/bazel/processes/PersistentWorkerTest.java index 0cdc68a7ff..9712394203 100644 --- a/persistentworkers/src/test/java/persistent/bazel/processes/PersistentWorkerTest.java +++ b/persistentworkers/src/test/java/persistent/bazel/processes/PersistentWorkerTest.java @@ -16,6 +16,7 @@ import persistent.bazel.client.PersistentWorker; import persistent.bazel.client.WorkerKey; +import persistent.common.processes.JavaProcessWrapper; import persistent.testutil.ProcessUtils; import persistent.testutil.WorkerUtils; @@ -55,7 +56,7 @@ public void endToEndAdder() throws Exception { ); ImmutableList initCmd = ImmutableList.of( - "java", + JavaProcessWrapper.CURRENT_JVM_COMMAND, "-cp", jarPath.toString(), "adder.Adder", diff --git a/src/main/java/build/buildfarm/BUILD b/src/main/java/build/buildfarm/BUILD index 601aa38eb4..3cbdeb5231 100644 --- a/src/main/java/build/buildfarm/BUILD +++ b/src/main/java/build/buildfarm/BUILD @@ -1,4 +1,4 @@ -load("//:jvm_flags.bzl", "ensure_accurate_metadata") +load("//:jvm_flags.bzl", "add_opens_sun_nio_fs", "ensure_accurate_metadata") package( default_visibility = ["//src:__subpackages__"], @@ -15,7 +15,7 @@ java_binary( classpath_resources = [ ":configs", ], - jvm_flags = ensure_accurate_metadata(), + jvm_flags = ensure_accurate_metadata() + add_opens_sun_nio_fs(), main_class = "build.buildfarm.server.BuildFarmServer", visibility = ["//visibility:public"], runtime_deps = [ @@ -29,7 +29,7 @@ java_binary( classpath_resources = [ ":configs", ], - jvm_flags = ensure_accurate_metadata(), + jvm_flags = ensure_accurate_metadata() + add_opens_sun_nio_fs(), main_class = "build.buildfarm.worker.shard.Worker", visibility = ["//visibility:public"], runtime_deps = [ diff --git a/src/test/java/build/buildfarm/cas/BUILD b/src/test/java/build/buildfarm/cas/BUILD index ff7774e067..fc127b1ea6 100644 --- a/src/test/java/build/buildfarm/cas/BUILD +++ b/src/test/java/build/buildfarm/cas/BUILD @@ -1,10 +1,10 @@ -load("//:jvm_flags.bzl", "ensure_accurate_metadata") +load("//:jvm_flags.bzl", "add_opens_sun_nio_fs", "ensure_accurate_metadata") java_test( name = "tests", size = "small", srcs = glob(["**/*.java"]), - jvm_flags = ensure_accurate_metadata(), + jvm_flags = ensure_accurate_metadata() + add_opens_sun_nio_fs(), test_class = "build.buildfarm.AllTests", deps = [ "//src/main/java/build/buildfarm/cas", diff --git a/src/test/java/build/buildfarm/common/BUILD b/src/test/java/build/buildfarm/common/BUILD index bda4f4243f..70ff4abc94 100644 --- a/src/test/java/build/buildfarm/common/BUILD +++ b/src/test/java/build/buildfarm/common/BUILD @@ -1,10 +1,10 @@ -load("//:jvm_flags.bzl", "ensure_accurate_metadata") +load("//:jvm_flags.bzl", "add_opens_sun_nio_fs", "ensure_accurate_metadata") java_test( name = "tests", size = "small", srcs = glob(["*.java"]), - jvm_flags = ensure_accurate_metadata(), + jvm_flags = ensure_accurate_metadata() + add_opens_sun_nio_fs(), test_class = "build.buildfarm.AllTests", deps = [ "//src/main/java/build/buildfarm/common", From f6459d199d1a40bdd8b31a75d7c19da7a1af69f4 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Wed, 18 Oct 2023 13:32:18 -0700 Subject: [PATCH 105/311] docs: add markdown language specifiers for code blocks --- README.md | 28 ++++++++--------- _site/docs/configuration/configuration.md | 32 ++++++++++---------- _site/docs/execution/execution_policies.md | 26 ++++++++++------ _site/docs/execution/execution_properties.md | 25 +++++++++------ _site/docs/quick_start.md | 25 +++++++++------ 5 files changed, 77 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index 675fe94dbd..cd9caf8ee3 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,8 @@ All commandline options override corresponding config settings. Run via -``` -docker run -d --rm --name buildfarm-redis -p 6379:6379 redis:5.0.9 +```shell +$ docker run -d --rm --name buildfarm-redis -p 6379:6379 redis:5.0.9 redis-cli config set stop-writes-on-bgsave-error no ``` @@ -28,8 +28,8 @@ redis-cli config set stop-writes-on-bgsave-error no Run via -``` -bazelisk run //src/main/java/build/buildfarm:buildfarm-server -- +```shell +$ bazelisk run //src/main/java/build/buildfarm:buildfarm-server -- Ex: bazelisk run //src/main/java/build/buildfarm:buildfarm-server -- --jvm_flag=-Djava.util.logging.config.file=$PWD/examples/logging.properties $PWD/examples/config.minimal.yml ``` @@ -40,8 +40,8 @@ Ex: bazelisk run //src/main/java/build/buildfarm:buildfarm-server -- --jvm_flag= Run via -``` -bazelisk run //src/main/java/build/buildfarm:buildfarm-shard-worker -- +```shell +$ bazelisk run //src/main/java/build/buildfarm:buildfarm-shard-worker -- Ex: bazelisk run //src/main/java/build/buildfarm:buildfarm-shard-worker -- --jvm_flag=-Djava.util.logging.config.file=$PWD/examples/logging.properties $PWD/examples/config.minimal.yml @@ -53,9 +53,9 @@ Ex: bazelisk run //src/main/java/build/buildfarm:buildfarm-shard-worker -- --jvm To use the example configured buildfarm with bazel (version 1.0 or higher), you can configure your `.bazelrc` as follows: -``` +```shell $ cat .bazelrc -build --remote_executor=grpc://localhost:8980 +$ build --remote_executor=grpc://localhost:8980 ``` Then run your build as you would normally do. @@ -67,20 +67,20 @@ Buildfarm uses [Java's Logging framework](https://docs.oracle.com/javase/10/core You can use typical Java logging configuration to filter these results and observe the flow of executions through your running services. An example `logging.properties` file has been provided at [examples/logging.properties](examples/logging.properties) for use as follows: -``` -bazel run //src/main/java/build/buildfarm:buildfarm-server -- --jvm_flag=-Djava.util.logging.config.file=$PWD/examples/logging.properties $PWD/examples/config.minimal.yml +```shell +$ bazel run //src/main/java/build/buildfarm:buildfarm-server -- --jvm_flag=-Djava.util.logging.config.file=$PWD/examples/logging.properties $PWD/examples/config.minimal.yml ``` and -``` -bazel run //src/main/java/build/buildfarm:buildfarm-shard-worker -- --jvm_flag=-Djava.util.logging.config.file=$PWD/examples/logging.properties $PWD/examples/config.minimal.yml +``` shell +$ bazel run //src/main/java/build/buildfarm:buildfarm-shard-worker -- --jvm_flag=-Djava.util.logging.config.file=$PWD/examples/logging.properties $PWD/examples/config.minimal.yml ``` To attach a remote debugger, run the executable with the `--debug=` flag. For example: -``` -bazel run //src/main/java/build/buildfarm:buildfarm-server -- --debug=5005 $PWD/examples/config.minimal.yml +```shell +$ bazel run //src/main/java/build/buildfarm:buildfarm-server -- --debug=5005 $PWD/examples/config.minimal.yml ``` diff --git a/_site/docs/configuration/configuration.md b/_site/docs/configuration/configuration.md index ae913adf88..ab3638f5b1 100644 --- a/_site/docs/configuration/configuration.md +++ b/_site/docs/configuration/configuration.md @@ -7,7 +7,7 @@ has_children: true Minimal required: -``` +```yaml backplane: redisUri: "redis://localhost:6379" queues: @@ -38,7 +38,7 @@ For an example configuration containing all of the configuration values, see `ex Example: -``` +```yaml digestFunction: SHA1 defaultActionTimeout: 1800 maximumActionTimeout: 1800 @@ -79,7 +79,7 @@ worker: Example: -``` +```yaml server: instanceType: SHARD name: shard @@ -96,7 +96,7 @@ server: Example: -``` +```yaml server: grpcMetrics: enabled: false @@ -114,7 +114,7 @@ server: Example: -``` +```yaml server: caches: directoryCacheMaxEntries: 10000 @@ -132,7 +132,7 @@ server: Example: -``` +```yaml server: admin: deploymentEnvironment: AWS @@ -151,14 +151,14 @@ server: Example: -``` +```yaml server: metrics: publisher: log logLevel: INFO ``` -``` +```yaml server: metrics: publisher: aws @@ -207,7 +207,7 @@ server: Example: -``` +```yaml backplane: type: SHARD redisUri: "redis://localhost:6379" @@ -224,7 +224,7 @@ backplane: Example: -``` +```yaml backplane: type: SHARD redisUri: "redis://localhost:6379" @@ -262,7 +262,7 @@ backplane: | realInputDirectories | List of Strings, _external_ | | A list of paths that will not be subject to the effects of linkInputDirectories setting, may also be used to provide writable directories as input roots for actions which expect to be able to write to an input location and will fail if they cannot | | gracefulShutdownSeconds | Integer, 0 | | Time in seconds to allow for operations in flight to finish when shutdown signal is received | -``` +```yaml worker: port: 8981 publicName: "localhost:8981" @@ -279,7 +279,7 @@ worker: Example: -``` +```yaml worker: capabilities: cas: true @@ -296,7 +296,7 @@ worker: Example: -``` +```yaml worker: sandboxSettings: alwaysUse: true @@ -313,7 +313,7 @@ worker: Example: -``` +```yaml worker: dequeueMatchSettings: acceptEverything: true @@ -333,7 +333,7 @@ worker: Example: -``` +```yaml worker: storages: - type: FILESYSTEM @@ -361,7 +361,7 @@ worker: Example: -``` +```yaml worker: executionPolicies: - name: test diff --git a/_site/docs/execution/execution_policies.md b/_site/docs/execution/execution_policies.md index 19698a9925..f0eaf295d9 100644 --- a/_site/docs/execution/execution_policies.md +++ b/_site/docs/execution/execution_policies.md @@ -17,7 +17,7 @@ This policy type specifies that a worker should prepend a single path, and a num This example will use the buildfarm-provided executable `as-nobody`, which will upon execution demote itself to a `nobody` effective process owner uid, and perform an `execvp(2)` with the remaining provided program arguments, which will subsequently execute as a user that no longer matches the worker process. -``` +```yaml # default wrapper policy application worker: executionPolicies: @@ -50,7 +50,8 @@ These wrappers are used for detecting actions that rely on time. Below is a dem This addresses two problems in regards to an action's dependence on time. The 1st problem is when an action takes longer than it should because it's sleeping unnecessarily. The 2nd problem is when an action relies on time which causes it to eventually be broken on master despite the code not changing. Both problems are expressed below as unit tests. We demonstrate a time-spoofing mechanism (the re-writing of syscalls) which allows us to detect these problems generically over any action. The objective is to analyze builds for performance inefficiency and discover future instabilities before they occur. ### Issue 1 (slow test) -``` + +```bash #!/bin/bash set -euo pipefail @@ -58,16 +59,19 @@ echo -n "testing... " sleep 10; echo "done" ``` + The test takes 10 seconds to run on average. -``` -bazel test --runs_per_test=10 --config=remote //cloud/buildfarm:sleep_test + +```shell +$ bazel test --runs_per_test=10 --config=remote //cloud/buildfarm:sleep_test //cloud/buildfarm:sleep_test PASSED in 10.2s Stats over 10 runs: max = 10.2s, min = 10.1s, avg = 10.2s, dev = 0.0s ``` We can check for performance improvements by using the `skip-sleep` option. -``` -bazel test --runs_per_test=10 --config=remote --remote_default_exec_properties='skip-sleep=true' //cloud/buildfarm:sleep_test + +```shell +$ bazel test --runs_per_test=10 --config=remote --remote_default_exec_properties='skip-sleep=true' //cloud/buildfarm:sleep_test //cloud/buildfarm:sleep_test PASSED in 1.0s Stats over 10 runs: max = 1.0s, min = 0.9s, avg = 1.0s, dev = 0.0s ``` @@ -75,7 +79,8 @@ bazel test --runs_per_test=10 --config=remote --remote_default_exec_properties=' Now the test is 10x faster. If skipping sleep makes an action perform significantly faster without affecting its success rate, that would warrant further investigation into the action's implementation. ### Issue 2 (future failing test) -``` + +```bash #!/bin/bash set -euo pipefail @@ -89,12 +94,15 @@ echo "Times change." date exit -1; ``` + The test passes today, but will it pass tomorrow? Will it pass a year from now? We can find out by using the `time-shift` option. -``` -bazel test --test_output=streamed --remote_default_exec_properties='time-shift=31556952' --config=remote //cloud/buildfarm:future_fail + +```shell +$ bazel test --test_output=streamed --remote_default_exec_properties='time-shift=31556952' --config=remote //cloud/buildfarm:future_fail INFO: Found 1 test target... Times change. Mon Sep 25 18:31:09 UTC 2023 //cloud/buildfarm:future_fail FAILED in 18.0s ``` + Time is shifted to the year 2023 and the test now fails. We can fix the problem before others see it. diff --git a/_site/docs/execution/execution_properties.md b/_site/docs/execution/execution_properties.md index 85579ed099..7966c70dd2 100644 --- a/_site/docs/execution/execution_properties.md +++ b/_site/docs/execution/execution_properties.md @@ -76,37 +76,42 @@ Despite being given 1 core, they see all of the cpus and decide to spawn that ma **Standard Example:** This test will succeed when env var TESTVAR is foobar, and fail otherwise. -``` + +```shell #!/bin/bash [ "$TESTVAR" = "foobar" ] ``` -``` -./bazel test \ + +```shell +$ ./bazel test \ --remote_executor=grpc://127.0.0.1:8980 --noremote_accept_cached --nocache_test_results \ //env_test:main FAIL ``` -``` -./bazel test --remote_default_exec_properties='env-vars={"TESTVAR": "foobar"}' \ +```shell +$ ./bazel test --remote_default_exec_properties='env-vars={"TESTVAR": "foobar"}' \ --remote_executor=grpc://127.0.0.1:8980 --noremote_accept_cached --nocache_test_results \ //env_test:main PASS ``` + **Template Example:** If you give a range of cores, buildfarm has the authority to decide how many your operation actually claims. You can let buildfarm resolve this value for you (via [mustache](https://mustache.github.io/)). -``` +```bash #!/bin/bash [ "$MKL_NUM_THREADS" = "1" ] ``` -``` -./bazel test \ + +```shell +$ ./bazel test \ --remote_executor=grpc://127.0.0.1:8980 --noremote_accept_cached --nocache_test_results \ //env_test:main FAIL ``` -``` -./bazel test \ + +```shell +$ ./bazel test \ --remote_default_exec_properties='env-vars="MKL_NUM_THREADS": "{{limits.cpu.claimed}}"' \ --remote_executor=grpc://127.0.0.1:8980 --noremote_accept_cached --nocache_test_results \ //env_test:main diff --git a/_site/docs/quick_start.md b/_site/docs/quick_start.md index 7af957ee63..8a9a9234db 100644 --- a/_site/docs/quick_start.md +++ b/_site/docs/quick_start.md @@ -25,7 +25,8 @@ Let's start with a bazel workspace with a single file to compile into an executa Create a new directory for our workspace and add the following files: `main.cc`: -``` + +```c #include int main( int argc, char *argv[] ) @@ -35,7 +36,8 @@ int main( int argc, char *argv[] ) ``` `BUILD`: -``` + +```starlark cc_binary( name = "main", srcs = ["main.cc"], @@ -118,15 +120,18 @@ That `2 remote` indicates that your compile and link ran remotely. Congratulatio ## Container Quick Start To bring up a minimal buildfarm cluster, you can run: + +```shell +$ ./examples/bf-run start ``` -./examples/bf-run start -``` + This will start all of the necessary containers at the latest version. Once the containers are up, you can build with `bazel run --remote_executor=grpc://localhost:8980 :main`. To stop the containers, run: -``` -./examples/bf-run stop + +```shell +$ ./examples/bf-run stop ``` ## Next Steps @@ -137,8 +142,8 @@ We've started our worker on the same host as our server, and also the same host You can now easily launch a new Buildfarm cluster locally or in AWS using an open sourced [Buildfarm Manager](https://github.com/80degreeswest/bfmgr). -``` -wget https://github.com/80degreeswest/bfmgr/releases/download/1.0.7/bfmgr-1.0.7.jar -java -jar bfmgr-1.0.7.jar -Navigate to http://localhost +```shell +$ wget https://github.com/80degreeswest/bfmgr/releases/download/1.0.7/bfmgr-1.0.7.jar +$ java -jar bfmgr-1.0.7.jar +$ open http://localhost ``` From 018e177642caebf76f8baeeba2b15c7c3b6f5286 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Wed, 25 Oct 2023 16:54:59 -0400 Subject: [PATCH 106/311] Support OutputPaths in OutputDirectory Specifying any number of OutputPaths will ignore OutputFiles (consistent with uploads). Where an OutputPath specifies an output directory, the action must be able to create the directory itself. --- .../worker/shard/CFCExecFileSystem.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java b/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java index 041868f69c..d042ee0fb9 100644 --- a/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java +++ b/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java @@ -397,16 +397,25 @@ private Set linkedDirectories( return ImmutableSet.of(); } + private OutputDirectory createOutputDirectory(Command command) { + Iterable files; + Iterable dirs; + if (command.getOutputPathsCount() != 0) { + files = command.getOutputPathsList(); + dirs = ImmutableList.of(); // output paths require the action to create their own directory + } else { + files = command.getOutputFilesList(); + dirs = command.getOutputDirectoriesList(); + } + return OutputDirectory.parse(files, dirs, command.getEnvironmentVariablesList()); + } + @Override public Path createExecDir( String operationName, Map directoriesIndex, Action action, Command command) throws IOException, InterruptedException { Digest inputRootDigest = action.getInputRootDigest(); - OutputDirectory outputDirectory = - OutputDirectory.parse( - command.getOutputFilesList(), - command.getOutputDirectoriesList(), - command.getEnvironmentVariablesList()); + OutputDirectory outputDirectory = createOutputDirectory(command); Path execDir = root.resolve(operationName); if (Files.exists(execDir)) { From 8b370138da8f21401e78ed3d931e50194b1f4a06 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Thu, 26 Oct 2023 11:50:30 -0400 Subject: [PATCH 107/311] Permit Absolute Symlink Targets with configuration Partial specification of the absolute symlink response per REAPI. Remaining work will be in output identification. --- _site/docs/configuration/configuration.md | 15 +++--- examples/config.yml | 1 + .../common/config/BuildfarmConfigs.java | 1 + .../server/AbstractServerInstance.java | 18 +++++++ .../instance/shard/ShardInstance.java | 14 +++++ .../worker/shard/CFCExecFileSystem.java | 7 ++- .../build/buildfarm/worker/shard/Worker.java | 1 + .../server/AbstractServerInstanceTest.java | 51 +++++++++++++++++++ 8 files changed, 100 insertions(+), 8 deletions(-) diff --git a/_site/docs/configuration/configuration.md b/_site/docs/configuration/configuration.md index ab3638f5b1..ccfc8e026c 100644 --- a/_site/docs/configuration/configuration.md +++ b/_site/docs/configuration/configuration.md @@ -28,13 +28,14 @@ For an example configuration containing all of the configuration values, see `ex ### Common -| Configuration | Accepted and _Default_ Values | Command Line Argument | Description | -|----------------------|-------------------------------|-----------------------|---------------------------------------------------| -| digestFunction | _SHA256_, SHA1 | | Digest function for this implementation | -| defaultActionTimeout | Integer, _600_ | | Default timeout value for an action (seconds) | -| maximumActionTimeout | Integer, _3600_ | | Maximum allowed action timeout (seconds) | -| maxEntrySizeBytes | Long, _2147483648_ | | Maximum size of a single blob accepted (bytes) | -| prometheusPort | Integer, _9090_ | --prometheus_port | Listening port of the Prometheus metrics endpoint | +| Configuration | Accepted and _Default_ Values | Command Line Argument | Description | +|------------------------------|-------------------------------|-----------------------|--------------------------------------------------------------| +| digestFunction | _SHA256_, SHA1 | | Digest function for this implementation | +| defaultActionTimeout | Integer, _600_ | | Default timeout value for an action (seconds) | +| maximumActionTimeout | Integer, _3600_ | | Maximum allowed action timeout (seconds) | +| maxEntrySizeBytes | Long, _2147483648_ | | Maximum size of a single blob accepted (bytes) | +| prometheusPort | Integer, _9090_ | --prometheus_port | Listening port of the Prometheus metrics endpoint | +| allowSymlinkTargetAbsolute | boolean, _false_ | | Permit inputs to contain symlinks with absolute path targets | Example: diff --git a/examples/config.yml b/examples/config.yml index bce19a3d60..5229fcd07c 100644 --- a/examples/config.yml +++ b/examples/config.yml @@ -3,6 +3,7 @@ defaultActionTimeout: 600 maximumActionTimeout: 3600 maxEntrySizeBytes: 2147483648 # 2 * 1024 * 1024 * 1024 prometheusPort: 9090 +allowSymlinkTargetAbsolute: false server: instanceType: SHARD name: shard diff --git a/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java b/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java index 444d25a13d..d6ebbe9e14 100644 --- a/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java +++ b/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java @@ -36,6 +36,7 @@ public final class BuildfarmConfigs { private long maximumActionTimeout = 3600; private long maxEntrySizeBytes = 2147483648L; // 2 * 1024 * 1024 * 1024 private int prometheusPort = 9090; + private boolean allowSymlinkTargetAbsolute = false; private Server server = new Server(); private Backplane backplane = new Backplane(); private Worker worker = new Worker(); diff --git a/src/main/java/build/buildfarm/instance/server/AbstractServerInstance.java b/src/main/java/build/buildfarm/instance/server/AbstractServerInstance.java index d828b7bd89..541e13701d 100644 --- a/src/main/java/build/buildfarm/instance/server/AbstractServerInstance.java +++ b/src/main/java/build/buildfarm/instance/server/AbstractServerInstance.java @@ -178,6 +178,8 @@ public abstract class AbstractServerInstance implements Instance { public static final String ENVIRONMENT_VARIABLES_NOT_SORTED = "The `Command`'s `environment_variables` are not correctly sorted by `name`."; + public static final String SYMLINK_TARGET_ABSOLUTE = "A symlink target is absolute."; + public static final String MISSING_ACTION = "The action was not found in the CAS."; public static final String MISSING_COMMAND = "The command was not found in the CAS."; @@ -790,6 +792,7 @@ public static void validateActionInputDirectory( Stack pathDigests, Set visited, Map directoriesIndex, + boolean allowSymlinkTargetAbsolute, Consumer onInputFile, Consumer onInputDirectory, Consumer onInputDigest, @@ -838,6 +841,14 @@ public static void validateActionInputDirectory( .setSubject("/" + directoryPath + ": " + lastSymlinkName + " > " + symlinkName) .setDescription(DIRECTORY_NOT_SORTED); } + String symlinkTarget = symlinkNode.getTarget(); + if (!allowSymlinkTargetAbsolute && symlinkTarget.charAt(0) == '/') { + preconditionFailure + .addViolationsBuilder() + .setType(VIOLATION_TYPE_INVALID) + .setSubject("/" + directoryPath + ": " + symlinkName + " -> " + symlinkTarget) + .setDescription(SYMLINK_TARGET_ABSOLUTE); + } /* FIXME serverside validity check? regex? Preconditions.checkState( isValidFilename(symlinkName), @@ -907,6 +918,7 @@ public static void validateActionInputDirectory( pathDigests, visited, directoriesIndex, + allowSymlinkTargetAbsolute, onInputFile, onInputDirectory, onInputDigest, @@ -922,6 +934,7 @@ private static void validateActionInputDirectoryDigest( Stack pathDigests, Set visited, Map directoriesIndex, + boolean allowSymlinkTargetAbsolute, Consumer onInputFile, Consumer onInputDirectory, Consumer onInputDigest, @@ -946,6 +959,7 @@ private static void validateActionInputDirectoryDigest( pathDigests, visited, directoriesIndex, + allowSymlinkTargetAbsolute, onInputFile, onInputDirectory, onInputDigest, @@ -1203,12 +1217,16 @@ protected void validateAction( ImmutableSet.Builder inputFilesBuilder = ImmutableSet.builder(); inputDirectoriesBuilder.add(ACTION_INPUT_ROOT_DIRECTORY_PATH); + boolean allowSymlinkTargetAbsolute = + getCacheCapabilities().getSymlinkAbsolutePathStrategy() + == SymlinkAbsolutePathStrategy.Value.ALLOWED; validateActionInputDirectoryDigest( ACTION_INPUT_ROOT_DIRECTORY_PATH, action.getInputRootDigest(), new Stack<>(), new HashSet<>(), directoriesIndex, + allowSymlinkTargetAbsolute, inputFilesBuilder::add, inputDirectoriesBuilder::add, onInputDigest, diff --git a/src/main/java/build/buildfarm/instance/shard/ShardInstance.java b/src/main/java/build/buildfarm/instance/shard/ShardInstance.java index c1c07b08f0..241f1a8fa1 100644 --- a/src/main/java/build/buildfarm/instance/shard/ShardInstance.java +++ b/src/main/java/build/buildfarm/instance/shard/ShardInstance.java @@ -47,6 +47,7 @@ import build.bazel.remote.execution.v2.Action; import build.bazel.remote.execution.v2.ActionResult; import build.bazel.remote.execution.v2.BatchReadBlobsResponse.Response; +import build.bazel.remote.execution.v2.CacheCapabilities; import build.bazel.remote.execution.v2.Command; import build.bazel.remote.execution.v2.Compressor; import build.bazel.remote.execution.v2.Digest; @@ -60,6 +61,7 @@ import build.bazel.remote.execution.v2.Platform.Property; import build.bazel.remote.execution.v2.RequestMetadata; import build.bazel.remote.execution.v2.ResultsCachePolicy; +import build.bazel.remote.execution.v2.SymlinkAbsolutePathStrategy; import build.buildfarm.actioncache.ActionCache; import build.buildfarm.actioncache.ShardActionCache; import build.buildfarm.backplane.Backplane; @@ -2726,4 +2728,16 @@ private boolean inDenyList(RequestMetadata requestMetadata) throws IOException { } return backplane.isBlacklisted(requestMetadata); } + + @Override + protected CacheCapabilities getCacheCapabilities() { + SymlinkAbsolutePathStrategy.Value symlinkAbsolutePathStrategy = + configs.isAllowSymlinkTargetAbsolute() + ? SymlinkAbsolutePathStrategy.Value.ALLOWED + : SymlinkAbsolutePathStrategy.Value.DISALLOWED; + return super.getCacheCapabilities() + .toBuilder() + .setSymlinkAbsolutePathStrategy(symlinkAbsolutePathStrategy) + .build(); + } } diff --git a/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java b/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java index d042ee0fb9..dba809fdcf 100644 --- a/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java +++ b/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java @@ -82,6 +82,9 @@ class CFCExecFileSystem implements ExecFileSystem { // indicate symlinking above for a set of matching paths private final Iterable linkedInputDirectories; + // permit symlinks to point to absolute paths in inputs + private final boolean allowSymlinkTargetAbsolute; + private final Map> rootInputFiles = new ConcurrentHashMap<>(); private final Map> rootInputDirectories = new ConcurrentHashMap<>(); private final ExecutorService fetchService = BuildfarmExecutors.getFetchServicePool(); @@ -95,6 +98,7 @@ class CFCExecFileSystem implements ExecFileSystem { @Nullable UserPrincipal owner, boolean linkInputDirectories, Iterable linkedInputDirectories, + boolean allowSymlinkTargetAbsolute, ExecutorService removeDirectoryService, ExecutorService accessRecorder) { this.root = root; @@ -104,6 +108,7 @@ class CFCExecFileSystem implements ExecFileSystem { this.linkedInputDirectories = Iterables.transform( linkedInputDirectories, realInputDirectory -> Pattern.compile(realInputDirectory)); + this.allowSymlinkTargetAbsolute = allowSymlinkTargetAbsolute; this.removeDirectoryService = removeDirectoryService; this.accessRecorder = accessRecorder; } @@ -179,7 +184,7 @@ public InputStream newInput(Compressor.Value compressor, Digest digest, long off private ListenableFuture putSymlink(Path path, SymlinkNode symlinkNode) { Path symlinkPath = path.resolve(symlinkNode.getName()); Path relativeTargetPath = path.getFileSystem().getPath(symlinkNode.getTarget()); - checkState(!relativeTargetPath.isAbsolute()); + checkState(allowSymlinkTargetAbsolute || !relativeTargetPath.isAbsolute()); return listeningDecorator(fetchService) .submit( () -> { diff --git a/src/main/java/build/buildfarm/worker/shard/Worker.java b/src/main/java/build/buildfarm/worker/shard/Worker.java index 038097de7f..eaf8b6cb1a 100644 --- a/src/main/java/build/buildfarm/worker/shard/Worker.java +++ b/src/main/java/build/buildfarm/worker/shard/Worker.java @@ -337,6 +337,7 @@ private ExecFileSystem createCFCExecFileSystem( owner, configs.getWorker().isLinkInputDirectories(), configs.getWorker().getLinkedInputDirectories(), + configs.isAllowSymlinkTargetAbsolute(), removeDirectoryService, accessRecorder /* deadlineAfter=*/ diff --git a/src/test/java/build/buildfarm/instance/server/AbstractServerInstanceTest.java b/src/test/java/build/buildfarm/instance/server/AbstractServerInstanceTest.java index add9136633..a23afaf0f7 100644 --- a/src/test/java/build/buildfarm/instance/server/AbstractServerInstanceTest.java +++ b/src/test/java/build/buildfarm/instance/server/AbstractServerInstanceTest.java @@ -23,6 +23,7 @@ import static build.buildfarm.instance.server.AbstractServerInstance.INVALID_COMMAND; import static build.buildfarm.instance.server.AbstractServerInstance.OUTPUT_DIRECTORY_IS_OUTPUT_ANCESTOR; import static build.buildfarm.instance.server.AbstractServerInstance.OUTPUT_FILE_IS_OUTPUT_ANCESTOR; +import static build.buildfarm.instance.server.AbstractServerInstance.SYMLINK_TARGET_ABSOLUTE; import static com.google.common.truth.Truth.assertThat; import static com.google.common.util.concurrent.Futures.immediateFuture; import static org.mockito.Mockito.any; @@ -43,6 +44,7 @@ import build.bazel.remote.execution.v2.OutputDirectory; import build.bazel.remote.execution.v2.Platform; import build.bazel.remote.execution.v2.RequestMetadata; +import build.bazel.remote.execution.v2.SymlinkNode; import build.bazel.remote.execution.v2.Tree; import build.buildfarm.actioncache.ActionCache; import build.buildfarm.cas.ContentAddressableStorage; @@ -270,6 +272,7 @@ public void duplicateFileInputIsInvalid() { /* pathDigests=*/ new Stack<>(), /* visited=*/ Sets.newHashSet(), /* directoriesIndex=*/ Maps.newHashMap(), + /* allowSymlinkTargetAbsolute=*/ false, /* onInputFile=*/ file -> {}, /* onInputDirectorie=*/ directory -> {}, /* onInputDigest=*/ digest -> {}, @@ -304,6 +307,7 @@ public void duplicateEmptyDirectoryCheckPasses() throws StatusException { /* pathDigests=*/ new Stack<>(), /* visited=*/ Sets.newHashSet(), /* directoriesIndex=*/ ImmutableMap.of(Digest.getDefaultInstance(), emptyDirectory), + /* allowSymlinkTargetAbsolute=*/ false, /* onInputFiles=*/ file -> {}, /* onInputDirectories=*/ directory -> {}, /* onInputDigests=*/ digest -> {}, @@ -327,6 +331,7 @@ public void unsortedFileInputIsInvalid() { /* pathDigests=*/ new Stack<>(), /* visited=*/ Sets.newHashSet(), /* directoriesIndex=*/ Maps.newHashMap(), + /* allowSymlinkTargetAbsolute=*/ false, /* onInputFiles=*/ file -> {}, /* onInputDirectories=*/ directory -> {}, /* onInputDigests=*/ digest -> {}, @@ -361,6 +366,7 @@ public void duplicateDirectoryInputIsInvalid() { /* pathDigests=*/ new Stack<>(), /* visited=*/ Sets.newHashSet(), /* directoriesIndex=*/ ImmutableMap.of(emptyDirectoryDigest, emptyDirectory), + /* allowSymlinkTargetAbsolute=*/ false, /* onInputFiles=*/ file -> {}, /* onInputDirectories=*/ directory -> {}, /* onInputDigests=*/ digest -> {}, @@ -395,6 +401,7 @@ public void unsortedDirectoryInputIsInvalid() { /* pathDigests=*/ new Stack<>(), /* visited=*/ Sets.newHashSet(), /* directoriesIndex=*/ ImmutableMap.of(emptyDirectoryDigest, emptyDirectory), + /* allowSymlinkTargetAbsolute=*/ false, /* onInputFiles=*/ file -> {}, /* onInputDirectories=*/ directory -> {}, /* onInputDigests=*/ digest -> {}, @@ -407,6 +414,48 @@ public void unsortedDirectoryInputIsInvalid() { assertThat(violation.getDescription()).isEqualTo(DIRECTORY_NOT_SORTED); } + @Test + public void shouldValidateIfSymlinkTargetAbsolute() { + // invalid for disallowed + PreconditionFailure.Builder preconditionFailure = PreconditionFailure.newBuilder(); + Directory absoluteSymlinkDirectory = + Directory.newBuilder() + .addSymlinks(SymlinkNode.newBuilder().setName("foo").setTarget("/root/secret").build()) + .build(); + AbstractServerInstance.validateActionInputDirectory( + ACTION_INPUT_ROOT_DIRECTORY_PATH, + absoluteSymlinkDirectory, + /* pathDigests=*/ new Stack<>(), + /* visited=*/ Sets.newHashSet(), + /* directoriesIndex=*/ Maps.newHashMap(), + /* allowSymlinkTargetAbsolute=*/ false, + /* onInputFile=*/ file -> {}, + /* onInputDirectorie=*/ directory -> {}, + /* onInputDigest=*/ digest -> {}, + preconditionFailure); + + assertThat(preconditionFailure.getViolationsCount()).isEqualTo(1); + Violation violation = preconditionFailure.getViolationsList().get(0); + assertThat(violation.getType()).isEqualTo(VIOLATION_TYPE_INVALID); + assertThat(violation.getSubject()).isEqualTo("/: foo -> /root/secret"); + assertThat(violation.getDescription()).isEqualTo(SYMLINK_TARGET_ABSOLUTE); + + // valid for allowed + preconditionFailure = PreconditionFailure.newBuilder(); + AbstractServerInstance.validateActionInputDirectory( + ACTION_INPUT_ROOT_DIRECTORY_PATH, + absoluteSymlinkDirectory, + /* pathDigests=*/ new Stack<>(), + /* visited=*/ Sets.newHashSet(), + /* directoriesIndex=*/ Maps.newHashMap(), + /* allowSymlinkTargetAbsolute=*/ true, + /* onInputFile=*/ file -> {}, + /* onInputDirectorie=*/ directory -> {}, + /* onInputDigest=*/ digest -> {}, + preconditionFailure); + assertThat(preconditionFailure.getViolationsCount()).isEqualTo(0); + } + @Test public void nestedOutputDirectoriesAreInvalid() { PreconditionFailure.Builder preconditionFailureBuilder = PreconditionFailure.newBuilder(); @@ -547,6 +596,7 @@ public void multipleIdenticalDirectoryMissingAreAllPreconditionFailures() { /* pathDigests=*/ new Stack<>(), /* visited=*/ Sets.newHashSet(), /* directoriesIndex=*/ ImmutableMap.of(), + /* allowSymlinkTargetAbsolute=*/ false, /* onInputFiles=*/ file -> {}, /* onInputDirectories=*/ directory -> {}, /* onInputDigests=*/ digest -> {}, @@ -608,6 +658,7 @@ public void validationRevisitReplicatesPreconditionFailures() { /* pathDigests=*/ new Stack<>(), /* visited=*/ Sets.newHashSet(), /* directoriesIndex=*/ ImmutableMap.of(fooDigest, foo), + /* allowSymlinkTargetAbsolute=*/ false, /* onInputFiles=*/ file -> {}, /* onInputDirectories=*/ directory -> {}, /* onInputDigests=*/ digest -> {}, From df9ce1ddbd0a51b22eb535152794601125d59b84 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Sun, 29 Oct 2023 14:05:45 -0700 Subject: [PATCH 108/311] chore: update bazel to 6.4.0 (#1513) Trying to get more info on the Lombok stamping issue on Windows CI. See also https://github.com/bazelbuild/bazel/issues/10363 and https://github.com/bazelbuild/bazel/pull/18185 --- .bazelversion | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bazelversion b/.bazelversion index 5e3254243a..19b860c187 100644 --- a/.bazelversion +++ b/.bazelversion @@ -1 +1 @@ -6.1.2 +6.4.0 From bd740c93510bc9c5abe2ba1860ae10bbbf4eae08 Mon Sep 17 00:00:00 2001 From: Trevor Hickey Date: Mon, 30 Oct 2023 12:22:15 -0400 Subject: [PATCH 109/311] Rename instance types (#1514) --- .../src/main/resources/proto/buildfarm.proto | 8 +-- .../build/buildfarm/instance/server/BUILD | 2 +- ...tServerInstance.java => NodeInstance.java} | 11 ++-- .../shard/RemoteInputStreamFactory.java | 2 +- ...ShardInstance.java => ServerInstance.java} | 28 +++++----- .../buildfarm/server/BuildFarmServer.java | 6 +-- .../build/buildfarm/worker/shard/Worker.java | 5 +- ...orkerInstance.java => WorkerInstance.java} | 8 +-- ...nstanceTest.java => NodeInstanceTest.java} | 53 +++++++++---------- .../java/build/buildfarm/instance/shard/BUILD | 4 +- ...tanceTest.java => ServerInstanceTest.java} | 12 ++--- ...tanceTest.java => WorkerInstanceTest.java} | 6 +-- 12 files changed, 71 insertions(+), 74 deletions(-) rename src/main/java/build/buildfarm/instance/server/{AbstractServerInstance.java => NodeInstance.java} (99%) rename src/main/java/build/buildfarm/instance/shard/{ShardInstance.java => ServerInstance.java} (99%) rename src/main/java/build/buildfarm/worker/shard/{ShardWorkerInstance.java => WorkerInstance.java} (98%) rename src/test/java/build/buildfarm/instance/server/{AbstractServerInstanceTest.java => NodeInstanceTest.java} (94%) rename src/test/java/build/buildfarm/instance/shard/{ShardInstanceTest.java => ServerInstanceTest.java} (99%) rename src/test/java/build/buildfarm/worker/shard/{ShardWorkerInstanceTest.java => WorkerInstanceTest.java} (97%) diff --git a/admin/main/src/main/resources/proto/buildfarm.proto b/admin/main/src/main/resources/proto/buildfarm.proto index 8a000132a3..d391847cb9 100644 --- a/admin/main/src/main/resources/proto/buildfarm.proto +++ b/admin/main/src/main/resources/proto/buildfarm.proto @@ -520,7 +520,7 @@ message RedisShardBackplaneConfig { int32 max_attempts = 33; } -message ShardInstanceConfig { +message ServerInstanceConfig { bool run_dispatched_monitor = 1; int32 dispatched_monitor_interval_seconds = 2; @@ -544,7 +544,7 @@ message ShardInstanceConfig { google.protobuf.Duration grpc_timeout = 8; } -message ShardWorkerInstanceConfig { +message WorkerInstanceConfig { // whether to stream stdout from processes bool stream_stdout = 6; @@ -568,7 +568,7 @@ message ShardWorkerInstanceConfig { } message ShardWorkerConfig { - ShardWorkerInstanceConfig shard_worker_instance_config = 1; + WorkerInstanceConfig shard_worker_instance_config = 1; int32 port = 2; @@ -836,7 +836,7 @@ message InstanceConfig { oneof type { MemoryInstanceConfig memory_instance_config = 3; - ShardInstanceConfig shard_instance_config = 4; + ServerInstanceConfig shard_instance_config = 4; } } diff --git a/src/main/java/build/buildfarm/instance/server/BUILD b/src/main/java/build/buildfarm/instance/server/BUILD index ecff968e79..1c63e9896c 100644 --- a/src/main/java/build/buildfarm/instance/server/BUILD +++ b/src/main/java/build/buildfarm/instance/server/BUILD @@ -1,8 +1,8 @@ java_library( name = "server", srcs = [ - "AbstractServerInstance.java", "GetDirectoryFunction.java", + "NodeInstance.java", "OperationsMap.java", "WatchFuture.java", ], diff --git a/src/main/java/build/buildfarm/instance/server/AbstractServerInstance.java b/src/main/java/build/buildfarm/instance/server/NodeInstance.java similarity index 99% rename from src/main/java/build/buildfarm/instance/server/AbstractServerInstance.java rename to src/main/java/build/buildfarm/instance/server/NodeInstance.java index 541e13701d..e44305f32e 100644 --- a/src/main/java/build/buildfarm/instance/server/AbstractServerInstance.java +++ b/src/main/java/build/buildfarm/instance/server/NodeInstance.java @@ -144,7 +144,7 @@ import lombok.extern.java.Log; @Log -public abstract class AbstractServerInstance implements Instance { +public abstract class NodeInstance implements Instance { private final String name; protected final ContentAddressableStorage contentAddressableStorage; protected final ActionCache actionCache; @@ -229,7 +229,7 @@ public abstract class AbstractServerInstance implements Instance { public static final String NO_REQUEUE_COMPLETE_MESSAGE = "Operation %s not requeued. Operation has already completed."; - public AbstractServerInstance( + public NodeInstance( String name, DigestUtil digestUtil, ContentAddressableStorage contentAddressableStorage, @@ -1967,19 +1967,18 @@ public ServerCapabilities getCapabilities() { @Override public WorkerProfileMessage getWorkerProfile() { throw new UnsupportedOperationException( - "AbstractServerInstance doesn't support getWorkerProfile() method."); + "NodeInstance doesn't support getWorkerProfile() method."); } @Override public WorkerListMessage getWorkerList() { - throw new UnsupportedOperationException( - "AbstractServerInstance doesn't support getWorkerList() method."); + throw new UnsupportedOperationException("NodeInstance doesn't support getWorkerList() method."); } @Override public PrepareWorkerForGracefulShutDownRequestResults shutDownWorkerGracefully() { throw new UnsupportedOperationException( - "AbstractServerInstance doesn't support drainWorkerPipeline() method."); + "NodeInstance doesn't support drainWorkerPipeline() method."); } @Override diff --git a/src/main/java/build/buildfarm/instance/shard/RemoteInputStreamFactory.java b/src/main/java/build/buildfarm/instance/shard/RemoteInputStreamFactory.java index 640878707f..8a00e9ae96 100644 --- a/src/main/java/build/buildfarm/instance/shard/RemoteInputStreamFactory.java +++ b/src/main/java/build/buildfarm/instance/shard/RemoteInputStreamFactory.java @@ -30,7 +30,7 @@ import build.buildfarm.common.DigestUtil; import build.buildfarm.common.InputStreamFactory; import build.buildfarm.instance.Instance; -import build.buildfarm.instance.shard.ShardInstance.WorkersCallback; +import build.buildfarm.instance.shard.ServerInstance.WorkersCallback; import com.google.common.base.Throwables; import com.google.common.cache.LoadingCache; import com.google.common.collect.Iterables; diff --git a/src/main/java/build/buildfarm/instance/shard/ShardInstance.java b/src/main/java/build/buildfarm/instance/shard/ServerInstance.java similarity index 99% rename from src/main/java/build/buildfarm/instance/shard/ShardInstance.java rename to src/main/java/build/buildfarm/instance/shard/ServerInstance.java index 241f1a8fa1..ab865b0e0e 100644 --- a/src/main/java/build/buildfarm/instance/shard/ShardInstance.java +++ b/src/main/java/build/buildfarm/instance/shard/ServerInstance.java @@ -81,7 +81,7 @@ import build.buildfarm.common.grpc.UniformDelegateServerCallStreamObserver; import build.buildfarm.instance.Instance; import build.buildfarm.instance.MatchListener; -import build.buildfarm.instance.server.AbstractServerInstance; +import build.buildfarm.instance.server.NodeInstance; import build.buildfarm.operations.EnrichedOperation; import build.buildfarm.operations.FindOperationsResults; import build.buildfarm.v1test.BackplaneStatus; @@ -167,7 +167,7 @@ import lombok.extern.java.Log; @Log -public class ShardInstance extends AbstractServerInstance { +public class ServerInstance extends NodeInstance { private static final ListenableFuture IMMEDIATE_VOID_FUTURE = Futures.immediateFuture(null); private static final String TIMEOUT_OUT_OF_BOUNDS = @@ -259,14 +259,14 @@ private static Backplane createBackplane(String identifier) throws Configuration identifier, /* subscribeToBackplane=*/ true, configs.getServer().isRunFailsafeOperation(), - ShardInstance::stripOperation, - ShardInstance::stripQueuedOperation); + ServerInstance::stripOperation, + ServerInstance::stripQueuedOperation); } else { throw new IllegalArgumentException("Shard Backplane not set in config"); } } - public ShardInstance(String name, String identifier, DigestUtil digestUtil, Runnable onStop) + public ServerInstance(String name, String identifier, DigestUtil digestUtil, Runnable onStop) throws InterruptedException, ConfigurationException { this( name, @@ -276,7 +276,7 @@ public ShardInstance(String name, String identifier, DigestUtil digestUtil, Runn /* actionCacheFetchService=*/ BuildfarmExecutors.getActionCacheFetchServicePool()); } - private ShardInstance( + private ServerInstance( String name, DigestUtil digestUtil, Backplane backplane, @@ -328,7 +328,7 @@ void initializeCaches() { .build(); } - public ShardInstance( + public ServerInstance( String name, DigestUtil digestUtil, Backplane backplane, @@ -1086,7 +1086,7 @@ public void onError(Throwable t) { backplane, workerSet, locationSet, - ShardInstance.this::workerStub, + ServerInstance.this::workerStub, blobDigest, directExecutor(), RequestMetadata.getDefaultInstance()), @@ -2251,7 +2251,7 @@ public ListenableFuture queue(ExecuteEntry executeEntry, Poller poller, Du log.log( Level.FINER, format( - "ShardInstance(%s): checkCache(%s): %sus elapsed", + "ServerInstance(%s): checkCache(%s): %sus elapsed", getName(), operation.getName(), checkCacheUSecs)); return IMMEDIATE_VOID_FUTURE; } @@ -2278,7 +2278,7 @@ private ListenableFuture transformAndQueue( log.log( Level.FINER, format( - "ShardInstance(%s): queue(%s): fetching action %s", + "ServerInstance(%s): queue(%s): fetching action %s", getName(), operation.getName(), actionDigest.getHash())); RequestMetadata requestMetadata = executeEntry.getRequestMetadata(); ListenableFuture actionFuture = @@ -2321,7 +2321,7 @@ private ListenableFuture transformAndQueue( log.log( Level.FINER, format( - "ShardInstance(%s): queue(%s): fetched action %s transforming queuedOperation", + "ServerInstance(%s): queue(%s): fetched action %s transforming queuedOperation", getName(), operation.getName(), actionDigest.getHash())); Stopwatch transformStopwatch = Stopwatch.createStarted(); return transform( @@ -2351,7 +2351,7 @@ private ListenableFuture transformAndQueue( log.log( Level.FINER, format( - "ShardInstance(%s): queue(%s): queuedOperation %s transformed, validating", + "ServerInstance(%s): queue(%s): queuedOperation %s transformed, validating", getName(), operation.getName(), DigestUtil.toString( @@ -2373,7 +2373,7 @@ private ListenableFuture transformAndQueue( log.log( Level.FINER, format( - "ShardInstance(%s): queue(%s): queuedOperation %s validated, uploading", + "ServerInstance(%s): queue(%s): queuedOperation %s validated, uploading", getName(), operation.getName(), DigestUtil.toString( @@ -2425,7 +2425,7 @@ public void onSuccess(ProfiledQueuedOperationMetadata profiledQueuedMetadata) { log.log( Level.FINER, format( - "ShardInstance(%s): queue(%s): %dus checkCache, %dus transform, %dus validate, %dus upload, %dus queue, %dus elapsed", + "ServerInstance(%s): queue(%s): %dus checkCache, %dus transform, %dus validate, %dus upload, %dus queue, %dus elapsed", getName(), queueOperation.getName(), checkCacheUSecs, diff --git a/src/main/java/build/buildfarm/server/BuildFarmServer.java b/src/main/java/build/buildfarm/server/BuildFarmServer.java index a20f4a6f77..8672c0df76 100644 --- a/src/main/java/build/buildfarm/server/BuildFarmServer.java +++ b/src/main/java/build/buildfarm/server/BuildFarmServer.java @@ -29,7 +29,7 @@ import build.buildfarm.common.services.ByteStreamService; import build.buildfarm.common.services.ContentAddressableStorageService; import build.buildfarm.instance.Instance; -import build.buildfarm.instance.shard.ShardInstance; +import build.buildfarm.instance.shard.ServerInstance; import build.buildfarm.metrics.prometheus.PrometheusPublisher; import build.buildfarm.server.services.ActionCacheService; import build.buildfarm.server.services.CapabilitiesService; @@ -109,9 +109,9 @@ public void prepareServerForGracefulShutdown() { } } - private ShardInstance createInstance() + private ServerInstance createInstance() throws IOException, ConfigurationException, InterruptedException { - return new ShardInstance( + return new ServerInstance( configs.getServer().getName(), configs.getServer().getSession() + "-" + configs.getServer().getName(), new DigestUtil(configs.getDigestFunction()), diff --git a/src/main/java/build/buildfarm/worker/shard/Worker.java b/src/main/java/build/buildfarm/worker/shard/Worker.java index eaf8b6cb1a..fd556fc8e8 100644 --- a/src/main/java/build/buildfarm/worker/shard/Worker.java +++ b/src/main/java/build/buildfarm/worker/shard/Worker.java @@ -123,7 +123,7 @@ public final class Worker extends LoggingMain { private boolean inGracefulShutdown = false; private boolean isPaused = false; - private ShardWorkerInstance instance; + private WorkerInstance instance; @SuppressWarnings("deprecation") private final HealthStatusManager healthStatusManager = new HealthStatusManager(); @@ -532,8 +532,7 @@ public void start() throws ConfigurationException, InterruptedException, IOExcep remoteInputStreamFactory, removeDirectoryService, accessRecorder, storage); instance = - new ShardWorkerInstance( - configs.getWorker().getPublicName(), digestUtil, backplane, storage); + new WorkerInstance(configs.getWorker().getPublicName(), digestUtil, backplane, storage); // Create the appropriate writer for the context CasWriter writer; diff --git a/src/main/java/build/buildfarm/worker/shard/ShardWorkerInstance.java b/src/main/java/build/buildfarm/worker/shard/WorkerInstance.java similarity index 98% rename from src/main/java/build/buildfarm/worker/shard/ShardWorkerInstance.java rename to src/main/java/build/buildfarm/worker/shard/WorkerInstance.java index a891af7faa..e100417f53 100644 --- a/src/main/java/build/buildfarm/worker/shard/ShardWorkerInstance.java +++ b/src/main/java/build/buildfarm/worker/shard/WorkerInstance.java @@ -36,7 +36,7 @@ import build.buildfarm.common.Write; import build.buildfarm.common.grpc.UniformDelegateServerCallStreamObserver; import build.buildfarm.instance.MatchListener; -import build.buildfarm.instance.server.AbstractServerInstance; +import build.buildfarm.instance.server.NodeInstance; import build.buildfarm.operations.EnrichedOperation; import build.buildfarm.operations.FindOperationsResults; import build.buildfarm.v1test.BackplaneStatus; @@ -68,13 +68,13 @@ import lombok.extern.java.Log; @Log -public class ShardWorkerInstance extends AbstractServerInstance { +public class WorkerInstance extends NodeInstance { private static final Counter IO_METRIC = Counter.build().name("io_bytes_read").help("Read I/O (bytes)").register(); private final Backplane backplane; - public ShardWorkerInstance( + public WorkerInstance( String name, DigestUtil digestUtil, Backplane backplane, @@ -346,7 +346,7 @@ protected static ExecuteOperationMetadata expectExecuteOperationMetadata(Operati return null; } } else { - return AbstractServerInstance.expectExecuteOperationMetadata(operation); + return NodeInstance.expectExecuteOperationMetadata(operation); } } diff --git a/src/test/java/build/buildfarm/instance/server/AbstractServerInstanceTest.java b/src/test/java/build/buildfarm/instance/server/NodeInstanceTest.java similarity index 94% rename from src/test/java/build/buildfarm/instance/server/AbstractServerInstanceTest.java rename to src/test/java/build/buildfarm/instance/server/NodeInstanceTest.java index a23afaf0f7..454440281f 100644 --- a/src/test/java/build/buildfarm/instance/server/AbstractServerInstanceTest.java +++ b/src/test/java/build/buildfarm/instance/server/NodeInstanceTest.java @@ -17,13 +17,13 @@ import static build.buildfarm.common.Actions.checkPreconditionFailure; import static build.buildfarm.common.Errors.VIOLATION_TYPE_INVALID; import static build.buildfarm.common.Errors.VIOLATION_TYPE_MISSING; -import static build.buildfarm.instance.server.AbstractServerInstance.ACTION_INPUT_ROOT_DIRECTORY_PATH; -import static build.buildfarm.instance.server.AbstractServerInstance.DIRECTORY_NOT_SORTED; -import static build.buildfarm.instance.server.AbstractServerInstance.DUPLICATE_DIRENT; -import static build.buildfarm.instance.server.AbstractServerInstance.INVALID_COMMAND; -import static build.buildfarm.instance.server.AbstractServerInstance.OUTPUT_DIRECTORY_IS_OUTPUT_ANCESTOR; -import static build.buildfarm.instance.server.AbstractServerInstance.OUTPUT_FILE_IS_OUTPUT_ANCESTOR; -import static build.buildfarm.instance.server.AbstractServerInstance.SYMLINK_TARGET_ABSOLUTE; +import static build.buildfarm.instance.server.NodeInstance.ACTION_INPUT_ROOT_DIRECTORY_PATH; +import static build.buildfarm.instance.server.NodeInstance.DIRECTORY_NOT_SORTED; +import static build.buildfarm.instance.server.NodeInstance.DUPLICATE_DIRENT; +import static build.buildfarm.instance.server.NodeInstance.INVALID_COMMAND; +import static build.buildfarm.instance.server.NodeInstance.OUTPUT_DIRECTORY_IS_OUTPUT_ANCESTOR; +import static build.buildfarm.instance.server.NodeInstance.OUTPUT_FILE_IS_OUTPUT_ANCESTOR; +import static build.buildfarm.instance.server.NodeInstance.SYMLINK_TARGET_ABSOLUTE; import static com.google.common.truth.Truth.assertThat; import static com.google.common.util.concurrent.Futures.immediateFuture; import static org.mockito.Mockito.any; @@ -99,10 +99,10 @@ @RunWith(JUnit4.class) @Log -public class AbstractServerInstanceTest { +public class NodeInstanceTest { private static final DigestUtil DIGEST_UTIL = new DigestUtil(HashFunction.SHA256); - static class DummyServerInstance extends AbstractServerInstance { + static class DummyServerInstance extends NodeInstance { DummyServerInstance( ContentAddressableStorage contentAddressableStorage, ActionCache actionCache) { super( @@ -261,7 +261,7 @@ public PrepareWorkerForGracefulShutDownRequestResults shutDownWorkerGracefully() @Test public void duplicateFileInputIsInvalid() { PreconditionFailure.Builder preconditionFailure = PreconditionFailure.newBuilder(); - AbstractServerInstance.validateActionInputDirectory( + NodeInstance.validateActionInputDirectory( ACTION_INPUT_ROOT_DIRECTORY_PATH, Directory.newBuilder() .addAllFiles( @@ -290,7 +290,7 @@ public void duplicateEmptyDirectoryCheckPasses() throws StatusException { Directory emptyDirectory = Directory.getDefaultInstance(); Digest emptyDirectoryDigest = DIGEST_UTIL.compute(emptyDirectory); PreconditionFailure.Builder preconditionFailure = PreconditionFailure.newBuilder(); - AbstractServerInstance.validateActionInputDirectory( + NodeInstance.validateActionInputDirectory( ACTION_INPUT_ROOT_DIRECTORY_PATH, Directory.newBuilder() .addAllDirectories( @@ -320,7 +320,7 @@ public void duplicateEmptyDirectoryCheckPasses() throws StatusException { @Test public void unsortedFileInputIsInvalid() { PreconditionFailure.Builder preconditionFailure = PreconditionFailure.newBuilder(); - AbstractServerInstance.validateActionInputDirectory( + NodeInstance.validateActionInputDirectory( ACTION_INPUT_ROOT_DIRECTORY_PATH, Directory.newBuilder() .addAllFiles( @@ -349,7 +349,7 @@ public void duplicateDirectoryInputIsInvalid() { Directory emptyDirectory = Directory.getDefaultInstance(); Digest emptyDirectoryDigest = DIGEST_UTIL.compute(emptyDirectory); PreconditionFailure.Builder preconditionFailure = PreconditionFailure.newBuilder(); - AbstractServerInstance.validateActionInputDirectory( + NodeInstance.validateActionInputDirectory( ACTION_INPUT_ROOT_DIRECTORY_PATH, Directory.newBuilder() .addAllDirectories( @@ -384,7 +384,7 @@ public void unsortedDirectoryInputIsInvalid() { Directory emptyDirectory = Directory.getDefaultInstance(); Digest emptyDirectoryDigest = DIGEST_UTIL.compute(emptyDirectory); PreconditionFailure.Builder preconditionFailure = PreconditionFailure.newBuilder(); - AbstractServerInstance.validateActionInputDirectory( + NodeInstance.validateActionInputDirectory( ACTION_INPUT_ROOT_DIRECTORY_PATH, Directory.newBuilder() .addAllDirectories( @@ -422,7 +422,7 @@ public void shouldValidateIfSymlinkTargetAbsolute() { Directory.newBuilder() .addSymlinks(SymlinkNode.newBuilder().setName("foo").setTarget("/root/secret").build()) .build(); - AbstractServerInstance.validateActionInputDirectory( + NodeInstance.validateActionInputDirectory( ACTION_INPUT_ROOT_DIRECTORY_PATH, absoluteSymlinkDirectory, /* pathDigests=*/ new Stack<>(), @@ -442,7 +442,7 @@ public void shouldValidateIfSymlinkTargetAbsolute() { // valid for allowed preconditionFailure = PreconditionFailure.newBuilder(); - AbstractServerInstance.validateActionInputDirectory( + NodeInstance.validateActionInputDirectory( ACTION_INPUT_ROOT_DIRECTORY_PATH, absoluteSymlinkDirectory, /* pathDigests=*/ new Stack<>(), @@ -459,7 +459,7 @@ public void shouldValidateIfSymlinkTargetAbsolute() { @Test public void nestedOutputDirectoriesAreInvalid() { PreconditionFailure.Builder preconditionFailureBuilder = PreconditionFailure.newBuilder(); - AbstractServerInstance.validateOutputs( + NodeInstance.validateOutputs( ImmutableSet.of(), ImmutableSet.of(), ImmutableSet.of(), @@ -476,7 +476,7 @@ public void nestedOutputDirectoriesAreInvalid() { @Test public void outputDirectoriesContainingOutputFilesAreInvalid() { PreconditionFailure.Builder preconditionFailureBuilder = PreconditionFailure.newBuilder(); - AbstractServerInstance.validateOutputs( + NodeInstance.validateOutputs( ImmutableSet.of(), ImmutableSet.of(), ImmutableSet.of("foo/bar"), @@ -493,7 +493,7 @@ public void outputDirectoriesContainingOutputFilesAreInvalid() { @Test public void outputFilesAsOutputDirectoryAncestorsAreInvalid() { PreconditionFailure.Builder preconditionFailureBuilder = PreconditionFailure.newBuilder(); - AbstractServerInstance.validateOutputs( + NodeInstance.validateOutputs( ImmutableSet.of(), ImmutableSet.of(), ImmutableSet.of("foo"), @@ -509,7 +509,7 @@ public void outputFilesAsOutputDirectoryAncestorsAreInvalid() { @Test public void emptyArgumentListIsInvalid() { - AbstractServerInstance instance = new DummyServerInstance(); + NodeInstance instance = new DummyServerInstance(); PreconditionFailure.Builder preconditionFailureBuilder = PreconditionFailure.newBuilder(); instance.validateCommand( @@ -529,7 +529,7 @@ public void emptyArgumentListIsInvalid() { @Test public void absoluteWorkingDirectoryIsInvalid() { - AbstractServerInstance instance = new DummyServerInstance(); + NodeInstance instance = new DummyServerInstance(); PreconditionFailure.Builder preconditionFailureBuilder = PreconditionFailure.newBuilder(); instance.validateCommand( @@ -549,7 +549,7 @@ public void absoluteWorkingDirectoryIsInvalid() { @Test public void undeclaredWorkingDirectoryIsInvalid() { - AbstractServerInstance instance = new DummyServerInstance(); + NodeInstance instance = new DummyServerInstance(); Digest inputRootDigest = DIGEST_UTIL.compute(Directory.getDefaultInstance()); PreconditionFailure.Builder preconditionFailureBuilder = PreconditionFailure.newBuilder(); @@ -590,7 +590,7 @@ public void multipleIdenticalDirectoryMissingAreAllPreconditionFailures() { .setDigest(missingDirectoryDigest) .build())) .build(); - AbstractServerInstance.validateActionInputDirectory( + NodeInstance.validateActionInputDirectory( ACTION_INPUT_ROOT_DIRECTORY_PATH, root, /* pathDigests=*/ new Stack<>(), @@ -652,7 +652,7 @@ public void validationRevisitReplicatesPreconditionFailures() { DirectoryNode.newBuilder().setName("bar").setDigest(fooDigest).build(), DirectoryNode.newBuilder().setName("foo").setDigest(fooDigest).build())) .build(); - AbstractServerInstance.validateActionInputDirectory( + NodeInstance.validateActionInputDirectory( ACTION_INPUT_ROOT_DIRECTORY_PATH, root, /* pathDigests=*/ new Stack<>(), @@ -721,8 +721,7 @@ public void outputDirectoriesFilesAreEnsuredPresent() throws Exception { .build(); ContentAddressableStorage contentAddressableStorage = mock(ContentAddressableStorage.class); ActionCache actionCache = mock(ActionCache.class); - AbstractServerInstance instance = - new DummyServerInstance(contentAddressableStorage, actionCache); + NodeInstance instance = new DummyServerInstance(contentAddressableStorage, actionCache); Tree tree = Tree.newBuilder() @@ -782,7 +781,7 @@ public void fetchBlobWriteCompleteIsSuccess() throws Exception { Digest expectedDigest = contentDigest.toBuilder().setSizeBytes(-1).build(); ContentAddressableStorage contentAddressableStorage = mock(ContentAddressableStorage.class); - AbstractServerInstance instance = new DummyServerInstance(contentAddressableStorage, null); + NodeInstance instance = new DummyServerInstance(contentAddressableStorage, null); RequestMetadata requestMetadata = RequestMetadata.getDefaultInstance(); Write write = mock(Write.class); diff --git a/src/test/java/build/buildfarm/instance/shard/BUILD b/src/test/java/build/buildfarm/instance/shard/BUILD index cd0ae18d24..b635c74ba5 100644 --- a/src/test/java/build/buildfarm/instance/shard/BUILD +++ b/src/test/java/build/buildfarm/instance/shard/BUILD @@ -110,10 +110,10 @@ java_test( ) java_test( - name = "ShardInstanceTest", + name = "ServerInstanceTest", size = "small", srcs = [ - "ShardInstanceTest.java", + "ServerInstanceTest.java", "UnobservableWatcher.java", ], data = ["//examples:example_configs"], diff --git a/src/test/java/build/buildfarm/instance/shard/ShardInstanceTest.java b/src/test/java/build/buildfarm/instance/shard/ServerInstanceTest.java similarity index 99% rename from src/test/java/build/buildfarm/instance/shard/ShardInstanceTest.java rename to src/test/java/build/buildfarm/instance/shard/ServerInstanceTest.java index aa1adc5d3d..cd959950a0 100644 --- a/src/test/java/build/buildfarm/instance/shard/ShardInstanceTest.java +++ b/src/test/java/build/buildfarm/instance/shard/ServerInstanceTest.java @@ -20,9 +20,9 @@ import static build.buildfarm.common.Actions.invalidActionVerboseMessage; import static build.buildfarm.common.Errors.VIOLATION_TYPE_INVALID; import static build.buildfarm.common.Errors.VIOLATION_TYPE_MISSING; -import static build.buildfarm.instance.server.AbstractServerInstance.INVALID_PLATFORM; -import static build.buildfarm.instance.server.AbstractServerInstance.MISSING_ACTION; -import static build.buildfarm.instance.server.AbstractServerInstance.MISSING_COMMAND; +import static build.buildfarm.instance.server.NodeInstance.INVALID_PLATFORM; +import static build.buildfarm.instance.server.NodeInstance.MISSING_ACTION; +import static build.buildfarm.instance.server.NodeInstance.MISSING_COMMAND; import static com.google.common.base.Predicates.notNull; import static com.google.common.truth.Truth.assertThat; import static com.google.common.util.concurrent.Futures.immediateFuture; @@ -121,14 +121,14 @@ import org.mockito.stubbing.Answer; @RunWith(JUnit4.class) -public class ShardInstanceTest { +public class ServerInstanceTest { private static final DigestUtil DIGEST_UTIL = new DigestUtil(HashFunction.SHA256); private static final long QUEUE_TEST_TIMEOUT_SECONDS = 3; private static final Duration DEFAULT_TIMEOUT = Durations.fromSeconds(60); private static final Command SIMPLE_COMMAND = Command.newBuilder().addAllArguments(ImmutableList.of("true")).build(); - private ShardInstance instance; + private ServerInstance instance; private Map blobDigests; @Mock private Backplane mockBackplane; @@ -145,7 +145,7 @@ public void setUp() throws InterruptedException { blobDigests = Maps.newHashMap(); ActionCache actionCache = new ShardActionCache(10, mockBackplane, newDirectExecutorService()); instance = - new ShardInstance( + new ServerInstance( "shard", DIGEST_UTIL, mockBackplane, diff --git a/src/test/java/build/buildfarm/worker/shard/ShardWorkerInstanceTest.java b/src/test/java/build/buildfarm/worker/shard/WorkerInstanceTest.java similarity index 97% rename from src/test/java/build/buildfarm/worker/shard/ShardWorkerInstanceTest.java rename to src/test/java/build/buildfarm/worker/shard/WorkerInstanceTest.java index 7a4e40be26..3df73187bb 100644 --- a/src/test/java/build/buildfarm/worker/shard/ShardWorkerInstanceTest.java +++ b/src/test/java/build/buildfarm/worker/shard/WorkerInstanceTest.java @@ -50,19 +50,19 @@ import org.mockito.MockitoAnnotations; @RunWith(JUnit4.class) -public class ShardWorkerInstanceTest { +public class WorkerInstanceTest { private final DigestUtil DIGEST_UTIL = new DigestUtil(HashFunction.SHA256); @Mock private Backplane backplane; @Mock private ContentAddressableStorage storage; - private ShardWorkerInstance instance; + private WorkerInstance instance; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - instance = new ShardWorkerInstance("test", DIGEST_UTIL, backplane, storage); + instance = new WorkerInstance("test", DIGEST_UTIL, backplane, storage); } @SuppressWarnings("unchecked") From 2a61f77dc1713f276674bdbc9a839ec2732feb07 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Mon, 30 Oct 2023 14:48:00 -0400 Subject: [PATCH 110/311] Create SymlinkNode outputs during upload (#1515) Default disabled, available with createSymlinkOutputs option in Worker config. --- _site/docs/configuration/configuration.md | 1 + examples/config.yml | 1 + .../build/buildfarm/common/config/Worker.java | 1 + .../worker/shard/ShardWorkerContext.java | 38 +++++++++++++++++-- 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/_site/docs/configuration/configuration.md b/_site/docs/configuration/configuration.md index ccfc8e026c..466375373f 100644 --- a/_site/docs/configuration/configuration.md +++ b/_site/docs/configuration/configuration.md @@ -262,6 +262,7 @@ backplane: | errorOperationRemainingResources | boolean, _false_ | | | | realInputDirectories | List of Strings, _external_ | | A list of paths that will not be subject to the effects of linkInputDirectories setting, may also be used to provide writable directories as input roots for actions which expect to be able to write to an input location and will fail if they cannot | | gracefulShutdownSeconds | Integer, 0 | | Time in seconds to allow for operations in flight to finish when shutdown signal is received | +| createSymlinkOutputs | boolean, _false_ | | Creates SymlinkNodes for symbolic links discovered in output paths for actions. No verification of the symlink target path occurs. Buildstream, for example, requires this. | ```yaml worker: diff --git a/examples/config.yml b/examples/config.yml index 5229fcd07c..008bf2e1ca 100644 --- a/examples/config.yml +++ b/examples/config.yml @@ -131,6 +131,7 @@ worker: alwaysUse: false selectForBlockNetwork: false selectForTmpFs: false + createSymlinkOutputs: false executionPolicies: - name: test executionWrapper: diff --git a/src/main/java/build/buildfarm/common/config/Worker.java b/src/main/java/build/buildfarm/common/config/Worker.java index e987c1e370..c446134fe2 100644 --- a/src/main/java/build/buildfarm/common/config/Worker.java +++ b/src/main/java/build/buildfarm/common/config/Worker.java @@ -39,6 +39,7 @@ public class Worker { private int gracefulShutdownSeconds = 0; private ExecutionPolicy[] executionPolicies = {}; private SandboxSettings sandboxSettings = new SandboxSettings(); + private boolean createSymlinkOutputs = false; // These limited resources are only for the individual worker. // An example would be hardware resources such as GPUs. diff --git a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java index c844f53963..98474b439c 100644 --- a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java +++ b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java @@ -31,6 +31,7 @@ import build.bazel.remote.execution.v2.ExecutionStage; import build.bazel.remote.execution.v2.FileNode; import build.bazel.remote.execution.v2.Platform; +import build.bazel.remote.execution.v2.SymlinkNode; import build.bazel.remote.execution.v2.Tree; import build.buildfarm.backplane.Backplane; import build.buildfarm.common.CommandUtils; @@ -572,6 +573,7 @@ private void uploadOutputFile( static class OutputDirectoryContext { private final List files = new ArrayList<>(); private final List directories = new ArrayList<>(); + private final List symlinks = new ArrayList<>(); void addFile(FileNode fileNode) { files.add(fileNode); @@ -581,10 +583,19 @@ void addDirectory(DirectoryNode directoryNode) { directories.add(directoryNode); } + void addSymlink(SymlinkNode symlinkNode) { + symlinks.add(symlinkNode); + } + Directory toDirectory() { files.sort(Comparator.comparing(FileNode::getName)); directories.sort(Comparator.comparing(DirectoryNode::getName)); - return Directory.newBuilder().addAllFiles(files).addAllDirectories(directories).build(); + symlinks.sort(Comparator.comparing(SymlinkNode::getName)); + return Directory.newBuilder() + .addAllFiles(files) + .addAllDirectories(directories) + .addAllSymlinks(symlinks) + .build(); } } @@ -621,8 +632,30 @@ private void uploadOutputDirectory( @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + if (configs.getWorker().isCreateSymlinkOutputs() && attrs.isSymbolicLink()) { + visitSymbolicLink(file); + } else { + visitRegularFile(file, attrs); + } + return FileVisitResult.CONTINUE; + } + + private void visitSymbolicLink(Path file) throws IOException { + // TODO convert symlinks with absolute targets within execution root to relative ones + currentDirectory.addSymlink( + SymlinkNode.newBuilder() + .setName(file.getFileName().toString()) + .setTarget(Files.readSymbolicLink(file).toString()) + .build()); + } + + private void visitRegularFile(Path file, BasicFileAttributes attrs) throws IOException { Digest digest; try { + // should we create symlink nodes in output? + // is buildstream trying to execute in a specific container?? + // can get to NSFE for nonexistent symlinks + // can fail outright for a symlink to a directory digest = getDigestUtil().compute(file); } catch (NoSuchFileException e) { log.log( @@ -631,7 +664,7 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) "error visiting file %s under output dir %s", outputDirPath.relativize(file), outputDirPath.toAbsolutePath()), e); - return FileVisitResult.CONTINUE; + return; } // should we cast to PosixFilePermissions and do gymnastics there for executable? @@ -655,7 +688,6 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) .setDescription( "An output could not be uploaded because it exceeded the maximum size of an entry"); } - return FileVisitResult.CONTINUE; } @Override From 76c2657111e5ebe92bdc99195a892195aa992be0 Mon Sep 17 00:00:00 2001 From: amishra-u <119983081+amishra-u@users.noreply.github.com> Date: Mon, 30 Oct 2023 19:26:18 -0700 Subject: [PATCH 111/311] feat: Implement CAS lease extension (#1455) Problem Enabling the findMissingBlobsViaBackplane flag in BuildfarmServer eliminates the need for the BuildfarmWorker's fmb API call. This BuildfarmWorker:fmb call was also responsible for tracking CAS entry access. As result, our CAS cache eviction strategy shifted from LRU to FIFO. When the findMissingBlobsViaBackplane flag is enabled, the buildfarm relies on the backplane as the definitive source for CAS availability. Since we don't update CAS expiry on each access, the backplane will independently expire CAS entries based on the specified cas_expire duration, even if they are actively being read. Solution Updated bfServer:fmb call to perform non-blocking fmb calls to workers, allowing these workers to record access for the relevant CAS entries. Extended expiry duration for available CAS entries in the backplane on each fmb call. With these changes, we can utilize Bazel's experimental_remote_cache_lease_extension and experimental_remote_cache_ttl flags for incremental builds. Closes #1428 --- defs.bzl | 1 + .../build/buildfarm/backplane/Backplane.java | 3 + .../instance/shard/CasWorkerMap.java | 7 +++ .../instance/shard/JedisCasWorkerMap.java | 11 ++++ .../instance/shard/RedisShardBackplane.java | 5 ++ .../instance/shard/RedissonCasWorkerMap.java | 8 +++ .../instance/shard/ServerInstance.java | 57 ++++++++++++++--- .../java/build/buildfarm/instance/shard/BUILD | 19 ++++++ .../instance/shard/JedisCasWorkerMapTest.java | 63 +++++++++++++++++++ .../instance/shard/ServerInstanceTest.java | 14 +++++ 10 files changed, 180 insertions(+), 8 deletions(-) create mode 100644 src/test/java/build/buildfarm/instance/shard/JedisCasWorkerMapTest.java diff --git a/defs.bzl b/defs.bzl index 5b0e4f640c..4b0a5e49bf 100644 --- a/defs.bzl +++ b/defs.bzl @@ -60,6 +60,7 @@ def buildfarm_init(name = "buildfarm"): "com.fasterxml.jackson.core:jackson-databind:2.15.0", "com.github.ben-manes.caffeine:caffeine:2.9.0", "com.github.docker-java:docker-java:3.2.11", + "com.github.fppt:jedis-mock:1.0.10", "com.github.jnr:jffi:1.2.16", "com.github.jnr:jffi:jar:native:1.2.16", "com.github.jnr:jnr-constants:0.9.9", diff --git a/src/main/java/build/buildfarm/backplane/Backplane.java b/src/main/java/build/buildfarm/backplane/Backplane.java index 557a7dc163..e13616b32e 100644 --- a/src/main/java/build/buildfarm/backplane/Backplane.java +++ b/src/main/java/build/buildfarm/backplane/Backplane.java @@ -278,4 +278,7 @@ boolean pollOperation(QueueEntry queueEntry, ExecutionStage.Value stage, long re Boolean propertiesEligibleForQueue(List provisions); GetClientStartTimeResult getClientStartTime(GetClientStartTimeRequest request) throws IOException; + + /** Set expiry time for digests */ + void updateDigestsExpiry(Iterable digests) throws IOException; } diff --git a/src/main/java/build/buildfarm/instance/shard/CasWorkerMap.java b/src/main/java/build/buildfarm/instance/shard/CasWorkerMap.java index 794b296a1f..55b2933e42 100644 --- a/src/main/java/build/buildfarm/instance/shard/CasWorkerMap.java +++ b/src/main/java/build/buildfarm/instance/shard/CasWorkerMap.java @@ -121,4 +121,11 @@ Map> getMap(RedisClient client, Iterable blobDigests * @note Suggested return identifier: mapSize. */ int size(RedisClient client) throws IOException; + + /** + * @brief Set the expiry duration for the digests. + * @param client Client used for interacting with redis when not using cacheMap. + * @param blobDigests The blob digests to set new the expiry duration. + */ + void setExpire(RedisClient client, Iterable blobDigests) throws IOException; } diff --git a/src/main/java/build/buildfarm/instance/shard/JedisCasWorkerMap.java b/src/main/java/build/buildfarm/instance/shard/JedisCasWorkerMap.java index d035d10491..65d1f06b87 100644 --- a/src/main/java/build/buildfarm/instance/shard/JedisCasWorkerMap.java +++ b/src/main/java/build/buildfarm/instance/shard/JedisCasWorkerMap.java @@ -234,6 +234,17 @@ public int size(RedisClient client) throws IOException { return client.call(jedis -> ScanCount.get(jedis, name + ":*", 1000)); } + @Override + public void setExpire(RedisClient client, Iterable blobDigests) throws IOException { + client.run( + jedis -> { + for (Digest blobDigest : blobDigests) { + String key = redisCasKey(blobDigest); + jedis.expire(key, keyExpiration_s); + } + }); + } + /** * @brief Get the redis key name. * @details This is to be used for the direct redis implementation. diff --git a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java index ebb832f5aa..535473f2a9 100644 --- a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java +++ b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java @@ -1501,4 +1501,9 @@ public GetClientStartTimeResult getClientStartTime(GetClientStartTimeRequest req } return GetClientStartTimeResult.newBuilder().addAllClientStartTime(startTimes).build(); } + + @Override + public void updateDigestsExpiry(Iterable digests) throws IOException { + state.casWorkerMap.setExpire(client, digests); + } } diff --git a/src/main/java/build/buildfarm/instance/shard/RedissonCasWorkerMap.java b/src/main/java/build/buildfarm/instance/shard/RedissonCasWorkerMap.java index 234e15fb15..52b010c31f 100644 --- a/src/main/java/build/buildfarm/instance/shard/RedissonCasWorkerMap.java +++ b/src/main/java/build/buildfarm/instance/shard/RedissonCasWorkerMap.java @@ -209,6 +209,14 @@ public int size(RedisClient client) { return cacheMap.size(); } + @Override + public void setExpire(RedisClient client, Iterable blobDigests) { + for (Digest blobDigest : blobDigests) { + String key = cacheMapCasKey(blobDigest); + cacheMap.expireKey(key, keyExpiration_s, TimeUnit.SECONDS); + } + } + /** * @brief Get a random element from the set. * @details Assumes the set is not empty. diff --git a/src/main/java/build/buildfarm/instance/shard/ServerInstance.java b/src/main/java/build/buildfarm/instance/shard/ServerInstance.java index ab865b0e0e..b1cbed0e07 100644 --- a/src/main/java/build/buildfarm/instance/shard/ServerInstance.java +++ b/src/main/java/build/buildfarm/instance/shard/ServerInstance.java @@ -135,10 +135,12 @@ import java.io.InputStream; import java.io.OutputStream; import java.time.Instant; +import java.util.AbstractMap; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collections; import java.util.Deque; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -660,7 +662,7 @@ public ListenableFuture> findMissingBlobs( } if (configs.getServer().isFindMissingBlobsViaBackplane()) { - return findMissingBlobsViaBackplane(nonEmptyDigests); + return findMissingBlobsViaBackplane(nonEmptyDigests, requestMetadata); } return findMissingBlobsQueryingEachWorker(nonEmptyDigests, requestMetadata); @@ -727,24 +729,40 @@ private ListenableFuture> findMissingBlobsQueryingEachWorker( // out-of-date and the server lies about which blobs are actually present. We provide this // alternative strategy for calculating missing blobs. private ListenableFuture> findMissingBlobsViaBackplane( - Iterable nonEmptyDigests) { + Iterable nonEmptyDigests, RequestMetadata requestMetadata) { try { Set uniqueDigests = new HashSet<>(); nonEmptyDigests.forEach(uniqueDigests::add); Map> foundBlobs = backplane.getBlobDigestsWorkers(uniqueDigests); Set workerSet = backplane.getStorageWorkers(); Map workersStartTime = backplane.getWorkersStartTimeInEpochSecs(workerSet); - return immediateFuture( + Map> digestAndWorkersMap = uniqueDigests.stream() - .filter( // best effort to present digests only missing on active workers + .map( digest -> { Set initialWorkers = foundBlobs.getOrDefault(digest, Collections.emptySet()); - return filterAndAdjustWorkersForDigest( - digest, initialWorkers, workerSet, workersStartTime) - .isEmpty(); + return new AbstractMap.SimpleEntry<>( + digest, + filterAndAdjustWorkersForDigest( + digest, initialWorkers, workerSet, workersStartTime)); }) - .collect(Collectors.toList())); + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + + ListenableFuture> missingDigestFuture = + immediateFuture( + digestAndWorkersMap.entrySet().stream() + .filter(entry -> entry.getValue().isEmpty()) + .map(Map.Entry::getKey) + .collect(Collectors.toList())); + return transformAsync( + missingDigestFuture, + (missingDigest) -> { + extendLeaseForDigests(digestAndWorkersMap, requestMetadata); + return immediateFuture(missingDigest); + }, + // Propagate context values but don't cascade its cancellation for downstream calls. + Context.current().fork().fixedContextExecutor(directExecutor())); } catch (Exception e) { log.log(Level.SEVERE, "find missing blob via backplane failed", e); return immediateFailedFuture(Status.fromThrowable(e).asException()); @@ -789,6 +807,29 @@ private Set filterAndAdjustWorkersForDigest( return workersStartedBeforeDigestInsertion; } + private void extendLeaseForDigests( + Map> digestAndWorkersMap, RequestMetadata requestMetadata) { + Map> workerAndDigestMap = new HashMap<>(); + digestAndWorkersMap.forEach( + (digest, workers) -> + workers.forEach( + worker -> + workerAndDigestMap.computeIfAbsent(worker, w -> new HashSet<>()).add(digest))); + + workerAndDigestMap.forEach( + (worker, digests) -> workerStub(worker).findMissingBlobs(digests, requestMetadata)); + + try { + backplane.updateDigestsExpiry(digestAndWorkersMap.keySet()); + } catch (IOException e) { + log.log( + Level.WARNING, + format( + "Failed to update expiry duration for digests (%s) insertion time", + digestAndWorkersMap.keySet())); + } + } + private void findMissingBlobsOnWorker( String requestId, Iterable blobDigests, diff --git a/src/test/java/build/buildfarm/instance/shard/BUILD b/src/test/java/build/buildfarm/instance/shard/BUILD index b635c74ba5..2f08b1003d 100644 --- a/src/test/java/build/buildfarm/instance/shard/BUILD +++ b/src/test/java/build/buildfarm/instance/shard/BUILD @@ -219,3 +219,22 @@ java_test( "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) + +java_test( + name = "JedisCasWorkerMapTest", + size = "small", + srcs = [ + "JedisCasWorkerMapTest.java", + ], + test_class = "build.buildfarm.AllTests", + deps = [ + "//src/main/java/build/buildfarm/common", + "//src/main/java/build/buildfarm/common/redis", + "//src/main/java/build/buildfarm/instance/shard", + "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", + "//src/test/java/build/buildfarm:test_runner", + "//third_party/jedis", + "@maven//:com_github_fppt_jedis_mock", + "@maven//:com_google_truth_truth", + ], +) diff --git a/src/test/java/build/buildfarm/instance/shard/JedisCasWorkerMapTest.java b/src/test/java/build/buildfarm/instance/shard/JedisCasWorkerMapTest.java new file mode 100644 index 0000000000..caa69536c1 --- /dev/null +++ b/src/test/java/build/buildfarm/instance/shard/JedisCasWorkerMapTest.java @@ -0,0 +1,63 @@ +package build.buildfarm.instance.shard; + +import static com.google.common.truth.Truth.assertThat; + +import build.bazel.remote.execution.v2.Digest; +import build.buildfarm.common.DigestUtil; +import build.buildfarm.common.redis.RedisClient; +import com.github.fppt.jedismock.RedisServer; +import com.github.fppt.jedismock.server.ServiceOptions; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import redis.clients.jedis.HostAndPort; +import redis.clients.jedis.JedisCluster; + +@RunWith(JUnit4.class) +public class JedisCasWorkerMapTest { + + private static final String CAS_PREFIX = "ContentAddressableStorage"; + + private RedisServer redisServer; + private RedisClient redisClient; + private JedisCasWorkerMap jedisCasWorkerMap; + + @Before + public void setup() throws IOException { + redisServer = + RedisServer.newRedisServer() + .setOptions(ServiceOptions.defaultOptions().withClusterModeEnabled()) + .start(); + redisClient = + new RedisClient( + new JedisCluster( + Collections.singleton( + new HostAndPort(redisServer.getHost(), redisServer.getBindPort())))); + jedisCasWorkerMap = new JedisCasWorkerMap(CAS_PREFIX, 60); + } + + @Test + public void testSetExpire() throws IOException { + Digest testDigest1 = Digest.newBuilder().setHash("abc").build(); + Digest testDigest2 = Digest.newBuilder().setHash("xyz").build(); + + String casKey1 = CAS_PREFIX + ":" + DigestUtil.toString(testDigest1); + String casKey2 = CAS_PREFIX + ":" + DigestUtil.toString(testDigest2); + + redisClient.run(jedis -> jedis.sadd(casKey1, "worker1")); + jedisCasWorkerMap.setExpire(redisClient, Arrays.asList(testDigest1, testDigest2)); + + assertThat((Long) redisClient.call(jedis -> jedis.ttl(casKey1))).isGreaterThan(0L); + assertThat((Long) redisClient.call(jedis -> jedis.ttl(casKey2))).isEqualTo(-2L); + } + + @After + public void tearDown() throws IOException { + redisServer.stop(); + } +} diff --git a/src/test/java/build/buildfarm/instance/shard/ServerInstanceTest.java b/src/test/java/build/buildfarm/instance/shard/ServerInstanceTest.java index cd959950a0..d66a600dab 100644 --- a/src/test/java/build/buildfarm/instance/shard/ServerInstanceTest.java +++ b/src/test/java/build/buildfarm/instance/shard/ServerInstanceTest.java @@ -31,9 +31,13 @@ import static java.util.concurrent.Executors.newSingleThreadExecutor; import static java.util.concurrent.TimeUnit.SECONDS; import static org.mockito.AdditionalAnswers.answer; +import static org.mockito.ArgumentMatchers.anyIterable; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.any; +import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.atMost; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; @@ -80,6 +84,7 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.longrunning.Operation; import com.google.protobuf.Any; @@ -95,6 +100,7 @@ import io.grpc.stub.ServerCallStreamObserver; import io.grpc.stub.StreamObserver; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; @@ -1110,8 +1116,12 @@ public void findMissingBlobsTest_ViaBackPlane() throws Exception { buildfarmConfigs.getServer().setFindMissingBlobsViaBackplane(true); Set activeAndImposterWorkers = Sets.newHashSet(Iterables.concat(activeWorkers, imposterWorkers)); + when(mockBackplane.getStorageWorkers()).thenReturn(activeAndImposterWorkers); when(mockBackplane.getBlobDigestsWorkers(any(Iterable.class))).thenReturn(digestAndWorkersMap); + when(mockInstanceLoader.load(anyString())).thenReturn(mockWorkerInstance); + when(mockWorkerInstance.findMissingBlobs(anyIterable(), any(RequestMetadata.class))) + .thenReturn(Futures.immediateFuture(new ArrayList<>())); long serverStartTime = 1686951033L; // june 15th, 2023 Map workersStartTime = new HashMap<>(); @@ -1134,6 +1144,10 @@ public void findMissingBlobsTest_ViaBackPlane() throws Exception { Iterables.concat(missingDigests, digestAvailableOnImposters); assertThat(actualMissingDigests).containsExactlyElementsIn(expectedMissingDigests); + verify(mockWorkerInstance, atMost(3)) + .findMissingBlobs(anyIterable(), any(RequestMetadata.class)); + verify(mockWorkerInstance, atLeast(1)) + .findMissingBlobs(anyIterable(), any(RequestMetadata.class)); for (Digest digest : actualMissingDigests) { assertThat(digest).isNotIn(availableDigests); From cfa2e18724914034eb19c4c01f293117610fa0b7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 31 Oct 2023 14:48:35 -0400 Subject: [PATCH 112/311] Bump org.json:json from 20230227 to 20231013 in /admin/main (#1516) Bumps [org.json:json](https://github.com/douglascrockford/JSON-java) from 20230227 to 20231013. - [Release notes](https://github.com/douglascrockford/JSON-java/releases) - [Changelog](https://github.com/stleary/JSON-java/blob/master/docs/RELEASES.md) - [Commits](https://github.com/douglascrockford/JSON-java/commits) --- updated-dependencies: - dependency-name: org.json:json dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- admin/main/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/main/pom.xml b/admin/main/pom.xml index 006217ccb4..8e128ee64c 100644 --- a/admin/main/pom.xml +++ b/admin/main/pom.xml @@ -94,7 +94,7 @@ org.json json - 20230227 + 20231013 org.projectlombok From ff00c8f3977aadf3df3febaceb07e575821ea9e2 Mon Sep 17 00:00:00 2001 From: Yuriy Belenitsky Date: Wed, 1 Nov 2023 16:14:45 -0400 Subject: [PATCH 113/311] Re-add missing graceful shutdown functionality (#1520) --- .../buildfarm/server/BuildFarmServer.java | 8 ++-- .../build/buildfarm/worker/shard/Worker.java | 47 +++++++++++++++++++ 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/main/java/build/buildfarm/server/BuildFarmServer.java b/src/main/java/build/buildfarm/server/BuildFarmServer.java index 8672c0df76..c448963209 100644 --- a/src/main/java/build/buildfarm/server/BuildFarmServer.java +++ b/src/main/java/build/buildfarm/server/BuildFarmServer.java @@ -88,20 +88,20 @@ public class BuildFarmServer extends LoggingMain { */ public void prepareServerForGracefulShutdown() { if (configs.getServer().getGracefulShutdownSeconds() == 0) { - System.err.println( + log.info( String.format("Graceful Shutdown is not enabled. Server is shutting down immediately.")); } else { try { - System.err.println( + log.info( String.format( "Graceful Shutdown - Waiting %d to allow connections to drain.", configs.getServer().getGracefulShutdownSeconds())); SECONDS.sleep(configs.getServer().getGracefulShutdownSeconds()); } catch (InterruptedException e) { - System.err.println( + log.info( "Graceful Shutdown - The server graceful shutdown is interrupted: " + e.getMessage()); } finally { - System.err.println( + log.info( String.format( "Graceful Shutdown - It took the server %d seconds to shutdown", configs.getServer().getGracefulShutdownSeconds())); diff --git a/src/main/java/build/buildfarm/worker/shard/Worker.java b/src/main/java/build/buildfarm/worker/shard/Worker.java index fd556fc8e8..ce69eb3d13 100644 --- a/src/main/java/build/buildfarm/worker/shard/Worker.java +++ b/src/main/java/build/buildfarm/worker/shard/Worker.java @@ -137,6 +137,52 @@ public final class Worker extends LoggingMain { private LoadingCache workerStubs; private AtomicBoolean released = new AtomicBoolean(true); + /** + * The method will prepare the worker for graceful shutdown when the worker is ready. Note on + * using stderr here instead of log. By the time this is called in PreDestroy, the log is no + * longer available and is not logging messages. + */ + public void prepareWorkerForGracefulShutdown() { + if (configs.getWorker().getGracefulShutdownSeconds() == 0) { + log.info( + String.format( + "Graceful Shutdown is not enabled. Worker is shutting down without finishing executions in progress.")); + } else { + inGracefulShutdown = true; + log.info( + "Graceful Shutdown - The current worker will not be registered again and should be shutdown gracefully!"); + pipeline.stopMatchingOperations(); + int scanRate = 30; // check every 30 seconds + int timeWaited = 0; + int timeOut = configs.getWorker().getGracefulShutdownSeconds(); + try { + if (pipeline.isEmpty()) { + log.info("Graceful Shutdown - no work in the pipeline."); + } else { + log.info(String.format("Graceful Shutdown - waiting for executions to finish.")); + } + while (!pipeline.isEmpty() && timeWaited < timeOut) { + SECONDS.sleep(scanRate); + timeWaited += scanRate; + log.info( + String.format( + "Graceful Shutdown - Pipeline is still not empty after %d seconds.", timeWaited)); + } + } catch (InterruptedException e) { + log.info( + "Graceful Shutdown - The worker gracefully shutdown is interrupted: " + e.getMessage()); + } finally { + log.info( + String.format( + "Graceful Shutdown - It took the worker %d seconds to %s", + timeWaited, + pipeline.isEmpty() + ? "finish all actions" + : "gracefully shutdown but still cannot finish all actions")); + } + } + } + private Worker() { super("BuildFarmShardWorker"); } @@ -626,6 +672,7 @@ public synchronized void stop() throws InterruptedException { private void shutdown() throws InterruptedException { log.info("*** shutting down gRPC server since JVM is shutting down"); + prepareWorkerForGracefulShutdown(); PrometheusPublisher.stopHttpServer(); boolean interrupted = Thread.interrupted(); if (pipeline != null) { From afb06039ae368fa610c6d200b050f14ab0cffd02 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Fri, 14 Jul 2023 08:40:34 -0400 Subject: [PATCH 114/311] Technically correct to unwrap EE on lock failure --- src/main/java/build/buildfarm/cas/cfc/CASFileCache.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java index 21c90e5fee..56e53c3b2c 100644 --- a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java +++ b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java @@ -1917,7 +1917,7 @@ private Entry safeStorageInsertion(String key, Entry entry) { lock = keyLocks.get(key); } catch (ExecutionException e) { // impossible without exception instantiating lock - throw new RuntimeException(e); + throw new RuntimeException(e.getCause()); } lock.lock(); From 9b5ec4340134b4a2825a712744b2d8855f7f80b0 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Tue, 17 Oct 2023 00:40:19 -0400 Subject: [PATCH 115/311] Bump rules_oss_audit and patch for py3.11 --- deps.bzl | 8 +++++--- third_party/rules_oss_audit_pyyaml.patch | 7 +++++++ 2 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 third_party/rules_oss_audit_pyyaml.patch diff --git a/deps.bzl b/deps.bzl index e2d2609acf..55b12ab136 100644 --- a/deps.bzl +++ b/deps.bzl @@ -151,9 +151,11 @@ def archive_dependencies(third_party): }, { "name": "rules_oss_audit", - "sha256": "02962810bcf82d0c66f929ccc163423f53773b8b154574ca956345523243e70d", - "strip_prefix": "rules_oss_audit-1b2690cefd5a960c181e0d89bf3c076294a0e6f4", - "url": "https://github.com/vmware/rules_oss_audit/archive/1b2690cefd5a960c181e0d89bf3c076294a0e6f4.zip", + "sha256": "8ee8376b05b5ddd2287b070e9a88ec85ef907d47f44e321ce5d4bc2b192eed4e", + "strip_prefix": "rules_oss_audit-167dab5b16abdb5996438f22364de544ff24693f", + "url": "https://github.com/vmware/rules_oss_audit/archive/167dab5b16abdb5996438f22364de544ff24693f.zip", + "patch_args": ["-p1"], + "patches": ["%s:rules_oss_audit_pyyaml.patch" % third_party], }, ] diff --git a/third_party/rules_oss_audit_pyyaml.patch b/third_party/rules_oss_audit_pyyaml.patch new file mode 100644 index 0000000000..d2297f018c --- /dev/null +++ b/third_party/rules_oss_audit_pyyaml.patch @@ -0,0 +1,7 @@ +diff --git a/oss_audit/tools/requirements.txt b/oss_audit/tools/requirements.txt +index 932bd69..be2b74d 100644 +--- a/oss_audit/tools/requirements.txt ++++ b/oss_audit/tools/requirements.txt +@@ -1 +1 @@ +-PyYAML==5.4.1 ++PyYAML==6.0.1 From f9ef75aa437e39ab5d93c309d21f7229294eb748 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Tue, 17 Oct 2023 01:11:25 -0400 Subject: [PATCH 116/311] Prevent healthStatusManager NPE on start failure --- src/main/java/build/buildfarm/server/BuildFarmServer.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/build/buildfarm/server/BuildFarmServer.java b/src/main/java/build/buildfarm/server/BuildFarmServer.java index c448963209..d963454de0 100644 --- a/src/main/java/build/buildfarm/server/BuildFarmServer.java +++ b/src/main/java/build/buildfarm/server/BuildFarmServer.java @@ -195,8 +195,10 @@ synchronized void stop() throws InterruptedException { private void shutdown() throws InterruptedException { log.info("*** shutting down gRPC server since JVM is shutting down"); prepareServerForGracefulShutdown(); - healthStatusManager.setStatus( - HealthStatusManager.SERVICE_NAME_ALL_SERVICES, ServingStatus.NOT_SERVING); + if (healthStatusManager != null) { + healthStatusManager.setStatus( + HealthStatusManager.SERVICE_NAME_ALL_SERVICES, ServingStatus.NOT_SERVING); + } PrometheusPublisher.stopHttpServer(); healthCheckMetric.labels("stop").inc(); try { From 20512f6980a2bbefbbd87c39209e345e2781934b Mon Sep 17 00:00:00 2001 From: George Gensure Date: Wed, 1 Nov 2023 16:48:04 -0400 Subject: [PATCH 117/311] Consistent check for publicName presence --- .../java/build/buildfarm/common/config/BuildfarmConfigs.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java b/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java index d6ebbe9e14..945695228f 100644 --- a/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java +++ b/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java @@ -72,7 +72,7 @@ public static BuildfarmConfigs loadServerConfigs(String[] args) throws Configura log.severe("Could not parse yml configuration file." + e); throw new RuntimeException(e); } - if (!options.publicName.isEmpty()) { + if (!Strings.isNullOrEmpty(options.publicName)) { buildfarmConfigs.getServer().setPublicName(options.publicName); } if (options.port > 0) { From 654032e17eb50f75c84d451b2a80c2f94f2c903b Mon Sep 17 00:00:00 2001 From: George Gensure Date: Wed, 1 Nov 2023 16:49:19 -0400 Subject: [PATCH 118/311] Read through external with query THROUGH=true Specifying a correlated invocation id with a uri containing a THROUGH=true query param will cause the CFC to read a blob through an external input stream, populating locally along the way. This permits client-based replication of blobs, and can enable N+1 replication and traffic balancing for reads. --- src/main/java/build/buildfarm/cas/BUILD | 1 + .../build/buildfarm/cas/cfc/CASFileCache.java | 38 ++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/main/java/build/buildfarm/cas/BUILD b/src/main/java/build/buildfarm/cas/BUILD index 146206caee..43e2daccde 100644 --- a/src/main/java/build/buildfarm/cas/BUILD +++ b/src/main/java/build/buildfarm/cas/BUILD @@ -27,6 +27,7 @@ java_library( "@maven//:io_grpc_grpc_core", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", + "@maven//:io_netty_netty_codec_http", "@maven//:io_prometheus_simpleclient", "@maven//:net_jcip_jcip_annotations", "@maven//:org_projectlombok_lombok", diff --git a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java index 56e53c3b2c..d6b47490df 100644 --- a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java +++ b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java @@ -92,6 +92,7 @@ import io.grpc.StatusException; import io.grpc.StatusRuntimeException; import io.grpc.stub.ServerCallStreamObserver; +import io.netty.handler.codec.http.QueryStringDecoder; import io.prometheus.client.Counter; import io.prometheus.client.Gauge; import io.prometheus.client.Histogram; @@ -99,6 +100,8 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.net.URI; +import java.net.URISyntaxException; import java.nio.channels.ClosedByInterruptException; import java.nio.channels.ClosedChannelException; import java.nio.file.FileAlreadyExistsException; @@ -606,6 +609,20 @@ public Blob get(Digest digest) { private static final int CHUNK_SIZE = 128 * 1024; + private static boolean shouldReadThrough(RequestMetadata requestMetadata) { + try { + URI uri = new URI(requestMetadata.getCorrelatedInvocationsId()); + QueryStringDecoder decoder = new QueryStringDecoder(uri); + return decoder + .parameters() + .getOrDefault("THROUGH", ImmutableList.of("false")) + .get(0) + .equals("true"); + } catch (URISyntaxException e) { + return false; + } + } + @Override public void get( Compressor.Value compressor, @@ -614,9 +631,28 @@ public void get( long count, ServerCallStreamObserver blobObserver, RequestMetadata requestMetadata) { + boolean readThrough = shouldReadThrough(requestMetadata); InputStream in; try { - in = newInput(compressor, digest, offset); + if (readThrough && !contains(digest, /* result=*/ null)) { + // really need to be able to reuse/restart the same write over + // multiple requests - if we get successive read throughs for a single + // digest, we should pick up from where we were last time + // Also servers should affinitize + // And share data, so that they can pick the same worker to pull from + // if possible. + Write write = getWrite(compressor, digest, UUID.randomUUID(), requestMetadata); + blobObserver.setOnCancelHandler(write::reset); + in = + new ReadThroughInputStream( + newExternalInput(compressor, digest, 0), + localOffset -> newTransparentInput(compressor, digest, localOffset), + digest.getSizeBytes(), + offset, + write); + } else { + in = newInput(compressor, digest, offset); + } } catch (IOException e) { blobObserver.onError(e); return; From b4359c5af432bf7302080767815e4ce77a1af8c3 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Wed, 1 Nov 2023 16:52:41 -0400 Subject: [PATCH 119/311] Add --port option to worker Option to run the worker with a cmdline specification for its gRPC server port. --- .../java/build/buildfarm/common/config/BuildfarmConfigs.java | 3 +++ .../java/build/buildfarm/common/config/BuildfarmOptions.java | 3 +++ src/main/java/build/buildfarm/common/config/ServerOptions.java | 3 --- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java b/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java index 945695228f..13b41732d8 100644 --- a/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java +++ b/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java @@ -100,6 +100,9 @@ public static BuildfarmConfigs loadWorkerConfigs(String[] args) throws Configura if (!Strings.isNullOrEmpty(options.publicName)) { buildfarmConfigs.getWorker().setPublicName(options.publicName); } + if (options.port >= 0) { + buildfarmConfigs.getWorker().setPort(options.port); + } if (options.prometheusPort >= 0) { buildfarmConfigs.setPrometheusPort(options.prometheusPort); } diff --git a/src/main/java/build/buildfarm/common/config/BuildfarmOptions.java b/src/main/java/build/buildfarm/common/config/BuildfarmOptions.java index 1dbe0c7f98..45d6f4aea3 100644 --- a/src/main/java/build/buildfarm/common/config/BuildfarmOptions.java +++ b/src/main/java/build/buildfarm/common/config/BuildfarmOptions.java @@ -33,4 +33,7 @@ public class BuildfarmOptions extends OptionsBase { help = "URI for Redis connection. Use 'redis://' or 'rediss://' for the scheme", defaultValue = "") public String redisUri; + + @Option(name = "port", help = "Port for the buildfarm service.", defaultValue = "-1") + public int port; } diff --git a/src/main/java/build/buildfarm/common/config/ServerOptions.java b/src/main/java/build/buildfarm/common/config/ServerOptions.java index 35f47d6d13..b151c24c7b 100644 --- a/src/main/java/build/buildfarm/common/config/ServerOptions.java +++ b/src/main/java/build/buildfarm/common/config/ServerOptions.java @@ -18,9 +18,6 @@ /** Command-line options definition for example server. */ public class ServerOptions extends BuildfarmOptions { - @Option(name = "port", abbrev = 'p', help = "Port to use.", defaultValue = "-1") - public int port; - @Option(name = "public_name", abbrev = 'n', help = "Name of this server.", defaultValue = "") public String publicName; } From 51958098e039fcdac2b4230ddb63915fa749f5e7 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Wed, 1 Nov 2023 16:53:31 -0400 Subject: [PATCH 120/311] Restore worker --root cmdline specification Root cmdline specification has been broken since the config change of v2. --- .../java/build/buildfarm/common/config/BuildfarmConfigs.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java b/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java index 13b41732d8..05d7915b27 100644 --- a/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java +++ b/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java @@ -109,6 +109,9 @@ public static BuildfarmConfigs loadWorkerConfigs(String[] args) throws Configura if (!Strings.isNullOrEmpty(options.redisUri)) { buildfarmConfigs.getBackplane().setRedisUri(options.redisUri); } + if (!Strings.isNullOrEmpty(options.root)) { + buildfarmConfigs.getWorker().setRoot(options.root); + } adjustWorkerConfigs(buildfarmConfigs); return buildfarmConfigs; } From 938c789dcdd8603eb6bb1d0525a8d891dbb077c0 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Wed, 1 Nov 2023 16:54:59 -0400 Subject: [PATCH 121/311] Make bf-executor small blob names consistent Remove the size identification for small blobs when uploading with bf-executor. --- src/main/java/build/buildfarm/tools/Executor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/build/buildfarm/tools/Executor.java b/src/main/java/build/buildfarm/tools/Executor.java index 4f2f9f3d6f..901ff33a95 100644 --- a/src/main/java/build/buildfarm/tools/Executor.java +++ b/src/main/java/build/buildfarm/tools/Executor.java @@ -238,7 +238,7 @@ private static void loadFilesIntoCAS(String instanceName, Channel channel, Path ByteStreamStub bsStub = ByteStreamGrpc.newStub(channel); for (Digest missingDigest : missingDigests) { - Path path = blobsDir.resolve(missingDigest.getHash() + "_" + missingDigest.getSizeBytes()); + Path path = blobsDir.resolve(missingDigest.getHash()); if (missingDigest.getSizeBytes() < Size.mbToBytes(1)) { Request request = Request.newBuilder() From 87face12f1544cbd28d9f6e0dc049f7402ed9363 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Thu, 2 Nov 2023 12:22:18 -0400 Subject: [PATCH 122/311] Configured output size operation failure Permit installations to control the failure process for operations which produce outputs larger than the maxEntrySizeBytes. A default value of false retains the existing behavior which appears transient and blacklists the executed action key. When enabled, the action will fail under an invalid violation that indicates user error. --- _site/docs/configuration/configuration.md | 1 + examples/config.yml | 1 + .../build/buildfarm/common/config/Worker.java | 2 ++ .../worker/shard/ShardWorkerContext.java | 20 ++++++++++++++----- .../build/buildfarm/worker/shard/Worker.java | 1 + .../worker/shard/ShardWorkerContextTest.java | 1 + 6 files changed, 21 insertions(+), 5 deletions(-) diff --git a/_site/docs/configuration/configuration.md b/_site/docs/configuration/configuration.md index 466375373f..373968f068 100644 --- a/_site/docs/configuration/configuration.md +++ b/_site/docs/configuration/configuration.md @@ -260,6 +260,7 @@ backplane: | onlyMulticoreTests | boolean, _false_ | | Only permit tests to exceed the default coresvalue for their min/max-cores range specification (only works with non-zero defaultMaxCores) | | allowBringYourOwnContainer | boolean, _false_ | | Enable execution in a custom Docker container | | errorOperationRemainingResources | boolean, _false_ | | | +| errorOperationOutputSizeExceeded | boolean, _false_ | | Operations which produce single output files which exceed maxEntrySizeBytes will fail with a violation type which implies a user error. When disabled, the violation will indicate a transient error, with the action blacklisted. | | realInputDirectories | List of Strings, _external_ | | A list of paths that will not be subject to the effects of linkInputDirectories setting, may also be used to provide writable directories as input roots for actions which expect to be able to write to an input location and will fail if they cannot | | gracefulShutdownSeconds | Integer, 0 | | Time in seconds to allow for operations in flight to finish when shutdown signal is received | | createSymlinkOutputs | boolean, _false_ | | Creates SymlinkNodes for symbolic links discovered in output paths for actions. No verification of the symlink target path occurs. Buildstream, for example, requires this. | diff --git a/examples/config.yml b/examples/config.yml index 008bf2e1ca..69536c5af8 100644 --- a/examples/config.yml +++ b/examples/config.yml @@ -126,6 +126,7 @@ worker: onlyMulticoreTests: false allowBringYourOwnContainer: false errorOperationRemainingResources: false + errorOperationOutputSizeExceeded: false gracefulShutdownSeconds: 0 sandboxSettings: alwaysUse: false diff --git a/src/main/java/build/buildfarm/common/config/Worker.java b/src/main/java/build/buildfarm/common/config/Worker.java index c446134fe2..1a95d94956 100644 --- a/src/main/java/build/buildfarm/common/config/Worker.java +++ b/src/main/java/build/buildfarm/common/config/Worker.java @@ -46,6 +46,8 @@ public class Worker { // If you want GPU actions to run exclusively, define a single GPU resource. private List resources = new ArrayList<>(); + private boolean errorOperationOutputSizeExceeded = false; + public ExecutionPolicy[] getExecutionPolicies() { if (executionPolicies != null) { return executionPolicies; diff --git a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java index 98474b439c..edf7162a36 100644 --- a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java +++ b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java @@ -133,6 +133,7 @@ class ShardWorkerContext implements WorkerContext { private final CasWriter writer; private final boolean errorOperationRemainingResources; private final LocalResourceSet resourceSet; + private final boolean errorOperationOutputSizeExceeded; static SetMultimap getMatchProvisions( Iterable policies, int executeStageWidth) { @@ -166,6 +167,7 @@ static SetMultimap getMatchProvisions( boolean onlyMulticoreTests, boolean allowBringYourOwnContainer, boolean errorOperationRemainingResources, + boolean errorOperationOutputSizeExceeded, LocalResourceSet resourceSet, CasWriter writer) { this.name = name; @@ -187,6 +189,7 @@ static SetMultimap getMatchProvisions( this.onlyMulticoreTests = onlyMulticoreTests; this.allowBringYourOwnContainer = allowBringYourOwnContainer; this.errorOperationRemainingResources = errorOperationRemainingResources; + this.errorOperationOutputSizeExceeded = errorOperationOutputSizeExceeded; this.resourceSet = resourceSet; this.writer = writer; } @@ -504,6 +507,7 @@ private void uploadOutputFile( ActionResult.Builder resultBuilder, Path outputPath, Path actionRoot, + String entrySizeViolationType, PreconditionFailure.Builder preconditionFailure) throws IOException, InterruptedException { String outputFile = actionRoot.relativize(outputPath).toString(); @@ -534,7 +538,7 @@ private void uploadOutputFile( outputPath, size, maxEntrySize); preconditionFailure .addViolationsBuilder() - .setType(VIOLATION_TYPE_MISSING) + .setType(entrySizeViolationType) .setSubject(outputFile + ": " + size) .setDescription(message); return; @@ -562,7 +566,7 @@ private void uploadOutputFile( } catch (EntryLimitException e) { preconditionFailure .addViolationsBuilder() - .setType(VIOLATION_TYPE_MISSING) + .setType(entrySizeViolationType) .setSubject("blobs/" + DigestUtil.toString(digest)) .setDescription( "An output could not be uploaded because it exceeded the maximum size of an entry"); @@ -603,6 +607,7 @@ private void uploadOutputDirectory( ActionResult.Builder resultBuilder, Path outputDirPath, Path actionRoot, + String entrySizeViolationType, PreconditionFailure.Builder preconditionFailure) throws IOException, InterruptedException { String outputDir = actionRoot.relativize(outputDirPath).toString(); @@ -683,7 +688,7 @@ private void visitRegularFile(Path file, BasicFileAttributes attrs) throws IOExc } catch (EntryLimitException e) { preconditionFailure .addViolationsBuilder() - .setType(VIOLATION_TYPE_MISSING) + .setType(entrySizeViolationType) .setSubject("blobs/" + DigestUtil.toString(digest)) .setDescription( "An output could not be uploaded because it exceeded the maximum size of an entry"); @@ -730,14 +735,19 @@ public FileVisitResult postVisitDirectory(Path dir, IOException exc) { public void uploadOutputs( Digest actionDigest, ActionResult.Builder resultBuilder, Path actionRoot, Command command) throws IOException, InterruptedException, StatusException { + String entrySizeViolationType = + errorOperationOutputSizeExceeded ? VIOLATION_TYPE_INVALID : VIOLATION_TYPE_MISSING; + PreconditionFailure.Builder preconditionFailure = PreconditionFailure.newBuilder(); List outputPaths = CommandUtils.getResolvedOutputPaths(command, actionRoot); for (Path outputPath : outputPaths) { if (Files.isDirectory(outputPath)) { - uploadOutputDirectory(resultBuilder, outputPath, actionRoot, preconditionFailure); + uploadOutputDirectory( + resultBuilder, outputPath, actionRoot, entrySizeViolationType, preconditionFailure); } else { - uploadOutputFile(resultBuilder, outputPath, actionRoot, preconditionFailure); + uploadOutputFile( + resultBuilder, outputPath, actionRoot, entrySizeViolationType, preconditionFailure); } } checkPreconditionFailure(actionDigest, preconditionFailure.build()); diff --git a/src/main/java/build/buildfarm/worker/shard/Worker.java b/src/main/java/build/buildfarm/worker/shard/Worker.java index ce69eb3d13..be0c24a1db 100644 --- a/src/main/java/build/buildfarm/worker/shard/Worker.java +++ b/src/main/java/build/buildfarm/worker/shard/Worker.java @@ -611,6 +611,7 @@ public void start() throws ConfigurationException, InterruptedException, IOExcep configs.getWorker().isOnlyMulticoreTests(), configs.getWorker().isAllowBringYourOwnContainer(), configs.getWorker().isErrorOperationRemainingResources(), + configs.getWorker().isErrorOperationOutputSizeExceeded(), LocalResourceSetUtils.create(configs.getWorker().getResources()), writer); diff --git a/src/test/java/build/buildfarm/worker/shard/ShardWorkerContextTest.java b/src/test/java/build/buildfarm/worker/shard/ShardWorkerContextTest.java index c24e681abb..efddbdb866 100644 --- a/src/test/java/build/buildfarm/worker/shard/ShardWorkerContextTest.java +++ b/src/test/java/build/buildfarm/worker/shard/ShardWorkerContextTest.java @@ -106,6 +106,7 @@ WorkerContext createTestContext(Iterable policies) { /* onlyMulticoreTests=*/ false, /* allowBringYourOwnContainer=*/ false, /* errorOperationRemainingResources=*/ false, + /* errorOperationOutputSizeExceeded=*/ false, /* resourceSet=*/ new LocalResourceSet(), writer); } From 58faec9eac95a2e610831051aff507bfb3f81110 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Thu, 2 Nov 2023 12:03:07 -0400 Subject: [PATCH 123/311] Restore abbrev port as -p --- .../build/buildfarm/common/config/BuildfarmOptions.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/build/buildfarm/common/config/BuildfarmOptions.java b/src/main/java/build/buildfarm/common/config/BuildfarmOptions.java index 45d6f4aea3..9fc3f1ed17 100644 --- a/src/main/java/build/buildfarm/common/config/BuildfarmOptions.java +++ b/src/main/java/build/buildfarm/common/config/BuildfarmOptions.java @@ -34,6 +34,10 @@ public class BuildfarmOptions extends OptionsBase { defaultValue = "") public String redisUri; - @Option(name = "port", help = "Port for the buildfarm service.", defaultValue = "-1") + @Option( + name = "port", + abbrev = 'p', + help = "Port for the buildfarm service.", + defaultValue = "-1") public int port; } From cf6fc58d851f529da103129e2a4b36eb6af748d0 Mon Sep 17 00:00:00 2001 From: Jerry Marino Date: Tue, 31 Oct 2023 13:04:16 -0700 Subject: [PATCH 124/311] Update zstd-jni for latest version There's been a few releases of it by now and this pulls the latest. For buildfarm, notable changes included performance enhancments during decompression. See: https://github.com/facebook/zstd/releases/tag/v1.5.5 --- defs.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/defs.bzl b/defs.bzl index 4b0a5e49bf..147177835c 100644 --- a/defs.bzl +++ b/defs.bzl @@ -68,7 +68,7 @@ def buildfarm_init(name = "buildfarm"): "com.github.jnr:jnr-posix:3.0.53", "com.github.pcj:google-options:1.0.0", "com.github.serceman:jnr-fuse:0.5.5", - "com.github.luben:zstd-jni:1.5.2-1", + "com.github.luben:zstd-jni:1.5.5-7", "com.github.oshi:oshi-core:6.4.0", "com.google.auth:google-auth-library-credentials:0.9.1", "com.google.auth:google-auth-library-oauth2-http:0.9.1", From 6bc70e1b3961c74b93886408b57f77bf1689e0f8 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Fri, 3 Nov 2023 11:28:43 -0400 Subject: [PATCH 125/311] Attempt to resolve windows stamping --- .bazelci/presubmit.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index 98b121e215..728e68d02d 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -70,6 +70,7 @@ tasks: build_targets: - "..." test_flags: + - "--@rules_jvm_external//settings:stamp_manifest=False" - "--test_tag_filters=-integration,-redis" test_targets: - "..." From b2267253bbf16ab30fe5b9d1b2dfaa8c87c295ae Mon Sep 17 00:00:00 2001 From: Anshuman Mishra Date: Wed, 1 Nov 2023 19:53:01 -0700 Subject: [PATCH 126/311] Bug: Fix workerSet update logic for RemoteCasWriter --- .../worker/shard/RemoteCasWriter.java | 32 +++++++++---------- .../build/buildfarm/worker/shard/Worker.java | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/main/java/build/buildfarm/worker/shard/RemoteCasWriter.java b/src/main/java/build/buildfarm/worker/shard/RemoteCasWriter.java index 8a5bfdb52f..b03c2794e7 100644 --- a/src/main/java/build/buildfarm/worker/shard/RemoteCasWriter.java +++ b/src/main/java/build/buildfarm/worker/shard/RemoteCasWriter.java @@ -21,6 +21,7 @@ import build.bazel.remote.execution.v2.Compressor; import build.bazel.remote.execution.v2.Digest; import build.bazel.remote.execution.v2.RequestMetadata; +import build.buildfarm.backplane.Backplane; import build.buildfarm.common.Size; import build.buildfarm.common.Write; import build.buildfarm.common.grpc.Retrier; @@ -48,13 +49,13 @@ @Log public class RemoteCasWriter implements CasWriter { - private final Set workerSet; + private final Backplane backplane; private final LoadingCache workerStubs; private final Retrier retrier; public RemoteCasWriter( - Set workerSet, LoadingCache workerStubs, Retrier retrier) { - this.workerSet = workerSet; + Backplane backplane, LoadingCache workerStubs, Retrier retrier) { + this.backplane = backplane; this.workerStubs = workerStubs; this.retrier = retrier; } @@ -114,20 +115,19 @@ public void insertBlob(Digest digest, ByteString content) } private String getRandomWorker() throws IOException { - synchronized (workerSet) { - if (workerSet.isEmpty()) { - throw new IOException("no available workers"); - } - Random rand = new Random(); - int index = rand.nextInt(workerSet.size()); - // best case no allocation average n / 2 selection - Iterator iter = workerSet.iterator(); - String worker = null; - while (iter.hasNext() && index-- >= 0) { - worker = iter.next(); - } - return worker; + Set workerSet = backplane.getStorageWorkers(); + if (workerSet.isEmpty()) { + throw new IOException("no available workers"); } + Random rand = new Random(); + int index = rand.nextInt(workerSet.size()); + // best case no allocation average n / 2 selection + Iterator iter = workerSet.iterator(); + String worker = null; + while (iter.hasNext() && index-- >= 0) { + worker = iter.next(); + } + return worker; } private Instance workerStub(String worker) { diff --git a/src/main/java/build/buildfarm/worker/shard/Worker.java b/src/main/java/build/buildfarm/worker/shard/Worker.java index be0c24a1db..ce7a3e7385 100644 --- a/src/main/java/build/buildfarm/worker/shard/Worker.java +++ b/src/main/java/build/buildfarm/worker/shard/Worker.java @@ -584,7 +584,7 @@ public void start() throws ConfigurationException, InterruptedException, IOExcep CasWriter writer; if (!configs.getWorker().getCapabilities().isCas()) { Retrier retrier = new Retrier(Backoff.sequential(5), Retrier.DEFAULT_IS_RETRIABLE); - writer = new RemoteCasWriter(backplane.getStorageWorkers(), workerStubs, retrier); + writer = new RemoteCasWriter(backplane, workerStubs, retrier); } else { writer = new LocalCasWriter(execFileSystem); } From 751ac90e9d18c8a25c3e8d8c26c3f4b4457310bc Mon Sep 17 00:00:00 2001 From: George Gensure Date: Fri, 3 Nov 2023 20:15:43 -0400 Subject: [PATCH 127/311] Detail storage requirements Update for further docs related to storage+type functionality Remove outdated Operation Queue worker definitions --- _site/docs/architecture/workers.md | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/_site/docs/architecture/workers.md b/_site/docs/architecture/workers.md index 28765b6a7f..ee3e67f8ad 100644 --- a/_site/docs/architecture/workers.md +++ b/_site/docs/architecture/workers.md @@ -7,20 +7,21 @@ nav_order: 2 # Workers -Workers of all types throughout buildfarm are responsible for presenting execution roots to operations that they are matched with, fetching content from a CAS, executing those processes, and reporting the outputs and results of executions. Additionally, buildfarm supports some common behaviors across worker types: +Workers have two major roles in Buildfarm: Execution and CAS Shard. Either of these options can be disabled, though a worker with both disabled provides no value. -* ExecutionPolicies, which allow for explicit and implicit behaviors to control execution. -* A CAS FileCache, which is capable of reading through content for Digests of files or directories, and efficiently presenting those contents based on usage and reference counting, as well as support for cascading into delegate CASs. -* Concurrent pipelined execution of operations, with support for superscalar stages at input fetch and execution. -* Operation exclusivity, preventing the same operation from running through the worker pipeline concurrently. +Regardless of role, a worker must have a local FILESYSTEM type [storage](https://bazelbuild.github.io/bazel-buildfarm/docs/configuration/configuration/#worker-cas) to retain content. This storage serves both as a resident LRU cache for Execution I/O, and the local storage for a CAS Shard. Workers can delegate to successive storage declarations (FILESYSTEM or GRPC), with read-through or expiration waterfall if configured, but only the first storage entry will be used for Executions. -# Worker Types +## Execution -## Operation Queue +Execution Workers are responsible for matching their environments against operations, presenting execution roots to those operations, fetching content from a CAS, executing processes required to complete the operations, and reporting the outputs and results of executions. Control and delivery of these behaviors is accomplished with several mechanisms: -Operation Queue workers are responsible for taking operations from the Memory OperationQueue service and reporting their contents via external CAS and AC services. Executions are the only driving force for their CAS FileCache. For more details on configuring the operation queue, [see here](https://github.com/bazelbuild/bazel-buildfarm/wiki/Operation-Queue). +* A CAS FileCache, which is capable of reading through content for Digests of files or directories, and efficiently presenting those contents based on usage and reference counting, as well as support for cascading into delegate CASs. +* ExecutionPolicies, which allow for explicit and implicit behaviors to control execution. +* Execution Resources to limit concurrent execution in installation-defined resource traunches. +* Concurrent pipelined execution of operations, with support for superscalar stages at input fetch and execution. +* Operation exclusivity, preventing the same operation from running through the worker pipeline concurrently. -## Shard +## CAS Shard Sharded workers interact with the shard backplane for both execution and CAS presentation. Their CAS FileCache serves a CAS gRPC interface as well as the execution root factory. @@ -56,18 +57,20 @@ The Report Result stage injects any outputs from the operation into the CAS, and # Exec Filesystem -Workers must present Exec Filesystems for actions, and manage their existence for the lifetime of an operation's presence within the pipeline. The realization of an operation's execution root with the execution filesystem constitutes a transaction that the operating directory for an action will appear, be writable for outputs, and released and be made unavailable as it proceeds and exits the pipeline. +Workers use ExecFileSystems to present content to actions, and manage their existence for the lifetime of an operation's presence within the pipeline. The realization of an operation's execution root with the execution filesystem constitutes a transaction that the operating directory for an action will appear, be writable for outputs, and released and be made unavailable as it proceeds and exits the pipeline. This means that an action's entire input directory must be available on a filesystem from a unique location per operation - the _Operation Action Input Root_, or just _Root_. Each input file within the Root must contain the content of the inputs, its requested executability via FileNode, and each directory must contain at the outset, child input files and directories. The filesystem is free to handle unspecified outputs as it sees fit, but the directory hierarchy of output files from the Root must be created before execution, and writable during it. When execution and observation of the outputs is completed, the exec filesystem will be asked to destroy the Root and release any associated resources from its retention. -There are two implementations of Execution Filesystem in Buildfarm. Choosing either a `filesystem` or `fuse` `cas` type in the worker config as the first `cas` entry will choose the _CASFileCache_ or _FuseCAS_ implementations, respectively. +Choosing a `filesystem` `storage` type in the worker config as the first `storage` entry will select the _CASFileCache_ _CFCExecFileSystem_. Choosing any other `storage` type will create a _FuseCAS_ _FuseExecFilesystem_. + +***We strongly recommend the use of `filesystem` `storage` as the ExecFileSystem-selecting `storage` entry, the _FuseCAS_ is experimental and may not function reliably over long hauls/with substantial load*** ## CASFileCache/CFCExecFilesystem The CASFileCache provides an Exec Filesystem via CFCExecFilesystem. The (CASFileCache)'s retention of paths is used to reflect individual files, with these paths hard-linked in CFCExecFilesystem under representative directories of the input root to signify usage. The CASFileCache directory retention system is also used to provide a configurable utilization of entire directory trees as a symlink, which was a heuristic optimization applied when substantial cost was observed setting up static trees of input links for operations compared to their execution time. `link_input_directories` in the common Worker configuration will enable this heuristic. Outputs of actions are physically streamed into CAS writes when they are observed after an action execution. -The CASFileCache's persistence in the filesystem and the availability of common POSIX features like symlinks and inode-based reference counts on almost any filesystem implementation have made it a solid choice for extremely large CAS installations - it scales to multi-TB host attached storages with millions of entries with relative ease. +The CASFileCache's persistence in the filesystem and the availability of common POSIX features like symlinks and inode-based reference counts on almost any filesystem implementation have made it a solid choice for extremely large CAS installations - it scales to multi-TB host attached storages containing millions of entries with relative ease. There are plans to improve CASFileCache that will be reflected in improved performance and memory footprint for the features used by CFCExecFilesystem. @@ -75,4 +78,4 @@ There are plans to improve CASFileCache that will be reflected in improved perfo A fuse implementation to provide Roots exists and is specifiable as well. This was an experiment to discover the capacity of a fuse to represent Roots transparently with a ContentAddressableStorage backing, and has not been fully vetted to provide the same reliability as the CFCExecFilesystem. This system is capable of blinking entire trees into existence with ease, as well as supporting write-throughs for outputs suitable for general purpose execution. Some problems with this type were initially observed and never completely resolved, including guaranteed resource release on Root destruction. This implementation is also only built to be backed by its own Memory CAS, with no general purpose CAS support added due to the difficulty of supporting a transaction model for an input tree to enforce the contract of availability. It remains unoptimized yet functional, but difficulties with integrating libfuse 3 into the bazel build, as well as time constraints, have kept it from being scaled and expanded as the rest of Buildfarm has grown. -There are plans to revisit this implementation and bring it back into viability with a CASFileCache-like backing. \ No newline at end of file +There are plans to revisit this implementation and bring it back into viability with a CASFileCache-like backing. From 2bf3eae0b80c55567352ad4b675ea01db32687f7 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Fri, 3 Nov 2023 20:16:22 -0400 Subject: [PATCH 128/311] Fix worker execution env title --- _site/docs/architecture/worker-execution-environment.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_site/docs/architecture/worker-execution-environment.md b/_site/docs/architecture/worker-execution-environment.md index 89bee694fa..a49343fda3 100644 --- a/_site/docs/architecture/worker-execution-environment.md +++ b/_site/docs/architecture/worker-execution-environment.md @@ -1,6 +1,6 @@ --- layout: default -title: Workers +title: Worker Execution Environment parent: Architecture nav_order: 3 --- @@ -124,4 +124,4 @@ java_image( And now that this is in place, we can use the following to build the container and make it available to our local docker daemon: -`bazel run :buildfarm-shard-worker-ubuntu20-java14` \ No newline at end of file +`bazel run :buildfarm-shard-worker-ubuntu20-java14` From b6bddffdeabf108e93e4224829ae9f7c21ba4345 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Fri, 3 Nov 2023 21:32:47 -0400 Subject: [PATCH 129/311] Add storage example descriptions --- _site/docs/configuration/configuration.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/_site/docs/configuration/configuration.md b/_site/docs/configuration/configuration.md index 373968f068..83d56a5900 100644 --- a/_site/docs/configuration/configuration.md +++ b/_site/docs/configuration/configuration.md @@ -325,6 +325,8 @@ worker: ### Worker CAS +Unless specified, options are only relevant for FILESYSTEM type + | Configuration | Accepted and _Default_ Values | Description | |------------------------------|-------------------------------|---------------------------------------------------------------------------------------------------------------| | type | _FILESYSTEM_, GRPC | Type of CAS used | @@ -336,6 +338,8 @@ worker: Example: +This definition will create a filesystem-based CAS file cache at the path "/cache" on the worker that will reject entries over 2GiB in size, and will expire LRU blobs when the aggregate size of all blobs exceeds 2GiB in order to insert additional entries. + ```yaml worker: storages: @@ -343,14 +347,15 @@ worker: path: "cache" maxSizeBytes: 2147483648 # 2 * 1024 * 1024 * 1024 maxEntrySizeBytes: 2147483648 # 2 * 1024 * 1024 * 1024 - target: ``` +This definition elides FILESYSTEM configuration with '...', will read-through an external GRPC CAS supporting the REAPI CAS Services into its storage, and will attempt to write expiring entries into the GRPC CAS (i.e. pushing new entries into the head of a worker LRU list will drop the entries from the tail into the GRPC CAS). + ``` worker: storages: - type: FILESYSTEM - path: "cache" + ... - type: GRPC target: "cas.external.com:1234" ``` From c49092568934d67dd5d80952e428b52757582992 Mon Sep 17 00:00:00 2001 From: Justin Won Date: Mon, 6 Nov 2023 08:10:36 -0800 Subject: [PATCH 130/311] Check for context cancelled before responding to error (#1526) When a write fails because the write was already cancelled before due to something like deadline exceeded, we get an unknown error. The exception comes from here and when it gets to errorResponse(), it only checks if status code is cancelled. In this case the status code is unknown, so we need to check if context is cancelled to prevent responseObserver from being invoked The code change adds checking if context is cancelled and a unit test testing when the exception has context cancelled. --- .../common/services/WriteStreamObserver.java | 3 +- .../services/WriteStreamObserverTest.java | 48 +++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java b/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java index 36cc0595a6..dd52f7769e 100644 --- a/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java +++ b/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java @@ -271,7 +271,8 @@ private void logWriteRequest(WriteRequest request, Exception e) { private boolean errorResponse(Throwable t) { if (exception.compareAndSet(null, t)) { - if (Status.fromThrowable(t).getCode() == Status.Code.CANCELLED) { + if (Status.fromThrowable(t).getCode() == Status.Code.CANCELLED + || Context.current().isCancelled()) { return false; } boolean isEntryLimitException = t instanceof EntryLimitException; diff --git a/src/test/java/build/buildfarm/common/services/WriteStreamObserverTest.java b/src/test/java/build/buildfarm/common/services/WriteStreamObserverTest.java index 4249223990..b6d144a66b 100644 --- a/src/test/java/build/buildfarm/common/services/WriteStreamObserverTest.java +++ b/src/test/java/build/buildfarm/common/services/WriteStreamObserverTest.java @@ -28,6 +28,7 @@ import io.grpc.Context; import io.grpc.Context.CancellableContext; import io.grpc.stub.StreamObserver; +import java.io.IOException; import java.util.UUID; import java.util.concurrent.TimeUnit; import org.junit.Test; @@ -90,4 +91,51 @@ public void cancelledBeforeGetOutputIsSilent() throws Exception { verify(out, times(1)).close(); verifyZeroInteractions(responseObserver); } + + @Test + public void noErrorWhenContextCancelled() throws Exception { + CancellableContext context = Context.current().withCancellation(); + Instance instance = mock(Instance.class); + StreamObserver responseObserver = mock(StreamObserver.class); + ByteString cancelled = ByteString.copyFromUtf8("cancelled data"); + Digest cancelledDigest = DIGEST_UTIL.compute(cancelled); + UUID uuid = UUID.randomUUID(); + UploadBlobRequest uploadBlobRequest = + UploadBlobRequest.newBuilder() + .setBlob(BlobInformation.newBuilder().setDigest(cancelledDigest)) + .setUuid(uuid.toString()) + .build(); + SettableFuture future = SettableFuture.create(); + Write write = mock(Write.class); + when(write.getFuture()).thenReturn(future); + when(write.isComplete()).thenReturn(Boolean.TRUE); + when(instance.getBlobWrite( + eq(Compressor.Value.IDENTITY), + eq(cancelledDigest), + eq(uuid), + any(RequestMetadata.class))) + .thenReturn(write); + + WriteStreamObserver observer = + context.call( + () -> new WriteStreamObserver(instance, 1, SECONDS, () -> {}, responseObserver)); + context.run( + () -> + observer.onNext( + WriteRequest.newBuilder() + .setResourceName(uploadResourceName(uploadBlobRequest)) + .setData(cancelled) + .build())); + context.cancel(new RuntimeException("Cancelled by test")); + future.setException(new IOException("test cancel")); + + verify(write, times(1)).isComplete(); + verify(instance, times(1)) + .getBlobWrite( + eq(Compressor.Value.IDENTITY), + eq(cancelledDigest), + eq(uuid), + any(RequestMetadata.class)); + verifyZeroInteractions(responseObserver); + } } From 2a51c3183c72147c4e1d73ad184941ef04a2ea6e Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Mon, 16 Oct 2023 11:41:41 -0700 Subject: [PATCH 131/311] chore(deps): bump com.google.errorprone:error-prone Release notes: https://github.com/google/error-prone/releases/tag/v2.22.0 --- defs.bzl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/defs.bzl b/defs.bzl index 147177835c..a40dccaefe 100644 --- a/defs.bzl +++ b/defs.bzl @@ -74,8 +74,8 @@ def buildfarm_init(name = "buildfarm"): "com.google.auth:google-auth-library-oauth2-http:0.9.1", "com.google.code.findbugs:jsr305:3.0.1", "com.google.code.gson:gson:2.9.0", - "com.google.errorprone:error_prone_annotations:2.9.0", - "com.google.errorprone:error_prone_core:0.92", + "com.google.errorprone:error_prone_annotations:2.22.0", + "com.google.errorprone:error_prone_core:2.22.0", "com.google.guava:failureaccess:1.0.1", "com.google.guava:guava:32.1.1-jre", "com.google.j2objc:j2objc-annotations:1.1", From 7ea1a9fb1ce46705ee774c98e92fe097f16898f9 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Wed, 8 Nov 2023 15:49:27 -0500 Subject: [PATCH 132/311] Worker name execution properties matching --- .../buildfarm/common/ExecutionProperties.java | 7 +++ .../worker/DequeueMatchEvaluator.java | 23 +++++++++- .../worker/shard/ShardWorkerContext.java | 3 +- .../worker/DequeueMatchEvaluatorTest.java | 44 +++++++++++++------ 4 files changed, 62 insertions(+), 15 deletions(-) diff --git a/src/main/java/build/buildfarm/common/ExecutionProperties.java b/src/main/java/build/buildfarm/common/ExecutionProperties.java index 8126bd607a..ee3975d6dd 100644 --- a/src/main/java/build/buildfarm/common/ExecutionProperties.java +++ b/src/main/java/build/buildfarm/common/ExecutionProperties.java @@ -293,4 +293,11 @@ public class ExecutionProperties { * operation queue). */ public static final String POOL = "Pool"; + + /** + * @field WORKER + * @brief The exec_property to ensure that the action only runs on the worker name given. + * @details Useful for diagnosing woker issues by targeting builds to a specific worker. + */ + public static final String WORKER = "Worker"; } diff --git a/src/main/java/build/buildfarm/worker/DequeueMatchEvaluator.java b/src/main/java/build/buildfarm/worker/DequeueMatchEvaluator.java index 3536ed6bac..59ccd00e37 100644 --- a/src/main/java/build/buildfarm/worker/DequeueMatchEvaluator.java +++ b/src/main/java/build/buildfarm/worker/DequeueMatchEvaluator.java @@ -46,6 +46,7 @@ public class DequeueMatchEvaluator { * @brief Decide whether the worker should keep the operation or put it back on the queue. * @details Compares the platform properties of the worker to the operation's platform properties. * @param workerProvisions The provisions of the worker. + * @param name Worker name. * @param resourceSet The limited resources that the worker has available. * @param queueEntry An entry recently removed from the queue. * @return Whether or not the worker should accept or reject the queue entry. @@ -56,9 +57,10 @@ public class DequeueMatchEvaluator { @NotNull public static boolean shouldKeepOperation( SetMultimap workerProvisions, + String name, LocalResourceSet resourceSet, QueueEntry queueEntry) { - return shouldKeepViaPlatform(workerProvisions, resourceSet, queueEntry.getPlatform()); + return shouldKeepViaPlatform(workerProvisions, name, resourceSet, queueEntry.getPlatform()); } /** @@ -67,6 +69,7 @@ public static boolean shouldKeepOperation( * @details Compares the platform properties of the worker to the platform properties of the * operation. * @param workerProvisions The provisions of the worker. + * @param name Worker name. * @param resourceSet The limited resources that the worker has available. * @param platform The platforms of operation. * @return Whether or not the worker should accept or reject the operation. @@ -76,6 +79,7 @@ public static boolean shouldKeepOperation( @NotNull private static boolean shouldKeepViaPlatform( SetMultimap workerProvisions, + String name, LocalResourceSet resourceSet, Platform platform) { // attempt to execute everything the worker gets off the queue, @@ -84,6 +88,12 @@ private static boolean shouldKeepViaPlatform( if (!LocalResourceSetUtils.claimResources(platform, resourceSet)) { return false; } + + // The action might be requesting to run on a particular action + if (!keepForThisWorker(platform, name)) { + return false; + } + if (configs.getWorker().getDequeueMatchSettings().isAcceptEverything()) { return true; } @@ -91,6 +101,17 @@ private static boolean shouldKeepViaPlatform( return satisfiesProperties(workerProvisions, platform); } + private static boolean keepForThisWorker(Platform platform, String name) { + for (Platform.Property property : platform.getPropertiesList()) { + if (property.getName().equals(ExecutionProperties.WORKER) + && !property.getValue().equals(name)) { + // requested worker does not match this worker, reject + return false; + } + } + return true; + } + /** * @brief Decide whether the worker should keep the operation by comparing its platform properties * with the queue entry. diff --git a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java index edf7162a36..5194444910 100644 --- a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java +++ b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java @@ -315,7 +315,8 @@ private QueueEntry takeEntryOffOperationQueue(MatchListener listener) private void decideWhetherToKeepOperation(QueueEntry queueEntry, MatchListener listener) throws IOException, InterruptedException { if (queueEntry == null - || DequeueMatchEvaluator.shouldKeepOperation(matchProvisions, resourceSet, queueEntry)) { + || DequeueMatchEvaluator.shouldKeepOperation( + matchProvisions, name, resourceSet, queueEntry)) { listener.onEntry(queueEntry); } else { backplane.rejectOperation(queueEntry); diff --git a/src/test/java/build/buildfarm/worker/DequeueMatchEvaluatorTest.java b/src/test/java/build/buildfarm/worker/DequeueMatchEvaluatorTest.java index 47f25cdf79..290470b845 100644 --- a/src/test/java/build/buildfarm/worker/DequeueMatchEvaluatorTest.java +++ b/src/test/java/build/buildfarm/worker/DequeueMatchEvaluatorTest.java @@ -59,7 +59,8 @@ public void shouldKeepOperationKeepEmptyQueueEntry() throws Exception { // ACT boolean shouldKeep = - DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + DequeueMatchEvaluator.shouldKeepOperation( + workerProvisions, "worker-name", resourceSet, entry); // ASSERT assertThat(shouldKeep).isTrue(); @@ -87,7 +88,8 @@ public void shouldKeepOperationValidMinCoresQueueEntry() throws Exception { // ACT boolean shouldKeep = - DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + DequeueMatchEvaluator.shouldKeepOperation( + workerProvisions, "worker-name", resourceSet, entry); // ASSERT // the worker accepts because it has more cores than the min-cores requested @@ -117,7 +119,8 @@ public void shouldKeepOperationInvalidMinCoresQueueEntry() throws Exception { // ACT boolean shouldKeep = - DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + DequeueMatchEvaluator.shouldKeepOperation( + workerProvisions, "worker-name", resourceSet, entry); // ASSERT // the worker rejects because it has less cores than the min-cores requested @@ -146,7 +149,8 @@ public void shouldKeepOperationMaxCoresDoNotInfluenceAcceptance() throws Excepti // ACT boolean shouldKeep = - DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + DequeueMatchEvaluator.shouldKeepOperation( + workerProvisions, "worker-name", resourceSet, entry); // ASSERT // the worker accepts because it has the same cores as the min-cores requested @@ -175,7 +179,8 @@ public void shouldKeepOperationUnmatchedPropertiesRejectionAcceptance() throws E // ACT boolean shouldKeep = - DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + DequeueMatchEvaluator.shouldKeepOperation( + workerProvisions, "worker-name", resourceSet, entry); // ASSERT assertThat(shouldKeep).isFalse(); @@ -184,7 +189,9 @@ public void shouldKeepOperationUnmatchedPropertiesRejectionAcceptance() throws E configs.getWorker().getDequeueMatchSettings().setAcceptEverything(true); // ACT - shouldKeep = DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + shouldKeep = + DequeueMatchEvaluator.shouldKeepOperation( + workerProvisions, "worker-name", resourceSet, entry); // ASSERT assertThat(shouldKeep).isTrue(); @@ -193,7 +200,9 @@ public void shouldKeepOperationUnmatchedPropertiesRejectionAcceptance() throws E configs.getWorker().getDequeueMatchSettings().setAllowUnmatched(true); // ACT - shouldKeep = DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + shouldKeep = + DequeueMatchEvaluator.shouldKeepOperation( + workerProvisions, "worker-name", resourceSet, entry); // ASSERT assertThat(shouldKeep).isTrue(); @@ -224,7 +233,8 @@ public void shouldKeepOperationClaimsResource() throws Exception { // ACT boolean shouldKeep = - DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + DequeueMatchEvaluator.shouldKeepOperation( + workerProvisions, "worker-name", resourceSet, entry); // ASSERT // the worker accepts because the resource is available. @@ -232,7 +242,9 @@ public void shouldKeepOperationClaimsResource() throws Exception { assertThat(resourceSet.resources.get("FOO").availablePermits()).isEqualTo(0); // ACT - shouldKeep = DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + shouldKeep = + DequeueMatchEvaluator.shouldKeepOperation( + workerProvisions, "worker-name", resourceSet, entry); // ASSERT // the worker rejects because there are no resources left. @@ -269,7 +281,8 @@ public void shouldKeepOperationClaimsMultipleResource() throws Exception { // ACT boolean shouldKeep = - DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + DequeueMatchEvaluator.shouldKeepOperation( + workerProvisions, "worker-name", resourceSet, entry); // ASSERT // the worker accepts because the resource is available. @@ -278,7 +291,9 @@ public void shouldKeepOperationClaimsMultipleResource() throws Exception { assertThat(resourceSet.resources.get("BAR").availablePermits()).isEqualTo(2); // ACT - shouldKeep = DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + shouldKeep = + DequeueMatchEvaluator.shouldKeepOperation( + workerProvisions, "worker-name", resourceSet, entry); // ASSERT // the worker accepts because the resource is available. @@ -287,7 +302,9 @@ public void shouldKeepOperationClaimsMultipleResource() throws Exception { assertThat(resourceSet.resources.get("BAR").availablePermits()).isEqualTo(0); // ACT - shouldKeep = DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + shouldKeep = + DequeueMatchEvaluator.shouldKeepOperation( + workerProvisions, "worker-name", resourceSet, entry); // ASSERT // the worker rejects because there are no resources left. @@ -330,7 +347,8 @@ public void shouldKeepOperationFailsToClaimSameAmountRemains() throws Exception // ACT boolean shouldKeep = - DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + DequeueMatchEvaluator.shouldKeepOperation( + workerProvisions, "worker-name", resourceSet, entry); // ASSERT // the worker rejects because there are no resources left. From a4822c125ae45b775e95d5eacbfa137aa38145ae Mon Sep 17 00:00:00 2001 From: Trevor Hickey Date: Fri, 21 Apr 2023 15:31:25 -0400 Subject: [PATCH 133/311] updates --- _site/docs/configuration/configuration.md | 12 +++++++----- examples/config.yml | 1 + .../buildfarm/common/config/SandboxSettings.java | 7 +++++++ .../buildfarm/worker/resources/ResourceDecider.java | 8 +++++++- 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/_site/docs/configuration/configuration.md b/_site/docs/configuration/configuration.md index 83d56a5900..4be39b9127 100644 --- a/_site/docs/configuration/configuration.md +++ b/_site/docs/configuration/configuration.md @@ -291,11 +291,12 @@ worker: ### Sandbox Settings -| Configuration | Accepted and _Default_ Values | Description | -|---------------|-------------------------------|---------------------------------------------------| -| alwaysUse | boolean, _false_ | Enforce that the sandbox be used on every acion. | -| selectForBlockNetwork | boolean, _false_ | `block-network` enables sandbox action execution. | -| selectForTmpFs | boolean, _false_ | `tmpfs` enables sandbox action execution. | +| Configuration | Accepted and _Default_ Values | Description | +|---------------|-------------------------------|------------------------------------------------------| +| alwaysUse | boolean, _false_ | Enforce that the sandbox be used on every acion. | +| alwaysUseTmpFs | boolean, _false_ | Enforce that the sandbox uses tmpfs on every acion. | +| selectForBlockNetwork | boolean, _false_ | `block-network` enables sandbox action execution. | +| selectForTmpFs | boolean, _false_ | `tmpfs` enables sandbox action execution. | Example: @@ -303,6 +304,7 @@ Example: worker: sandboxSettings: alwaysUse: true + alwaysUseTmpFs: true selectForBlockNetwork: false selectForTmpFs: false ``` diff --git a/examples/config.yml b/examples/config.yml index 69536c5af8..b0626f467e 100644 --- a/examples/config.yml +++ b/examples/config.yml @@ -130,6 +130,7 @@ worker: gracefulShutdownSeconds: 0 sandboxSettings: alwaysUse: false + alwaysUseTmpFs: false selectForBlockNetwork: false selectForTmpFs: false createSymlinkOutputs: false diff --git a/src/main/java/build/buildfarm/common/config/SandboxSettings.java b/src/main/java/build/buildfarm/common/config/SandboxSettings.java index 030377bf0c..b7e238a07e 100644 --- a/src/main/java/build/buildfarm/common/config/SandboxSettings.java +++ b/src/main/java/build/buildfarm/common/config/SandboxSettings.java @@ -32,6 +32,13 @@ public class SandboxSettings { */ public boolean alwaysUse = false; + /** + * @field alwaysUseTmpFs + * @brief Whether or not to always use tmpfs when using the sandbox. + * @details It may be preferred to enforce sandbox usage than rely on client selection. + */ + public boolean alwaysUseTmpFs = false; + /** * @field selectForBlockNetwork * @brief If the action requires "block network" use the sandbox to fulfill this request. diff --git a/src/main/java/build/buildfarm/worker/resources/ResourceDecider.java b/src/main/java/build/buildfarm/worker/resources/ResourceDecider.java index a5229a3377..bd352a00a3 100644 --- a/src/main/java/build/buildfarm/worker/resources/ResourceDecider.java +++ b/src/main/java/build/buildfarm/worker/resources/ResourceDecider.java @@ -203,10 +203,16 @@ private static void decideSandboxUsage(ResourceLimits limits, SandboxSettings sa // configured on if (sandbox.isAlwaysUse()) { limits.useLinuxSandbox = true; - limits.description.add("enabled"); + limits.description.add("enabled sandbox by default"); return; } + // configured on + if (sandbox.isAlwaysUseTmpFs()) { + limits.tmpFs = true; + limits.description.add("enabled tmpfs by default"); + } + // selected based on other features if (limits.network.blockNetwork && sandbox.isSelectForBlockNetwork()) { limits.useLinuxSandbox = true; From f1ea9b51280557b3b6b68c8a36fc53ecb35c9bc8 Mon Sep 17 00:00:00 2001 From: Trevor Hickey Date: Fri, 21 Apr 2023 16:45:31 -0400 Subject: [PATCH 134/311] updates --- .../common/config/SandboxSettings.java | 7 ++++ .../worker/resources/ResourceDecider.java | 11 ++++-- .../worker/resources/ResourceLimits.java | 7 ++++ .../worker/shard/ShardWorkerContext.java | 39 ++++++++++--------- 4 files changed, 42 insertions(+), 22 deletions(-) diff --git a/src/main/java/build/buildfarm/common/config/SandboxSettings.java b/src/main/java/build/buildfarm/common/config/SandboxSettings.java index b7e238a07e..d9988c845b 100644 --- a/src/main/java/build/buildfarm/common/config/SandboxSettings.java +++ b/src/main/java/build/buildfarm/common/config/SandboxSettings.java @@ -32,6 +32,13 @@ public class SandboxSettings { */ public boolean alwaysUse = false; + /** + * @field alwaysUseCgroups + * @brief Whether or not to use cgroups when sandboxing actions. + * @details It may be preferred to enforce cgroup usage. + */ + public boolean alwaysUseCgroups = false; + /** * @field alwaysUseTmpFs * @brief Whether or not to always use tmpfs when using the sandbox. diff --git a/src/main/java/build/buildfarm/worker/resources/ResourceDecider.java b/src/main/java/build/buildfarm/worker/resources/ResourceDecider.java index bd352a00a3..78021f1ed5 100644 --- a/src/main/java/build/buildfarm/worker/resources/ResourceDecider.java +++ b/src/main/java/build/buildfarm/worker/resources/ResourceDecider.java @@ -200,14 +200,17 @@ private static void adjustLimits( } private static void decideSandboxUsage(ResourceLimits limits, SandboxSettings sandbox) { - // configured on + + // Decide which sandbox limitations are enabled by default acording to the deployment's + // configuration. if (sandbox.isAlwaysUse()) { limits.useLinuxSandbox = true; limits.description.add("enabled sandbox by default"); - return; } - - // configured on + if (sandbox.isAlwaysUseCgroups()) { + limits.cgroups = true; + limits.description.add("enabled cgroups by default"); + } if (sandbox.isAlwaysUseTmpFs()) { limits.tmpFs = true; limits.description.add("enabled tmpfs by default"); diff --git a/src/main/java/build/buildfarm/worker/resources/ResourceLimits.java b/src/main/java/build/buildfarm/worker/resources/ResourceLimits.java index 4e5601625c..e3ddc4485b 100644 --- a/src/main/java/build/buildfarm/worker/resources/ResourceLimits.java +++ b/src/main/java/build/buildfarm/worker/resources/ResourceLimits.java @@ -75,6 +75,13 @@ public class ResourceLimits { */ public ContainerSettings containerSettings = new ContainerSettings(); + /** + * @field cgroups + * @brief Whether to use cgroups for resource limitation. + * @details Decides whether to use cgroups for restricting cores, mem, etc. + */ + public boolean cgroups = true; + /** * @field cpu * @brief Resource limitations on CPUs. diff --git a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java index 5194444910..590d492dee 100644 --- a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java +++ b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java @@ -922,28 +922,31 @@ IOResource limitSpecifiedExecution( // ResourceLimits object. We apply the cgroup settings to file resources // and collect group names to use on the CLI. String operationId = getOperationId(operationName); - final Group group = operationsGroup.getChild(operationId); ArrayList resources = new ArrayList<>(); - ArrayList usedGroups = new ArrayList<>(); - // Possibly set core restrictions. - if (limits.cpu.limit) { - applyCpuLimits(group, limits, resources); - usedGroups.add(group.getCpu().getName()); - } + if (limits.cgroups) { + final Group group = operationsGroup.getChild(operationId); + ArrayList usedGroups = new ArrayList<>(); - // Possibly set memory restrictions. - if (limits.mem.limit) { - applyMemLimits(group, limits, resources); - usedGroups.add(group.getMem().getName()); - } + // Possibly set core restrictions. + if (limits.cpu.limit) { + applyCpuLimits(group, limits, resources); + usedGroups.add(group.getCpu().getName()); + } - // Decide the CLI for running under cgroups - if (!usedGroups.isEmpty()) { - arguments.add( - configs.getExecutionWrappers().getCgroups(), - "-g", - String.join(",", usedGroups) + ":" + group.getHierarchy()); + // Possibly set memory restrictions. + if (limits.mem.limit) { + applyMemLimits(group, limits, resources); + usedGroups.add(group.getMem().getName()); + } + + // Decide the CLI for running under cgroups + if (!usedGroups.isEmpty()) { + arguments.add( + configs.getExecutionWrappers().getCgroups(), + "-g", + String.join(",", usedGroups) + ":" + group.getHierarchy()); + } } // Possibly set network restrictions. From ccf763da22b173967b9ee8bad1dcc4f3b8f80a1e Mon Sep 17 00:00:00 2001 From: Trevor Hickey Date: Fri, 21 Apr 2023 16:49:24 -0400 Subject: [PATCH 135/311] updates --- .../java/build/buildfarm/common/config/SandboxSettings.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/build/buildfarm/common/config/SandboxSettings.java b/src/main/java/build/buildfarm/common/config/SandboxSettings.java index d9988c845b..fc56aa889f 100644 --- a/src/main/java/build/buildfarm/common/config/SandboxSettings.java +++ b/src/main/java/build/buildfarm/common/config/SandboxSettings.java @@ -37,7 +37,7 @@ public class SandboxSettings { * @brief Whether or not to use cgroups when sandboxing actions. * @details It may be preferred to enforce cgroup usage. */ - public boolean alwaysUseCgroups = false; + public boolean alwaysUseCgroups = true; /** * @field alwaysUseTmpFs From b7f56613d1aa5a963beb254028c1ea8e86acb17c Mon Sep 17 00:00:00 2001 From: Trevor Hickey Date: Fri, 21 Apr 2023 16:56:00 -0400 Subject: [PATCH 136/311] updates --- _site/docs/configuration/configuration.md | 8 ++++++-- examples/config.yml | 3 ++- .../build/buildfarm/common/config/SandboxSettings.java | 4 ++-- .../build/buildfarm/worker/resources/ResourceDecider.java | 3 +-- .../buildfarm/worker/resources/ResourceDeciderTest.java | 2 +- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/_site/docs/configuration/configuration.md b/_site/docs/configuration/configuration.md index 4be39b9127..83d4dcc8d0 100644 --- a/_site/docs/configuration/configuration.md +++ b/_site/docs/configuration/configuration.md @@ -293,7 +293,8 @@ worker: | Configuration | Accepted and _Default_ Values | Description | |---------------|-------------------------------|------------------------------------------------------| -| alwaysUse | boolean, _false_ | Enforce that the sandbox be used on every acion. | +| alwaysUseSandbox | boolean, _false_ | Enforce that the sandbox be used on every acion. | +| alwaysUseCgroups | boolean, _true_ | Enforce that actions run under cgroups. | | alwaysUseTmpFs | boolean, _false_ | Enforce that the sandbox uses tmpfs on every acion. | | selectForBlockNetwork | boolean, _false_ | `block-network` enables sandbox action execution. | | selectForTmpFs | boolean, _false_ | `tmpfs` enables sandbox action execution. | @@ -303,12 +304,15 @@ Example: ```yaml worker: sandboxSettings: - alwaysUse: true + alwaysUseSandbox: true + alwaysUseCgroups: true alwaysUseTmpFs: true selectForBlockNetwork: false selectForTmpFs: false ``` +Note: In order for these settings to take effect, you must also configure `limitGlobalExecution: true`. + ### Dequeue Match | Configuration | Accepted and _Default_ Values | Description | diff --git a/examples/config.yml b/examples/config.yml index b0626f467e..d69688b5b4 100644 --- a/examples/config.yml +++ b/examples/config.yml @@ -129,7 +129,8 @@ worker: errorOperationOutputSizeExceeded: false gracefulShutdownSeconds: 0 sandboxSettings: - alwaysUse: false + alwaysUseSandbox: false + alwaysUseCgroups: false alwaysUseTmpFs: false selectForBlockNetwork: false selectForTmpFs: false diff --git a/src/main/java/build/buildfarm/common/config/SandboxSettings.java b/src/main/java/build/buildfarm/common/config/SandboxSettings.java index fc56aa889f..f432989015 100644 --- a/src/main/java/build/buildfarm/common/config/SandboxSettings.java +++ b/src/main/java/build/buildfarm/common/config/SandboxSettings.java @@ -26,11 +26,11 @@ @Data public class SandboxSettings { /** - * @field alwaysUse + * @field alwaysUseSandbox * @brief Whether or not to always use the sandbox when running actions. * @details It may be preferred to enforce sandbox usage than rely on client selection. */ - public boolean alwaysUse = false; + public boolean alwaysUseSandbox = false; /** * @field alwaysUseCgroups diff --git a/src/main/java/build/buildfarm/worker/resources/ResourceDecider.java b/src/main/java/build/buildfarm/worker/resources/ResourceDecider.java index 78021f1ed5..5523f1aa79 100644 --- a/src/main/java/build/buildfarm/worker/resources/ResourceDecider.java +++ b/src/main/java/build/buildfarm/worker/resources/ResourceDecider.java @@ -200,10 +200,9 @@ private static void adjustLimits( } private static void decideSandboxUsage(ResourceLimits limits, SandboxSettings sandbox) { - // Decide which sandbox limitations are enabled by default acording to the deployment's // configuration. - if (sandbox.isAlwaysUse()) { + if (sandbox.isAlwaysUseSandbox()) { limits.useLinuxSandbox = true; limits.description.add("enabled sandbox by default"); } diff --git a/src/test/java/build/buildfarm/worker/resources/ResourceDeciderTest.java b/src/test/java/build/buildfarm/worker/resources/ResourceDeciderTest.java index 8fa711ab5a..9c531c7e78 100644 --- a/src/test/java/build/buildfarm/worker/resources/ResourceDeciderTest.java +++ b/src/test/java/build/buildfarm/worker/resources/ResourceDeciderTest.java @@ -726,7 +726,7 @@ public void decideResourceLimitationsAlwaysUseSandbox() throws Exception { // ARRANGE Command command = Command.newBuilder().build(); SandboxSettings sandboxSettings = new SandboxSettings(); - sandboxSettings.alwaysUse = true; + sandboxSettings.alwaysUseSandbox = true; // ACT ResourceLimits limits = From 72b40ae5c3bf757e9129bbea272fc9a2f5b94bab Mon Sep 17 00:00:00 2001 From: Trevor Hickey Date: Sun, 23 Apr 2023 13:41:39 -0400 Subject: [PATCH 137/311] updates --- .../worker/shard/ShardWorkerContext.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java index 590d492dee..ad46a7cae9 100644 --- a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java +++ b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java @@ -829,7 +829,9 @@ boolean shouldLimitCoreUsage() { @Override public void createExecutionLimits() { if (shouldLimitCoreUsage()) { - createOperationExecutionLimits(); + if (configs.getWorker().getSandboxSettings().isAlwaysUseCgroups()) { + createOperationExecutionLimits(); + } } } @@ -860,11 +862,13 @@ void createOperationExecutionLimits() { @Override public void destroyExecutionLimits() { - try { - operationsGroup.getCpu().close(); - executionsGroup.getCpu().close(); - } catch (IOException e) { - throw new RuntimeException(e); + if (configs.getWorker().getSandboxSettings().isAlwaysUseCgroups()) { + try { + operationsGroup.getCpu().close(); + executionsGroup.getCpu().close(); + } catch (IOException e) { + throw new RuntimeException(e); + } } } From 14c759b4be181bb3bffa8adc18c0deb87a70c3fb Mon Sep 17 00:00:00 2001 From: Trevor Hickey Date: Thu, 9 Nov 2023 05:15:56 +0800 Subject: [PATCH 138/311] Update ShardWorkerContext.java --- .../java/build/buildfarm/worker/shard/ShardWorkerContext.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java index ad46a7cae9..a8058f6f5e 100644 --- a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java +++ b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java @@ -828,10 +828,8 @@ boolean shouldLimitCoreUsage() { @Override public void createExecutionLimits() { - if (shouldLimitCoreUsage()) { - if (configs.getWorker().getSandboxSettings().isAlwaysUseCgroups()) { + if (shouldLimitCoreUsage() && configs.getWorker().getSandboxSettings().isAlwaysUseCgroups()) { createOperationExecutionLimits(); - } } } From ca9bb92b9f72f463d7d653298e2ca2619c451e2e Mon Sep 17 00:00:00 2001 From: Trevor Hickey Date: Thu, 9 Nov 2023 05:17:08 +0800 Subject: [PATCH 139/311] Update ShardWorkerContext.java --- .../java/build/buildfarm/worker/shard/ShardWorkerContext.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java index a8058f6f5e..11f5e49b35 100644 --- a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java +++ b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java @@ -828,8 +828,8 @@ boolean shouldLimitCoreUsage() { @Override public void createExecutionLimits() { - if (shouldLimitCoreUsage() && configs.getWorker().getSandboxSettings().isAlwaysUseCgroups()) { - createOperationExecutionLimits(); + if (shouldLimitCoreUsage() && configs.getWorker().getSandboxSettings().isAlwaysUseCgroups()) { + createOperationExecutionLimits(); } } From 35883a4d064c33f2c507e51c11661ca761543e44 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Thu, 9 Nov 2023 13:25:39 -0500 Subject: [PATCH 140/311] Release resources when not keeping an operation (#1535) --- .../worker/DequeueMatchEvaluator.java | 18 +++++---- .../buildfarm/worker/DequeueResults.java | 38 ++++++++++++++++++ .../worker/shard/ShardWorkerContext.java | 18 ++++++--- .../worker/DequeueMatchEvaluatorTest.java | 39 ++++++++++++------- 4 files changed, 88 insertions(+), 25 deletions(-) create mode 100644 src/main/java/build/buildfarm/worker/DequeueResults.java diff --git a/src/main/java/build/buildfarm/worker/DequeueMatchEvaluator.java b/src/main/java/build/buildfarm/worker/DequeueMatchEvaluator.java index 59ccd00e37..997fc6862c 100644 --- a/src/main/java/build/buildfarm/worker/DequeueMatchEvaluator.java +++ b/src/main/java/build/buildfarm/worker/DequeueMatchEvaluator.java @@ -55,7 +55,7 @@ public class DequeueMatchEvaluator { */ @SuppressWarnings("NullableProblems") @NotNull - public static boolean shouldKeepOperation( + public static DequeueResults shouldKeepOperation( SetMultimap workerProvisions, String name, LocalResourceSet resourceSet, @@ -77,28 +77,32 @@ public static boolean shouldKeepOperation( */ @SuppressWarnings("NullableProblems") @NotNull - private static boolean shouldKeepViaPlatform( + private static DequeueResults shouldKeepViaPlatform( SetMultimap workerProvisions, String name, LocalResourceSet resourceSet, Platform platform) { // attempt to execute everything the worker gets off the queue, // provided there is enough resources to do so. - // this is a recommended configuration. + DequeueResults results = new DequeueResults(); + if (!LocalResourceSetUtils.claimResources(platform, resourceSet)) { - return false; + return results; } + results.resourcesClaimed = true; // The action might be requesting to run on a particular action if (!keepForThisWorker(platform, name)) { - return false; + return results; } if (configs.getWorker().getDequeueMatchSettings().isAcceptEverything()) { - return true; + results.keep = true; + return results; } - return satisfiesProperties(workerProvisions, platform); + results.keep = satisfiesProperties(workerProvisions, platform); + return results; } private static boolean keepForThisWorker(Platform platform, String name) { diff --git a/src/main/java/build/buildfarm/worker/DequeueResults.java b/src/main/java/build/buildfarm/worker/DequeueResults.java new file mode 100644 index 0000000000..f449907db0 --- /dev/null +++ b/src/main/java/build/buildfarm/worker/DequeueResults.java @@ -0,0 +1,38 @@ +// Copyright 2021 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package build.buildfarm.worker; + +/** + * @class DequeueResults + * @brief The results of evaluating a dequeued operation. + * @details Contains information about whether the operation should be kept and if resources were + * claimed. + */ +public class DequeueResults { + /** + * @field keep + * @brief Whether the operation should be kept. + * @details Operations not kept should be put back on the queue. + */ + public boolean keep = false; + + /** + * @field resourcesClaimed + * @brief Whether resources have been claimed while deciding to keep operation. + * @details If resources are claimed but the operation is not kept, the resources should be + * released. + */ + public boolean resourcesClaimed = false; +} diff --git a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java index 11f5e49b35..af380750c6 100644 --- a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java +++ b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java @@ -55,6 +55,7 @@ import build.buildfarm.v1test.QueueEntry; import build.buildfarm.v1test.QueuedOperation; import build.buildfarm.worker.DequeueMatchEvaluator; +import build.buildfarm.worker.DequeueResults; import build.buildfarm.worker.ExecutionPolicies; import build.buildfarm.worker.RetryingMatchListener; import build.buildfarm.worker.WorkerContext; @@ -283,10 +284,14 @@ public QueuedOperation getQueuedOperation(QueueEntry queueEntry) @SuppressWarnings("ConstantConditions") private void matchInterruptible(MatchListener listener) throws IOException, InterruptedException { QueueEntry queueEntry = takeEntryOffOperationQueue(listener); - decideWhetherToKeepOperation(queueEntry, listener); + if (queueEntry == null) { + listener.onEntry(null); + } else { + decideWhetherToKeepOperation(queueEntry, listener); + } } - private QueueEntry takeEntryOffOperationQueue(MatchListener listener) + private @Nullable QueueEntry takeEntryOffOperationQueue(MatchListener listener) throws IOException, InterruptedException { listener.onWaitStart(); QueueEntry queueEntry = null; @@ -314,11 +319,14 @@ private QueueEntry takeEntryOffOperationQueue(MatchListener listener) private void decideWhetherToKeepOperation(QueueEntry queueEntry, MatchListener listener) throws IOException, InterruptedException { - if (queueEntry == null - || DequeueMatchEvaluator.shouldKeepOperation( - matchProvisions, name, resourceSet, queueEntry)) { + DequeueResults results = + DequeueMatchEvaluator.shouldKeepOperation(matchProvisions, name, resourceSet, queueEntry); + if (results.keep) { listener.onEntry(queueEntry); } else { + if (results.resourcesClaimed) { + returnLocalResources(queueEntry); + } backplane.rejectOperation(queueEntry); } if (Thread.interrupted()) { diff --git a/src/test/java/build/buildfarm/worker/DequeueMatchEvaluatorTest.java b/src/test/java/build/buildfarm/worker/DequeueMatchEvaluatorTest.java index 290470b845..112d7a63eb 100644 --- a/src/test/java/build/buildfarm/worker/DequeueMatchEvaluatorTest.java +++ b/src/test/java/build/buildfarm/worker/DequeueMatchEvaluatorTest.java @@ -60,7 +60,8 @@ public void shouldKeepOperationKeepEmptyQueueEntry() throws Exception { // ACT boolean shouldKeep = DequeueMatchEvaluator.shouldKeepOperation( - workerProvisions, "worker-name", resourceSet, entry); + workerProvisions, "worker-name", resourceSet, entry) + .keep; // ASSERT assertThat(shouldKeep).isTrue(); @@ -89,7 +90,8 @@ public void shouldKeepOperationValidMinCoresQueueEntry() throws Exception { // ACT boolean shouldKeep = DequeueMatchEvaluator.shouldKeepOperation( - workerProvisions, "worker-name", resourceSet, entry); + workerProvisions, "worker-name", resourceSet, entry) + .keep; // ASSERT // the worker accepts because it has more cores than the min-cores requested @@ -120,7 +122,8 @@ public void shouldKeepOperationInvalidMinCoresQueueEntry() throws Exception { // ACT boolean shouldKeep = DequeueMatchEvaluator.shouldKeepOperation( - workerProvisions, "worker-name", resourceSet, entry); + workerProvisions, "worker-name", resourceSet, entry) + .keep; // ASSERT // the worker rejects because it has less cores than the min-cores requested @@ -150,7 +153,8 @@ public void shouldKeepOperationMaxCoresDoNotInfluenceAcceptance() throws Excepti // ACT boolean shouldKeep = DequeueMatchEvaluator.shouldKeepOperation( - workerProvisions, "worker-name", resourceSet, entry); + workerProvisions, "worker-name", resourceSet, entry) + .keep; // ASSERT // the worker accepts because it has the same cores as the min-cores requested @@ -180,7 +184,8 @@ public void shouldKeepOperationUnmatchedPropertiesRejectionAcceptance() throws E // ACT boolean shouldKeep = DequeueMatchEvaluator.shouldKeepOperation( - workerProvisions, "worker-name", resourceSet, entry); + workerProvisions, "worker-name", resourceSet, entry) + .keep; // ASSERT assertThat(shouldKeep).isFalse(); @@ -191,7 +196,8 @@ public void shouldKeepOperationUnmatchedPropertiesRejectionAcceptance() throws E // ACT shouldKeep = DequeueMatchEvaluator.shouldKeepOperation( - workerProvisions, "worker-name", resourceSet, entry); + workerProvisions, "worker-name", resourceSet, entry) + .keep; // ASSERT assertThat(shouldKeep).isTrue(); @@ -202,7 +208,8 @@ public void shouldKeepOperationUnmatchedPropertiesRejectionAcceptance() throws E // ACT shouldKeep = DequeueMatchEvaluator.shouldKeepOperation( - workerProvisions, "worker-name", resourceSet, entry); + workerProvisions, "worker-name", resourceSet, entry) + .keep; // ASSERT assertThat(shouldKeep).isTrue(); @@ -234,7 +241,8 @@ public void shouldKeepOperationClaimsResource() throws Exception { // ACT boolean shouldKeep = DequeueMatchEvaluator.shouldKeepOperation( - workerProvisions, "worker-name", resourceSet, entry); + workerProvisions, "worker-name", resourceSet, entry) + .keep; // ASSERT // the worker accepts because the resource is available. @@ -244,7 +252,8 @@ public void shouldKeepOperationClaimsResource() throws Exception { // ACT shouldKeep = DequeueMatchEvaluator.shouldKeepOperation( - workerProvisions, "worker-name", resourceSet, entry); + workerProvisions, "worker-name", resourceSet, entry) + .keep; // ASSERT // the worker rejects because there are no resources left. @@ -282,7 +291,8 @@ public void shouldKeepOperationClaimsMultipleResource() throws Exception { // ACT boolean shouldKeep = DequeueMatchEvaluator.shouldKeepOperation( - workerProvisions, "worker-name", resourceSet, entry); + workerProvisions, "worker-name", resourceSet, entry) + .keep; // ASSERT // the worker accepts because the resource is available. @@ -293,7 +303,8 @@ public void shouldKeepOperationClaimsMultipleResource() throws Exception { // ACT shouldKeep = DequeueMatchEvaluator.shouldKeepOperation( - workerProvisions, "worker-name", resourceSet, entry); + workerProvisions, "worker-name", resourceSet, entry) + .keep; // ASSERT // the worker accepts because the resource is available. @@ -304,7 +315,8 @@ public void shouldKeepOperationClaimsMultipleResource() throws Exception { // ACT shouldKeep = DequeueMatchEvaluator.shouldKeepOperation( - workerProvisions, "worker-name", resourceSet, entry); + workerProvisions, "worker-name", resourceSet, entry) + .keep; // ASSERT // the worker rejects because there are no resources left. @@ -348,7 +360,8 @@ public void shouldKeepOperationFailsToClaimSameAmountRemains() throws Exception // ACT boolean shouldKeep = DequeueMatchEvaluator.shouldKeepOperation( - workerProvisions, "worker-name", resourceSet, entry); + workerProvisions, "worker-name", resourceSet, entry) + .keep; // ASSERT // the worker rejects because there are no resources left. From 9d80f4ee8726dbdc7578ac7307038f503aace901 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Thu, 9 Nov 2023 15:35:41 -0500 Subject: [PATCH 141/311] Update queues.md Refer to new camelized DMS fields. Expand predefined dynamic execution property name matches. --- _site/docs/architecture/queues.md | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/_site/docs/architecture/queues.md b/_site/docs/architecture/queues.md index 872b689735..2dc706bf4a 100644 --- a/_site/docs/architecture/queues.md +++ b/_site/docs/architecture/queues.md @@ -25,33 +25,38 @@ If your configuration file does not specify any provisioned queues, buildfarm wi This will ensure the expected behavior for the paradigm in which all work is put on the same queue. ### Matching Algorithm -The matching algorithm is performed by the operation queue when the caller is requesting to push or pop elements. +The matching algorithm is performed by the operation queue when the server or worker is requesting to push or pop elements, respectively. The matching algorithm is designed to find the appropriate queue to perform these actions on. On the scheduler side, the action's platform properties are used for matching. On the worker side, the `dequeue_match_settings` are used. ![Operation Queue Matching]({{site.url}}{{site.baseurl}}/assets/images/Operation-Queue-Matching1.png) -This is how the matching algorithm works: +The matching algorithm works as follows: Each provision queue is checked in the order that it is configured. The first provision queue that is deemed eligible is chosen and used. When deciding if an action is eligible for the provision queue, each platform property is checked individually. By default, there must be a perfect match on each key/value. Wildcards ("*") can be used to avoid the need of a perfect match. Additionally, if the action contains any platform properties is not mentioned by the provision queue, it will be deemed ineligible. -setting `allow_unmatched: true` can be used to allow a superset of action properties as long as a subset matches the provision queue. +setting `allowUnmatched: true` can be used to allow a superset of action properties as long as a subset matches the provision queue. If no provision queues can be matched, the operation queue will provide an analysis on why none of the queues were eligible. -When taking elements off of the operation queue, the matching algorithm behaves a similar way. -The worker's `DequeueMatchSettings` also have an `allow_unmatched` property. +When taking elements off of the operation queue, the worker's matching algorithm behaves in a similar manner: +The worker's `DequeueMatchSettings` also have an `allowUnmatched` property. Workers also have the ability to reject an operation after matching with a provision queue and dequeuing a value. -To avoid any of these rejections by the worker, you can use `accept_everything: true`. +To avoid any of these rejections by the worker, you can use `acceptEverything: true`. When configuring your worker, consider the following decisions: -First, if the accept_everything setting is true, the job is accepted. +First, if the `allowEverything` setting is `true`, the job is accepted. Otherwise, if any execution property for the queue has a wildcard key, the job is accepted. -Otherwise, if the allow_unmatched setting is true, each key present in the queue's properties must be a wildcard or exist in the execution request's properties with an equal value. +Otherwise, if the `allowUnmatched` setting is `true`, each key present in the queue's properties must be a wildcard or exist in the execution request's properties with an equal value. Otherwise, the execution request's properties must have exactly the same set of keys as the queue's execution properties, and the request's value for each property must equal the queue's if the queue's value for this property is not a wildcard. +There are special predefined execution property names which resolve to dynamic configuration for the worker to match against: +`Worker`: The worker's `publicName` with no wildcard resolution +`min-cores`: Less than or equal to the `executeStageWidth` +`process-wrapper`: The set of named `process-wrappers` present in configuration + ### Server Example In this example the scheduler declares a GPU queue and CPU queue. All queues must be declared for the server deployment: From aac33b60ee36e71a9f4facafa5f704edbd02fc25 Mon Sep 17 00:00:00 2001 From: Matas Rastenis Date: Thu, 9 Nov 2023 16:52:21 -0800 Subject: [PATCH 142/311] Implement custom label header support for Grpc metrics interceptor (#1530) Add an option to provide a list of custom label headers to add to metrics. --- _site/docs/configuration/configuration.md | 2 ++ examples/config.yml | 1 + .../java/build/buildfarm/common/config/GrpcMetrics.java | 7 +++++++ 3 files changed, 10 insertions(+) diff --git a/_site/docs/configuration/configuration.md b/_site/docs/configuration/configuration.md index 83d4dcc8d0..d51a1f2292 100644 --- a/_site/docs/configuration/configuration.md +++ b/_site/docs/configuration/configuration.md @@ -94,6 +94,7 @@ server: |--------------------------|-------------------------------|--------------------------------------------------------| | enabled | boolean, _false_ | Publish basic GRPC metrics to a Prometheus endpoint | | provideLatencyHistograms | boolean, _false_ | Publish detailed, more expensive to calculate, metrics | +| labelsToReport | List of Strings, _[]_ | Include custom metrics labels in Prometheus metrics | Example: @@ -102,6 +103,7 @@ server: grpcMetrics: enabled: false provideLatencyHistograms: false + labelsToReport: [] ``` ### Server Caches diff --git a/examples/config.yml b/examples/config.yml index d69688b5b4..825121ea44 100644 --- a/examples/config.yml +++ b/examples/config.yml @@ -13,6 +13,7 @@ server: enabled: true provideLatencyHistograms: true latencyBuckets: [0.001, 0.01, 0.1, 1, 5, 10, 20, 40, 60, +Infinity] + labelsToReport: [] maxInboundMessageSizeBytes: 0 maxInboundMetadataSize: 0 casWriteTimeout: 3600 diff --git a/src/main/java/build/buildfarm/common/config/GrpcMetrics.java b/src/main/java/build/buildfarm/common/config/GrpcMetrics.java index 8855ae5fdb..a6e8653500 100644 --- a/src/main/java/build/buildfarm/common/config/GrpcMetrics.java +++ b/src/main/java/build/buildfarm/common/config/GrpcMetrics.java @@ -1,6 +1,7 @@ package build.buildfarm.common.config; import io.grpc.ServerBuilder; +import java.util.List; import lombok.Data; import me.dinowernli.grpc.prometheus.Configuration; import me.dinowernli.grpc.prometheus.MonitoringServerInterceptor; @@ -10,6 +11,7 @@ public class GrpcMetrics { private boolean enabled = false; private boolean provideLatencyHistograms = false; private double[] latencyBuckets; + private List labelsToReport; public static void handleGrpcMetricIntercepts( ServerBuilder serverBuilder, GrpcMetrics grpcMetrics) { @@ -30,6 +32,11 @@ public static void handleGrpcMetricIntercepts( grpcConfig = grpcConfig.withLatencyBuckets(grpcMetrics.getLatencyBuckets()); } + // report custom metric labels + if (grpcMetrics.getLabelsToReport() != null) { + grpcConfig = grpcConfig.withLabelHeaders(grpcMetrics.getLabelsToReport()); + } + // Apply config to create an interceptor and apply it to the GRPC server. MonitoringServerInterceptor monitoringInterceptor = MonitoringServerInterceptor.create(grpcConfig); From f9882f7454c39c17fb957c2eaa7538695a41b255 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Sat, 11 Nov 2023 00:36:03 -0500 Subject: [PATCH 143/311] Specify direct guava dependency usage (#1538) Testing with bazel HEAD using jdk21 compilation has revealed new direct dependencies on guava. --- persistentworkers/src/test/java/persistent/bazel/BUILD | 1 + src/test/java/build/buildfarm/common/grpc/BUILD | 1 + src/test/java/build/buildfarm/common/io/BUILD | 1 + src/test/java/build/buildfarm/common/redis/BUILD | 1 + src/test/java/build/buildfarm/common/services/BUILD | 1 + src/test/java/build/buildfarm/server/services/BUILD | 1 + 6 files changed, 6 insertions(+) diff --git a/persistentworkers/src/test/java/persistent/bazel/BUILD b/persistentworkers/src/test/java/persistent/bazel/BUILD index 0cf829a111..b85db78006 100644 --- a/persistentworkers/src/test/java/persistent/bazel/BUILD +++ b/persistentworkers/src/test/java/persistent/bazel/BUILD @@ -3,6 +3,7 @@ COMMON_DEPS = [ "//persistentworkers/src/main/java/persistent/bazel:bazel-persistent-workers", "//persistentworkers/src/test/java/persistent/testutil:testutil", "//persistentworkers/src/main/protobuf:worker_protocol_java_proto", + "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_truth_truth", "@maven//:commons_io_commons_io", diff --git a/src/test/java/build/buildfarm/common/grpc/BUILD b/src/test/java/build/buildfarm/common/grpc/BUILD index d470ee243a..35be7f36da 100644 --- a/src/test/java/build/buildfarm/common/grpc/BUILD +++ b/src/test/java/build/buildfarm/common/grpc/BUILD @@ -23,6 +23,7 @@ java_test( "//src/test/java/build/buildfarm:test_runner", "@googleapis//:google_bytestream_bytestream_java_grpc", "@googleapis//:google_bytestream_bytestream_java_proto", + "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_truth_truth", "@maven//:io_grpc_grpc_api", diff --git a/src/test/java/build/buildfarm/common/io/BUILD b/src/test/java/build/buildfarm/common/io/BUILD index 551b96ea58..1f5d1ca179 100644 --- a/src/test/java/build/buildfarm/common/io/BUILD +++ b/src/test/java/build/buildfarm/common/io/BUILD @@ -8,6 +8,7 @@ java_test( "//src/test/java/build/buildfarm:test_runner", "@googleapis//:google_bytestream_bytestream_java_grpc", "@googleapis//:google_bytestream_bytestream_java_proto", + "@maven//:com_google_guava_guava", "@maven//:com_google_jimfs_jimfs", "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_truth_truth", diff --git a/src/test/java/build/buildfarm/common/redis/BUILD b/src/test/java/build/buildfarm/common/redis/BUILD index 7b3978fb53..f388e339e0 100644 --- a/src/test/java/build/buildfarm/common/redis/BUILD +++ b/src/test/java/build/buildfarm/common/redis/BUILD @@ -6,6 +6,7 @@ COMMON_DEPS = [ "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", "//third_party/jedis", + "@maven//:com_google_guava_guava", "@maven//:com_google_truth_truth", "@maven//:io_grpc_grpc_api", "@maven//:org_mockito_mockito_core", diff --git a/src/test/java/build/buildfarm/common/services/BUILD b/src/test/java/build/buildfarm/common/services/BUILD index 2ba54ab58a..6fe1f35c55 100644 --- a/src/test/java/build/buildfarm/common/services/BUILD +++ b/src/test/java/build/buildfarm/common/services/BUILD @@ -16,6 +16,7 @@ java_test( "//src/test/java/build/buildfarm:test_runner", "@googleapis//:google_bytestream_bytestream_java_grpc", "@googleapis//:google_bytestream_bytestream_java_proto", + "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_truth_truth", "@maven//:io_grpc_grpc_api", diff --git a/src/test/java/build/buildfarm/server/services/BUILD b/src/test/java/build/buildfarm/server/services/BUILD index 09916ed7f0..a83385da04 100644 --- a/src/test/java/build/buildfarm/server/services/BUILD +++ b/src/test/java/build/buildfarm/server/services/BUILD @@ -11,6 +11,7 @@ java_test( "//src/main/java/build/buildfarm/server/services", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", + "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_truth_truth", "@maven//:io_grpc_grpc_stub", From 69e0248b64256de2f519866cc6dd33769a18ff24 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Sat, 11 Nov 2023 00:38:29 -0500 Subject: [PATCH 144/311] Update lombok dependency for jdk21 (#1540) Annotations under lombok were fixed for jdk21 in 1.18.28, update to current. --- defs.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/defs.bzl b/defs.bzl index a40dccaefe..ea145d1b9f 100644 --- a/defs.bzl +++ b/defs.bzl @@ -112,7 +112,7 @@ def buildfarm_init(name = "buildfarm"): "org.xerial:sqlite-jdbc:3.34.0", "org.jetbrains:annotations:16.0.2", "org.yaml:snakeyaml:2.0", - "org.projectlombok:lombok:1.18.24", + "org.projectlombok:lombok:1.18.30", ], generate_compat_repositories = True, override_targets = IO_GRPC_GRPC_JAVA_OVERRIDE_TARGETS, From 339aa131a971c1e541ede590ea8096cfbde97824 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Sat, 11 Nov 2023 00:47:00 -0500 Subject: [PATCH 145/311] Reorganize DequeueMatchEvaluator (#1537) Remove acceptEverything DequeueMatchSetting Place worker name in workerProvisions Only enable allowUnmatched effects on key mismatch Only acquire resources after asserting compatibility Update documentation to match changes --- _site/docs/architecture/queues.md | 20 ++-- _site/docs/configuration/configuration.md | 2 - examples/config.yml | 1 - .../common/config/DequeueMatchSettings.java | 7 +- .../worker/DequeueMatchEvaluator.java | 54 ++-------- .../worker/shard/ShardWorkerContext.java | 32 ++---- .../worker/DequeueMatchEvaluatorTest.java | 102 ++++++++---------- 7 files changed, 79 insertions(+), 139 deletions(-) diff --git a/_site/docs/architecture/queues.md b/_site/docs/architecture/queues.md index 2dc706bf4a..4ee44764bf 100644 --- a/_site/docs/architecture/queues.md +++ b/_site/docs/architecture/queues.md @@ -41,19 +41,17 @@ Additionally, if the action contains any platform properties is not mentioned by setting `allowUnmatched: true` can be used to allow a superset of action properties as long as a subset matches the provision queue. If no provision queues can be matched, the operation queue will provide an analysis on why none of the queues were eligible. -When taking elements off of the operation queue, the worker's matching algorithm behaves in a similar manner: -The worker's `DequeueMatchSettings` also have an `allowUnmatched` property. -Workers also have the ability to reject an operation after matching with a provision queue and dequeuing a value. -To avoid any of these rejections by the worker, you can use `acceptEverything: true`. - -When configuring your worker, consider the following decisions: -First, if the `allowEverything` setting is `true`, the job is accepted. -Otherwise, if any execution property for the queue has a wildcard key, the job is accepted. -Otherwise, if the `allowUnmatched` setting is `true`, each key present in the queue's properties must be a wildcard or exist in the execution request's properties with an equal value. -Otherwise, the execution request's properties must have exactly the same set of keys as the queue's execution properties, and the request's value for each property must equal the queue's if the queue's value for this property is not a wildcard. +A worker will dequeue operations from matching queues and determine whether to keep and execute it according to the following procedure: +For each property key-value in the operation's platform, an operation is REJECTED if: + The key is `min-cores` and the integer value is greater than the number of cores on the worker. + Or The key is `min-mem` and the integer value is greater than the number of bytes of RAM on the worker. + Or if the key exists in the `DequeueMatchSettings` platform with neither the value nor a `*` in the corresponding DMS platform key's values, + Or if the `allowUnmatched` setting is `false`. +For each resource requested in the operation's platform with the resource: prefix, the action is rejected if: + The resource amount cannot currently be satisfied with the associated resource capacity count There are special predefined execution property names which resolve to dynamic configuration for the worker to match against: -`Worker`: The worker's `publicName` with no wildcard resolution +`Worker`: The worker's `publicName` `min-cores`: Less than or equal to the `executeStageWidth` `process-wrapper`: The set of named `process-wrappers` present in configuration diff --git a/_site/docs/configuration/configuration.md b/_site/docs/configuration/configuration.md index d51a1f2292..ebbb8ca0e4 100644 --- a/_site/docs/configuration/configuration.md +++ b/_site/docs/configuration/configuration.md @@ -319,7 +319,6 @@ Note: In order for these settings to take effect, you must also configure `limit | Configuration | Accepted and _Default_ Values | Description | |------------------|-------------------------------|-------------| -| acceptEverything | boolean, _true_ | | | allowUnmatched | boolean, _false_ | | Example: @@ -327,7 +326,6 @@ Example: ```yaml worker: dequeueMatchSettings: - acceptEverything: true allowUnmatched: false ``` diff --git a/examples/config.yml b/examples/config.yml index 825121ea44..c02ff4cfcb 100644 --- a/examples/config.yml +++ b/examples/config.yml @@ -103,7 +103,6 @@ worker: inlineContentLimit: 1048567 # 1024 * 1024 operationPollPeriod: 1 dequeueMatchSettings: - acceptEverything: true allowUnmatched: false storages: - type: FILESYSTEM diff --git a/src/main/java/build/buildfarm/common/config/DequeueMatchSettings.java b/src/main/java/build/buildfarm/common/config/DequeueMatchSettings.java index 20ccbf85b4..57aad77832 100644 --- a/src/main/java/build/buildfarm/common/config/DequeueMatchSettings.java +++ b/src/main/java/build/buildfarm/common/config/DequeueMatchSettings.java @@ -3,11 +3,16 @@ import build.bazel.remote.execution.v2.Platform; import java.util.ArrayList; import java.util.List; +import lombok.AccessLevel; import lombok.Data; +import lombok.Getter; @Data public class DequeueMatchSettings { - private boolean acceptEverything = true; + + @Getter(AccessLevel.NONE) + private boolean acceptEverything; // deprecated + private boolean allowUnmatched = false; private List properties = new ArrayList(); diff --git a/src/main/java/build/buildfarm/worker/DequeueMatchEvaluator.java b/src/main/java/build/buildfarm/worker/DequeueMatchEvaluator.java index 997fc6862c..3f5815fd10 100644 --- a/src/main/java/build/buildfarm/worker/DequeueMatchEvaluator.java +++ b/src/main/java/build/buildfarm/worker/DequeueMatchEvaluator.java @@ -55,12 +55,11 @@ public class DequeueMatchEvaluator { */ @SuppressWarnings("NullableProblems") @NotNull - public static DequeueResults shouldKeepOperation( + public static boolean shouldKeepOperation( SetMultimap workerProvisions, - String name, LocalResourceSet resourceSet, QueueEntry queueEntry) { - return shouldKeepViaPlatform(workerProvisions, name, resourceSet, queueEntry.getPlatform()); + return shouldKeepViaPlatform(workerProvisions, resourceSet, queueEntry.getPlatform()); } /** @@ -77,43 +76,12 @@ public static DequeueResults shouldKeepOperation( */ @SuppressWarnings("NullableProblems") @NotNull - private static DequeueResults shouldKeepViaPlatform( + private static boolean shouldKeepViaPlatform( SetMultimap workerProvisions, - String name, LocalResourceSet resourceSet, Platform platform) { - // attempt to execute everything the worker gets off the queue, - // provided there is enough resources to do so. - DequeueResults results = new DequeueResults(); - - if (!LocalResourceSetUtils.claimResources(platform, resourceSet)) { - return results; - } - results.resourcesClaimed = true; - - // The action might be requesting to run on a particular action - if (!keepForThisWorker(platform, name)) { - return results; - } - - if (configs.getWorker().getDequeueMatchSettings().isAcceptEverything()) { - results.keep = true; - return results; - } - - results.keep = satisfiesProperties(workerProvisions, platform); - return results; - } - - private static boolean keepForThisWorker(Platform platform, String name) { - for (Platform.Property property : platform.getPropertiesList()) { - if (property.getName().equals(ExecutionProperties.WORKER) - && !property.getValue().equals(name)) { - // requested worker does not match this worker, reject - return false; - } - } - return true; + return satisfiesProperties(workerProvisions, platform) + && LocalResourceSetUtils.claimResources(platform, resourceSet); } /** @@ -183,13 +151,13 @@ private static boolean satisfiesProperty( return possibleMemories >= memBytesRequested; } - // accept other properties not specified on the worker - if (configs.getWorker().getDequeueMatchSettings().isAllowUnmatched()) { - return true; + // ensure exact matches + if (workerProvisions.containsKey(property.getName())) { + return workerProvisions.containsEntry(property.getName(), property.getValue()) + || workerProvisions.containsEntry(property.getName(), "*"); } - // ensure exact matches - return workerProvisions.containsEntry(property.getName(), property.getValue()) - || workerProvisions.containsEntry(property.getName(), "*"); + // accept other properties not specified on the worker + return configs.getWorker().getDequeueMatchSettings().isAllowUnmatched(); } } diff --git a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java index af380750c6..ac020f5046 100644 --- a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java +++ b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java @@ -18,6 +18,7 @@ import static build.buildfarm.common.Actions.checkPreconditionFailure; import static build.buildfarm.common.Errors.VIOLATION_TYPE_INVALID; import static build.buildfarm.common.Errors.VIOLATION_TYPE_MISSING; +import static build.buildfarm.worker.DequeueMatchEvaluator.shouldKeepOperation; import static java.lang.String.format; import static java.util.concurrent.TimeUnit.DAYS; @@ -38,6 +39,7 @@ import build.buildfarm.common.DigestUtil; import build.buildfarm.common.DigestUtil.ActionKey; import build.buildfarm.common.EntryLimitException; +import build.buildfarm.common.ExecutionProperties; import build.buildfarm.common.InputStreamFactory; import build.buildfarm.common.LinuxSandboxOptions; import build.buildfarm.common.Poller; @@ -54,8 +56,6 @@ import build.buildfarm.v1test.CASInsertionPolicy; import build.buildfarm.v1test.QueueEntry; import build.buildfarm.v1test.QueuedOperation; -import build.buildfarm.worker.DequeueMatchEvaluator; -import build.buildfarm.worker.DequeueResults; import build.buildfarm.worker.ExecutionPolicies; import build.buildfarm.worker.RetryingMatchListener; import build.buildfarm.worker.WorkerContext; @@ -137,7 +137,7 @@ class ShardWorkerContext implements WorkerContext { private final boolean errorOperationOutputSizeExceeded; static SetMultimap getMatchProvisions( - Iterable policies, int executeStageWidth) { + Iterable policies, String name, int executeStageWidth) { ImmutableSetMultimap.Builder provisions = ImmutableSetMultimap.builder(); Platform matchPlatform = ExecutionPolicies.getMatchPlatform( @@ -146,6 +146,7 @@ static SetMultimap getMatchProvisions( provisions.put(property.getName(), property.getValue()); } provisions.put(PROVISION_CORES_NAME, String.format("%d", executeStageWidth)); + provisions.put(ExecutionProperties.WORKER, name); return provisions.build(); } @@ -172,7 +173,7 @@ static SetMultimap getMatchProvisions( LocalResourceSet resourceSet, CasWriter writer) { this.name = name; - this.matchProvisions = getMatchProvisions(policies, executeStageWidth); + this.matchProvisions = getMatchProvisions(policies, name, executeStageWidth); this.operationPollPeriod = operationPollPeriod; this.operationPoller = operationPoller; this.inputFetchStageWidth = inputFetchStageWidth; @@ -284,10 +285,10 @@ public QueuedOperation getQueuedOperation(QueueEntry queueEntry) @SuppressWarnings("ConstantConditions") private void matchInterruptible(MatchListener listener) throws IOException, InterruptedException { QueueEntry queueEntry = takeEntryOffOperationQueue(listener); - if (queueEntry == null) { - listener.onEntry(null); + if (queueEntry == null || shouldKeepOperation(matchProvisions, resourceSet, queueEntry)) { + listener.onEntry(queueEntry); } else { - decideWhetherToKeepOperation(queueEntry, listener); + backplane.rejectOperation(queueEntry); } } @@ -317,23 +318,6 @@ private void matchInterruptible(MatchListener listener) throws IOException, Inte return queueEntry; } - private void decideWhetherToKeepOperation(QueueEntry queueEntry, MatchListener listener) - throws IOException, InterruptedException { - DequeueResults results = - DequeueMatchEvaluator.shouldKeepOperation(matchProvisions, name, resourceSet, queueEntry); - if (results.keep) { - listener.onEntry(queueEntry); - } else { - if (results.resourcesClaimed) { - returnLocalResources(queueEntry); - } - backplane.rejectOperation(queueEntry); - } - if (Thread.interrupted()) { - throw new InterruptedException(); - } - } - @Override public void returnLocalResources(QueueEntry queueEntry) { LocalResourceSetUtils.releaseClaims(queueEntry.getPlatform(), resourceSet); diff --git a/src/test/java/build/buildfarm/worker/DequeueMatchEvaluatorTest.java b/src/test/java/build/buildfarm/worker/DequeueMatchEvaluatorTest.java index 112d7a63eb..4d484b8c45 100644 --- a/src/test/java/build/buildfarm/worker/DequeueMatchEvaluatorTest.java +++ b/src/test/java/build/buildfarm/worker/DequeueMatchEvaluatorTest.java @@ -59,9 +59,7 @@ public void shouldKeepOperationKeepEmptyQueueEntry() throws Exception { // ACT boolean shouldKeep = - DequeueMatchEvaluator.shouldKeepOperation( - workerProvisions, "worker-name", resourceSet, entry) - .keep; + DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); // ASSERT assertThat(shouldKeep).isTrue(); @@ -89,9 +87,7 @@ public void shouldKeepOperationValidMinCoresQueueEntry() throws Exception { // ACT boolean shouldKeep = - DequeueMatchEvaluator.shouldKeepOperation( - workerProvisions, "worker-name", resourceSet, entry) - .keep; + DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); // ASSERT // the worker accepts because it has more cores than the min-cores requested @@ -106,7 +102,6 @@ public void shouldKeepOperationValidMinCoresQueueEntry() throws Exception { @Test public void shouldKeepOperationInvalidMinCoresQueueEntry() throws Exception { // ARRANGE - configs.getWorker().getDequeueMatchSettings().setAcceptEverything(false); SetMultimap workerProvisions = HashMultimap.create(); LocalResourceSet resourceSet = new LocalResourceSet(); workerProvisions.put("cores", "10"); @@ -121,9 +116,7 @@ public void shouldKeepOperationInvalidMinCoresQueueEntry() throws Exception { // ACT boolean shouldKeep = - DequeueMatchEvaluator.shouldKeepOperation( - workerProvisions, "worker-name", resourceSet, entry) - .keep; + DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); // ASSERT // the worker rejects because it has less cores than the min-cores requested @@ -152,9 +145,7 @@ public void shouldKeepOperationMaxCoresDoNotInfluenceAcceptance() throws Excepti // ACT boolean shouldKeep = - DequeueMatchEvaluator.shouldKeepOperation( - workerProvisions, "worker-name", resourceSet, entry) - .keep; + DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); // ASSERT // the worker accepts because it has the same cores as the min-cores requested @@ -168,7 +159,6 @@ public void shouldKeepOperationMaxCoresDoNotInfluenceAcceptance() throws Excepti @Test public void shouldKeepOperationUnmatchedPropertiesRejectionAcceptance() throws Exception { // ARRANGE - configs.getWorker().getDequeueMatchSettings().setAcceptEverything(false); configs.getWorker().getDequeueMatchSettings().setAllowUnmatched(false); SetMultimap workerProvisions = HashMultimap.create(); LocalResourceSet resourceSet = new LocalResourceSet(); @@ -183,33 +173,16 @@ public void shouldKeepOperationUnmatchedPropertiesRejectionAcceptance() throws E // ACT boolean shouldKeep = - DequeueMatchEvaluator.shouldKeepOperation( - workerProvisions, "worker-name", resourceSet, entry) - .keep; + DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); // ASSERT assertThat(shouldKeep).isFalse(); - // ARRANGE - configs.getWorker().getDequeueMatchSettings().setAcceptEverything(true); - - // ACT - shouldKeep = - DequeueMatchEvaluator.shouldKeepOperation( - workerProvisions, "worker-name", resourceSet, entry) - .keep; - - // ASSERT - assertThat(shouldKeep).isTrue(); - // ARRANGE configs.getWorker().getDequeueMatchSettings().setAllowUnmatched(true); // ACT - shouldKeep = - DequeueMatchEvaluator.shouldKeepOperation( - workerProvisions, "worker-name", resourceSet, entry) - .keep; + shouldKeep = DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); // ASSERT assertThat(shouldKeep).isTrue(); @@ -221,7 +194,6 @@ public void shouldKeepOperationUnmatchedPropertiesRejectionAcceptance() throws E @Test public void shouldKeepOperationClaimsResource() throws Exception { // ARRANGE - configs.getWorker().getDequeueMatchSettings().setAcceptEverything(true); configs.getWorker().getDequeueMatchSettings().setAllowUnmatched(true); SetMultimap workerProvisions = HashMultimap.create(); LocalResourceSet resourceSet = new LocalResourceSet(); @@ -240,9 +212,7 @@ public void shouldKeepOperationClaimsResource() throws Exception { // ACT boolean shouldKeep = - DequeueMatchEvaluator.shouldKeepOperation( - workerProvisions, "worker-name", resourceSet, entry) - .keep; + DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); // ASSERT // the worker accepts because the resource is available. @@ -250,10 +220,7 @@ public void shouldKeepOperationClaimsResource() throws Exception { assertThat(resourceSet.resources.get("FOO").availablePermits()).isEqualTo(0); // ACT - shouldKeep = - DequeueMatchEvaluator.shouldKeepOperation( - workerProvisions, "worker-name", resourceSet, entry) - .keep; + shouldKeep = DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); // ASSERT // the worker rejects because there are no resources left. @@ -261,13 +228,45 @@ public void shouldKeepOperationClaimsResource() throws Exception { assertThat(resourceSet.resources.get("FOO").availablePermits()).isEqualTo(0); } + // Function under test: shouldKeepOperation + // Reason for testing: the local resource should be claimed + // Failure explanation: semaphore claim did not work as expected. + @Test + public void rejectOperationIgnoresResource() throws Exception { + // ARRANGE + configs.getWorker().getDequeueMatchSettings().setAllowUnmatched(false); + SetMultimap workerProvisions = HashMultimap.create(); + LocalResourceSet resourceSet = new LocalResourceSet(); + resourceSet.resources.put("FOO", new Semaphore(1)); + + QueueEntry entry = + QueueEntry.newBuilder() + .setPlatform( + Platform.newBuilder() + .addProperties( + Platform.Property.newBuilder().setName("resource:FOO").setValue("1")) + .addProperties(Platform.Property.newBuilder().setName("os").setValue("randos"))) + .build(); + + // PRE-ASSERT + assertThat(resourceSet.resources.get("FOO").availablePermits()).isEqualTo(1); + + // ACT + boolean shouldKeep = + DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + + // ASSERT + // the worker rejects because the os is not satisfied + assertThat(shouldKeep).isFalse(); + assertThat(resourceSet.resources.get("FOO").availablePermits()).isEqualTo(1); + } + // Function under test: shouldKeepOperation // Reason for testing: the local resources should be claimed // Failure explanation: semaphore claim did not work as expected. @Test public void shouldKeepOperationClaimsMultipleResource() throws Exception { // ARRANGE - configs.getWorker().getDequeueMatchSettings().setAcceptEverything(true); configs.getWorker().getDequeueMatchSettings().setAllowUnmatched(true); SetMultimap workerProvisions = HashMultimap.create(); LocalResourceSet resourceSet = new LocalResourceSet(); @@ -290,9 +289,7 @@ public void shouldKeepOperationClaimsMultipleResource() throws Exception { // ACT boolean shouldKeep = - DequeueMatchEvaluator.shouldKeepOperation( - workerProvisions, "worker-name", resourceSet, entry) - .keep; + DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); // ASSERT // the worker accepts because the resource is available. @@ -301,10 +298,7 @@ public void shouldKeepOperationClaimsMultipleResource() throws Exception { assertThat(resourceSet.resources.get("BAR").availablePermits()).isEqualTo(2); // ACT - shouldKeep = - DequeueMatchEvaluator.shouldKeepOperation( - workerProvisions, "worker-name", resourceSet, entry) - .keep; + shouldKeep = DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); // ASSERT // the worker accepts because the resource is available. @@ -313,10 +307,7 @@ public void shouldKeepOperationClaimsMultipleResource() throws Exception { assertThat(resourceSet.resources.get("BAR").availablePermits()).isEqualTo(0); // ACT - shouldKeep = - DequeueMatchEvaluator.shouldKeepOperation( - workerProvisions, "worker-name", resourceSet, entry) - .keep; + shouldKeep = DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); // ASSERT // the worker rejects because there are no resources left. @@ -332,7 +323,6 @@ public void shouldKeepOperationClaimsMultipleResource() throws Exception { @Test public void shouldKeepOperationFailsToClaimSameAmountRemains() throws Exception { // ARRANGE - configs.getWorker().getDequeueMatchSettings().setAcceptEverything(true); configs.getWorker().getDequeueMatchSettings().setAllowUnmatched(true); SetMultimap workerProvisions = HashMultimap.create(); LocalResourceSet resourceSet = new LocalResourceSet(); @@ -359,9 +349,7 @@ public void shouldKeepOperationFailsToClaimSameAmountRemains() throws Exception // ACT boolean shouldKeep = - DequeueMatchEvaluator.shouldKeepOperation( - workerProvisions, "worker-name", resourceSet, entry) - .keep; + DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); // ASSERT // the worker rejects because there are no resources left. From 025305ad9dd06c4f04e702dadb150e314d15c826 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Sat, 11 Nov 2023 08:54:51 -0500 Subject: [PATCH 146/311] Upgrade com_google_protobuf for jvm compatibility (#1539) Correct deprecated AccessController usage warning Requires a newer bazel than 6.4.0 for macos to choose unix toolchain with C++ std=c++14 specification for protobuf->absl dependency. --- .bazelci/presubmit.yml | 3 +++ deps.bzl | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index 728e68d02d..e08f2f07b6 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -55,7 +55,10 @@ tasks: - "..." macos: name: "Unit Tests" + environment: + USE_BAZEL_VERSION: 17be878292730359c9c90efdceabed26126df7ae build_flags: + - "--cxxopt=-std=c++14" - "--build_tag_filters=-container" build_targets: - "..." diff --git a/deps.bzl b/deps.bzl index 55b12ab136..51dfbb953b 100644 --- a/deps.bzl +++ b/deps.bzl @@ -36,9 +36,9 @@ def archive_dependencies(third_party): # Needed for "well-known protos" and @com_google_protobuf//:protoc. { "name": "com_google_protobuf", - "sha256": "25f1292d4ea6666f460a2a30038eef121e6c3937ae0f61d610611dfb14b0bd32", - "strip_prefix": "protobuf-3.19.1", - "urls": ["https://github.com/protocolbuffers/protobuf/archive/v3.19.1.zip"], + "sha256": "79082dc68d8bab2283568ce0be3982b73e19ddd647c2411d1977ca5282d2d6b3", + "strip_prefix": "protobuf-25.0", + "urls": ["https://github.com/protocolbuffers/protobuf/archive/v25.0.zip"], }, { "name": "com_github_bazelbuild_buildtools", From f7209098f5d1b4fc671d3008af22aafaa8689902 Mon Sep 17 00:00:00 2001 From: Yuriy Belenitsky Date: Sat, 11 Nov 2023 09:12:37 -0500 Subject: [PATCH 147/311] Create buildfarm-worker-base-build-and-deploy.yml (#1534) Create a github workflow to build base buildfarm worker image. --- ...buildfarm-worker-base-build-and-deploy.yml | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .github/workflows/buildfarm-worker-base-build-and-deploy.yml diff --git a/.github/workflows/buildfarm-worker-base-build-and-deploy.yml b/.github/workflows/buildfarm-worker-base-build-and-deploy.yml new file mode 100644 index 0000000000..7550639dd3 --- /dev/null +++ b/.github/workflows/buildfarm-worker-base-build-and-deploy.yml @@ -0,0 +1,28 @@ +name: Build and push base Buildfarm worker image + +on: + push: + branches: + - main + paths: + - ci/base-worker-image/jammy/Dockerfile +jobs: + build: + name: Build Base Buildfarm Worker Image + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Build Docker Image + id: buildAndPushImage + uses: MaximilianoBz/dockerhub-buildpush@v1.0 + with: + registry_url: 'docker.io' + repository_name: 'bazelbuild' + user_name: ${{ secrets.BAZELBUILD_DOCKERHUB_USERNAME }} + password: ${{ secrets.BAZELBUILD_DOCKERHUB_TOKEN }} + image_version: 'buildfarm-worker-base:jammy' + docker_file: './ci/base-worker-image/jammy' + - name: Get pre step result output image_pull_url + run: echo "The time was ${{ steps.buildAndPushImage.outputs.image_pull_url }}" From b7daba3e2ee9efe77cd13e91aae1bfd63e89e85b Mon Sep 17 00:00:00 2001 From: Yuriy Belenitsky Date: Sat, 11 Nov 2023 16:27:24 -0500 Subject: [PATCH 148/311] Add base image generation scripts (#1532) --- ci/base-worker-image/jammy/Dockerfile | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 ci/base-worker-image/jammy/Dockerfile diff --git a/ci/base-worker-image/jammy/Dockerfile b/ci/base-worker-image/jammy/Dockerfile new file mode 100644 index 0000000000..2e54a2804e --- /dev/null +++ b/ci/base-worker-image/jammy/Dockerfile @@ -0,0 +1,6 @@ +# A minimal container for building a base worker image. +# Buildfarm public releases are build using this image as a starting point. +FROM ubuntu:22.04 + +RUN apt-get update +RUN apt-get -y install default-jre default-jdk build-essential libfuse2 From dcff4f006805ff4c9664f70da9a08675b0883ffb Mon Sep 17 00:00:00 2001 From: Yuriy Belenitsky Date: Sat, 11 Nov 2023 18:55:16 -0500 Subject: [PATCH 149/311] Fix buildfarm-worker-base-build-and-deploy.yml (#1541) --- .../workflows/buildfarm-worker-base-build-and-deploy.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/buildfarm-worker-base-build-and-deploy.yml b/.github/workflows/buildfarm-worker-base-build-and-deploy.yml index 7550639dd3..a91f6c8593 100644 --- a/.github/workflows/buildfarm-worker-base-build-and-deploy.yml +++ b/.github/workflows/buildfarm-worker-base-build-and-deploy.yml @@ -19,10 +19,8 @@ jobs: uses: MaximilianoBz/dockerhub-buildpush@v1.0 with: registry_url: 'docker.io' - repository_name: 'bazelbuild' + repository_name: 'bazelbuild/buildfarm-worker-base' user_name: ${{ secrets.BAZELBUILD_DOCKERHUB_USERNAME }} password: ${{ secrets.BAZELBUILD_DOCKERHUB_TOKEN }} - image_version: 'buildfarm-worker-base:jammy' + image_version: 'jammy' docker_file: './ci/base-worker-image/jammy' - - name: Get pre step result output image_pull_url - run: echo "The time was ${{ steps.buildAndPushImage.outputs.image_pull_url }}" From 52318f87c29eae3967da88ab06ec8e7b92953e2f Mon Sep 17 00:00:00 2001 From: Yuriy Belenitsky Date: Tue, 14 Nov 2023 15:32:54 -0500 Subject: [PATCH 150/311] Add public buildfarm image generation actions (#1542) --- .../buildfarm-images-build-and-deploy.yml | 30 +++++++++++++++++++ ...buildfarm-worker-base-build-and-deploy.yml | 16 ++++++++-- BUILD | 26 ++++++++++++++-- ci/base-worker-image/mantic/Dockerfile | 6 ++++ images.bzl | 20 +++++++++++-- 5 files changed, 92 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/buildfarm-images-build-and-deploy.yml create mode 100644 ci/base-worker-image/mantic/Dockerfile diff --git a/.github/workflows/buildfarm-images-build-and-deploy.yml b/.github/workflows/buildfarm-images-build-and-deploy.yml new file mode 100644 index 0000000000..789086aafd --- /dev/null +++ b/.github/workflows/buildfarm-images-build-and-deploy.yml @@ -0,0 +1,30 @@ +name: Build and push Buildfarm images + +on: + push: + branches: + - main + +jobs: + build: + name: Build Buildfarm Images + runs-on: ubuntu-latest + steps: + - uses: bazelbuild/setup-bazelisk@v2 + + - name: Checkout + uses: actions/checkout@v3 + + - name: Login to Bazelbuild Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.BAZELBUILD_DOCKERHUB_USERNAME }} + password: ${{ secrets.BAZELBUILD_DOCKERHUB_TOKEN }} + + - name: Build Server Image + id: buildAndPushServerImage + run: bazel run public_push_buildfarm-server + + - name: Build Worker Image + id: buildAndPushWorkerImage + run: bazel run public_push_buildfarm-worker diff --git a/.github/workflows/buildfarm-worker-base-build-and-deploy.yml b/.github/workflows/buildfarm-worker-base-build-and-deploy.yml index a91f6c8593..ac620042ba 100644 --- a/.github/workflows/buildfarm-worker-base-build-and-deploy.yml +++ b/.github/workflows/buildfarm-worker-base-build-and-deploy.yml @@ -6,6 +6,7 @@ on: - main paths: - ci/base-worker-image/jammy/Dockerfile + - ci/base-worker-image/mantic/Dockerfile jobs: build: name: Build Base Buildfarm Worker Image @@ -14,8 +15,8 @@ jobs: - name: Checkout uses: actions/checkout@v3 - - name: Build Docker Image - id: buildAndPushImage + - name: Build Jammy Docker Image + id: buildAndPushJammyImage uses: MaximilianoBz/dockerhub-buildpush@v1.0 with: registry_url: 'docker.io' @@ -24,3 +25,14 @@ jobs: password: ${{ secrets.BAZELBUILD_DOCKERHUB_TOKEN }} image_version: 'jammy' docker_file: './ci/base-worker-image/jammy' + + - name: Build Mantic Docker Image + id: buildAndPushManticImage + uses: MaximilianoBz/dockerhub-buildpush@v1.0 + with: + registry_url: 'docker.io' + repository_name: 'bazelbuild/buildfarm-worker-base' + user_name: ${{ secrets.BAZELBUILD_DOCKERHUB_USERNAME }} + password: ${{ secrets.BAZELBUILD_DOCKERHUB_TOKEN }} + image_version: 'mantic' + docker_file: './ci/base-worker-image/mantic' diff --git a/BUILD b/BUILD index eb773e1a16..b81921d3c0 100644 --- a/BUILD +++ b/BUILD @@ -2,7 +2,7 @@ load("@com_github_bazelbuild_buildtools//buildifier:def.bzl", "buildifier") load("@io_bazel_rules_docker//java:image.bzl", "java_image") load("@io_bazel_rules_docker//docker/package_managers:download_pkgs.bzl", "download_pkgs") load("@io_bazel_rules_docker//docker/package_managers:install_pkgs.bzl", "install_pkgs") -load("@io_bazel_rules_docker//container:container.bzl", "container_image") +load("@io_bazel_rules_docker//container:container.bzl", "container_image", "container_push") load("@rules_oss_audit//oss_audit:java/oss_audit.bzl", "oss_audit") load("//:jvm_flags.bzl", "server_jvm_flags", "worker_jvm_flags") @@ -120,7 +120,7 @@ sh_binary( java_image( name = "buildfarm-server", args = ["/app/build_buildfarm/examples/config.minimal.yml"], - base = "@ubuntu-mantic//image", + base = "@amazon_corretto_java_image_base//image", classpath_resources = [ "//src/main/java/build/buildfarm:configs", ], @@ -195,3 +195,25 @@ oss_audit( src = "//src/main/java/build/buildfarm:buildfarm-shard-worker", tags = ["audit"], ) + +# Below targets push public docker images to bazelbuild dockerhub. + +container_push( + name = "public_push_buildfarm-server", + format = "Docker", + image = ":buildfarm-server", + registry = "index.docker.io", + repository = "bazelbuild/buildfarm-server", + tag = "latest", + tags = ["container"], +) + +container_push( + name = "public_push_buildfarm-worker", + format = "Docker", + image = ":buildfarm-shard-worker", + registry = "index.docker.io", + repository = "bazelbuild/buildfarm-worker", + tag = "latest", + tags = ["container"], +) diff --git a/ci/base-worker-image/mantic/Dockerfile b/ci/base-worker-image/mantic/Dockerfile new file mode 100644 index 0000000000..3dc2802331 --- /dev/null +++ b/ci/base-worker-image/mantic/Dockerfile @@ -0,0 +1,6 @@ +# A minimal container for building a base worker image. +# Buildfarm public releases are build using this image as a starting point. +FROM ubuntu:23.04 + +RUN apt-get update +RUN apt-get -y install default-jre default-jdk build-essential libfuse2 diff --git a/images.bzl b/images.bzl index 939a752ed5..faa70c3ff1 100644 --- a/images.bzl +++ b/images.bzl @@ -26,10 +26,26 @@ def buildfarm_images(): repository = "distroless/java", ) + # Base mantic worker image for public releases (built via github action from ci/base-worker-image/mantic/Dockerfile) container_pull( name = "ubuntu-mantic", - digest = "sha256:1419bba15470a95242e917b3abcd8981ae36707b99df5ac705e1eee4d920c51c", registry = "index.docker.io", repository = "bazelbuild/buildfarm-worker-base", - tag = "mantic-java17-gcc", + tag = "mantic", + ) + + # Base worker image for public releases (built via github action from ci/base-worker-image/jammy/Dockerfile) + container_pull( + name = "ubuntu-jammy", + registry = "index.docker.io", + repository = "bazelbuild/buildfarm-worker-base", + tag = "jammy", + ) + + # Server base image + container_pull( + name = "amazon_corretto_java_image_base", + registry = "public.ecr.aws/amazoncorretto", + repository = "amazoncorretto", + tag = "21", ) From e3433937236b8c796fcab3c9fe9874a3b34e95d8 Mon Sep 17 00:00:00 2001 From: Yuriy Belenitsky Date: Wed, 15 Nov 2023 20:27:53 -0500 Subject: [PATCH 151/311] Update base image building action (#1544) --- .../buildfarm-images-build-and-deploy.yml | 2 +- ...buildfarm-worker-base-build-and-deploy.yml | 36 +++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/.github/workflows/buildfarm-images-build-and-deploy.yml b/.github/workflows/buildfarm-images-build-and-deploy.yml index 789086aafd..2560eadb3c 100644 --- a/.github/workflows/buildfarm-images-build-and-deploy.yml +++ b/.github/workflows/buildfarm-images-build-and-deploy.yml @@ -1,4 +1,4 @@ -name: Build and push Buildfarm images +name: Build and Push Latest Buildfarm Images on: push: diff --git a/.github/workflows/buildfarm-worker-base-build-and-deploy.yml b/.github/workflows/buildfarm-worker-base-build-and-deploy.yml index ac620042ba..49f1cf40e8 100644 --- a/.github/workflows/buildfarm-worker-base-build-and-deploy.yml +++ b/.github/workflows/buildfarm-worker-base-build-and-deploy.yml @@ -1,4 +1,4 @@ -name: Build and push base Buildfarm worker image +name: Build and Push Base Buildfarm Worker Images on: push: @@ -15,24 +15,24 @@ jobs: - name: Checkout uses: actions/checkout@v3 - - name: Build Jammy Docker Image - id: buildAndPushJammyImage - uses: MaximilianoBz/dockerhub-buildpush@v1.0 + - name: Login to Bazelbuild Docker Hub + uses: docker/login-action@v3 with: - registry_url: 'docker.io' - repository_name: 'bazelbuild/buildfarm-worker-base' - user_name: ${{ secrets.BAZELBUILD_DOCKERHUB_USERNAME }} + username: ${{ secrets.BAZELBUILD_DOCKERHUB_USERNAME }} password: ${{ secrets.BAZELBUILD_DOCKERHUB_TOKEN }} - image_version: 'jammy' - docker_file: './ci/base-worker-image/jammy' - - name: Build Mantic Docker Image - id: buildAndPushManticImage - uses: MaximilianoBz/dockerhub-buildpush@v1.0 + - name: Build Jammy Docker image + uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671 with: - registry_url: 'docker.io' - repository_name: 'bazelbuild/buildfarm-worker-base' - user_name: ${{ secrets.BAZELBUILD_DOCKERHUB_USERNAME }} - password: ${{ secrets.BAZELBUILD_DOCKERHUB_TOKEN }} - image_version: 'mantic' - docker_file: './ci/base-worker-image/mantic' + context: . + file: ./ci/base-worker-image/jammy/Dockerfile + push: true + tags: bazelbuild/buildfarm-worker-base:jammy + + - name: Build Mantic Docker image + uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671 + with: + context: . + file: ./ci/base-worker-image/mantic/Dockerfile + push: true + tags: bazelbuild/buildfarm-worker-base:mantic From dae7f78eda808b745d1e0bc59cfdfb4a3ba67681 Mon Sep 17 00:00:00 2001 From: Yuriy Belenitsky Date: Wed, 15 Nov 2023 21:53:23 -0500 Subject: [PATCH 152/311] Add release image generation action (#1545) --- .bazelci/presubmit.yml | 4 +++ .../buildfarm-images-build-and-deploy.yml | 4 +-- .../buildfarm-release-build-and-deploy.yml | 29 +++++++++++++++++++ BUILD | 4 +-- 4 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/buildfarm-release-build-and-deploy.yml diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index e08f2f07b6..dfdf37f892 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -41,6 +41,8 @@ tasks: name: "Unit Tests" build_targets: - "..." + build_flags: + - "--build_tag_filters=-container" test_flags: - "--test_tag_filters=-integration,-redis" test_targets: @@ -49,6 +51,8 @@ tasks: name: "Unit Tests" build_targets: - "..." + build_flags: + - "--build_tag_filters=-container" test_flags: - "--test_tag_filters=-integration,-redis" test_targets: diff --git a/.github/workflows/buildfarm-images-build-and-deploy.yml b/.github/workflows/buildfarm-images-build-and-deploy.yml index 2560eadb3c..a7f4812c94 100644 --- a/.github/workflows/buildfarm-images-build-and-deploy.yml +++ b/.github/workflows/buildfarm-images-build-and-deploy.yml @@ -23,8 +23,8 @@ jobs: - name: Build Server Image id: buildAndPushServerImage - run: bazel run public_push_buildfarm-server + run: bazel run public_push_buildfarm-server --define release_version=latest - name: Build Worker Image id: buildAndPushWorkerImage - run: bazel run public_push_buildfarm-worker + run: bazel run public_push_buildfarm-worker --define release_version=latest diff --git a/.github/workflows/buildfarm-release-build-and-deploy.yml b/.github/workflows/buildfarm-release-build-and-deploy.yml new file mode 100644 index 0000000000..31200e3ebf --- /dev/null +++ b/.github/workflows/buildfarm-release-build-and-deploy.yml @@ -0,0 +1,29 @@ +name: Build and Push Buildfarm Releases + +on: + release: + types: [published] + +jobs: + build: + name: Build Buildfarm Images + runs-on: ubuntu-latest + steps: + - uses: bazelbuild/setup-bazelisk@v2 + + - name: Checkout + uses: actions/checkout@v3 + + - name: Login to Bazelbuild Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.BAZELBUILD_DOCKERHUB_USERNAME }} + password: ${{ secrets.BAZELBUILD_DOCKERHUB_TOKEN }} + + - name: Build Server Image + id: buildAndPushServerImage + run: bazel run public_push_buildfarm-server --define release_version=${{ github.event.release.tag_name }} + + - name: Build Worker Image + id: buildAndPushWorkerImage + run: bazel run public_push_buildfarm-worker --define release_version=${{ github.event.release.tag_name }} diff --git a/BUILD b/BUILD index b81921d3c0..c0400a6061 100644 --- a/BUILD +++ b/BUILD @@ -204,7 +204,7 @@ container_push( image = ":buildfarm-server", registry = "index.docker.io", repository = "bazelbuild/buildfarm-server", - tag = "latest", + tag = "$(release_version)", tags = ["container"], ) @@ -214,6 +214,6 @@ container_push( image = ":buildfarm-shard-worker", registry = "index.docker.io", repository = "bazelbuild/buildfarm-worker", - tag = "latest", + tag = "$(release_version)", tags = ["container"], ) From b01889d86e05ce088cad6899ded21038858ccdc3 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Thu, 16 Nov 2023 16:47:18 -0500 Subject: [PATCH 153/311] Limit workflow to canonical repository (#1547) --- .github/workflows/buildfarm-images-build-and-deploy.yml | 1 + .github/workflows/buildfarm-release-build-and-deploy.yml | 1 + .github/workflows/buildfarm-worker-base-build-and-deploy.yml | 1 + 3 files changed, 3 insertions(+) diff --git a/.github/workflows/buildfarm-images-build-and-deploy.yml b/.github/workflows/buildfarm-images-build-and-deploy.yml index a7f4812c94..97936b3fe9 100644 --- a/.github/workflows/buildfarm-images-build-and-deploy.yml +++ b/.github/workflows/buildfarm-images-build-and-deploy.yml @@ -7,6 +7,7 @@ on: jobs: build: + if: github.repository == 'bazelbuild/bazel-buildfarm' name: Build Buildfarm Images runs-on: ubuntu-latest steps: diff --git a/.github/workflows/buildfarm-release-build-and-deploy.yml b/.github/workflows/buildfarm-release-build-and-deploy.yml index 31200e3ebf..537919bbbc 100644 --- a/.github/workflows/buildfarm-release-build-and-deploy.yml +++ b/.github/workflows/buildfarm-release-build-and-deploy.yml @@ -6,6 +6,7 @@ on: jobs: build: + if: github.repository == 'bazelbuild/bazel-buildfarm' name: Build Buildfarm Images runs-on: ubuntu-latest steps: diff --git a/.github/workflows/buildfarm-worker-base-build-and-deploy.yml b/.github/workflows/buildfarm-worker-base-build-and-deploy.yml index 49f1cf40e8..a212e5e61a 100644 --- a/.github/workflows/buildfarm-worker-base-build-and-deploy.yml +++ b/.github/workflows/buildfarm-worker-base-build-and-deploy.yml @@ -9,6 +9,7 @@ on: - ci/base-worker-image/mantic/Dockerfile jobs: build: + if: github.repository == 'bazelbuild/bazel-buildfarm' name: Build Base Buildfarm Worker Image runs-on: ubuntu-latest steps: From dcee798579773981812c90ad0280dad234194ee5 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Thu, 16 Nov 2023 16:47:43 -0500 Subject: [PATCH 154/311] Check for "cores" exec property as min-cores match (#1548) The execution platform property "cores" is detailed in documentation as specifying "min-cores" and "max-cores". Match this definition and prevent "cores" from being evaluated as a strict match with the worker provision properties (with likely rejection). --- .../worker/DequeueMatchEvaluator.java | 3 +- .../worker/DequeueMatchEvaluatorTest.java | 122 +++++++++++++----- 2 files changed, 91 insertions(+), 34 deletions(-) diff --git a/src/main/java/build/buildfarm/worker/DequeueMatchEvaluator.java b/src/main/java/build/buildfarm/worker/DequeueMatchEvaluator.java index 3f5815fd10..8f9d712481 100644 --- a/src/main/java/build/buildfarm/worker/DequeueMatchEvaluator.java +++ b/src/main/java/build/buildfarm/worker/DequeueMatchEvaluator.java @@ -119,7 +119,8 @@ private static boolean satisfiesProperties( private static boolean satisfiesProperty( SetMultimap workerProvisions, Platform.Property property) { // validate min cores - if (property.getName().equals(ExecutionProperties.MIN_CORES)) { + if (property.getName().equals(ExecutionProperties.CORES) + || property.getName().equals(ExecutionProperties.MIN_CORES)) { if (!workerProvisions.containsKey(ExecutionProperties.CORES)) { return false; } diff --git a/src/test/java/build/buildfarm/worker/DequeueMatchEvaluatorTest.java b/src/test/java/build/buildfarm/worker/DequeueMatchEvaluatorTest.java index 4d484b8c45..91f83872ca 100644 --- a/src/test/java/build/buildfarm/worker/DequeueMatchEvaluatorTest.java +++ b/src/test/java/build/buildfarm/worker/DequeueMatchEvaluatorTest.java @@ -14,6 +14,10 @@ package build.buildfarm.worker; +import static build.buildfarm.common.ExecutionProperties.CORES; +import static build.buildfarm.common.ExecutionProperties.MAX_CORES; +import static build.buildfarm.common.ExecutionProperties.MIN_CORES; +import static build.buildfarm.worker.DequeueMatchEvaluator.shouldKeepOperation; import static com.google.common.truth.Truth.assertThat; import build.bazel.remote.execution.v2.Platform; @@ -58,8 +62,7 @@ public void shouldKeepOperationKeepEmptyQueueEntry() throws Exception { QueueEntry entry = QueueEntry.newBuilder().setPlatform(Platform.newBuilder()).build(); // ACT - boolean shouldKeep = - DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + boolean shouldKeep = shouldKeepOperation(workerProvisions, resourceSet, entry); // ASSERT assertThat(shouldKeep).isTrue(); @@ -75,19 +78,32 @@ public void shouldKeepOperationValidMinCoresQueueEntry() throws Exception { // ARRANGE SetMultimap workerProvisions = HashMultimap.create(); LocalResourceSet resourceSet = new LocalResourceSet(); - workerProvisions.put("cores", "11"); + workerProvisions.put(CORES, "11"); - QueueEntry entry = + QueueEntry minCoresEntry = QueueEntry.newBuilder() .setPlatform( Platform.newBuilder() .addProperties( - Platform.Property.newBuilder().setName("min-cores").setValue("10"))) + Platform.Property.newBuilder().setName(MIN_CORES).setValue("10"))) .build(); // ACT - boolean shouldKeep = - DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + boolean shouldKeep = shouldKeepOperation(workerProvisions, resourceSet, minCoresEntry); + + // ASSERT + // the worker accepts because it has more cores than the min-cores requested + assertThat(shouldKeep).isTrue(); + + QueueEntry coresEntry = + QueueEntry.newBuilder() + .setPlatform( + Platform.newBuilder() + .addProperties(Platform.Property.newBuilder().setName(CORES).setValue("10"))) + .build(); + + // ACT + shouldKeep = shouldKeepOperation(workerProvisions, resourceSet, coresEntry); // ASSERT // the worker accepts because it has more cores than the min-cores requested @@ -104,19 +120,32 @@ public void shouldKeepOperationInvalidMinCoresQueueEntry() throws Exception { // ARRANGE SetMultimap workerProvisions = HashMultimap.create(); LocalResourceSet resourceSet = new LocalResourceSet(); - workerProvisions.put("cores", "10"); + workerProvisions.put(CORES, "10"); - QueueEntry entry = + QueueEntry minCoresEntry = QueueEntry.newBuilder() .setPlatform( Platform.newBuilder() .addProperties( - Platform.Property.newBuilder().setName("min-cores").setValue("11"))) + Platform.Property.newBuilder().setName(MIN_CORES).setValue("11"))) .build(); // ACT - boolean shouldKeep = - DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + boolean shouldKeep = shouldKeepOperation(workerProvisions, resourceSet, minCoresEntry); + + // ASSERT + // the worker rejects because it has less cores than the min-cores requested + assertThat(shouldKeep).isFalse(); + + QueueEntry coresEntry = + QueueEntry.newBuilder() + .setPlatform( + Platform.newBuilder() + .addProperties(Platform.Property.newBuilder().setName(CORES).setValue("11"))) + .build(); + + // ACT + shouldKeep = shouldKeepOperation(workerProvisions, resourceSet, coresEntry); // ASSERT // the worker rejects because it has less cores than the min-cores requested @@ -131,25 +160,39 @@ public void shouldKeepOperationMaxCoresDoNotInfluenceAcceptance() throws Excepti // ARRANGE SetMultimap workerProvisions = HashMultimap.create(); LocalResourceSet resourceSet = new LocalResourceSet(); - workerProvisions.put("cores", "10"); + workerProvisions.put(CORES, "10"); - QueueEntry entry = + QueueEntry minCoresEntry = QueueEntry.newBuilder() .setPlatform( Platform.newBuilder() + .addProperties(Platform.Property.newBuilder().setName(MIN_CORES).setValue("10")) .addProperties( - Platform.Property.newBuilder().setName("min-cores").setValue("10")) - .addProperties( - Platform.Property.newBuilder().setName("max-cores").setValue("20"))) + Platform.Property.newBuilder().setName(MAX_CORES).setValue("20"))) .build(); // ACT - boolean shouldKeep = - DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + boolean shouldKeep = shouldKeepOperation(workerProvisions, resourceSet, minCoresEntry); // ASSERT // the worker accepts because it has the same cores as the min-cores requested assertThat(shouldKeep).isTrue(); + + QueueEntry coresEntry = + QueueEntry.newBuilder() + .setPlatform( + Platform.newBuilder() + .addProperties(Platform.Property.newBuilder().setName(CORES).setValue("10")) + .addProperties( + Platform.Property.newBuilder().setName(MAX_CORES).setValue("20"))) + .build(); + + // ACT + shouldKeep = shouldKeepOperation(workerProvisions, resourceSet, coresEntry); + + // ASSERT + // the worker accepts because it has the same cores as the cores requested + assertThat(shouldKeep).isTrue(); } // Function under test: shouldKeepOperation @@ -172,8 +215,7 @@ public void shouldKeepOperationUnmatchedPropertiesRejectionAcceptance() throws E .build(); // ACT - boolean shouldKeep = - DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + boolean shouldKeep = shouldKeepOperation(workerProvisions, resourceSet, entry); // ASSERT assertThat(shouldKeep).isFalse(); @@ -182,7 +224,7 @@ public void shouldKeepOperationUnmatchedPropertiesRejectionAcceptance() throws E configs.getWorker().getDequeueMatchSettings().setAllowUnmatched(true); // ACT - shouldKeep = DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + shouldKeep = shouldKeepOperation(workerProvisions, resourceSet, entry); // ASSERT assertThat(shouldKeep).isTrue(); @@ -211,8 +253,7 @@ public void shouldKeepOperationClaimsResource() throws Exception { assertThat(resourceSet.resources.get("FOO").availablePermits()).isEqualTo(1); // ACT - boolean shouldKeep = - DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + boolean shouldKeep = shouldKeepOperation(workerProvisions, resourceSet, entry); // ASSERT // the worker accepts because the resource is available. @@ -220,7 +261,7 @@ public void shouldKeepOperationClaimsResource() throws Exception { assertThat(resourceSet.resources.get("FOO").availablePermits()).isEqualTo(0); // ACT - shouldKeep = DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + shouldKeep = shouldKeepOperation(workerProvisions, resourceSet, entry); // ASSERT // the worker rejects because there are no resources left. @@ -252,8 +293,7 @@ public void rejectOperationIgnoresResource() throws Exception { assertThat(resourceSet.resources.get("FOO").availablePermits()).isEqualTo(1); // ACT - boolean shouldKeep = - DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + boolean shouldKeep = shouldKeepOperation(workerProvisions, resourceSet, entry); // ASSERT // the worker rejects because the os is not satisfied @@ -288,8 +328,7 @@ public void shouldKeepOperationClaimsMultipleResource() throws Exception { assertThat(resourceSet.resources.get("BAR").availablePermits()).isEqualTo(4); // ACT - boolean shouldKeep = - DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + boolean shouldKeep = shouldKeepOperation(workerProvisions, resourceSet, entry); // ASSERT // the worker accepts because the resource is available. @@ -298,7 +337,7 @@ public void shouldKeepOperationClaimsMultipleResource() throws Exception { assertThat(resourceSet.resources.get("BAR").availablePermits()).isEqualTo(2); // ACT - shouldKeep = DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + shouldKeep = shouldKeepOperation(workerProvisions, resourceSet, entry); // ASSERT // the worker accepts because the resource is available. @@ -307,7 +346,7 @@ public void shouldKeepOperationClaimsMultipleResource() throws Exception { assertThat(resourceSet.resources.get("BAR").availablePermits()).isEqualTo(0); // ACT - shouldKeep = DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + shouldKeep = shouldKeepOperation(workerProvisions, resourceSet, entry); // ASSERT // the worker rejects because there are no resources left. @@ -348,8 +387,7 @@ public void shouldKeepOperationFailsToClaimSameAmountRemains() throws Exception assertThat(resourceSet.resources.get("BAZ").availablePermits()).isEqualTo(200); // ACT - boolean shouldKeep = - DequeueMatchEvaluator.shouldKeepOperation(workerProvisions, resourceSet, entry); + boolean shouldKeep = shouldKeepOperation(workerProvisions, resourceSet, entry); // ASSERT // the worker rejects because there are no resources left. @@ -359,4 +397,22 @@ public void shouldKeepOperationFailsToClaimSameAmountRemains() throws Exception assertThat(resourceSet.resources.get("BAR").availablePermits()).isEqualTo(100); assertThat(resourceSet.resources.get("BAZ").availablePermits()).isEqualTo(200); } + + @Test + public void shouldMatchCoresAsMinAndMax() throws Exception { + SetMultimap workerProvisions = HashMultimap.create(); + LocalResourceSet resourceSet = new LocalResourceSet(); + configs.getWorker().getDequeueMatchSettings().setAllowUnmatched(false); + + QueueEntry multicoreEntry = + QueueEntry.newBuilder() + .setPlatform( + Platform.newBuilder() + .addProperties(Platform.Property.newBuilder().setName(CORES).setValue("2")) + .build()) + .build(); + + // cores must be present from worker provisions to keep cores specified in platform + assertThat(shouldKeepOperation(workerProvisions, resourceSet, multicoreEntry)).isFalse(); + } } From 221eae91e2545f22d78311b45d90734b0caa4c84 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Sat, 18 Nov 2023 22:12:43 -0500 Subject: [PATCH 155/311] Consider output_* as relative to WD (#1550) Per the REAPI spec: `The paths are relative to the working directory of the action execution.` Prefix the WorkingDirectory to paths used as OutputDirectory parameters, and verify that these are present in the layout of the directory for use. --- .../worker/shard/CFCExecFileSystem.java | 8 +++- .../worker/shard/CFCExecFileSystemTest.java | 43 +++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 src/test/java/build/buildfarm/worker/shard/CFCExecFileSystemTest.java diff --git a/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java b/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java index dba809fdcf..15aaa10781 100644 --- a/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java +++ b/src/main/java/build/buildfarm/worker/shard/CFCExecFileSystem.java @@ -46,6 +46,7 @@ import build.buildfarm.worker.ExecDirException; import build.buildfarm.worker.ExecDirException.ViolationException; import build.buildfarm.worker.OutputDirectory; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; @@ -402,7 +403,8 @@ private Set linkedDirectories( return ImmutableSet.of(); } - private OutputDirectory createOutputDirectory(Command command) { + @VisibleForTesting + static OutputDirectory createOutputDirectory(Command command) { Iterable files; Iterable dirs; if (command.getOutputPathsCount() != 0) { @@ -412,6 +414,10 @@ private OutputDirectory createOutputDirectory(Command command) { files = command.getOutputFilesList(); dirs = command.getOutputDirectoriesList(); } + if (!command.getWorkingDirectory().isEmpty()) { + files = Iterables.transform(files, file -> command.getWorkingDirectory() + "/" + file); + dirs = Iterables.transform(dirs, dir -> command.getWorkingDirectory() + "/" + dir); + } return OutputDirectory.parse(files, dirs, command.getEnvironmentVariablesList()); } diff --git a/src/test/java/build/buildfarm/worker/shard/CFCExecFileSystemTest.java b/src/test/java/build/buildfarm/worker/shard/CFCExecFileSystemTest.java new file mode 100644 index 0000000000..8d7c0c9f64 --- /dev/null +++ b/src/test/java/build/buildfarm/worker/shard/CFCExecFileSystemTest.java @@ -0,0 +1,43 @@ +// Copyright 2023 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package build.buildfarm.worker.shard; + +import static com.google.common.truth.Truth.assertThat; + +import build.bazel.remote.execution.v2.Command; +import build.buildfarm.worker.OutputDirectory; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class CFCExecFileSystemTest { + @Test + public void outputDirectoryWorkingDirectoryRelative() { + Command command = + Command.newBuilder() + .setWorkingDirectory("foo/bar") + .addOutputFiles("baz/quux") + .addOutputDirectories("nope") + .build(); + + // verification is actually here with checked contents below + // throws unless the directory is relative to the WorkingDirectory + OutputDirectory workingOutputDirectory = + CFCExecFileSystem.createOutputDirectory(command).getChild("foo").getChild("bar"); + assertThat(workingOutputDirectory.getChild("baz").isLeaf()).isTrue(); + assertThat(workingOutputDirectory.getChild("nope").isLeaf()).isFalse(); + } +} From 91587e73d42fe6d689dd2d1be2b9ca5029e9fc12 Mon Sep 17 00:00:00 2001 From: Win Wang <1862202+wiwa@users.noreply.github.com> Date: Mon, 20 Nov 2023 14:53:56 -0500 Subject: [PATCH 156/311] Implement Persistent Workers as an execution path (#1260) Followup to #1195 Add a new execution pathway in worker/Executor.java to use persistent workers via PersistentExecutor, like DockerExecutor. Mostly unchanged from the form we used to experiment back at Twitter, but now with tests. Co-authored-by: Shane Delmore shane@delmore.io --- .../buildfarm/common/ExecutionProperties.java | 16 +- .../common/config/DequeueMatchSettings.java | 1 - src/main/java/build/buildfarm/worker/BUILD | 4 + .../java/build/buildfarm/worker/Executor.java | 34 ++- .../buildfarm/worker/OperationContext.java | 2 +- .../build/buildfarm/worker/persistent/BUILD | 31 ++ .../worker/persistent/FileAccessUtils.java | 171 +++++++++++ .../buildfarm/worker/persistent/Keymaker.java | 112 +++++++ .../worker/persistent/PersistentExecutor.java | 268 +++++++++++++++++ .../worker/persistent/ProtoCoordinator.java | 284 ++++++++++++++++++ .../worker/persistent/RequestCtx.java | 42 +++ .../worker/persistent/ResponseCtx.java | 34 +++ .../worker/persistent/WorkFilesContext.java | 85 ++++++ .../worker/persistent/WorkerInputs.java | 117 ++++++++ .../resources/ExecutionPropertiesParser.java | 32 ++ .../worker/resources/ResourceLimits.java | 13 + .../java/build/buildfarm/worker/util/BUILD | 24 ++ .../buildfarm/worker/util/InputsIndexer.java | 141 +++++++++ .../instance/shard/JedisCasWorkerMapTest.java | 1 - .../build/buildfarm/worker/persistent/BUILD | 36 +++ .../persistent/ProtoCoordinatorTest.java | 132 ++++++++ .../java/build/buildfarm/worker/util/BUILD | 61 ++++ .../worker/util/InputsIndexerTest.java | 184 ++++++++++++ .../worker/util/WorkerTestUtils.java | 226 ++++++++++++++ 24 files changed, 2043 insertions(+), 8 deletions(-) create mode 100644 src/main/java/build/buildfarm/worker/persistent/BUILD create mode 100644 src/main/java/build/buildfarm/worker/persistent/FileAccessUtils.java create mode 100644 src/main/java/build/buildfarm/worker/persistent/Keymaker.java create mode 100644 src/main/java/build/buildfarm/worker/persistent/PersistentExecutor.java create mode 100644 src/main/java/build/buildfarm/worker/persistent/ProtoCoordinator.java create mode 100644 src/main/java/build/buildfarm/worker/persistent/RequestCtx.java create mode 100644 src/main/java/build/buildfarm/worker/persistent/ResponseCtx.java create mode 100644 src/main/java/build/buildfarm/worker/persistent/WorkFilesContext.java create mode 100644 src/main/java/build/buildfarm/worker/persistent/WorkerInputs.java create mode 100644 src/main/java/build/buildfarm/worker/util/BUILD create mode 100644 src/main/java/build/buildfarm/worker/util/InputsIndexer.java create mode 100644 src/test/java/build/buildfarm/worker/persistent/BUILD create mode 100644 src/test/java/build/buildfarm/worker/persistent/ProtoCoordinatorTest.java create mode 100644 src/test/java/build/buildfarm/worker/util/BUILD create mode 100644 src/test/java/build/buildfarm/worker/util/InputsIndexerTest.java create mode 100644 src/test/java/build/buildfarm/worker/util/WorkerTestUtils.java diff --git a/src/main/java/build/buildfarm/common/ExecutionProperties.java b/src/main/java/build/buildfarm/common/ExecutionProperties.java index ee3975d6dd..198783d21b 100644 --- a/src/main/java/build/buildfarm/common/ExecutionProperties.java +++ b/src/main/java/build/buildfarm/common/ExecutionProperties.java @@ -297,7 +297,21 @@ public class ExecutionProperties { /** * @field WORKER * @brief The exec_property to ensure that the action only runs on the worker name given. - * @details Useful for diagnosing woker issues by targeting builds to a specific worker. + * @details Useful for diagnosing worker issues by targeting builds to a specific worker. */ public static final String WORKER = "Worker"; + + /** + * @field PERSISTENT_WORKER_KEY + * @brief Hash of tool inputs from --experiemental_remote_mark_tool_inputs + * @details See https://github.com/bazelbuild/bazel/issues/10091 + */ + public static final String PERSISTENT_WORKER_KEY = "persistentWorkerKey"; + + /** + * @field PERSISTENT_WORKER_COMMAND + * @brief Command string to start the persistent worker + * @details See https://github.com/bazelbuild/bazel/issues/10091 + */ + public static final String PERSISTENT_WORKER_COMMAND = "persistentWorkerCommand"; } diff --git a/src/main/java/build/buildfarm/common/config/DequeueMatchSettings.java b/src/main/java/build/buildfarm/common/config/DequeueMatchSettings.java index 57aad77832..29655e20de 100644 --- a/src/main/java/build/buildfarm/common/config/DequeueMatchSettings.java +++ b/src/main/java/build/buildfarm/common/config/DequeueMatchSettings.java @@ -9,7 +9,6 @@ @Data public class DequeueMatchSettings { - @Getter(AccessLevel.NONE) private boolean acceptEverything; // deprecated diff --git a/src/main/java/build/buildfarm/worker/BUILD b/src/main/java/build/buildfarm/worker/BUILD index e24b50d731..7352a3900e 100644 --- a/src/main/java/build/buildfarm/worker/BUILD +++ b/src/main/java/build/buildfarm/worker/BUILD @@ -4,12 +4,16 @@ java_library( plugins = ["//src/main/java/build/buildfarm/common:lombok"], visibility = ["//visibility:public"], deps = [ + "//persistentworkers/src/main/java/persistent/bazel:bazel-persistent-workers", + "//persistentworkers/src/main/java/persistent/common:persistent-common", "//src/main/java/build/buildfarm/cas", "//src/main/java/build/buildfarm/common", "//src/main/java/build/buildfarm/common/config", "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/instance/stub", + "//src/main/java/build/buildfarm/worker/persistent", "//src/main/java/build/buildfarm/worker/resources", + "//src/main/java/build/buildfarm/worker/util", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "@bazel//src/main/protobuf:execution_statistics_java_proto", "@googleapis//:google_rpc_code_java_proto", diff --git a/src/main/java/build/buildfarm/worker/Executor.java b/src/main/java/build/buildfarm/worker/Executor.java index f4776a6f00..ee0de0b1ba 100644 --- a/src/main/java/build/buildfarm/worker/Executor.java +++ b/src/main/java/build/buildfarm/worker/Executor.java @@ -36,12 +36,16 @@ import build.buildfarm.common.config.ExecutionPolicy; import build.buildfarm.common.config.ExecutionWrapper; import build.buildfarm.v1test.ExecutingOperationMetadata; +import build.buildfarm.v1test.Tree; import build.buildfarm.worker.WorkerContext.IOResource; +import build.buildfarm.worker.persistent.PersistentExecutor; +import build.buildfarm.worker.persistent.WorkFilesContext; import build.buildfarm.worker.resources.ResourceLimits; import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.core.DockerClientBuilder; import com.google.common.base.Stopwatch; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.shell.Protos.ExecutionStatistics; import com.google.longrunning.Operation; import com.google.protobuf.Any; @@ -427,16 +431,38 @@ private Code executeCommand( for (EnvironmentVariable environmentVariable : environmentVariables) { environment.put(environmentVariable.getName(), environmentVariable.getValue()); } - for (Map.Entry environmentVariable : - limits.extraEnvironmentVariables.entrySet()) { - environment.put(environmentVariable.getKey(), environmentVariable.getValue()); - } + environment.putAll(limits.extraEnvironmentVariables); // allow debugging before an execution if (limits.debugBeforeExecution) { return ExecutionDebugger.performBeforeExecutionDebug(processBuilder, limits, resultBuilder); } + boolean usePersistentWorker = + !limits.persistentWorkerKey.isEmpty() && !limits.persistentWorkerCommand.isEmpty(); + + if (usePersistentWorker) { + log.fine( + "usePersistentWorker; got persistentWorkerCommand of : " + + limits.persistentWorkerCommand); + + Tree execTree = workerContext.getQueuedOperation(operationContext.queueEntry).getTree(); + + WorkFilesContext filesContext = + WorkFilesContext.fromContext(execDir, execTree, operationContext.command); + + return PersistentExecutor.runOnPersistentWorker( + limits.persistentWorkerCommand, + filesContext, + operationName, + ImmutableList.copyOf(arguments), + ImmutableMap.copyOf(environment), + limits, + timeout, + PersistentExecutor.defaultWorkRootsDir, + resultBuilder); + } + // run the action under docker if (limits.containerSettings.enabled) { DockerClient dockerClient = DockerClientBuilder.getInstance().build(); diff --git a/src/main/java/build/buildfarm/worker/OperationContext.java b/src/main/java/build/buildfarm/worker/OperationContext.java index 71b1975783..ef73e1bbf9 100644 --- a/src/main/java/build/buildfarm/worker/OperationContext.java +++ b/src/main/java/build/buildfarm/worker/OperationContext.java @@ -22,7 +22,7 @@ import com.google.longrunning.Operation; import java.nio.file.Path; -final class OperationContext { +public final class OperationContext { final ExecuteResponse.Builder executeResponse; final Operation operation; final Poller poller; diff --git a/src/main/java/build/buildfarm/worker/persistent/BUILD b/src/main/java/build/buildfarm/worker/persistent/BUILD new file mode 100644 index 0000000000..b476e0ebb2 --- /dev/null +++ b/src/main/java/build/buildfarm/worker/persistent/BUILD @@ -0,0 +1,31 @@ +java_library( + name = "persistent", + srcs = glob(["*.java"]), + plugins = ["//src/main/java/build/buildfarm/common:lombok"], + visibility = ["//visibility:public"], + deps = [ + "//persistentworkers/src/main/java/persistent/bazel:bazel-persistent-workers", + "//persistentworkers/src/main/java/persistent/common:persistent-common", + "//persistentworkers/src/main/java/persistent/common/util", + "//persistentworkers/src/main/protobuf:worker_protocol_java_proto", + "//src/main/java/build/buildfarm/common", + "//src/main/java/build/buildfarm/worker/resources", + "//src/main/java/build/buildfarm/worker/util", + "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", + "@maven//:com_google_api_grpc_proto_google_common_protos", + "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", + "@maven//:com_google_protobuf_protobuf_java_util", + "@maven//:commons_io_commons_io", + "@maven//:io_grpc_grpc_api", + "@maven//:io_grpc_grpc_context", + "@maven//:io_grpc_grpc_core", + "@maven//:io_grpc_grpc_netty", + "@maven//:io_grpc_grpc_protobuf", + "@maven//:io_grpc_grpc_stub", + "@maven//:io_prometheus_simpleclient", + "@maven//:org_apache_commons_commons_compress", + "@maven//:org_jetbrains_annotations", + "@maven//:org_projectlombok_lombok", + ], +) diff --git a/src/main/java/build/buildfarm/worker/persistent/FileAccessUtils.java b/src/main/java/build/buildfarm/worker/persistent/FileAccessUtils.java new file mode 100644 index 0000000000..ca81384e16 --- /dev/null +++ b/src/main/java/build/buildfarm/worker/persistent/FileAccessUtils.java @@ -0,0 +1,171 @@ +// Copyright 2023 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package build.buildfarm.worker.persistent; + +import static java.nio.file.StandardCopyOption.COPY_ATTRIBUTES; +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; + +import com.google.common.collect.ImmutableSet; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.PosixFilePermission; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Supplier; +import lombok.extern.java.Log; + +/** + * Utility for concurrent move/copy of files Can be extended in the future to (sym)linking if we + * need performance + */ +@Log +public final class FileAccessUtils { + // singleton class with only static methods + private FileAccessUtils() {} + + public static Path addPosixOwnerWrite(Path absPath) throws IOException { + Set perms = Files.getPosixFilePermissions(absPath); + + ImmutableSet permsWithWrite = + ImmutableSet.builder() + .addAll(perms) + .add(PosixFilePermission.OWNER_WRITE) + .build(); + + return Files.setAttribute(absPath, "posix:permissions", permsWithWrite); + } + + private static final ConcurrentHashMap fileLocks = new ConcurrentHashMap<>(); + + // Used here as a simple lock for locking "files" (paths) + private static class PathLock { + // Not used elsewhere + private PathLock() {} + } + + /** + * Copies a file, creating necessary directories, replacing existing files. The resulting file is + * set to be writeable, and we throw if we cannot set that. Thread-safe (within a process) against + * writes to the same path. + * + * @param from + * @param to + * @throws IOException + */ + public static void copyFile(Path from, Path to) throws IOException { + Path absTo = to.toAbsolutePath(); + log.finer("copyFile: " + from + " to " + absTo); + if (!Files.exists(from)) { + throw new IOException("copyFile: source file doesn't exist: " + from); + } + IOException ioException = + writeFileSafe( + to, + () -> { + try { + Files.copy(from, absTo, REPLACE_EXISTING, COPY_ATTRIBUTES); + addPosixOwnerWrite(absTo); + return null; + } catch (IOException e) { + return new IOException("copyFile() could not set writeable: " + absTo, e); + } + }); + if (ioException != null) { + throw ioException; + } + } + + /** + * Moves a file, creating necessary directories, replacing existing files. The resulting file is + * set to be writeable, and we throw if we cannot set that. Thread-safe against writes to the same + * path. + * + * @param from + * @param to + * @throws IOException + */ + public static void moveFile(Path from, Path to) throws IOException { + Path absTo = to.toAbsolutePath(); + log.finer("moveFile: " + from + " to " + absTo); + if (!Files.exists(from)) { + throw new IOException("moveFile: source file doesn't exist: " + from); + } + IOException ioException = + writeFileSafe( + absTo, + () -> { + try { + Files.move(from, absTo, REPLACE_EXISTING); + addPosixOwnerWrite(absTo); + return null; + } catch (IOException e) { + return new IOException("copyFile() could not set writeable: " + absTo, e); + } + }); + if (ioException != null) { + throw ioException; + } + } + + /** + * Deletes a file; Thread-safe against writes to the same path. + * + * @param toDelete + * @throws IOException + */ + public static void deleteFileIfExists(Path toDelete) throws IOException { + Path absTo = toDelete.toAbsolutePath(); + PathLock toLock = fileLock(absTo); + synchronized (toLock) { + try { + Files.deleteIfExists(absTo); + } finally { + fileLocks.remove(absTo); + } + } + } + + /** + * Thread-safe (not multi-process-safe) wrapper for locking paths before a write operation. + * + *

This method will create necessary parent directories. + * + *

It is up to the write operation to specify whether or not to overwrite existing files. + */ + @SuppressWarnings("PMD.UnnecessaryLocalBeforeReturn") + private static IOException writeFileSafe(Path absTo, Supplier writeOp) { + PathLock toLock = fileLock(absTo); + synchronized (toLock) { + try { + // If 'absTo' is a symlink, checks if its target file exists + Files.createDirectories(absTo.getParent()); + return writeOp.get(); + } catch (IOException e) { + // PMD will complain about UnnecessaryLocalBeforeReturn + // In this case, it is necessary to catch the exception + return e; + } finally { + // Clean up to prevent too many locks. + fileLocks.remove(absTo); + } + } + } + + // "Logical" file lock + private static PathLock fileLock(Path writeTo) { + return fileLocks.computeIfAbsent(writeTo, k -> new PathLock()); + } +} diff --git a/src/main/java/build/buildfarm/worker/persistent/Keymaker.java b/src/main/java/build/buildfarm/worker/persistent/Keymaker.java new file mode 100644 index 0000000000..edfaaf23c3 --- /dev/null +++ b/src/main/java/build/buildfarm/worker/persistent/Keymaker.java @@ -0,0 +1,112 @@ +// Copyright 2023 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package build.buildfarm.worker.persistent; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSortedMap; +import com.google.common.hash.HashCode; +import com.google.common.hash.Hasher; +import com.google.common.hash.Hashing; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.util.Objects; +import java.util.SortedMap; +import persistent.bazel.client.PersistentWorker; +import persistent.bazel.client.WorkerKey; + +/** Much of the logic (hashing) is from Bazel itself (private library/methods, i.e. WorkerKey). */ +public class Keymaker { + // Constructs a key with its worker tool input files being relative paths + public static WorkerKey make( + Path opRoot, + Path workRootsDir, + ImmutableList workerInitCmd, + ImmutableList workerInitArgs, + ImmutableMap workerEnv, + String executionName, + WorkerInputs workerFiles) { + // Cancellation not yet supported; can change in the future, + // Presumably, following how Bazel's own persistent workers work + boolean sandboxed = true; + boolean cancellable = false; + + Path workRoot = + calculateWorkRoot( + workRootsDir, + workerInitCmd, + workerInitArgs, + workerEnv, + executionName, + sandboxed, + cancellable); + Path toolsRoot = workRoot.resolve(PersistentWorker.TOOL_INPUT_SUBDIR); + + SortedMap hashedTools = workerFilesWithHashes(workerFiles); + HashCode combinedToolsHash = workerFilesCombinedHash(toolsRoot, hashedTools); + + return new WorkerKey( + workerInitCmd, + workerInitArgs, + workerEnv, + workRoot, + executionName, + combinedToolsHash, + hashedTools, + sandboxed, + cancellable); + } + + // Hash of a subset of the WorkerKey + private static Path calculateWorkRoot( + Path workRootsDir, + ImmutableList workerInitCmd, + ImmutableList workerInitArgs, + ImmutableMap workerEnv, + String executionName, + boolean sandboxed, + boolean cancellable) { + int workRootId = Objects.hash(workerInitCmd, workerInitArgs, workerEnv, sandboxed, cancellable); + String workRootDirName = "work-root_" + executionName + "_" + workRootId; + return workRootsDir.resolve(workRootDirName); + } + + private static ImmutableSortedMap workerFilesWithHashes( + WorkerInputs workerFiles) { + ImmutableSortedMap.Builder workerFileHashBuilder = + ImmutableSortedMap.naturalOrder(); + + for (Path opPath : workerFiles.opToolInputs) { + Path relPath = workerFiles.opRoot.relativize(opPath); + + HashCode toolInputHash = HashCode.fromBytes(workerFiles.digestFor(opPath).toByteArray()); + workerFileHashBuilder.put(relPath, toolInputHash); + } + + return workerFileHashBuilder.build(); + } + + // Even though we hash the toolsRoot-resolved path, it doesn't exist yet. + private static HashCode workerFilesCombinedHash( + Path toolsRoot, SortedMap hashedTools) { + Hasher hasher = Hashing.sha256().newHasher(); + hashedTools.forEach( + (relPath, toolHash) -> { + hasher.putString(toolsRoot.resolve(relPath).toString(), StandardCharsets.UTF_8); + hasher.putBytes(toolHash.asBytes()); + }); + return hasher.hash(); + } +} diff --git a/src/main/java/build/buildfarm/worker/persistent/PersistentExecutor.java b/src/main/java/build/buildfarm/worker/persistent/PersistentExecutor.java new file mode 100644 index 0000000000..a96d678a03 --- /dev/null +++ b/src/main/java/build/buildfarm/worker/persistent/PersistentExecutor.java @@ -0,0 +1,268 @@ +// Copyright 2023 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package build.buildfarm.worker.persistent; + +import build.bazel.remote.execution.v2.ActionResult; +import build.buildfarm.worker.resources.ResourceLimits; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.devtools.build.lib.worker.WorkerProtocol.Input; +import com.google.devtools.build.lib.worker.WorkerProtocol.WorkRequest; +import com.google.devtools.build.lib.worker.WorkerProtocol.WorkResponse; +import com.google.protobuf.ByteString; +import com.google.protobuf.Duration; +import com.google.rpc.Code; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Map; +import java.util.logging.Level; +import java.util.stream.Collectors; +import lombok.extern.java.Log; +import persistent.bazel.client.WorkerKey; + +/** + * Executes an Action like Executor/DockerExecutor, writing to ActionResult. + * + *

Currently has special code for discriminating between Javac/Scalac, and other persistent + * workers, likely for debugging purposes, but need to revisit. (Can't remember fully since it was + * so long ago!) + */ +@Log +public class PersistentExecutor { + private static final ProtoCoordinator coordinator = + ProtoCoordinator.ofCommonsPool(getMaxWorkersPerKey()); + + // TODO load from config (i.e. {worker_root}/persistent) + public static final Path defaultWorkRootsDir = Paths.get("/tmp/worker/persistent/"); + + public static final String PERSISTENT_WORKER_FLAG = "--persistent_worker"; + + // TODO Revisit hardcoded actions + static final String JAVABUILDER_JAR = + "external/remote_java_tools/java_tools/JavaBuilder_deploy.jar"; + + private static final String SCALAC_EXEC_NAME = "Scalac"; + private static final String JAVAC_EXEC_NAME = "JavaBuilder"; + + // How many workers can exist at once for a given WorkerKey + // There may be multiple WorkerKeys per mnemonic, + // e.g. if builds are run with different tool fingerprints + private static final int defaultMaxWorkersPerKey = 6; + + private static int getMaxWorkersPerKey() { + try { + return Integer.parseInt(System.getenv("BUILDFARM_MAX_WORKERS_PER_KEY")); + } catch (Exception ignored) { + log.info( + "Could not get env var BUILDFARM_MAX_WORKERS_PER_KEY; defaulting to " + + defaultMaxWorkersPerKey); + } + return defaultMaxWorkersPerKey; + } + + /** + * 1) Parses action inputs into tool inputs and request inputs 2) Makes the WorkerKey 3) Loads the + * tool inputs, if needed, into the WorkerKey tool inputs dir 4) Runs the work request on its + * Coordinator, passing it the required context 5) Passes output to the resultBuilder + */ + public static Code runOnPersistentWorker( + String persistentWorkerInitCmd, + WorkFilesContext context, + String operationName, + ImmutableList argsList, + ImmutableMap envVars, + ResourceLimits limits, + Duration timeout, + Path workRootsDir, + ActionResult.Builder resultBuilder) + throws IOException { + //// Pull out persistent worker start command from the overall action request + + log.log(Level.FINE, "executeCommandOnPersistentWorker[" + operationName + "]"); + + ImmutableList initCmd = parseInitCmd(persistentWorkerInitCmd, argsList); + + String executionName = getExecutionName(argsList); + if (executionName.isEmpty()) { + log.log(Level.SEVERE, "Invalid Argument: " + argsList); + return Code.INVALID_ARGUMENT; + } + + // TODO revisit why this was necessary in the first place + // (@wiwa) I believe the reason has to do with JavaBuilder workers not relying on env vars, + // as compared to rules_scala, only reading info from the argslist of each command. + // That would mean the Java worker keys should be invariant to the env vars we see. + ImmutableMap env; + if (executionName.equals(JAVAC_EXEC_NAME)) { + env = ImmutableMap.of(); + } else { + env = envVars; + } + + int requestArgsIdx = initCmd.size(); + ImmutableList workerExecCmd = initCmd; + ImmutableList workerInitArgs = + ImmutableList.builder().add(PERSISTENT_WORKER_FLAG).build(); + ImmutableList requestArgs = argsList.subList(requestArgsIdx, argsList.size()); + + //// Make Key + + WorkerInputs workerFiles = WorkerInputs.from(context, requestArgs); + + Path binary = Paths.get(workerExecCmd.get(0)); + if (!workerFiles.containsTool(binary) && !binary.isAbsolute()) { + throw new IllegalArgumentException( + "Binary wasn't a tool input nor an absolute path: " + binary); + } + + WorkerKey key = + Keymaker.make( + context.opRoot, + workRootsDir, + workerExecCmd, + workerInitArgs, + env, + executionName, + workerFiles); + + coordinator.copyToolInputsIntoWorkerToolRoot(key, workerFiles); + + //// Make request + + // Inputs should be relative paths (if they are from operation root) + ImmutableList.Builder reqInputsBuilder = ImmutableList.builder(); + + for (Map.Entry opInput : workerFiles.allInputs.entrySet()) { + Input relInput = opInput.getValue(); + Path opPath = opInput.getKey(); + if (opPath.startsWith(workerFiles.opRoot)) { + relInput = + relInput.toBuilder().setPath(workerFiles.opRoot.relativize(opPath).toString()).build(); + } + reqInputsBuilder.add(relInput); + } + ImmutableList reqInputs = reqInputsBuilder.build(); + + WorkRequest request = + WorkRequest.newBuilder() + .addAllArguments(requestArgs) + .addAllInputs(reqInputs) + .setRequestId(0) + .build(); + + RequestCtx requestCtx = new RequestCtx(request, context, workerFiles, timeout); + + //// Run request + //// Required file operations (in/out) are the responsibility of the coordinator + + log.log(Level.FINE, "Request with key: " + key); + WorkResponse response; + String stdErr = ""; + try { + ResponseCtx fullResponse = coordinator.runRequest(key, requestCtx); + + response = fullResponse.response; + stdErr = fullResponse.errorString; + } catch (Exception e) { + String debug = + "\n\tRequest.initCmd: " + + workerExecCmd + + "\n\tRequest.initArgs: " + + workerInitArgs + + "\n\tRequest.requestArgs: " + + request.getArgumentsList(); + String msg = "Exception while running request: " + e + debug + "\n\n"; + + log.log(Level.SEVERE, msg, e); + + response = + WorkResponse.newBuilder() + .setOutput(msg) + .setExitCode(-1) // incomplete + .build(); + } + + //// Set results + + String responseOut = response.getOutput(); + log.log(Level.FINE, "WorkResponse.output: " + responseOut); + + int exitCode = response.getExitCode(); + resultBuilder + .setExitCode(exitCode) + .setStdoutRaw(response.getOutputBytes()) + .setStderrRaw(ByteString.copyFrom(stdErr, StandardCharsets.UTF_8)); + + if (exitCode == 0) { + return Code.OK; + } + + log.severe( + "PersistentExecutor.runOnPersistentWorker Failed with code: " + + exitCode + + "\n" + + responseOut + + "\n" + + executionName + + " inputs:\n" + + ImmutableList.copyOf( + reqInputs.stream().map(Input::getPath).collect(Collectors.toList()))); + return Code.FAILED_PRECONDITION; + } + + private static ImmutableList parseInitCmd(String cmdStr, ImmutableList argsList) { + if (!cmdStr.endsWith(PERSISTENT_WORKER_FLAG)) { + throw new IllegalArgumentException( + "Persistent Worker request must contain " + + PERSISTENT_WORKER_FLAG + + "\nGot: parseInitCmd[" + + cmdStr + + "]" + + "\n" + + argsList); + } + + String cmd = + cmdStr.trim().substring(0, (cmdStr.length() - PERSISTENT_WORKER_FLAG.length()) - 1); + + // Parse init command into list of space-separated words, without the persistent worker flag + ImmutableList.Builder initCmdBuilder = ImmutableList.builder(); + for (String s : argsList) { + if (cmd.isEmpty()) { + break; + } + cmd = cmd.substring(s.length()).trim(); + initCmdBuilder.add(s); + } + ImmutableList initCmd = initCmdBuilder.build(); + // Check that the persistent worker init command matches the action command + if (!initCmd.equals(argsList.subList(0, initCmd.size()))) { + throw new IllegalArgumentException("parseInitCmd?![" + initCmd + "]" + "\n" + argsList); + } + return initCmd; + } + + private static String getExecutionName(ImmutableList argsList) { + boolean isScalac = argsList.size() > 1 && argsList.get(0).endsWith("scalac/scalac"); + if (isScalac) { + return SCALAC_EXEC_NAME; + } else if (argsList.contains(JAVABUILDER_JAR)) { + return JAVAC_EXEC_NAME; + } + return "SomeOtherExec"; + } +} diff --git a/src/main/java/build/buildfarm/worker/persistent/ProtoCoordinator.java b/src/main/java/build/buildfarm/worker/persistent/ProtoCoordinator.java new file mode 100644 index 0000000000..e3c890225f --- /dev/null +++ b/src/main/java/build/buildfarm/worker/persistent/ProtoCoordinator.java @@ -0,0 +1,284 @@ +// Copyright 2023 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package build.buildfarm.worker.persistent; + +import static persistent.bazel.client.PersistentWorker.TOOL_INPUT_SUBDIR; + +import com.google.devtools.build.lib.worker.WorkerProtocol.WorkRequest; +import com.google.devtools.build.lib.worker.WorkerProtocol.WorkResponse; +import com.google.protobuf.Duration; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Timer; +import java.util.TimerTask; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Level; +import lombok.extern.java.Log; +import persistent.bazel.client.CommonsWorkerPool; +import persistent.bazel.client.PersistentWorker; +import persistent.bazel.client.WorkCoordinator; +import persistent.bazel.client.WorkerKey; +import persistent.bazel.client.WorkerSupervisor; + +/** + * Responsible for: 1) Initializing a new Worker's file environment correctly 2) pre-request + * requirements, e.g. ensuring tool input files 3) post-response requirements, i.e. putting output + * files in the right place + */ +@Log +public class ProtoCoordinator extends WorkCoordinator { + private static final String WORKER_INIT_LOG_SUFFIX = ".initargs.log"; + + private static final ConcurrentHashMap pendingReqs = + new ConcurrentHashMap<>(); + + private static final Timer timeoutScheduler = new Timer("persistent-worker-timeout", true); + + // Synchronize writes to the tool input directory per WorkerKey + // TODO: We only need a Set of WorkerKeys to synchronize on, but no ConcurrentHashSet + private static final ConcurrentHashMap toolInputSyncs = + new ConcurrentHashMap<>(); + + // Enforces locking on the same object given the same WorkerKey + private static WorkerKey keyLock(WorkerKey key) { + return toolInputSyncs.computeIfAbsent(key, k -> k); + } + + public ProtoCoordinator(CommonsWorkerPool workerPool) { + super(workerPool); + } + + public ProtoCoordinator(WorkerSupervisor supervisor, int maxWorkersPerKey) { + super(new CommonsWorkerPool(supervisor, maxWorkersPerKey)); + } + + // We copy tool inputs from the shared WorkerKey tools directory into our worker exec root, + // since there are multiple workers per key, + // and presumably there might be writes to tool inputs? + // Tool inputs which are absolute-paths (e.g. /usr/bin/...) are not affected + public static ProtoCoordinator ofCommonsPool(int maxWorkersPerKey) { + WorkerSupervisor loadToolsOnCreate = + new WorkerSupervisor() { + @Override + public PersistentWorker create(WorkerKey workerKey) throws Exception { + Path keyExecRoot = workerKey.getExecRoot(); + String workerExecDir = getUniqueSubdir(keyExecRoot); + Path workerExecRoot = keyExecRoot.resolve(workerExecDir); + copyToolsIntoWorkerExecRoot(workerKey, workerExecRoot); + + Path initArgsLogFile = workerExecRoot.resolve(workerExecDir + WORKER_INIT_LOG_SUFFIX); + if (!Files.exists(initArgsLogFile)) { + StringBuilder initArgs = new StringBuilder(); + for (String s : workerKey.getCmd()) { + initArgs.append(s); + initArgs.append('\n'); + } + for (String s : workerKey.getArgs()) { + initArgs.append(s); + initArgs.append('\n'); + } + + Files.write(initArgsLogFile, initArgs.toString().getBytes()); + } + + return new PersistentWorker(workerKey, workerExecDir); + } + }; + return new ProtoCoordinator(loadToolsOnCreate, maxWorkersPerKey); + } + + public void copyToolInputsIntoWorkerToolRoot(WorkerKey key, WorkerInputs workerFiles) + throws IOException { + WorkerKey lock = keyLock(key); + synchronized (lock) { + try { + // Move tool inputs as needed + Path workToolRoot = key.getExecRoot().resolve(PersistentWorker.TOOL_INPUT_SUBDIR); + for (Path opToolPath : workerFiles.opToolInputs) { + Path workToolPath = workerFiles.relativizeInput(workToolRoot, opToolPath); + if (!Files.exists(workToolPath)) { + workerFiles.copyInputFile(opToolPath, workToolPath); + } + } + } finally { + toolInputSyncs.remove(key); + } + } + } + + private static String getUniqueSubdir(Path workRoot) { + String uuid = UUID.randomUUID().toString(); + while (Files.exists(workRoot.resolve(uuid))) { + uuid = UUID.randomUUID().toString(); + } + return uuid; + } + + // copyToolInputsIntoWorkerToolRoot() should have been called before this. + private static void copyToolsIntoWorkerExecRoot(WorkerKey key, Path workerExecRoot) + throws IOException { + log.log(Level.FINE, "loadToolsIntoWorkerRoot() into: " + workerExecRoot); + + Path toolInputRoot = key.getExecRoot().resolve(TOOL_INPUT_SUBDIR); + for (Path relPath : key.getWorkerFilesWithHashes().keySet()) { + Path toolInputPath = toolInputRoot.resolve(relPath); + Path execRootPath = workerExecRoot.resolve(relPath); + + FileAccessUtils.copyFile(toolInputPath, execRootPath); + } + } + + @Override + public WorkRequest preWorkInit(WorkerKey key, RequestCtx request, PersistentWorker worker) + throws IOException { + PersistentWorker pendingWorker = pendingReqs.putIfAbsent(request, worker); + // null means that this request was not in pendingReqs (the expected case) + if (pendingWorker != null) { + if (pendingWorker != worker) { + throw new IllegalArgumentException( + "Already have a persistent worker on the job: " + request.request); + } else { + throw new IllegalArgumentException( + "Got the same request for the same worker while it's running: " + request.request); + } + } + startTimeoutTimer(request); + + // Symlinking should hypothetically be faster+leaner than copying inputs, but it's buggy. + copyNontoolInputs(request.workerInputs, worker.getExecRoot()); + + return request.request; + } + + // After the worker has finished, output files need to be visible in the operation directory + @Override + public ResponseCtx postWorkCleanup( + WorkResponse response, PersistentWorker worker, RequestCtx request) throws IOException { + pendingReqs.remove(request); + + if (response == null) { + throw new RuntimeException("postWorkCleanup: WorkResponse was null!"); + } + + if (response.getExitCode() == 0) { + try { + Path workerExecRoot = worker.getExecRoot(); + moveOutputsToOperationRoot(request.filesContext, workerExecRoot); + cleanUpNontoolInputs(request.workerInputs, workerExecRoot); + } catch (IOException e) { + throw logBadCleanup(request, e); + } + } + + return new ResponseCtx(response, worker.flushStdErr()); + } + + private IOException logBadCleanup(RequestCtx request, IOException e) { + WorkFilesContext context = request.filesContext; + + StringBuilder sb = new StringBuilder(122); + sb.append("Output files failure debug for request with args<") + .append(request.request.getArgumentsList()) + .append(">:\ngetOutputPathsList:\n") + .append(context.outputPaths) + .append("getOutputFilesList:\n") + .append(context.outputFiles) + .append("getOutputDirectoriesList:\n") + .append(context.outputDirectories); + + log.log(Level.SEVERE, sb.toString(), e); + + return new IOException("Response was OK but failed on postWorkCleanup", e); + } + + private void copyNontoolInputs(WorkerInputs workerInputs, Path workerExecRoot) + throws IOException { + for (Path opPath : workerInputs.allInputs.keySet()) { + if (!workerInputs.allToolInputs.contains(opPath)) { + Path execPath = workerInputs.relativizeInput(workerExecRoot, opPath); + workerInputs.copyInputFile(opPath, execPath); + } + } + } + + // Make outputs visible to the rest of Worker machinery + // see DockerExecutor::copyOutputsOutOfContainer + void moveOutputsToOperationRoot(WorkFilesContext context, Path workerExecRoot) + throws IOException { + Path opRoot = context.opRoot; + + for (String outputDir : context.outputDirectories) { + Path outputDirPath = Paths.get(outputDir); + Files.createDirectories(outputDirPath); + } + + for (String relOutput : context.outputFiles) { + Path execOutputPath = workerExecRoot.resolve(relOutput); + Path opOutputPath = opRoot.resolve(relOutput); + + FileAccessUtils.moveFile(execOutputPath, opOutputPath); + } + } + + private void cleanUpNontoolInputs(WorkerInputs workerInputs, Path workerExecRoot) + throws IOException { + for (Path opPath : workerInputs.allInputs.keySet()) { + if (!workerInputs.allToolInputs.contains(opPath)) { + workerInputs.deleteInputFileIfExists(workerExecRoot, opPath); + } + } + } + + private void startTimeoutTimer(RequestCtx request) { + Duration timeout = request.timeout; + if (timeout != null) { + long timeoutNanos = timeout.getSeconds() * 1000000000L + timeout.getNanos(); + timeoutScheduler.schedule(new RequestTimeoutHandler(request), timeoutNanos); + } + } + + private class RequestTimeoutHandler extends TimerTask { + private final RequestCtx request; + + private RequestTimeoutHandler(RequestCtx request) { + this.request = request; + } + + @Override + public void run() { + onTimeout(this.request, pendingReqs.get(this.request)); + } + } + + private void onTimeout(RequestCtx request, PersistentWorker worker) { + if (worker != null) { + log.severe("Persistent Worker timed out on request: " + request.request); + try { + this.workerPool.invalidateObject(worker.getKey(), worker); + } catch (Exception e) { + log.severe( + "Tried to invalidate worker for request:\n" + + request + + "\n\tbut got: " + + e + + "\n\nCalling worker.destroy() and moving on."); + worker.destroy(); + } + } + } +} diff --git a/src/main/java/build/buildfarm/worker/persistent/RequestCtx.java b/src/main/java/build/buildfarm/worker/persistent/RequestCtx.java new file mode 100644 index 0000000000..36f42b2f12 --- /dev/null +++ b/src/main/java/build/buildfarm/worker/persistent/RequestCtx.java @@ -0,0 +1,42 @@ +// Copyright 2023 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package build.buildfarm.worker.persistent; + +import com.google.devtools.build.lib.worker.WorkerProtocol.WorkRequest; +import com.google.protobuf.Duration; +import persistent.common.CtxAround; + +public class RequestCtx implements CtxAround { + public final WorkRequest request; + + public final WorkFilesContext filesContext; + + public final WorkerInputs workerInputs; + + public final Duration timeout; + + public RequestCtx( + WorkRequest request, WorkFilesContext ctx, WorkerInputs workFiles, Duration timeout) { + this.request = request; + this.filesContext = ctx; + this.workerInputs = workFiles; + this.timeout = timeout; + } + + @Override + public WorkRequest get() { + return request; + } +} diff --git a/src/main/java/build/buildfarm/worker/persistent/ResponseCtx.java b/src/main/java/build/buildfarm/worker/persistent/ResponseCtx.java new file mode 100644 index 0000000000..0ff6edcdae --- /dev/null +++ b/src/main/java/build/buildfarm/worker/persistent/ResponseCtx.java @@ -0,0 +1,34 @@ +// Copyright 2023 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package build.buildfarm.worker.persistent; + +import com.google.devtools.build.lib.worker.WorkerProtocol.WorkResponse; +import persistent.common.CtxAround; + +public class ResponseCtx implements CtxAround { + public final WorkResponse response; + + public final String errorString; + + public ResponseCtx(WorkResponse response, String errorString) { + this.response = response; + this.errorString = errorString; + } + + @Override + public WorkResponse get() { + return response; + } +} diff --git a/src/main/java/build/buildfarm/worker/persistent/WorkFilesContext.java b/src/main/java/build/buildfarm/worker/persistent/WorkFilesContext.java new file mode 100644 index 0000000000..4aefc7f290 --- /dev/null +++ b/src/main/java/build/buildfarm/worker/persistent/WorkFilesContext.java @@ -0,0 +1,85 @@ +// Copyright 2023 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package build.buildfarm.worker.persistent; + +import build.bazel.remote.execution.v2.Command; +import build.buildfarm.v1test.Tree; +import build.buildfarm.worker.util.InputsIndexer; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.devtools.build.lib.worker.WorkerProtocol.Input; +import java.nio.file.Path; + +/** POJO/data class grouping all the input/output file requirements for persistent workers */ +public class WorkFilesContext { + public final Path opRoot; + + public final Tree execTree; + + public final ImmutableList outputPaths; + + public final ImmutableList outputFiles; + + public final ImmutableList outputDirectories; + + private final InputsIndexer inputsIndexer; + + private ImmutableMap pathInputs = null; + + private ImmutableMap toolInputs = null; + + public WorkFilesContext( + Path opRoot, + Tree execTree, + ImmutableList outputPaths, + ImmutableList outputFiles, + ImmutableList outputDirectories) { + this.opRoot = opRoot.toAbsolutePath(); + this.execTree = execTree; + this.outputPaths = outputPaths; + this.outputFiles = outputFiles; + this.outputDirectories = outputDirectories; + + this.inputsIndexer = new InputsIndexer(execTree, this.opRoot); + } + + public static WorkFilesContext fromContext(Path opRoot, Tree inputsTree, Command opCommand) { + return new WorkFilesContext( + opRoot, + inputsTree, + ImmutableList.copyOf(opCommand.getOutputPathsList()), + ImmutableList.copyOf(opCommand.getOutputFilesList()), + ImmutableList.copyOf(opCommand.getOutputDirectoriesList())); + } + + // Paths are absolute paths from the opRoot; same as the Input.getPath(); + public ImmutableMap getPathInputs() { + synchronized (this) { + if (pathInputs == null) { + pathInputs = inputsIndexer.getAllInputs(); + } + } + return pathInputs; + } + + public ImmutableMap getToolInputs() { + synchronized (this) { + if (toolInputs == null) { + toolInputs = inputsIndexer.getToolInputs(); + } + } + return toolInputs; + } +} diff --git a/src/main/java/build/buildfarm/worker/persistent/WorkerInputs.java b/src/main/java/build/buildfarm/worker/persistent/WorkerInputs.java new file mode 100644 index 0000000000..de731b9d83 --- /dev/null +++ b/src/main/java/build/buildfarm/worker/persistent/WorkerInputs.java @@ -0,0 +1,117 @@ +// Copyright 2023 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package build.buildfarm.worker.persistent; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.devtools.build.lib.worker.WorkerProtocol.Input; +import com.google.protobuf.ByteString; +import java.io.IOException; +import java.nio.file.Path; +import java.util.List; +import lombok.extern.java.Log; + +@Log +public class WorkerInputs { + public final Path opRoot; + // Some tool inputs are not under opRoot + public final ImmutableSet absToolInputs; + // The Paths in these collections should all be absolute and under opRoot + public final ImmutableSet opToolInputs; + public final ImmutableMap allInputs; + + public final ImmutableSet allToolInputs; + + public WorkerInputs( + Path opRoot, + ImmutableSet absToolInputs, + ImmutableSet opToolInputs, + ImmutableMap allInputs) { + this.opRoot = opRoot; + this.absToolInputs = absToolInputs; + this.opToolInputs = opToolInputs; + this.allInputs = allInputs; + + this.allToolInputs = + ImmutableSet.builder().addAll(absToolInputs).addAll(opToolInputs).build(); + + // Currently not a concern but could be in the future + for (Path tool : opToolInputs) { + if (!allInputs.containsKey(tool)) { + String msg = "Tool not found in inputs: " + tool; + log.severe(msg); + throw new IllegalArgumentException(msg); + } + } + } + + public boolean containsTool(Path tool) { + return allToolInputs.contains(opRoot.resolve(tool)); + } + + public Path relativizeInput(Path newRoot, Path input) { + return newRoot.resolve(opRoot.relativize(input)); + } + + public void copyInputFile(Path from, Path to) throws IOException { + checkFileIsInput("copyInputFile()", from); + FileAccessUtils.copyFile(from, to); + } + + public void deleteInputFileIfExists(Path workerExecRoot, Path opPathInput) throws IOException { + checkFileIsInput("deleteInputFile()", opPathInput); + Path execPathInput = relativizeInput(workerExecRoot, opPathInput); + FileAccessUtils.deleteFileIfExists(execPathInput); + } + + private void checkFileIsInput(String operation, Path file) { + if (!allInputs.containsKey(file)) { + throw new IllegalArgumentException(operation + " called on non-input file: " + file); + } + } + + public ByteString digestFor(Path inputPath) { + Input input = allInputs.get(inputPath); + if (input == null) { + throw new IllegalArgumentException("digestFor() called on non-input file: " + inputPath); + } + return input.getDigest(); + } + + public static WorkerInputs from(WorkFilesContext workFilesContext, List reqArgs) { + ImmutableMap pathInputs = workFilesContext.getPathInputs(); + + ImmutableSet toolsAbsPaths = workFilesContext.getToolInputs().keySet(); + + ImmutableSet toolInputs = + ImmutableSet.copyOf( + toolsAbsPaths.stream().filter(p -> p.startsWith(workFilesContext.opRoot)).iterator()); + ImmutableSet absToolInputs = + ImmutableSet.copyOf(toolsAbsPaths.stream().filter(p -> !toolInputs.contains(p)).iterator()); + + String inputsDebugMsg = + "ParsedWorkFiles:" + + "\nallInputs: " + + pathInputs.keySet() + + "\ntoolInputs: " + + toolInputs + + "\nabsToolInputs: " + + absToolInputs; + + log.fine(inputsDebugMsg); + + return new WorkerInputs(workFilesContext.opRoot, absToolInputs, toolInputs, pathInputs); + } +} diff --git a/src/main/java/build/buildfarm/worker/resources/ExecutionPropertiesParser.java b/src/main/java/build/buildfarm/worker/resources/ExecutionPropertiesParser.java index 183c48da18..2c219589fb 100644 --- a/src/main/java/build/buildfarm/worker/resources/ExecutionPropertiesParser.java +++ b/src/main/java/build/buildfarm/worker/resources/ExecutionPropertiesParser.java @@ -67,6 +67,12 @@ public static ResourceLimits Parse(Command command) { parser.put( ExecutionProperties.DEBUG_TESTS_ONLY, ExecutionPropertiesParser::storeDebugTestsOnly); parser.put(ExecutionProperties.DEBUG_TARGET, ExecutionPropertiesParser::storeDebugTarget); + parser.put( + ExecutionProperties.PERSISTENT_WORKER_KEY, + ExecutionPropertiesParser::storePersistentWorkerKey); + parser.put( + ExecutionProperties.PERSISTENT_WORKER_COMMAND, + ExecutionPropertiesParser::storePersistentWorkerCommand); ResourceLimits limits = new ResourceLimits(); command @@ -327,6 +333,32 @@ private static void storeDebugTarget(ResourceLimits limits, Property property) { describeChange(limits.description, "debug target", property.getValue(), property); } + /** + * @brief Stores persistentWorkerKey + * @details Parses and stores a String. + * @param limits Current limits to apply changes to. + * @param property The property to store. + */ + private static void storePersistentWorkerKey(ResourceLimits limits, Property property) { + limits.persistentWorkerKey = property.getValue(); + ArrayList xs = new ArrayList<>(); + xs.add("Hash of tool inputs for remote persistent workers"); + describeChange(xs, "persistentWorkerKey(hash of tool inputs)", property.getValue(), property); + } + + /** + * @brief Stores persistentWorkerCommand + * @details Parses and stores a String. + * @param limits Current limits to apply changes to. + * @param property The property to store. + */ + private static void storePersistentWorkerCommand(ResourceLimits limits, Property property) { + limits.persistentWorkerCommand = property.getValue(); + ArrayList xs = new ArrayList<>(); + xs.add("persistentWorkerCommand"); + describeChange(xs, "persistentWorkerCommand", property.getValue(), property); + } + /** * @brief Store the description of the change made. * @details Adds a debug message on the resource change. diff --git a/src/main/java/build/buildfarm/worker/resources/ResourceLimits.java b/src/main/java/build/buildfarm/worker/resources/ResourceLimits.java index e3ddc4485b..e20f2c9c27 100644 --- a/src/main/java/build/buildfarm/worker/resources/ResourceLimits.java +++ b/src/main/java/build/buildfarm/worker/resources/ResourceLimits.java @@ -163,4 +163,17 @@ public class ResourceLimits { * @details This can be used to debug execution behavior. */ public final ArrayList description = new ArrayList<>(); + /** + * @field persistentWorkerKey + * @brief Hash of tool inputs for remote persistent workers + * @details See https://github.com/bazelbuild/bazel/issues/10091 + */ + public String persistentWorkerKey = ""; + + /** + * @field persistentWorkerCommand + * @brief Command string to start the persistent worker + * @details See https://github.com/bazelbuild/bazel/issues/10091 + */ + public String persistentWorkerCommand = ""; } diff --git a/src/main/java/build/buildfarm/worker/util/BUILD b/src/main/java/build/buildfarm/worker/util/BUILD new file mode 100644 index 0000000000..a92360d732 --- /dev/null +++ b/src/main/java/build/buildfarm/worker/util/BUILD @@ -0,0 +1,24 @@ +java_library( + name = "util", + srcs = glob(["*.java"]), + visibility = ["//visibility:public"], + deps = [ + "//persistentworkers/src/main/protobuf:worker_protocol_java_proto", + "//src/main/java/build/buildfarm/common", + "//src/main/java/build/buildfarm/instance", + "//src/main/java/build/buildfarm/instance/stub", + "//src/main/java/build/buildfarm/worker/resources", + "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", + "@maven//:com_google_code_gson_gson", + "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", + "@maven//:com_google_protobuf_protobuf_java_util", + "@maven//:commons_io_commons_io", + "@maven//:io_grpc_grpc_api", + "@maven//:io_grpc_grpc_context", + "@maven//:io_grpc_grpc_core", + "@maven//:io_grpc_grpc_netty", + "@maven//:io_grpc_grpc_protobuf", + "@maven//:io_grpc_grpc_stub", + ], +) diff --git a/src/main/java/build/buildfarm/worker/util/InputsIndexer.java b/src/main/java/build/buildfarm/worker/util/InputsIndexer.java new file mode 100644 index 0000000000..84497b04a0 --- /dev/null +++ b/src/main/java/build/buildfarm/worker/util/InputsIndexer.java @@ -0,0 +1,141 @@ +// Copyright 2023 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package build.buildfarm.worker.util; + +import build.bazel.remote.execution.v2.Digest; +import build.bazel.remote.execution.v2.Directory; +import build.bazel.remote.execution.v2.FileNode; +import build.bazel.remote.execution.v2.NodeProperty; +import build.buildfarm.common.ProxyDirectoriesIndex; +import build.buildfarm.v1test.Tree; +import com.google.common.collect.ImmutableMap; +import com.google.devtools.build.lib.worker.WorkerProtocol.Input; +import java.nio.file.FileSystem; +import java.nio.file.Path; +import java.util.Map; + +/** + * Organizes action Inputs into files, extracting their paths, and differentiates tool inputs (e.g. + * JavaBuilder, Scalac, etc.) + * + *

Indexes (and partitions) Inputs from an action's Merkle Tree. + */ +public class InputsIndexer { + // See: https://github.com/bazelbuild/bazel/issues/10091 + public static final String BAZEL_TOOL_INPUT_MARKER = "bazel_tool_input"; + + final Tree tree; + final Map proxyDirs; + + final FileSystem fs; + + final Path opRoot; + + ImmutableMap files = null; + ImmutableMap absPathInputs = null; + ImmutableMap toolInputs = null; + + public InputsIndexer(Tree tree, Path opRoot) { + this.tree = tree; + this.proxyDirs = new ProxyDirectoriesIndex(tree.getDirectoriesMap()); + this.opRoot = opRoot; + this.fs = opRoot.getFileSystem(); + } + + // https://stackoverflow.com/questions/22611919/why-do-i-get-providermismatchexception-when-i-try-to-relativize-a-path-agains + public Path pathTransform(final Path path) { + Path ret = fs.getPath(path.isAbsolute() ? fs.getSeparator() : ""); + for (final Path component : path) ret = ret.resolve(component.getFileName().toString()); + return ret; + } + + public ImmutableMap getAllInputs() { + if (absPathInputs == null) { + ImmutableMap relFiles = getAllFiles(); + ImmutableMap.Builder inputs = ImmutableMap.builder(); + + for (Map.Entry pf : relFiles.entrySet()) { + Path absPath = this.opRoot.resolve(pf.getKey()).normalize(); + inputs.put(absPath, inputFromFile(absPath, pf.getValue())); + } + absPathInputs = inputs.build(); + } + return absPathInputs; + } + + public ImmutableMap getToolInputs() { + if (toolInputs == null) { + ImmutableMap relFiles = getAllFiles(); + ImmutableMap.Builder inputs = ImmutableMap.builder(); + + for (Map.Entry pf : relFiles.entrySet()) { + FileNode fn = pf.getValue(); + if (isToolInput(fn)) { + Path absPath = this.opRoot.resolve(pf.getKey()); + inputs.put(absPath, inputFromFile(absPath, fn)); + } + } + toolInputs = inputs.build(); + } + return toolInputs; + } + + private ImmutableMap getAllFiles() { + if (files == null) { + ImmutableMap.Builder accumulator = ImmutableMap.builder(); + Directory rootDir = proxyDirs.get(tree.getRootDigest()); + + Path fsRelative = fs.getPath("."); + files = getFilesFromDir(fsRelative, rootDir, accumulator).build(); + } + return files; + } + + private Input inputFromFile(Path absPath, FileNode fileNode) { + return Input.newBuilder() + .setPath(absPath.toString()) + .setDigest(fileNode.getDigest().getHashBytes()) + .build(); + } + + private ImmutableMap.Builder getFilesFromDir( + Path dirPath, Directory dir, ImmutableMap.Builder acc) { + dir.getFilesList() + .forEach( + fileNode -> { + Path path = dirPath.resolve(fileNode.getName()).normalize(); + acc.put(path, fileNode); + }); + + // Recurse into subdirectories + dir.getDirectoriesList() + .forEach( + dirNode -> + getFilesFromDir( + dirPath.resolve(dirNode.getName()), + this.proxyDirs.get(dirNode.getDigest()), + acc)); + return acc; + } + + private static boolean isToolInput(FileNode fileNode) { + for (NodeProperty prop : fileNode.getNodeProperties().getPropertiesList()) { + if (prop.getName().equals(BAZEL_TOOL_INPUT_MARKER)) { + return true; + } + } + return false; + } +} diff --git a/src/test/java/build/buildfarm/instance/shard/JedisCasWorkerMapTest.java b/src/test/java/build/buildfarm/instance/shard/JedisCasWorkerMapTest.java index caa69536c1..0b6f3d2020 100644 --- a/src/test/java/build/buildfarm/instance/shard/JedisCasWorkerMapTest.java +++ b/src/test/java/build/buildfarm/instance/shard/JedisCasWorkerMapTest.java @@ -20,7 +20,6 @@ @RunWith(JUnit4.class) public class JedisCasWorkerMapTest { - private static final String CAS_PREFIX = "ContentAddressableStorage"; private RedisServer redisServer; diff --git a/src/test/java/build/buildfarm/worker/persistent/BUILD b/src/test/java/build/buildfarm/worker/persistent/BUILD new file mode 100644 index 0000000000..0520097ff6 --- /dev/null +++ b/src/test/java/build/buildfarm/worker/persistent/BUILD @@ -0,0 +1,36 @@ +java_test( + name = "tests", + size = "small", + srcs = glob(["*.java"]), + test_class = "build.buildfarm.AllTests", + deps = [ + "//persistentworkers/src/main/java/persistent/bazel:bazel-persistent-workers", + "//persistentworkers/src/main/java/persistent/common:persistent-common", + "//persistentworkers/src/main/java/persistent/common/util", + "//persistentworkers/src/main/protobuf:worker_protocol_java_proto", + "//src/main/java/build/buildfarm/common", + "//src/main/java/build/buildfarm/common/config", + "//src/main/java/build/buildfarm/instance", + "//src/main/java/build/buildfarm/worker", + "//src/main/java/build/buildfarm/worker/persistent", + "//src/main/java/build/buildfarm/worker/resources", + "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", + "//src/test/java/build/buildfarm:test_runner", + "//src/test/java/build/buildfarm/worker/util:worker_test_utils", + "@googleapis//:google_rpc_code_java_proto", + "@maven//:com_github_jnr_jnr_constants", + "@maven//:com_github_jnr_jnr_ffi", + "@maven//:com_github_serceman_jnr_fuse", + "@maven//:com_google_guava_guava", + "@maven//:com_google_jimfs_jimfs", + "@maven//:com_google_protobuf_protobuf_java", + "@maven//:com_google_truth_truth", + "@maven//:io_grpc_grpc_api", + "@maven//:io_grpc_grpc_context", + "@maven//:io_grpc_grpc_core", + "@maven//:io_grpc_grpc_protobuf", + "@maven//:org_mockito_mockito_core", + "@maven//:org_projectlombok_lombok", + "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", + ], +) diff --git a/src/test/java/build/buildfarm/worker/persistent/ProtoCoordinatorTest.java b/src/test/java/build/buildfarm/worker/persistent/ProtoCoordinatorTest.java new file mode 100644 index 0000000000..908a1746e4 --- /dev/null +++ b/src/test/java/build/buildfarm/worker/persistent/ProtoCoordinatorTest.java @@ -0,0 +1,132 @@ +// Copyright 2023 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package build.buildfarm.worker.persistent; + +import build.bazel.remote.execution.v2.Command; +import build.buildfarm.v1test.Tree; +import build.buildfarm.worker.util.WorkerTestUtils; +import build.buildfarm.worker.util.WorkerTestUtils.TreeFile; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; +import com.google.common.jimfs.Configuration; +import com.google.common.jimfs.Jimfs; +import com.google.devtools.build.lib.worker.WorkerProtocol.Input; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import persistent.bazel.client.PersistentWorker; +import persistent.bazel.client.WorkerKey; + +@RunWith(JUnit4.class) +public class ProtoCoordinatorTest { + private WorkerKey makeWorkerKey( + WorkFilesContext ctx, WorkerInputs workerFiles, Path workRootsDir) { + return Keymaker.make( + ctx.opRoot, + workRootsDir, + ImmutableList.of("workerExecCmd"), + ImmutableList.of("workerInitArgs"), + ImmutableMap.of(), + "executionName", + workerFiles); + } + + private Path rootDir = null; + + public Path jimFsRoot() { + if (rootDir == null) { + rootDir = + Iterables.getFirst( + Jimfs.newFileSystem( + Configuration.unix() + .toBuilder() + .setAttributeViews("basic", "owner", "posix", "unix") + .build()) + .getRootDirectories(), + null); + } + return rootDir; + } + + @Test + public void testProtoCoordinator() throws Exception { + ProtoCoordinator pc = ProtoCoordinator.ofCommonsPool(4); + + Path fsRoot = jimFsRoot(); + Path opRoot = fsRoot.resolve("opRoot"); + assert (Files.notExists(opRoot)); + Files.createDirectory(opRoot); + + assert (Files.exists(opRoot)); + + String treeRootDir = opRoot.toString(); + List fileInputs = + ImmutableList.of( + new TreeFile("file_1", "file contents 1"), + new TreeFile("subdir/subdir_file_2", "file contents 2"), + new TreeFile("tools_dir/tool_file", "tool file contents", true), + new TreeFile("tools_dir/tool_file_2", "tool file contents 2", true)); + + Tree tree = WorkerTestUtils.makeTree(treeRootDir, fileInputs); + + Command command = WorkerTestUtils.makeCommand(); + WorkFilesContext ctx = WorkFilesContext.fromContext(opRoot, tree, command); + ImmutableList requestArgs = ImmutableList.of("reqArg1"); + + WorkerInputs workerFiles = WorkerInputs.from(ctx, requestArgs); + + for (Map.Entry entry : workerFiles.allInputs.entrySet()) { + Path file = entry.getKey(); + Files.createDirectories(file.getParent()); + Files.createFile(file); + } + + WorkerKey key = makeWorkerKey(ctx, workerFiles, fsRoot.resolve("workRootsDir")); + + Path workRoot = key.getExecRoot(); + Path toolsRoot = workRoot.resolve(PersistentWorker.TOOL_INPUT_SUBDIR); + + pc.copyToolInputsIntoWorkerToolRoot(key, workerFiles); + + assert Files.exists(workRoot); + List expectedToolInputs = new ArrayList<>(); + for (TreeFile file : fileInputs) { + if (file.isTool) { + expectedToolInputs.add(toolsRoot.resolve(file.path)); + } + } + WorkerTestUtils.assertFilesExistExactly(workRoot, expectedToolInputs); + + List expectedOpRootFiles = new ArrayList<>(); + + // Check that we move specified output files (assuming they exist) + for (String pathStr : ctx.outputFiles) { + Path file = workRoot.resolve(pathStr); + Files.createDirectories(file.getParent()); + Files.createFile(file); + expectedOpRootFiles.add(opRoot.resolve(pathStr)); + } + + pc.moveOutputsToOperationRoot(ctx, workRoot); + + WorkerTestUtils.assertFilesExistExactly(opRoot, expectedOpRootFiles); + } +} diff --git a/src/test/java/build/buildfarm/worker/util/BUILD b/src/test/java/build/buildfarm/worker/util/BUILD new file mode 100644 index 0000000000..c0d0bbe46f --- /dev/null +++ b/src/test/java/build/buildfarm/worker/util/BUILD @@ -0,0 +1,61 @@ +java_library( + name = "worker_test_utils", + srcs = ["WorkerTestUtils.java"], + visibility = ["//src/test/java:__subpackages__"], + deps = [ + "//persistentworkers/src/main/protobuf:worker_protocol_java_proto", + "//src/main/java/build/buildfarm/cas", + "//src/main/java/build/buildfarm/common", + "//src/main/java/build/buildfarm/common/config", + "//src/main/java/build/buildfarm/worker/util", + "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", + "//src/test/java/build/buildfarm:test_runner", + "@googleapis//:google_rpc_code_java_proto", + "@maven//:com_github_jnr_jnr_constants", + "@maven//:com_github_jnr_jnr_ffi", + "@maven//:com_github_serceman_jnr_fuse", + "@maven//:com_google_guava_guava", + "@maven//:com_google_jimfs_jimfs", + "@maven//:com_google_protobuf_protobuf_java", + "@maven//:com_google_truth_truth", + "@maven//:io_grpc_grpc_api", + "@maven//:io_grpc_grpc_context", + "@maven//:io_grpc_grpc_core", + "@maven//:io_grpc_grpc_protobuf", + "@maven//:org_mockito_mockito_core", + "@maven//:org_projectlombok_lombok", + "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", + ], +) + +java_test( + name = "tests", + size = "small", + srcs = glob(["*Test.java"]), + test_class = "build.buildfarm.AllTests", + deps = [ + ":worker_test_utils", + "//persistentworkers/src/main/protobuf:worker_protocol_java_proto", + "//src/main/java/build/buildfarm/cas", + "//src/main/java/build/buildfarm/common", + "//src/main/java/build/buildfarm/common/config", + "//src/main/java/build/buildfarm/worker/util", + "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", + "//src/test/java/build/buildfarm:test_runner", + "@googleapis//:google_rpc_code_java_proto", + "@maven//:com_github_jnr_jnr_constants", + "@maven//:com_github_jnr_jnr_ffi", + "@maven//:com_github_serceman_jnr_fuse", + "@maven//:com_google_guava_guava", + "@maven//:com_google_jimfs_jimfs", + "@maven//:com_google_protobuf_protobuf_java", + "@maven//:com_google_truth_truth", + "@maven//:io_grpc_grpc_api", + "@maven//:io_grpc_grpc_context", + "@maven//:io_grpc_grpc_core", + "@maven//:io_grpc_grpc_protobuf", + "@maven//:org_mockito_mockito_core", + "@maven//:org_projectlombok_lombok", + "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", + ], +) diff --git a/src/test/java/build/buildfarm/worker/util/InputsIndexerTest.java b/src/test/java/build/buildfarm/worker/util/InputsIndexerTest.java new file mode 100644 index 0000000000..954eb61e4e --- /dev/null +++ b/src/test/java/build/buildfarm/worker/util/InputsIndexerTest.java @@ -0,0 +1,184 @@ +// Copyright 2023 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package build.buildfarm.worker.util; + +import static build.buildfarm.worker.util.InputsIndexer.BAZEL_TOOL_INPUT_MARKER; +import static com.google.common.truth.Truth.assertThat; + +import build.bazel.remote.execution.v2.Digest; +import build.bazel.remote.execution.v2.Directory; +import build.bazel.remote.execution.v2.DirectoryNode; +import build.bazel.remote.execution.v2.FileNode; +import build.bazel.remote.execution.v2.NodeProperties; +import build.bazel.remote.execution.v2.NodeProperty; +import build.buildfarm.common.DigestUtil; +import build.buildfarm.v1test.Tree; +import com.google.common.collect.ImmutableMap; +import com.google.devtools.build.lib.worker.WorkerProtocol.Input; +import com.google.protobuf.ByteString; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.stream.Collectors; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +// TODO: use WorkerTestUtils.makeTree +@RunWith(JUnit4.class) +public class InputsIndexerTest { + private final DigestUtil DIGEST_UTIL = new DigestUtil(DigestUtil.HashFunction.SHA256); + + @Test + public void basicEmptyTree() { + Tree emptyTree = Tree.newBuilder().build(); + InputsIndexer indexer = new InputsIndexer(emptyTree, Paths.get(".")); + assertThat(indexer.tree).isEqualTo(emptyTree); + } + + @Test + public void canGetRootDir() { + Tree.Builder treeBuilder = Tree.newBuilder(); + + Directory rootDir = Directory.getDefaultInstance(); + Digest rootDirDigest = addDirToTree(treeBuilder, "my_root_dir", rootDir); + treeBuilder.setRootDigest(rootDirDigest); + + Path arbitraryOpRoot = Paths.get("."); + + InputsIndexer indexer = new InputsIndexer(treeBuilder.build(), arbitraryOpRoot); + assertThat(indexer.proxyDirs.get(rootDirDigest)).isEqualTo(rootDir); + assertThat(indexer.getAllInputs().size()).isEqualTo(0); + } + + @Test + public void rootDirWithFiles() { + Tree.Builder treeBuilder = Tree.newBuilder(); + + FileNode myfile = + makeFileNode("my_file", "my file contents", NodeProperties.getDefaultInstance()); + Directory rootDir = Directory.newBuilder().addFiles(myfile).build(); + Digest rootDirDigest = addDirToTree(treeBuilder, "my_root_dir", rootDir); + treeBuilder.setRootDigest(rootDirDigest); + + Path arbitraryOpRoot = Paths.get("asdf"); + InputsIndexer indexer = new InputsIndexer(treeBuilder.build(), arbitraryOpRoot); + assertThat(indexer.proxyDirs.get(rootDirDigest)).isEqualTo(rootDir); + + Input myfileInput = makeInput(arbitraryOpRoot, myfile); + + ImmutableMap expectedInputs = + ImmutableMap.of(Paths.get(myfileInput.getPath()), myfileInput); + + assertThat(indexer.getAllInputs()).isEqualTo(expectedInputs); + } + + @Test + public void canRecurseAndDistinguishToolInputs() { + Tree.Builder treeBuilder = Tree.newBuilder(); + + FileNode myfile = + makeFileNode("my_file", "my file contents", NodeProperties.getDefaultInstance()); + FileNode subdirfile = + makeFileNode("subdir_file", "my subdir file contents", NodeProperties.getDefaultInstance()); + FileNode toolfile = + makeFileNode( + "tool_file", + "my tool file contents", + makeNodeProperties(ImmutableMap.of(BAZEL_TOOL_INPUT_MARKER, "value doesn't matter"))); + + Directory subDir = Directory.newBuilder().addFiles(subdirfile).build(); + String subDirName = "my_sub_dir"; + Digest subDirDigest = addDirToTree(treeBuilder, subDirName, subDir); + + Directory rootDir = + Directory.newBuilder() + .addFiles(myfile) + .addFiles(toolfile) + .addDirectories(makeDirNode(subDirName, subDirDigest)) + .build(); + + Digest rootDirDigest = addDirToTree(treeBuilder, "my_root_dir", rootDir); + treeBuilder.setRootDigest(rootDirDigest); + + Path arbitraryOpRoot = Paths.get("asdf"); + + InputsIndexer indexer = new InputsIndexer(treeBuilder.build(), arbitraryOpRoot); + assertThat(indexer.proxyDirs.get(rootDirDigest)).isEqualTo(rootDir); + assertThat(indexer.proxyDirs.size()).isEqualTo(2); + + Input myfileInput = makeInput(arbitraryOpRoot, myfile); + Input subdirfileInput = makeInput(arbitraryOpRoot.resolve(subDirName), subdirfile); + Input toolfileInput = makeInput(arbitraryOpRoot, toolfile); + + ImmutableMap nonToolInputs = + ImmutableMap.of( + Paths.get(myfileInput.getPath()), + myfileInput, + Paths.get(subdirfileInput.getPath()), + subdirfileInput); + ImmutableMap toolInputs = + ImmutableMap.of(Paths.get(toolfileInput.getPath()), toolfileInput); + ImmutableMap allInputs = + ImmutableMap.builder().putAll(nonToolInputs).putAll(toolInputs).build(); + + assertThat(indexer.getAllInputs()).isEqualTo(allInputs); + assertThat(indexer.getAllInputs().size()).isEqualTo(3); + assertThat(indexer.getToolInputs()).isEqualTo(toolInputs); + } + + Digest addDirToTree(Tree.Builder treeBuilder, String dirname, Directory dir) { + ByteString dirnameBytes = ByteString.copyFromUtf8(dirname); + Digest digest = DIGEST_UTIL.compute(dirnameBytes); + String hash = digest.getHash(); + treeBuilder.putDirectories(hash, dir); + return digest; + } + + FileNode makeFileNode(String filename, String content, NodeProperties nodeProperties) { + return FileNode.newBuilder() + .setName(filename) + .setDigest(DIGEST_UTIL.compute(ByteString.copyFromUtf8(content))) + .setIsExecutable(false) + .setNodeProperties(nodeProperties) + .build(); + } + + DirectoryNode makeDirNode(String dirname, Digest dirDigest) { + // Pretty sure we don't need the actual hash for our testing purposes + return DirectoryNode.newBuilder().setName(dirname).setDigest(dirDigest).build(); + } + + NodeProperties makeNodeProperties(ImmutableMap props) { + return NodeProperties.newBuilder() + .addAllProperties( + props.entrySet().stream() + .map( + kv -> + NodeProperty.newBuilder() + .setName(kv.getKey()) + .setValue(kv.getValue()) + .build()) + .collect(Collectors.toList())) + .build(); + } + + Input makeInput(Path fileDir, FileNode file) { + Path fileNodePath = fileDir.resolve(file.getName()); + return Input.newBuilder() + .setPath(fileNodePath.toString()) + .setDigest(file.getDigest().getHashBytes()) + .build(); + } +} diff --git a/src/test/java/build/buildfarm/worker/util/WorkerTestUtils.java b/src/test/java/build/buildfarm/worker/util/WorkerTestUtils.java new file mode 100644 index 0000000000..dbaeca5c9f --- /dev/null +++ b/src/test/java/build/buildfarm/worker/util/WorkerTestUtils.java @@ -0,0 +1,226 @@ +// Copyright 2023 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package build.buildfarm.worker.util; + +import static build.buildfarm.worker.util.InputsIndexer.BAZEL_TOOL_INPUT_MARKER; +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + +import build.bazel.remote.execution.v2.Command; +import build.bazel.remote.execution.v2.Digest; +import build.bazel.remote.execution.v2.Directory; +import build.bazel.remote.execution.v2.DirectoryNode; +import build.bazel.remote.execution.v2.FileNode; +import build.bazel.remote.execution.v2.NodeProperties; +import build.bazel.remote.execution.v2.NodeProperty; +import build.buildfarm.common.DigestUtil; +import build.buildfarm.v1test.Tree; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.devtools.build.lib.worker.WorkerProtocol.Input; +import com.google.protobuf.ByteString; +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.FileVisitor; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class WorkerTestUtils { + public static final DigestUtil DIGEST_UTIL = new DigestUtil(DigestUtil.HashFunction.SHA256); + + public static FileNode makeFileNode( + String filename, String content, NodeProperties nodeProperties) { + return FileNode.newBuilder() + .setName(filename) + .setDigest(DIGEST_UTIL.compute(ByteString.copyFromUtf8(content))) + .setIsExecutable(false) + .setNodeProperties(nodeProperties) + .build(); + } + + public static DirectoryNode makeDirNode(String dirname, Digest dirDigest) { + // Pretty sure we don't need the actual hash for our testing purposes + return DirectoryNode.newBuilder().setName(dirname).setDigest(dirDigest).build(); + } + + public static Digest addDirToTree(Tree.Builder treeBuilder, String dirname, Directory dir) { + ByteString dirnameBytes = ByteString.copyFromUtf8(dirname); + Digest digest = DIGEST_UTIL.compute(dirnameBytes); + String hash = digest.getHash(); + treeBuilder.putDirectories(hash, dir); + return digest; + } + + public static NodeProperties makeNodeProperties(ImmutableMap props) { + return NodeProperties.newBuilder() + .addAllProperties( + props.entrySet().stream() + .map( + kv -> + NodeProperty.newBuilder() + .setName(kv.getKey()) + .setValue(kv.getValue()) + .build()) + .collect(Collectors.toList())) + .build(); + } + + public static Input makeInput(Path fileDir, FileNode file) { + Path fileNodePath = fileDir.resolve(file.getName()); + return Input.newBuilder() + .setPath(fileNodePath.toString()) + .setDigest(file.getDigest().getHashBytes()) + .build(); + } + + public static Command makeCommand() { + ImmutableList outputFiles = ImmutableList.of("output_file", "out_subdir/out_subfile"); + ImmutableList outputDirs = ImmutableList.of("out_subdir"); + ImmutableList outputPaths = + ImmutableList.builder().addAll(outputFiles).addAll(outputDirs).build(); + + return Command.newBuilder() + .addAllOutputFiles(outputFiles) + .addAllOutputDirectories(outputDirs) + .addAllOutputPaths(outputPaths) + .build(); + } + + public static class TreeFile { + public final String path; + public final boolean isTool; + + // null means directory + public final String content; + + public TreeFile(String path) { + this(path, "", false); + } + + public TreeFile(String path, String content) { + this(path, content, false); + } + + public TreeFile(String path, String content, boolean isTool) { + this.path = path; + this.isTool = isTool; + this.content = content; + } + + public boolean isDir() { + return this.content == null; + } + + public String name() { + return Paths.get(this.path).getFileName().toString(); + } + } + + public static Tree makeTree(String rootDirPath, List files) { + Tree.Builder treeBuilder = Tree.newBuilder(); + if (files.isEmpty()) { + return treeBuilder.build(); + } + Directory.Builder rootDirBuilder = Directory.newBuilder(); + + Map dirBuilders = new HashMap<>(); + + for (TreeFile file : files) { + if (file.isDir()) { + dirBuilders.computeIfAbsent(file.path, (filePath) -> Directory.newBuilder()); + } else { + NodeProperties props = NodeProperties.getDefaultInstance(); + if (file.isTool) { + props = makeNodeProperties(ImmutableMap.of(BAZEL_TOOL_INPUT_MARKER, "")); + } + FileNode fileNode = makeFileNode(file.name(), file.content, props); + Path parentDirPath = Paths.get(file.path).getParent(); + if (parentDirPath != null) { + String parentDirPathStr = parentDirPath.normalize().toString(); + Directory.Builder parentDirBuilder = + dirBuilders.computeIfAbsent(parentDirPathStr, (filePath) -> Directory.newBuilder()); + parentDirBuilder.addFiles(fileNode); + } else { + rootDirBuilder.addFiles(fileNode); + } + } + } + + for (Map.Entry entry : dirBuilders.entrySet()) { + String subDirName = entry.getKey(); + Directory subDir = entry.getValue().build(); + Digest subDirDigest = addDirToTree(treeBuilder, subDirName, subDir); + rootDirBuilder.addDirectories(makeDirNode(subDirName, subDirDigest)); + } + + Digest rootDirDigest = addDirToTree(treeBuilder, rootDirPath, rootDirBuilder.build()); + treeBuilder.setRootDigest(rootDirDigest); + + return treeBuilder.build(); + } + + public static List listFilesRec(Path root) throws IOException { + List filesFound = new ArrayList<>(); + + Files.walkFileTree( + root, + new FileVisitor() { + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) + throws IOException { + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) + throws IOException { + filesFound.add(file); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { + throw new IOException("visitFileFailed"); + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + filesFound.add(dir); + return FileVisitResult.CONTINUE; + } + }); + + return filesFound; + } + + // Check all expected files exist and that only they exist + public static void assertFilesExistExactly(Path root, List expectedFiles) + throws IOException { + List listedPaths = listFilesRec(root); + for (Path filePath : listedPaths) { + assertWithMessage("Path not match prefix of any expected file: " + filePath) + .that(expectedFiles.stream().anyMatch(p -> p.startsWith(p))) + .isTrue(); + } + assertThat(listedPaths).containsAtLeastElementsIn(expectedFiles); + } +} From a56b1616681462b2237c6cc8581edad8576c3de6 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Wed, 22 Nov 2023 00:38:36 -0500 Subject: [PATCH 157/311] Locate Output Paths relative to WorkingDirectory (#1553) * Locate Output Paths relative to WorkingDirectory Required as a corollary to OutputDirectory changes to consider outputs as relative to working directory. * Windows builds emit relativize paths with native separators --- .../build/buildfarm/common/CommandUtils.java | 8 ++--- .../buildfarm/worker/ReportResultStage.java | 2 +- .../worker/shard/ShardWorkerContext.java | 35 +++++++++++++++---- .../worker/shard/ShardWorkerContextTest.java | 28 +++++++++++++++ 4 files changed, 61 insertions(+), 12 deletions(-) diff --git a/src/main/java/build/buildfarm/common/CommandUtils.java b/src/main/java/build/buildfarm/common/CommandUtils.java index c6eeb150d2..1604743629 100644 --- a/src/main/java/build/buildfarm/common/CommandUtils.java +++ b/src/main/java/build/buildfarm/common/CommandUtils.java @@ -46,7 +46,7 @@ public static boolean isTest(Command command) { * @return The list of output paths. * @note Suggested return identifier: output_paths. */ - public static List getResolvedOutputPaths(Command command, Path actionRoot) { + public static List getResolvedOutputPaths(Command command, Path workingDirectory) { // REAPI clients previously needed to specify whether the output path was a directory or file. // This turned out to be too restrictive-- some build tools don't know what an action produces // until it is done. @@ -65,7 +65,7 @@ public static List getResolvedOutputPaths(Command command, Path actionRoot // `output_directories` will be ignored!" if (command.getOutputPathsCount() != 0) { for (String outputPath : command.getOutputPathsList()) { - resolvedPaths.add(actionRoot.resolve(outputPath)); + resolvedPaths.add(workingDirectory.resolve(outputPath)); } return resolvedPaths; } @@ -73,10 +73,10 @@ public static List getResolvedOutputPaths(Command command, Path actionRoot // Assuming `output_paths` was not used, // fetch deprecated `output_files` and `output_directories` for backwards compatibility. for (String outputPath : command.getOutputFilesList()) { - resolvedPaths.add(actionRoot.resolve(outputPath)); + resolvedPaths.add(workingDirectory.resolve(outputPath)); } for (String outputPath : command.getOutputDirectoriesList()) { - resolvedPaths.add(actionRoot.resolve(outputPath)); + resolvedPaths.add(workingDirectory.resolve(outputPath)); } return resolvedPaths; diff --git a/src/main/java/build/buildfarm/worker/ReportResultStage.java b/src/main/java/build/buildfarm/worker/ReportResultStage.java index d7bf8eeba2..f5709eec28 100644 --- a/src/main/java/build/buildfarm/worker/ReportResultStage.java +++ b/src/main/java/build/buildfarm/worker/ReportResultStage.java @@ -98,7 +98,7 @@ private OperationContext reportPolled(OperationContext operationContext) workerContext.uploadOutputs( operationContext.queueEntry.getExecuteEntry().getActionDigest(), resultBuilder, - operationContext.execDir, + operationContext.execDir.resolve(operationContext.command.getWorkingDirectory()), operationContext.command); } catch (StatusException | StatusRuntimeException e) { ExecuteResponse executeResponse = operationContext.executeResponse.build(); diff --git a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java index ac020f5046..37e46a5892 100644 --- a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java +++ b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java @@ -82,6 +82,7 @@ import io.grpc.Status; import io.grpc.StatusException; import io.prometheus.client.Counter; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.file.FileVisitResult; @@ -496,14 +497,24 @@ private void updateActionResultStdOutputs(ActionResult.Builder resultBuilder) } } + private static String toREOutputPath(String nativePath) { + // RE API OutputFile/Directory path + // The path separator is a forward slash `/`. + if (File.separatorChar != '/') { + return nativePath.replace(File.separatorChar, '/'); + } + return nativePath; + } + private void uploadOutputFile( ActionResult.Builder resultBuilder, Path outputPath, - Path actionRoot, + Path workingDirectory, String entrySizeViolationType, PreconditionFailure.Builder preconditionFailure) throws IOException, InterruptedException { - String outputFile = actionRoot.relativize(outputPath).toString(); + String outputFile = toREOutputPath(workingDirectory.relativize(outputPath).toString()); + if (!Files.exists(outputPath)) { log.log(Level.FINER, "ReportResultStage: " + outputFile + " does not exist..."); return; @@ -599,11 +610,12 @@ Directory toDirectory() { private void uploadOutputDirectory( ActionResult.Builder resultBuilder, Path outputDirPath, - Path actionRoot, + Path workingDirectory, String entrySizeViolationType, PreconditionFailure.Builder preconditionFailure) throws IOException, InterruptedException { - String outputDir = actionRoot.relativize(outputDirPath).toString(); + String outputDir = toREOutputPath(workingDirectory.relativize(outputDirPath).toString()); + if (!Files.exists(outputDirPath)) { log.log(Level.FINER, "ReportResultStage: " + outputDir + " does not exist..."); return; @@ -733,14 +745,23 @@ public void uploadOutputs( PreconditionFailure.Builder preconditionFailure = PreconditionFailure.newBuilder(); - List outputPaths = CommandUtils.getResolvedOutputPaths(command, actionRoot); + Path workingDirectory = actionRoot.resolve(command.getWorkingDirectory()); + List outputPaths = CommandUtils.getResolvedOutputPaths(command, workingDirectory); for (Path outputPath : outputPaths) { if (Files.isDirectory(outputPath)) { uploadOutputDirectory( - resultBuilder, outputPath, actionRoot, entrySizeViolationType, preconditionFailure); + resultBuilder, + outputPath, + workingDirectory, + entrySizeViolationType, + preconditionFailure); } else { uploadOutputFile( - resultBuilder, outputPath, actionRoot, entrySizeViolationType, preconditionFailure); + resultBuilder, + outputPath, + workingDirectory, + entrySizeViolationType, + preconditionFailure); } } checkPreconditionFailure(actionDigest, preconditionFailure.build()); diff --git a/src/test/java/build/buildfarm/worker/shard/ShardWorkerContextTest.java b/src/test/java/build/buildfarm/worker/shard/ShardWorkerContextTest.java index efddbdb866..cf93a1cd4f 100644 --- a/src/test/java/build/buildfarm/worker/shard/ShardWorkerContextTest.java +++ b/src/test/java/build/buildfarm/worker/shard/ShardWorkerContextTest.java @@ -15,6 +15,7 @@ package build.buildfarm.worker.shard; import static build.buildfarm.common.config.Server.INSTANCE_TYPE.SHARD; +import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -22,9 +23,14 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import build.bazel.remote.execution.v2.ActionResult; +import build.bazel.remote.execution.v2.Command; +import build.bazel.remote.execution.v2.Digest; +import build.bazel.remote.execution.v2.OutputFile; import build.bazel.remote.execution.v2.Platform; import build.bazel.remote.execution.v2.Platform.Property; import build.buildfarm.backplane.Backplane; +import build.buildfarm.cas.ContentAddressableStorage; import build.buildfarm.common.DigestUtil; import build.buildfarm.common.DigestUtil.HashFunction; import build.buildfarm.common.InputStreamFactory; @@ -37,7 +43,11 @@ import build.buildfarm.worker.WorkerContext; import build.buildfarm.worker.resources.LocalResourceSet; import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import com.google.common.jimfs.Jimfs; import com.google.protobuf.Duration; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import org.junit.Before; @@ -165,4 +175,22 @@ public void dequeueMatchSettingsPlatformAcceptsValidQueueEntry() throws Exceptio context.match(listener); verify(listener, times(1)).onEntry(queueEntry); } + + @Test + public void uploadOutputsWorkingDirectoryRelative() throws Exception { + WorkerContext context = createTestContext(); + Command command = + Command.newBuilder().setWorkingDirectory("foo/bar").addOutputFiles("baz/quux").build(); + ContentAddressableStorage storage = mock(ContentAddressableStorage.class); + when(execFileSystem.getStorage()).thenReturn(storage); + Path actionRoot = Iterables.getFirst(Jimfs.newFileSystem().getRootDirectories(), null); + Files.createDirectories(actionRoot.resolve("foo/bar/baz")); + Files.createFile(actionRoot.resolve("foo/bar/baz/quux")); + ActionResult.Builder resultBuilder = ActionResult.newBuilder(); + context.uploadOutputs(Digest.getDefaultInstance(), resultBuilder, actionRoot, command); + + ActionResult result = resultBuilder.build(); + OutputFile outputFile = Iterables.getOnlyElement(result.getOutputFilesList()); + assertThat(outputFile.getPath()).isEqualTo("baz/quux"); + } } From 53e1fbae9362fed3de96a3a5c64dc77daacaa655 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Wed, 22 Nov 2023 09:48:11 -0500 Subject: [PATCH 158/311] Remove incorrect external resolve of WD on upload (#1554) Previous patch included a change in actionRoot parameter, expecting it to prefer the working directory rooted path to discover outputs. Might want to reapply this later, but for now leave the resolution in uploadOutputs. --- src/main/java/build/buildfarm/worker/ReportResultStage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/build/buildfarm/worker/ReportResultStage.java b/src/main/java/build/buildfarm/worker/ReportResultStage.java index f5709eec28..d7bf8eeba2 100644 --- a/src/main/java/build/buildfarm/worker/ReportResultStage.java +++ b/src/main/java/build/buildfarm/worker/ReportResultStage.java @@ -98,7 +98,7 @@ private OperationContext reportPolled(OperationContext operationContext) workerContext.uploadOutputs( operationContext.queueEntry.getExecuteEntry().getActionDigest(), resultBuilder, - operationContext.execDir.resolve(operationContext.command.getWorkingDirectory()), + operationContext.execDir, operationContext.command); } catch (StatusException | StatusRuntimeException e) { ExecuteResponse executeResponse = operationContext.executeResponse.build(); From dd5c87bdc8b5b18bd039e21cd87b8a40aa289d49 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Wed, 29 Nov 2023 23:53:47 -0500 Subject: [PATCH 159/311] Instance cleanups (#1555) * Prevent multiple fetches of QueuedOperation Propagate the Tree in OperationContext for use during the persistent workers clause in Executor * Correct WSO and StubWriteOutputStream completion onCompleted should always be called on open requests when StubWriteOutputStreams are closed, even when completed early by the server. onCompleted must be delivered to responseObserver when onCompleted is invoked, lest a no-request write stream be left hanging to DEADLINE_EXCEEDED. * Explicit reset on WriteOffset 0 and blob write Avoid unnecessary queryWriteStatus requests when a WriteRequest appears with write offset 0 in WSO, and reset the stream initially for internal ServerInstance blob uploads. --- .../common/grpc/StubWriteOutputStream.java | 28 +++++++++---------- .../common/services/WriteStreamObserver.java | 26 +++++++++++++---- .../instance/shard/ServerInstance.java | 1 + .../java/build/buildfarm/worker/Executor.java | 2 +- .../build/buildfarm/worker/InputFetcher.java | 6 ++-- .../buildfarm/worker/OperationContext.java | 18 ++++++++++-- .../services/ByteStreamServiceTest.java | 7 +++-- 7 files changed, 61 insertions(+), 27 deletions(-) diff --git a/src/main/java/build/buildfarm/common/grpc/StubWriteOutputStream.java b/src/main/java/build/buildfarm/common/grpc/StubWriteOutputStream.java index 4e500398b2..855b650ff9 100644 --- a/src/main/java/build/buildfarm/common/grpc/StubWriteOutputStream.java +++ b/src/main/java/build/buildfarm/common/grpc/StubWriteOutputStream.java @@ -131,21 +131,25 @@ public StubWriteOutputStream( @Override public void close() throws IOException { + StreamObserver finishedWriteObserver; + boolean cancelled = false; if (!checkComplete()) { boolean finishWrite = expectedSize == UNLIMITED_EXPECTED_SIZE; if (finishWrite || offset != 0) { initiateWrite(); flushSome(finishWrite); } - synchronized (this) { - if (writeObserver != null) { - if (finishWrite || getCommittedSize() + offset == expectedSize) { - writeObserver.onCompleted(); - } else { - writeObserver.onError(Status.CANCELLED.asException()); - } - writeObserver = null; - } + cancelled = !finishWrite && getCommittedSize() + offset != expectedSize; + } + synchronized (this) { + finishedWriteObserver = writeObserver; + writeObserver = null; + } + if (finishedWriteObserver != null) { + if (cancelled) { + finishedWriteObserver.onError(Status.CANCELLED.asException()); + } else { + finishedWriteObserver.onCompleted(); } } } @@ -334,11 +338,7 @@ public FeedbackOutputStream getOutput( this.deadlineAfter = deadlineAfter; this.deadlineAfterUnits = deadlineAfterUnits; this.onReadyHandler = onReadyHandler; - synchronized (this) { - if (writeObserver == null) { - initiateWrite(); - } - } + initiateWrite(); return this; } diff --git a/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java b/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java index dd52f7769e..41442da5fb 100644 --- a/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java +++ b/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java @@ -205,7 +205,6 @@ void commitActive(long committedSize) { log.log( Level.FINEST, format("delivering committed_size for %s of %d", name, committedSize)); responseObserver.onNext(response); - responseObserver.onCompleted(); } catch (Exception e) { log.log(Level.SEVERE, format("error delivering committed_size to %s", name), e); } @@ -326,6 +325,9 @@ private void handleWrite(String resourceName, long offset, ByteString data, bool throws EntryLimitException { long committedSize; try { + if (offset == 0) { + write.reset(); + } committedSize = getCommittedSizeForWrite(); } catch (IOException e) { errorResponse(e); @@ -352,10 +354,6 @@ private void handleWrite(String resourceName, long offset, ByteString data, bool resourceName, name)) .asException()); } else { - if (offset == 0 && offset != committedSize) { - write.reset(); - committedSize = 0; - } if (earliestOffset < 0 || offset < earliestOffset) { earliestOffset = offset; } @@ -479,5 +477,23 @@ public void onError(Throwable t) { @Override public void onCompleted() { log.log(Level.FINER, format("write completed for %s", name)); + if (write == null) { + responseObserver.onCompleted(); + } else { + Futures.addCallback( + write.getFuture(), + new FutureCallback() { + @Override + public void onSuccess(Long committedSize) { + responseObserver.onCompleted(); + } + + @Override + public void onFailure(Throwable t) { + // ignore + } + }, + directExecutor()); + } } } diff --git a/src/main/java/build/buildfarm/instance/shard/ServerInstance.java b/src/main/java/build/buildfarm/instance/shard/ServerInstance.java index b1cbed0e07..b4f118f1ad 100644 --- a/src/main/java/build/buildfarm/instance/shard/ServerInstance.java +++ b/src/main/java/build/buildfarm/instance/shard/ServerInstance.java @@ -1655,6 +1655,7 @@ public void onFailure(Throwable t) { } }, directExecutor()); + write.reset(); // prevents a queryWriteStatus at index 0 try (OutputStream out = write.getOutput(timeout.getSeconds(), SECONDS, () -> {})) { content.writeTo(out); } catch (IOException e) { diff --git a/src/main/java/build/buildfarm/worker/Executor.java b/src/main/java/build/buildfarm/worker/Executor.java index ee0de0b1ba..2891488f52 100644 --- a/src/main/java/build/buildfarm/worker/Executor.java +++ b/src/main/java/build/buildfarm/worker/Executor.java @@ -446,7 +446,7 @@ private Code executeCommand( "usePersistentWorker; got persistentWorkerCommand of : " + limits.persistentWorkerCommand); - Tree execTree = workerContext.getQueuedOperation(operationContext.queueEntry).getTree(); + Tree execTree = operationContext.tree; WorkFilesContext filesContext = WorkFilesContext.fromContext(execDir, execTree, operationContext.command); diff --git a/src/main/java/build/buildfarm/worker/InputFetcher.java b/src/main/java/build/buildfarm/worker/InputFetcher.java index 7be7a29e96..23a0d6af2f 100644 --- a/src/main/java/build/buildfarm/worker/InputFetcher.java +++ b/src/main/java/build/buildfarm/worker/InputFetcher.java @@ -31,6 +31,7 @@ import build.buildfarm.common.ProxyDirectoriesIndex; import build.buildfarm.v1test.ExecuteEntry; import build.buildfarm.v1test.QueuedOperation; +import build.buildfarm.v1test.Tree; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Stopwatch; import com.google.common.collect.Iterables; @@ -232,7 +233,7 @@ long fetchPolled(Stopwatch stopwatch) throws InterruptedException { boolean completed = false; try { long fetchUSecs = stopwatch.elapsed(MICROSECONDS); - proceedToOutput(queuedOperation.getAction(), command, execDir); + proceedToOutput(queuedOperation.getAction(), command, execDir, queuedOperation.getTree()); completed = true; return stopwatch.elapsed(MICROSECONDS) - fetchUSecs; } finally { @@ -248,7 +249,7 @@ long fetchPolled(Stopwatch stopwatch) throws InterruptedException { } } - private void proceedToOutput(Action action, Command command, Path execDir) + private void proceedToOutput(Action action, Command command, Path execDir, Tree tree) throws InterruptedException { // switch poller to disable deadline operationContext.poller.pause(); @@ -266,6 +267,7 @@ private void proceedToOutput(Action action, Command command, Path execDir) .setExecDir(execDir) .setAction(action) .setCommand(command) + .setTree(tree) .build(); boolean claimed = owner.output().claim(fetchedOperationContext); operationContext.poller.pause(); diff --git a/src/main/java/build/buildfarm/worker/OperationContext.java b/src/main/java/build/buildfarm/worker/OperationContext.java index ef73e1bbf9..7220fc100b 100644 --- a/src/main/java/build/buildfarm/worker/OperationContext.java +++ b/src/main/java/build/buildfarm/worker/OperationContext.java @@ -19,6 +19,7 @@ import build.bazel.remote.execution.v2.ExecuteResponse; import build.buildfarm.common.Poller; import build.buildfarm.v1test.QueueEntry; +import build.buildfarm.v1test.Tree; import com.google.longrunning.Operation; import java.nio.file.Path; @@ -29,6 +30,7 @@ public final class OperationContext { final Path execDir; final Action action; final Command command; + final Tree tree; final QueueEntry queueEntry; private OperationContext( @@ -38,6 +40,7 @@ private OperationContext( Path execDir, Action action, Command command, + Tree tree, QueueEntry queueEntry) { this.executeResponse = executeResponse; this.operation = operation; @@ -45,6 +48,7 @@ private OperationContext( this.execDir = execDir; this.action = action; this.command = command; + this.tree = tree; this.queueEntry = queueEntry; } @@ -55,6 +59,7 @@ public static class Builder { private Path execDir; private Action action; private Command command; + private Tree tree; private QueueEntry queueEntry; private Builder( @@ -64,6 +69,7 @@ private Builder( Path execDir, Action action, Command command, + Tree tree, QueueEntry queueEntry) { this.executeResponse = executeResponse; this.operation = operation; @@ -71,6 +77,7 @@ private Builder( this.execDir = execDir; this.action = action; this.command = command; + this.tree = tree; this.queueEntry = queueEntry; } @@ -99,6 +106,11 @@ public Builder setCommand(Command command) { return this; } + public Builder setTree(Tree tree) { + this.tree = tree; + return this; + } + public Builder setQueueEntry(QueueEntry queueEntry) { this.queueEntry = queueEntry; return this; @@ -106,7 +118,7 @@ public Builder setQueueEntry(QueueEntry queueEntry) { public OperationContext build() { return new OperationContext( - executeResponse, operation, poller, execDir, action, command, queueEntry); + executeResponse, operation, poller, execDir, action, command, tree, queueEntry); } } @@ -118,10 +130,12 @@ public static Builder newBuilder() { /* execDir=*/ null, /* action=*/ null, /* command=*/ null, + /* tree=*/ null, /* queueEntry=*/ null); } public Builder toBuilder() { - return new Builder(executeResponse, operation, poller, execDir, action, command, queueEntry); + return new Builder( + executeResponse, operation, poller, execDir, action, command, tree, queueEntry); } } diff --git a/src/test/java/build/buildfarm/common/services/ByteStreamServiceTest.java b/src/test/java/build/buildfarm/common/services/ByteStreamServiceTest.java index 2e1918b5d5..5b36340ba9 100644 --- a/src/test/java/build/buildfarm/common/services/ByteStreamServiceTest.java +++ b/src/test/java/build/buildfarm/common/services/ByteStreamServiceTest.java @@ -173,6 +173,7 @@ public boolean isReady() { .setResourceName(resourceName) .setData(shortContent) .build()); + verify(write, times(1)).reset(); requestObserver.onNext( WriteRequest.newBuilder().setWriteOffset(0).setData(content).setFinishWrite(true).build()); assertThat(futureResponder.get()) @@ -181,8 +182,8 @@ public boolean isReady() { verify(write, atLeastOnce()).getCommittedSize(); verify(write, atLeastOnce()) .getOutput(any(Long.class), any(TimeUnit.class), any(Runnable.class)); - verify(write, times(1)).reset(); - verify(write, times(1)).getFuture(); + verify(write, times(2)).reset(); + verify(write, times(2)).getFuture(); } @Test @@ -263,7 +264,7 @@ public boolean isReady() { verify(write, atLeastOnce()).getCommittedSize(); verify(write, atLeastOnce()) .getOutput(any(Long.class), any(TimeUnit.class), any(Runnable.class)); - verify(write, times(2)).getFuture(); + verify(write, times(3)).getFuture(); } static class CountingReadObserver implements StreamObserver { From d24939316f96078016223f1dd1725ced721bcb34 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Thu, 30 Nov 2023 13:39:16 -0500 Subject: [PATCH 160/311] BuildfarmExecutors moved to its own target (#1557) --- src/main/java/build/buildfarm/cas/BUILD | 1 + src/main/java/build/buildfarm/common/BUILD | 54 ++++++++++++++++--- .../java/build/buildfarm/instance/shard/BUILD | 1 + .../java/build/buildfarm/worker/shard/BUILD | 1 + 4 files changed, 51 insertions(+), 6 deletions(-) diff --git a/src/main/java/build/buildfarm/cas/BUILD b/src/main/java/build/buildfarm/cas/BUILD index 43e2daccde..2af2edc8df 100644 --- a/src/main/java/build/buildfarm/cas/BUILD +++ b/src/main/java/build/buildfarm/cas/BUILD @@ -8,6 +8,7 @@ java_library( ], deps = [ "//src/main/java/build/buildfarm/common", + "//src/main/java/build/buildfarm/common:BuildfarmExecutors", "//src/main/java/build/buildfarm/common/config", "//src/main/java/build/buildfarm/common/grpc", "//src/main/java/build/buildfarm/common/resources", diff --git a/src/main/java/build/buildfarm/common/BUILD b/src/main/java/build/buildfarm/common/BUILD index 76a40cfa9f..a214140840 100644 --- a/src/main/java/build/buildfarm/common/BUILD +++ b/src/main/java/build/buildfarm/common/BUILD @@ -1,11 +1,14 @@ java_library( name = "common", - srcs = glob([ - "*.java", - "function/*.java", - "io/*.java", - "net/*.java", - ]), + srcs = glob( + [ + "*.java", + "function/*.java", + "io/*.java", + "net/*.java", + ], + exclude = ["BuildfarmExecutors.java"], + ), plugins = [":lombok"], visibility = ["//visibility:public"], deps = [ @@ -38,6 +41,45 @@ java_library( ], ) +java_library( + name = "BuildfarmExecutors", + srcs = [ + "BuildfarmExecutors.java", + ], + plugins = [":lombok"], + visibility = ["//visibility:public"], + deps = [ + "//src/main/java/build/buildfarm/common", + "//src/main/java/build/buildfarm/common/config", + "//src/main/java/build/buildfarm/common/resources", + "//src/main/java/build/buildfarm/common/resources:resource_java_proto", + "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", + "//third_party/jedis", + "@googleapis//:google_longrunning_operations_java_proto", + "@googleapis//:google_rpc_code_java_proto", + "@googleapis//:google_rpc_error_details_java_proto", + "@maven//:com_github_jnr_jnr_constants", + "@maven//:com_github_jnr_jnr_ffi", + "@maven//:com_github_jnr_jnr_posix", + "@maven//:com_github_luben_zstd_jni", + "@maven//:com_github_oshi_oshi_core", + "@maven//:com_google_code_findbugs_jsr305", + "@maven//:com_google_guava_failureaccess", + "@maven//:com_google_guava_guava", + "@maven//:com_google_protobuf_protobuf_java", + "@maven//:com_google_protobuf_protobuf_java_util", + "@maven//:commons_io_commons_io", + "@maven//:io_grpc_grpc_api", + "@maven//:io_grpc_grpc_context", + "@maven//:io_grpc_grpc_protobuf", + "@maven//:io_prometheus_simpleclient", + "@maven//:org_apache_commons_commons_compress", + "@maven//:org_projectlombok_lombok", + "@maven//:org_threeten_threetenbp", + "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", + ], +) + java_plugin( name = "lombok", generates_api = True, diff --git a/src/main/java/build/buildfarm/instance/shard/BUILD b/src/main/java/build/buildfarm/instance/shard/BUILD index 38e6992aae..9512f7fd70 100644 --- a/src/main/java/build/buildfarm/instance/shard/BUILD +++ b/src/main/java/build/buildfarm/instance/shard/BUILD @@ -8,6 +8,7 @@ java_library( "//src/main/java/build/buildfarm/backplane", "//src/main/java/build/buildfarm/cas", "//src/main/java/build/buildfarm/common", + "//src/main/java/build/buildfarm/common:BuildfarmExecutors", "//src/main/java/build/buildfarm/common/config", "//src/main/java/build/buildfarm/common/grpc", "//src/main/java/build/buildfarm/common/redis", diff --git a/src/main/java/build/buildfarm/worker/shard/BUILD b/src/main/java/build/buildfarm/worker/shard/BUILD index b62e4369de..4fa52c985d 100644 --- a/src/main/java/build/buildfarm/worker/shard/BUILD +++ b/src/main/java/build/buildfarm/worker/shard/BUILD @@ -7,6 +7,7 @@ java_library( "//src/main/java/build/buildfarm/backplane", "//src/main/java/build/buildfarm/cas", "//src/main/java/build/buildfarm/common", + "//src/main/java/build/buildfarm/common:BuildfarmExecutors", "//src/main/java/build/buildfarm/common/config", "//src/main/java/build/buildfarm/common/grpc", "//src/main/java/build/buildfarm/common/services", From a7ef69354e783f1571b7995863c5df1f665a2af7 Mon Sep 17 00:00:00 2001 From: amishra-u <119983081+amishra-u@users.noreply.github.com> Date: Fri, 1 Dec 2023 13:00:08 -0800 Subject: [PATCH 161/311] Update Jedis connection error handling for addWorker (#1552) --- .../buildfarm/common/redis/RedisClient.java | 3 +++ .../common/redis/RedisClientTest.java | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/main/java/build/buildfarm/common/redis/RedisClient.java b/src/main/java/build/buildfarm/common/redis/RedisClient.java index bd1e4578a1..6db7849df3 100644 --- a/src/main/java/build/buildfarm/common/redis/RedisClient.java +++ b/src/main/java/build/buildfarm/common/redis/RedisClient.java @@ -24,6 +24,7 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.exceptions.JedisClusterMaxAttemptsException; import redis.clients.jedis.exceptions.JedisConnectionException; import redis.clients.jedis.exceptions.JedisDataException; import redis.clients.jedis.exceptions.JedisException; @@ -153,6 +154,8 @@ public T call(JedisContext withJedis) throws IOException { } } throw new IOException(status.withCause(cause == null ? e : cause).asRuntimeException()); + } catch (JedisClusterMaxAttemptsException e) { + throw new IOException(Status.UNAVAILABLE.withCause(e.getCause()).asRuntimeException()); } } } diff --git a/src/test/java/build/buildfarm/common/redis/RedisClientTest.java b/src/test/java/build/buildfarm/common/redis/RedisClientTest.java index dd124227c9..f6855af23c 100644 --- a/src/test/java/build/buildfarm/common/redis/RedisClientTest.java +++ b/src/test/java/build/buildfarm/common/redis/RedisClientTest.java @@ -26,6 +26,7 @@ import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.exceptions.JedisClusterMaxAttemptsException; import redis.clients.jedis.exceptions.JedisConnectionException; @RunWith(JUnit4.class) @@ -75,4 +76,22 @@ public void runExceptionSocketTimeoutExceptionIsDeadlineExceeded() } assertThat(status.getCode()).isEqualTo(Code.DEADLINE_EXCEEDED); } + + @Test + public void runJedisClusterMaxAttemptsExceptionIsUnavailable() { + RedisClient client = new RedisClient(mock(JedisCluster.class)); + Status status = Status.UNKNOWN; + try { + JedisClusterMaxAttemptsException jcoe = + new JedisClusterMaxAttemptsException("No more cluster attempts left."); + jcoe.addSuppressed(new JedisConnectionException(new SocketException("Connection reset"))); + client.run( + jedis -> { + throw jcoe; + }); + } catch (IOException e) { + status = Status.fromThrowable(e); + } + assertThat(status.getCode()).isEqualTo(Code.UNAVAILABLE); + } } From a06b095eeabda77ac67c1d21991fd9571bf9e474 Mon Sep 17 00:00:00 2001 From: Andrew Rothstein Date: Mon, 4 Dec 2023 23:48:05 -0500 Subject: [PATCH 162/311] add github action to package and publish the helm chart as a released artifact (#1556) * bundle with helm publish release with gh cli * add a basic doc for the helm chart --- .../buildfarm-helm-chart-publish.yml | 25 +++++++++++++++++++ README.md | 12 +++++++++ 2 files changed, 37 insertions(+) create mode 100644 .github/workflows/buildfarm-helm-chart-publish.yml diff --git a/.github/workflows/buildfarm-helm-chart-publish.yml b/.github/workflows/buildfarm-helm-chart-publish.yml new file mode 100644 index 0000000000..0207d1593b --- /dev/null +++ b/.github/workflows/buildfarm-helm-chart-publish.yml @@ -0,0 +1,25 @@ +--- +name: Package and Publish Helm Chart + +on: + push: + tags: + - '*' + +env: + GH_TOKEN: ${{ github.token }} + +jobs: + build: + if: github.repository == 'bazelbuild/bazel-buildfarm' + name: Package and Release BuildFarm Helm Chart + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: helm package + run: |- + set -ex + helm dep up kubernetes/helm-charts/buildfarm + helm package kubernetes/helm-charts/buildfarm + gh release create "${{ github.ref_name }}" *.tgz diff --git a/README.md b/README.md index cd9caf8ee3..ab861d609e 100644 --- a/README.md +++ b/README.md @@ -132,3 +132,15 @@ load("@build_buildfarm//:images.bzl", "buildfarm_images") buildfarm_images() ``` + +### Helm Chart + +To install with helm: + +```bash +helm install \ + -n bazel-buildfarm \ + --create-namespace \ + bazel-buildfarm \ + "https://github.com/bazelbuild/bazel-buildfarm/releases/download/${BUILDFARM_VERSION:-2.7.1}/buildfarm-${CHART_VERSION:-0.1.0}.tgz" +``` From 68182ec9757140b7e309219612da427e56e2a72a Mon Sep 17 00:00:00 2001 From: George Gensure Date: Wed, 6 Dec 2023 15:48:12 -0500 Subject: [PATCH 163/311] Assert correct context called for WSO responses (#1561) --- .../common/services/WriteStreamObserver.java | 2 +- .../services/WriteStreamObserverTest.java | 65 +++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java b/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java index 41442da5fb..99581c7498 100644 --- a/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java +++ b/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java @@ -493,7 +493,7 @@ public void onFailure(Throwable t) { // ignore } }, - directExecutor()); + withCancellation.fixedContextExecutor(directExecutor())); } } } diff --git a/src/test/java/build/buildfarm/common/services/WriteStreamObserverTest.java b/src/test/java/build/buildfarm/common/services/WriteStreamObserverTest.java index b6d144a66b..b41ad18645 100644 --- a/src/test/java/build/buildfarm/common/services/WriteStreamObserverTest.java +++ b/src/test/java/build/buildfarm/common/services/WriteStreamObserverTest.java @@ -1,11 +1,14 @@ package build.buildfarm.common.services; import static build.buildfarm.common.resources.ResourceParser.uploadResourceName; +import static com.google.common.truth.Truth.assertThat; import static java.util.concurrent.TimeUnit.SECONDS; import static org.mockito.Mockito.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; @@ -138,4 +141,66 @@ public void noErrorWhenContextCancelled() throws Exception { any(RequestMetadata.class)); verifyZeroInteractions(responseObserver); } + + @Test + public void observerCalledInRequestContext() throws Exception { + Context.Key REQ_KEY = Context.key("requester"); + Instance instance = mock(Instance.class); + StreamObserver responseObserver = + spy( + new StreamObserver() { + @Override + public void onNext(WriteResponse response) { + assertThat(REQ_KEY.get()).isEqualTo("true"); + } + + @Override + public void onError(Throwable t) { + assertThat(REQ_KEY.get()).isEqualTo("true"); + } + + @Override + public void onCompleted() { + assertThat(REQ_KEY.get()).isEqualTo("true"); + } + }); + ByteString data = ByteString.copyFromUtf8("contextual data"); + Digest digest = DIGEST_UTIL.compute(data); + UUID uuid = UUID.randomUUID(); + UploadBlobRequest uploadBlobRequest = + UploadBlobRequest.newBuilder() + .setBlob(BlobInformation.newBuilder().setDigest(digest)) + .setUuid(uuid.toString()) + .build(); + SettableFuture future = SettableFuture.create(); + Write write = mock(Write.class); + when(write.getFuture()).thenReturn(future); + when(write.isComplete()).thenReturn(Boolean.TRUE); + when(instance.getBlobWrite( + eq(Compressor.Value.IDENTITY), eq(digest), eq(uuid), any(RequestMetadata.class))) + .thenReturn(write); + + Context requester = Context.current().withValue(REQ_KEY, "true"); + assertThat(REQ_KEY.get()).isNull(); + WriteStreamObserver observer = + requester.call( + () -> new WriteStreamObserver(instance, 1, SECONDS, () -> {}, responseObserver)); + requester.run( + () -> + observer.onNext( + WriteRequest.newBuilder() + .setResourceName(uploadResourceName(uploadBlobRequest)) + .setData(data) + .build())); + requester.run(observer::onCompleted); + verify(responseObserver, never()).onCompleted(); + + future.set(digest.getSizeBytes()); + + verify(write, times(1)).isComplete(); + verify(instance, times(1)) + .getBlobWrite( + eq(Compressor.Value.IDENTITY), eq(digest), eq(uuid), any(RequestMetadata.class)); + verify(responseObserver, times(1)).onCompleted(); + } } From e26a000c2be825dde2991eddeb7036e947b131c8 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Tue, 12 Dec 2023 02:12:38 -0500 Subject: [PATCH 164/311] Write onNext requires onCompleted to follow (#1565) For reasons passing understanding, a WriteResponse is not delivered to a client solely from onNext to be received by a client called via bsStub. onCompleted must follow the onNext for a timely delivery of the response, particularly when it occurs before an onCompleted from the client. This does not seem to affect the bazel client, which could indicate a difference in behavior between grpc versions, or simply that it manages to complete its upload completely ignorant of the early return status. More investigation is required. This will fix hanging builds which occur with exec-only workers failing to complete uploads to shard peers. --- .../common/services/WriteStreamObserver.java | 16 +---- .../services/ByteStreamServiceTest.java | 4 +- .../services/WriteStreamObserverTest.java | 65 ------------------- 3 files changed, 3 insertions(+), 82 deletions(-) diff --git a/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java b/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java index 99581c7498..c2518921a0 100644 --- a/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java +++ b/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java @@ -205,6 +205,7 @@ void commitActive(long committedSize) { log.log( Level.FINEST, format("delivering committed_size for %s of %d", name, committedSize)); responseObserver.onNext(response); + responseObserver.onCompleted(); } catch (Exception e) { log.log(Level.SEVERE, format("error delivering committed_size to %s", name), e); } @@ -479,21 +480,6 @@ public void onCompleted() { log.log(Level.FINER, format("write completed for %s", name)); if (write == null) { responseObserver.onCompleted(); - } else { - Futures.addCallback( - write.getFuture(), - new FutureCallback() { - @Override - public void onSuccess(Long committedSize) { - responseObserver.onCompleted(); - } - - @Override - public void onFailure(Throwable t) { - // ignore - } - }, - withCancellation.fixedContextExecutor(directExecutor())); } } } diff --git a/src/test/java/build/buildfarm/common/services/ByteStreamServiceTest.java b/src/test/java/build/buildfarm/common/services/ByteStreamServiceTest.java index 5b36340ba9..85b16dacf5 100644 --- a/src/test/java/build/buildfarm/common/services/ByteStreamServiceTest.java +++ b/src/test/java/build/buildfarm/common/services/ByteStreamServiceTest.java @@ -183,7 +183,7 @@ public boolean isReady() { verify(write, atLeastOnce()) .getOutput(any(Long.class), any(TimeUnit.class), any(Runnable.class)); verify(write, times(2)).reset(); - verify(write, times(2)).getFuture(); + verify(write, times(1)).getFuture(); } @Test @@ -264,7 +264,7 @@ public boolean isReady() { verify(write, atLeastOnce()).getCommittedSize(); verify(write, atLeastOnce()) .getOutput(any(Long.class), any(TimeUnit.class), any(Runnable.class)); - verify(write, times(3)).getFuture(); + verify(write, times(2)).getFuture(); } static class CountingReadObserver implements StreamObserver { diff --git a/src/test/java/build/buildfarm/common/services/WriteStreamObserverTest.java b/src/test/java/build/buildfarm/common/services/WriteStreamObserverTest.java index b41ad18645..b6d144a66b 100644 --- a/src/test/java/build/buildfarm/common/services/WriteStreamObserverTest.java +++ b/src/test/java/build/buildfarm/common/services/WriteStreamObserverTest.java @@ -1,14 +1,11 @@ package build.buildfarm.common.services; import static build.buildfarm.common.resources.ResourceParser.uploadResourceName; -import static com.google.common.truth.Truth.assertThat; import static java.util.concurrent.TimeUnit.SECONDS; import static org.mockito.Mockito.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; @@ -141,66 +138,4 @@ public void noErrorWhenContextCancelled() throws Exception { any(RequestMetadata.class)); verifyZeroInteractions(responseObserver); } - - @Test - public void observerCalledInRequestContext() throws Exception { - Context.Key REQ_KEY = Context.key("requester"); - Instance instance = mock(Instance.class); - StreamObserver responseObserver = - spy( - new StreamObserver() { - @Override - public void onNext(WriteResponse response) { - assertThat(REQ_KEY.get()).isEqualTo("true"); - } - - @Override - public void onError(Throwable t) { - assertThat(REQ_KEY.get()).isEqualTo("true"); - } - - @Override - public void onCompleted() { - assertThat(REQ_KEY.get()).isEqualTo("true"); - } - }); - ByteString data = ByteString.copyFromUtf8("contextual data"); - Digest digest = DIGEST_UTIL.compute(data); - UUID uuid = UUID.randomUUID(); - UploadBlobRequest uploadBlobRequest = - UploadBlobRequest.newBuilder() - .setBlob(BlobInformation.newBuilder().setDigest(digest)) - .setUuid(uuid.toString()) - .build(); - SettableFuture future = SettableFuture.create(); - Write write = mock(Write.class); - when(write.getFuture()).thenReturn(future); - when(write.isComplete()).thenReturn(Boolean.TRUE); - when(instance.getBlobWrite( - eq(Compressor.Value.IDENTITY), eq(digest), eq(uuid), any(RequestMetadata.class))) - .thenReturn(write); - - Context requester = Context.current().withValue(REQ_KEY, "true"); - assertThat(REQ_KEY.get()).isNull(); - WriteStreamObserver observer = - requester.call( - () -> new WriteStreamObserver(instance, 1, SECONDS, () -> {}, responseObserver)); - requester.run( - () -> - observer.onNext( - WriteRequest.newBuilder() - .setResourceName(uploadResourceName(uploadBlobRequest)) - .setData(data) - .build())); - requester.run(observer::onCompleted); - verify(responseObserver, never()).onCompleted(); - - future.set(digest.getSizeBytes()); - - verify(write, times(1)).isComplete(); - verify(instance, times(1)) - .getBlobWrite( - eq(Compressor.Value.IDENTITY), eq(digest), eq(uuid), any(RequestMetadata.class)); - verify(responseObserver, times(1)).onCompleted(); - } } From 859abb6d7de0b88704b693140a22bbf9329a0e7d Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Tue, 12 Dec 2023 15:41:40 -0800 Subject: [PATCH 165/311] chore: update maven dependencies (#1434) * chore(deps): bump com.amazonaws:aws-java-sdk-* Update to 1.12.544 * chore(deps): bump org.redisson:redisson Update to 3.23.4 * chore(deps): bump org.threeten:threetenbp Update to 1.6.8 * chore(deps): bump org.snakeyaml:snakeyaml Update to 2.2 * chore(deps): bump com.github.docker-java:docker-java * chore(deps): bump com.github.jnr:* Bumping all packages in this groupId to the latest. * chore(deps): bump com.github.serceman:jnr-fuse * chore(deps): bump com.github.oshi:oshi-core * chore(deps): bump com.google.auth:* Oauth libraries to the latest. * chore(deps): bump com.google.code.findbugs:jsr305 * chore(deps): bump com.google.code.gson:gson * chore(deps): bump com.google.j2objc:j2objc-annotations * chore(deps): bump com.google.jimfs:jimfs * chore(deps): bump org.slf4j.slf4j-simple * chore(deps): bump com.jayway.jsonpath:json-path * chore(deps): bump io.netty:* * chore(deps): bump io.prometheus:* * chore(deps): bump junit:junit * chore(deps): bump org.apache.commons:commons-compress * chore(deps): bump org.apache.commons:commons-pool2 * chore(deps): bump org.apache.commons:commons-lang3 * chore(deps): bump commons-io:commons-io * chore(deps): bump me.dinowernli:java-grpc-prometheus * chore(deps): bump org.checkerframework:checker-qual * chore(deps): bump com.google.truth:truth * chore(deps): bump org.openjdk.jmh:* --- defs.bzl | 68 +++++++++---------- .../instance/stub/StubInstanceTest.java | 2 +- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/defs.bzl b/defs.bzl index ea145d1b9f..ad0790593e 100644 --- a/defs.bzl +++ b/defs.bzl @@ -55,63 +55,63 @@ def buildfarm_init(name = "buildfarm"): name: the name of the repository """ maven_install( - artifacts = ["com.amazonaws:aws-java-sdk-%s:1.11.729" % module for module in COM_AWS_MODULES] + + artifacts = ["com.amazonaws:aws-java-sdk-%s:1.12.544" % module for module in COM_AWS_MODULES] + [ "com.fasterxml.jackson.core:jackson-databind:2.15.0", "com.github.ben-manes.caffeine:caffeine:2.9.0", - "com.github.docker-java:docker-java:3.2.11", + "com.github.docker-java:docker-java:3.3.3", "com.github.fppt:jedis-mock:1.0.10", - "com.github.jnr:jffi:1.2.16", - "com.github.jnr:jffi:jar:native:1.2.16", - "com.github.jnr:jnr-constants:0.9.9", - "com.github.jnr:jnr-ffi:2.1.7", - "com.github.jnr:jnr-posix:3.0.53", + "com.github.jnr:jffi:1.3.11", + "com.github.jnr:jffi:jar:native:1.3.11", + "com.github.jnr:jnr-constants:0.10.4", + "com.github.jnr:jnr-ffi:2.2.14", + "com.github.jnr:jnr-posix:3.1.17", "com.github.pcj:google-options:1.0.0", - "com.github.serceman:jnr-fuse:0.5.5", + "com.github.serceman:jnr-fuse:0.5.7", "com.github.luben:zstd-jni:1.5.5-7", - "com.github.oshi:oshi-core:6.4.0", - "com.google.auth:google-auth-library-credentials:0.9.1", - "com.google.auth:google-auth-library-oauth2-http:0.9.1", - "com.google.code.findbugs:jsr305:3.0.1", - "com.google.code.gson:gson:2.9.0", + "com.github.oshi:oshi-core:6.4.5", + "com.google.auth:google-auth-library-credentials:1.19.0", + "com.google.auth:google-auth-library-oauth2-http:1.19.0", + "com.google.code.findbugs:jsr305:3.0.2", + "com.google.code.gson:gson:2.10.1", "com.google.errorprone:error_prone_annotations:2.22.0", "com.google.errorprone:error_prone_core:2.22.0", "com.google.guava:failureaccess:1.0.1", "com.google.guava:guava:32.1.1-jre", - "com.google.j2objc:j2objc-annotations:1.1", - "com.google.jimfs:jimfs:1.1", + "com.google.j2objc:j2objc-annotations:2.8", + "com.google.jimfs:jimfs:1.3.0", "com.google.protobuf:protobuf-java-util:3.19.1", "com.google.protobuf:protobuf-java:3.19.1", - "com.google.truth:truth:0.44", - "org.slf4j:slf4j-simple:1.7.35", + "com.google.truth:truth:1.1.5", + "org.slf4j:slf4j-simple:2.0.9", "com.googlecode.json-simple:json-simple:1.1.1", - "com.jayway.jsonpath:json-path:2.4.0", + "com.jayway.jsonpath:json-path:2.8.0", "org.bouncycastle:bcprov-jdk15on:1.70", "net.jcip:jcip-annotations:1.0", - ] + ["io.netty:netty-%s:4.1.94.Final" % module for module in IO_NETTY_MODULES] + + ] + ["io.netty:netty-%s:4.1.97.Final" % module for module in IO_NETTY_MODULES] + ["io.grpc:grpc-%s:1.56.1" % module for module in IO_GRPC_MODULES] + [ - "io.prometheus:simpleclient:0.10.0", - "io.prometheus:simpleclient_hotspot:0.10.0", - "io.prometheus:simpleclient_httpserver:0.10.0", - "junit:junit:4.13.1", + "io.prometheus:simpleclient:0.15.0", + "io.prometheus:simpleclient_hotspot:0.15.0", + "io.prometheus:simpleclient_httpserver:0.15.0", + "junit:junit:4.13.2", "javax.annotation:javax.annotation-api:1.3.2", "net.javacrumbs.future-converter:future-converter-java8-guava:1.2.0", - "org.apache.commons:commons-compress:1.21", - "org.apache.commons:commons-pool2:2.9.0", - "org.apache.commons:commons-lang3:3.12.0", - "commons-io:commons-io:2.11.0", - "me.dinowernli:java-grpc-prometheus:0.5.0", + "org.apache.commons:commons-compress:1.23.0", + "org.apache.commons:commons-pool2:2.11.1", + "org.apache.commons:commons-lang3:3.13.0", + "commons-io:commons-io:2.13.0", + "me.dinowernli:java-grpc-prometheus:0.6.0", "org.apache.tomcat:annotations-api:6.0.53", - "org.checkerframework:checker-qual:2.5.2", + "org.checkerframework:checker-qual:3.38.0", "org.mockito:mockito-core:2.25.0", - "org.openjdk.jmh:jmh-core:1.23", - "org.openjdk.jmh:jmh-generator-annprocess:1.23", - "org.redisson:redisson:3.13.1", - "org.threeten:threetenbp:1.3.3", + "org.openjdk.jmh:jmh-core:1.37", + "org.openjdk.jmh:jmh-generator-annprocess:1.37", + "org.redisson:redisson:3.23.4", + "org.threeten:threetenbp:1.6.8", "org.xerial:sqlite-jdbc:3.34.0", "org.jetbrains:annotations:16.0.2", - "org.yaml:snakeyaml:2.0", + "org.yaml:snakeyaml:2.2", "org.projectlombok:lombok:1.18.30", ], generate_compat_repositories = True, diff --git a/src/test/java/build/buildfarm/instance/stub/StubInstanceTest.java b/src/test/java/build/buildfarm/instance/stub/StubInstanceTest.java index e3845494b8..526946af1e 100644 --- a/src/test/java/build/buildfarm/instance/stub/StubInstanceTest.java +++ b/src/test/java/build/buildfarm/instance/stub/StubInstanceTest.java @@ -320,7 +320,7 @@ public void batchUpdateBlobs( ImmutableList digests = ImmutableList.of(DIGEST_UTIL.compute(first), DIGEST_UTIL.compute(last)); assertThat(instance.putAllBlobs(blobs, RequestMetadata.getDefaultInstance())) - .containsAllIn(digests); + .containsAtLeastElementsIn(digests); } @Test From 27194c7ab70176e1e4dde779298b25ce8d9cff54 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Tue, 12 Dec 2023 15:51:39 -0800 Subject: [PATCH 166/311] build: support compiling protobuf on macOS (#1563) MacOS needs extra args to convince it to support C++14. --- .bazelrc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.bazelrc b/.bazelrc index c3caf4d8fb..5cc10724d9 100644 --- a/.bazelrc +++ b/.bazelrc @@ -24,3 +24,6 @@ common --incompatible_disallow_empty_glob # TODO: migrate all dependencies from WORKSPACE to MODULE.bazel # https://github.com/bazelbuild/bazel-buildfarm/issues/1479 common --noenable_bzlmod + +# Support protobuf on macOS with Xcode 15.x +common:macos --host_cxxopt=-std=c++14 --cxxopt=-std=c++14 From 1046e979580eff501e6b498bba8ddb6c1a955562 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Tue, 12 Dec 2023 15:52:28 -0800 Subject: [PATCH 167/311] tests: bump bazelversion for integration tests (#1566) Bumping 5.2.0 -> 6.4.0 --- src/test/many/.bazelversion | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/many/.bazelversion b/src/test/many/.bazelversion index 7cbea073be..19b860c187 100644 --- a/src/test/many/.bazelversion +++ b/src/test/many/.bazelversion @@ -1 +1 @@ -5.2.0 \ No newline at end of file +6.4.0 From 8d6e93fe0798978bff997c78458ac00fc35d0eeb Mon Sep 17 00:00:00 2001 From: Trevor Hickey Date: Tue, 12 Dec 2023 21:20:25 -0500 Subject: [PATCH 168/311] [tests] add unit test for local resources (#1558) Add a unit test related to handling of local resources. --- .../resources/LocalResourceSetUtilsTest.java | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 src/test/java/build/buildfarm/worker/resources/LocalResourceSetUtilsTest.java diff --git a/src/test/java/build/buildfarm/worker/resources/LocalResourceSetUtilsTest.java b/src/test/java/build/buildfarm/worker/resources/LocalResourceSetUtilsTest.java new file mode 100644 index 0000000000..94387e8834 --- /dev/null +++ b/src/test/java/build/buildfarm/worker/resources/LocalResourceSetUtilsTest.java @@ -0,0 +1,51 @@ +// Copyright 2023 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package build.buildfarm.worker.resources; + +import build.bazel.remote.execution.v2.Platform; +import build.buildfarm.v1test.QueueEntry; +import java.util.concurrent.Semaphore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * @class LocalResourceSetUtilsTest + * @brief Tests how local resources are claimed and released. + * @details Shows behaviour of local resource claims and releases. + */ +@RunWith(JUnit4.class) +public class LocalResourceSetUtilsTest { + // Function under test: releaseClaims + // Reason for testing: Show its okay to return claims that were never taken. + // Failure explanation: can't return claims that were never taken. + @Test + public void decideResourceLimitationsTestCoreSetting() throws Exception { + // ARRANGE + LocalResourceSet resourceSet = new LocalResourceSet(); + resourceSet.resources.put("FOO", new Semaphore(1)); + + QueueEntry entry = + QueueEntry.newBuilder() + .setPlatform( + Platform.newBuilder() + .addProperties( + Platform.Property.newBuilder().setName("resource:FOO").setValue("10"))) + .build(); + + // ACT + LocalResourceSetUtils.releaseClaims(entry.getPlatform(), resourceSet); + } +} From fe2eba2adf62d8e4918bb11aa8b7b19be0e0e9a6 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Wed, 13 Dec 2023 06:19:52 -0800 Subject: [PATCH 169/311] refactor: swap HealthStatusManager (#1568) Swapping to the recommended class that isn't deprecated. Also, remove unnecessary String.format(...) with no format args. --- src/main/java/build/buildfarm/server/BuildFarmServer.java | 6 ++---- src/main/java/build/buildfarm/worker/shard/Worker.java | 3 +-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/java/build/buildfarm/server/BuildFarmServer.java b/src/main/java/build/buildfarm/server/BuildFarmServer.java index d963454de0..5d25339be8 100644 --- a/src/main/java/build/buildfarm/server/BuildFarmServer.java +++ b/src/main/java/build/buildfarm/server/BuildFarmServer.java @@ -41,8 +41,8 @@ import io.grpc.ServerBuilder; import io.grpc.ServerInterceptor; import io.grpc.health.v1.HealthCheckResponse.ServingStatus; +import io.grpc.protobuf.services.HealthStatusManager; import io.grpc.protobuf.services.ProtoReflectionService; -import io.grpc.services.HealthStatusManager; import io.grpc.util.TransmitStatusRuntimeExceptionInterceptor; import io.prometheus.client.Counter; import java.io.File; @@ -55,7 +55,6 @@ import lombok.extern.java.Log; import org.bouncycastle.jce.provider.BouncyCastleProvider; -@SuppressWarnings("deprecation") @Log public class BuildFarmServer extends LoggingMain { private static final java.util.logging.Logger nettyLogger = @@ -88,8 +87,7 @@ public class BuildFarmServer extends LoggingMain { */ public void prepareServerForGracefulShutdown() { if (configs.getServer().getGracefulShutdownSeconds() == 0) { - log.info( - String.format("Graceful Shutdown is not enabled. Server is shutting down immediately.")); + log.info("Graceful Shutdown is not enabled. Server is shutting down immediately."); } else { try { log.info( diff --git a/src/main/java/build/buildfarm/worker/shard/Worker.java b/src/main/java/build/buildfarm/worker/shard/Worker.java index ce7a3e7385..6b175e1350 100644 --- a/src/main/java/build/buildfarm/worker/shard/Worker.java +++ b/src/main/java/build/buildfarm/worker/shard/Worker.java @@ -70,8 +70,8 @@ import io.grpc.Status; import io.grpc.Status.Code; import io.grpc.health.v1.HealthCheckResponse.ServingStatus; +import io.grpc.protobuf.services.HealthStatusManager; import io.grpc.protobuf.services.ProtoReflectionService; -import io.grpc.services.HealthStatusManager; import io.prometheus.client.Counter; import io.prometheus.client.Gauge; import java.io.File; @@ -125,7 +125,6 @@ public final class Worker extends LoggingMain { private WorkerInstance instance; - @SuppressWarnings("deprecation") private final HealthStatusManager healthStatusManager = new HealthStatusManager(); private Server server; From 284845a9c9dcba2021849ca7c37a0e05e672a614 Mon Sep 17 00:00:00 2001 From: amishra-u <119983081+amishra-u@users.noreply.github.com> Date: Fri, 15 Dec 2023 20:24:02 -0800 Subject: [PATCH 170/311] Update log level for blob location adjust (#1573) --- .../java/build/buildfarm/instance/shard/ServerInstance.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/build/buildfarm/instance/shard/ServerInstance.java b/src/main/java/build/buildfarm/instance/shard/ServerInstance.java index b4f118f1ad..50c1de2f6f 100644 --- a/src/main/java/build/buildfarm/instance/shard/ServerInstance.java +++ b/src/main/java/build/buildfarm/instance/shard/ServerInstance.java @@ -795,7 +795,7 @@ private Set filterAndAdjustWorkersForDigest( .immutableCopy(); if (!workersToBeRemoved.isEmpty()) { try { - log.log(Level.INFO, format("adjusting locations for the digest %s", digest)); + log.log(Level.FINE, format("adjusting locations for the digest %s", digest)); backplane.adjustBlobLocations(digest, Collections.emptySet(), workersToBeRemoved); } catch (IOException e) { log.log( From 89509537ebcdb8617a548e237a1ebd1daf3b1609 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Fri, 15 Dec 2023 20:30:37 -0800 Subject: [PATCH 171/311] feat: Redis password from file (#1569) * feat(config): read Redis password from Redis URI or redis password file * tests(common): add a test for build.buildfarm.common.config.Backplane * docs(configuration): document redisPasswordFile Documenting new configuration parameter and the precedence of each password option. --- _site/docs/configuration/configuration.md | 71 ++++++++++--------- .../java/build/buildfarm/common/config/BUILD | 4 ++ .../buildfarm/common/config/Backplane.java | 31 ++++++++ .../java/build/buildfarm/common/config/BUILD | 1 + .../common/config/BackplaneTest.java | 55 ++++++++++++++ 5 files changed, 127 insertions(+), 35 deletions(-) create mode 100644 src/test/java/build/buildfarm/common/config/BackplaneTest.java diff --git a/_site/docs/configuration/configuration.md b/_site/docs/configuration/configuration.md index ebbb8ca0e4..9e9d0ab0f9 100644 --- a/_site/docs/configuration/configuration.md +++ b/_site/docs/configuration/configuration.md @@ -172,41 +172,42 @@ server: ### Redis Backplane -| Configuration | Accepted and _Default_ Values | Environment Var | Command Line Argument | Description | -|------------------------------|------------------------------------------|-----------------|-----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| type | _SHARD_ | | | Type of backplane. Currently, the only implementation is SHARD utilizing Redis | -| redisUri | String, redis://localhost:6379 | REDIS_URI | --redis_uri | Redis cluster endpoint. This must be a single URI | -| redisPassword | String, _null_ | | | Redis password, if applicable | -| redisNodes | List of Strings, _null_ | | | List of individual Redis nodes, if applicable | -| jedisPoolMaxTotal | Integer, _4000_ | | | The size of the Redis connection pool | -| workersHashName | String, _Workers_ | | | Redis key used to store a hash of registered workers | -| workerChannel | String, _WorkerChannel_ | | | Redis pubsub channel key where changes of the cluster membership are announced | -| actionCachePrefix | String, _ActionCache_ | | | Redis key prefix for all ActionCache entries | -| actionCacheExpire | Integer, _2419200_ | | | The TTL maintained for ActionCache entries, not refreshed on getActionResult hit | -| actionBlacklistPrefix | String, _ActionBlacklist_ | | | Redis key prefix for all blacklisted actions, which are rejected | -| actionBlacklistExpire | Integer, _3600_ | | | The TTL maintained for action blacklist entries | -| invocationBlacklistPrefix | String, _InvocationBlacklist_ | | | Redis key prefix for blacklisted invocations, suffixed with a a tool invocation ID | -| operationPrefix | String, _Operation_ | | | Redis key prefix for all operations, suffixed with the operation's name | -| operationExpire | Integer, _604800_ | | | The TTL maintained for all operations, updated on each modification | -| preQueuedOperationsListName | String, _{Arrival}:PreQueuedOperations_ | | | Redis key used to store a list of ExecuteEntry awaiting transformation into QueryEntry | -| processingListName | String, _{Arrival}:ProcessingOperations_ | | | Redis key of a list used to ensure reliable processing of arrival queue entries with operation watch monitoring | -| processingPrefix | String, _Processing_ | | | Redis key prefix for operations which are being dequeued from the arrival queue | -| processingTimeoutMillis | Integer, _20000_ | | | Delay (in ms) used to populate processing operation entries | -| queuedOperationsListName | String, _{Execution}:QueuedOperations_ | | | Redis key used to store a list of QueueEntry awaiting execution by workers | -| dispatchingPrefix | String, _Dispatching_ | | | Redis key prefix for operations which are being dequeued from the ready to run queue | -| dispatchingTimeoutMillis | Integer, _10000_ | | | Delay (in ms) used to populate dispatching operation entries | -| dispatchedOperationsHashName | String, _DispatchedOperations_ | | | Redis key of a hash of operation names to the worker lease for its execution, which are monitored by the dispatched monitor | -| operationChannelPrefix | String, _OperationChannel_ | | | Redis pubsub channel prefix suffixed by an operation name | -| casPrefix | String, _ContentAddressableStorage_ | | | Redis key prefix suffixed with a blob digest that maps to a set of workers with that blob's availability | -| casExpire | Integer, _604800_ | | | The TTL maintained for CAS entries, which is not refreshed on any read access of the blob | -| subscribeToBackplane | boolean, _true_ | | | Enable an agent of the backplane client which subscribes to worker channel and operation channel events. If disabled, responsiveness of watchers and CAS are reduced | -| runFailsafeOperation | boolean, _true_ | | | Enable an agent in the backplane client which monitors watched operations and ensures they are in a known maintained, or expirable state | -| maxQueueDepth | Integer, _100000_ | | | Maximum length that the ready to run queue is allowed to reach to control an arrival flow for execution | -| maxPreQueueDepth | Integer, _1000000_ | | | Maximum lengh that the arrival queue is allowed to reach to control load on the Redis cluster | -| priorityQueue | boolean, _false_ | | | Priority queue type allows prioritizing operations based on Bazel's --remote_execution_priority= flag | -| timeout | Integer, _10000_ | | | Default timeout | -| maxAttempts | Integer, _20_ | | | Maximum number of execution attempts | -| cacheCas | boolean, _false_ | | | | +| Configuration | Accepted and _Default_ Values | Environment Var | Command Line Argument | Description | +|------------------------------|------------------------------------------|-----------------|-----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| type | _SHARD_ | | | Type of backplane. Currently, the only implementation is SHARD utilizing Redis | +| redisUri | String, redis://localhost:6379 | REDIS_URI | --redis_uri | Redis cluster endpoint. This must be a single URI. This can embed a username/password per RFC-3986 Section 3.2.1 and this will take precedence over `redisPassword` and `redisPasswordFile`. | +| redisPassword | String, _null_ | | | Redis password, if applicable | +| redisPasswordFile | String, _null_ | | | File to read for a Redis password. If specified, this takes precedence over `redisPassword` | +| redisNodes | List of Strings, _null_ | | | List of individual Redis nodes, if applicable | +| jedisPoolMaxTotal | Integer, _4000_ | | | The size of the Redis connection pool | +| workersHashName | String, _Workers_ | | | Redis key used to store a hash of registered workers | +| workerChannel | String, _WorkerChannel_ | | | Redis pubsub channel key where changes of the cluster membership are announced | +| actionCachePrefix | String, _ActionCache_ | | | Redis key prefix for all ActionCache entries | +| actionCacheExpire | Integer, _2419200_ | | | The TTL maintained for ActionCache entries, not refreshed on getActionResult hit | +| actionBlacklistPrefix | String, _ActionBlacklist_ | | | Redis key prefix for all blacklisted actions, which are rejected | +| actionBlacklistExpire | Integer, _3600_ | | | The TTL maintained for action blacklist entries | +| invocationBlacklistPrefix | String, _InvocationBlacklist_ | | | Redis key prefix for blacklisted invocations, suffixed with a a tool invocation ID | +| operationPrefix | String, _Operation_ | | | Redis key prefix for all operations, suffixed with the operation's name | +| operationExpire | Integer, _604800_ | | | The TTL maintained for all operations, updated on each modification | +| preQueuedOperationsListName | String, _{Arrival}:PreQueuedOperations_ | | | Redis key used to store a list of ExecuteEntry awaiting transformation into QueryEntry | +| processingListName | String, _{Arrival}:ProcessingOperations_ | | | Redis key of a list used to ensure reliable processing of arrival queue entries with operation watch monitoring | +| processingPrefix | String, _Processing_ | | | Redis key prefix for operations which are being dequeued from the arrival queue | +| processingTimeoutMillis | Integer, _20000_ | | | Delay (in ms) used to populate processing operation entries | +| queuedOperationsListName | String, _{Execution}:QueuedOperations_ | | | Redis key used to store a list of QueueEntry awaiting execution by workers | +| dispatchingPrefix | String, _Dispatching_ | | | Redis key prefix for operations which are being dequeued from the ready to run queue | +| dispatchingTimeoutMillis | Integer, _10000_ | | | Delay (in ms) used to populate dispatching operation entries | +| dispatchedOperationsHashName | String, _DispatchedOperations_ | | | Redis key of a hash of operation names to the worker lease for its execution, which are monitored by the dispatched monitor | +| operationChannelPrefix | String, _OperationChannel_ | | | Redis pubsub channel prefix suffixed by an operation name | +| casPrefix | String, _ContentAddressableStorage_ | | | Redis key prefix suffixed with a blob digest that maps to a set of workers with that blob's availability | +| casExpire | Integer, _604800_ | | | The TTL maintained for CAS entries, which is not refreshed on any read access of the blob | +| subscribeToBackplane | boolean, _true_ | | | Enable an agent of the backplane client which subscribes to worker channel and operation channel events. If disabled, responsiveness of watchers and CAS are reduced | +| runFailsafeOperation | boolean, _true_ | | | Enable an agent in the backplane client which monitors watched operations and ensures they are in a known maintained, or expirable state | +| maxQueueDepth | Integer, _100000_ | | | Maximum length that the ready to run queue is allowed to reach to control an arrival flow for execution | +| maxPreQueueDepth | Integer, _1000000_ | | | Maximum lengh that the arrival queue is allowed to reach to control load on the Redis cluster | +| priorityQueue | boolean, _false_ | | | Priority queue type allows prioritizing operations based on Bazel's --remote_execution_priority= flag | +| timeout | Integer, _10000_ | | | Default timeout | +| maxAttempts | Integer, _20_ | | | Maximum number of execution attempts | +| cacheCas | boolean, _false_ | | | | Example: diff --git a/src/main/java/build/buildfarm/common/config/BUILD b/src/main/java/build/buildfarm/common/config/BUILD index 4d9c8eb7a0..843774e2a0 100644 --- a/src/main/java/build/buildfarm/common/config/BUILD +++ b/src/main/java/build/buildfarm/common/config/BUILD @@ -10,13 +10,17 @@ java_library( "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "@googleapis//:google_longrunning_operations_java_proto", "@googleapis//:google_rpc_code_java_proto", + "@jedis//jar", + "@maven//:com_github_oshi_oshi_core", "@maven//:com_github_pcj_google_options", + "@maven//:com_google_code_findbugs_jsr305", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:io_grpc_grpc_api", "@maven//:me_dinowernli_java_grpc_prometheus", "@maven//:org_projectlombok_lombok", + "@maven//:org_redisson_redisson", "@maven//:org_yaml_snakeyaml", ], ) diff --git a/src/main/java/build/buildfarm/common/config/Backplane.java b/src/main/java/build/buildfarm/common/config/Backplane.java index cc15a6028a..16a90e9111 100644 --- a/src/main/java/build/buildfarm/common/config/Backplane.java +++ b/src/main/java/build/buildfarm/common/config/Backplane.java @@ -1,10 +1,15 @@ package build.buildfarm.common.config; +import com.google.common.base.Strings; +import java.net.URI; import java.util.ArrayList; import java.util.List; +import javax.annotation.Nullable; import lombok.AccessLevel; import lombok.Data; import lombok.Getter; +import oshi.util.FileUtil; +import redis.clients.jedis.util.JedisURIHelper; @Data public class Backplane { @@ -46,6 +51,7 @@ public enum BACKPLANE_TYPE { private int maxPreQueueDepth = 1000000; private boolean priorityQueue = false; private Queue[] queues = {}; + private String redisCredentialFile; private String redisPassword; private int timeout = 10000; private String[] redisNodes = {}; @@ -56,4 +62,29 @@ public enum BACKPLANE_TYPE { // These limited resources are shared across all workers. // An example would be a limited number of seats to a license server. private List resources = new ArrayList<>(); + + /** + * Look in several prioritized ways to get a Redis password: + * + *

    + *
  1. the password in the Redis URI (wherever that came from) + *
  2. The `redisPassword` from config YAML + *
  3. the `redisCredentialFile`. + *
+ * + * @return The redis password, or null if unset. + */ + public @Nullable String getRedisPassword() { + URI redisProperUri = URI.create(getRedisUri()); + if (!Strings.isNullOrEmpty(JedisURIHelper.getPassword(redisProperUri))) { + return JedisURIHelper.getPassword(redisProperUri); + } + + if (!Strings.isNullOrEmpty(redisCredentialFile)) { + // Get the password from the config file. + return FileUtil.getStringFromFile(redisCredentialFile); + } + + return Strings.emptyToNull(redisPassword); + } } diff --git a/src/test/java/build/buildfarm/common/config/BUILD b/src/test/java/build/buildfarm/common/config/BUILD index 4819a6bca8..1c411712fa 100644 --- a/src/test/java/build/buildfarm/common/config/BUILD +++ b/src/test/java/build/buildfarm/common/config/BUILD @@ -5,6 +5,7 @@ java_test( deps = [ "//src/main/java/build/buildfarm/common/config", "//src/test/java/build/buildfarm:test_runner", + "@maven//:com_google_truth_truth", "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_testing", "@maven//:me_dinowernli_java_grpc_prometheus", diff --git a/src/test/java/build/buildfarm/common/config/BackplaneTest.java b/src/test/java/build/buildfarm/common/config/BackplaneTest.java new file mode 100644 index 0000000000..9cf61eadc5 --- /dev/null +++ b/src/test/java/build/buildfarm/common/config/BackplaneTest.java @@ -0,0 +1,55 @@ +// Copyright 2023 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package build.buildfarm.common.config; + +import static com.google.common.truth.Truth.assertThat; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * @class BackplaneTest + * @brief Tests utility functions for Backplane configuration overrides + */ +@RunWith(JUnit4.class) +public class BackplaneTest { + + @Before + public void assertNoEnvVariable() { + // If a REDIS_PASSWORD env variable is set, it wins. We're not mocking env vars. + assertThat(System.getenv("REDIS_PASSWORD")).isNull(); + } + + @Test + public void testRedisPasswordFromUri() { + Backplane b = new Backplane(); + String testRedisUri = "redis://user:pass1@redisHost.redisDomain"; + b.setRedisUri(testRedisUri); + assertThat(b.getRedisPassword()).isEqualTo("pass1"); + } + + /** + * Validate that the redis URI password is higher priority than the `redisPassword` in the config + */ + @Test + public void testRedisPasswordPriorities() { + Backplane b = new Backplane(); + b.setRedisUri("redis://user:pass1@redisHost.redisDomain"); + b.setRedisPassword("pass2"); + assertThat(b.getRedisPassword()).isEqualTo("pass1"); + } +} From a4551f025b8cfc6b3052fe9420d4df8a45aa499f Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Fri, 15 Dec 2023 21:27:44 -0800 Subject: [PATCH 172/311] docs: update AUTHORS and CONTRIBUTORS (#1572) Adding myself and my copyright holder to `CONTRIBUTORS` and `AUTHORS`, respectively. --- AUTHORS | 1 + CONTRIBUTORS | 1 + 2 files changed, 2 insertions(+) diff --git a/AUTHORS b/AUTHORS index f9314dfc35..ed0de30898 100644 --- a/AUTHORS +++ b/AUTHORS @@ -9,3 +9,4 @@ Uber Technologies Inc. Aurora Innovation, Inc. VMware, Inc. +Salesforce, Inc. diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 1eb0fc98cd..9961c13001 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -13,3 +13,4 @@ George Gensure Yuriy Belenitsky Trevor Hickey Jacob Mou +Jason Schroeder From f9140c49aa8b17803775649f322cefade3f09770 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Sat, 16 Dec 2023 11:07:07 -0500 Subject: [PATCH 173/311] Identify Graceful Shutdown errors with severe (#1574) Ensure that the log reflects these as errors, not just info --- src/main/java/build/buildfarm/server/BuildFarmServer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/build/buildfarm/server/BuildFarmServer.java b/src/main/java/build/buildfarm/server/BuildFarmServer.java index 5d25339be8..be5f934539 100644 --- a/src/main/java/build/buildfarm/server/BuildFarmServer.java +++ b/src/main/java/build/buildfarm/server/BuildFarmServer.java @@ -87,7 +87,7 @@ public class BuildFarmServer extends LoggingMain { */ public void prepareServerForGracefulShutdown() { if (configs.getServer().getGracefulShutdownSeconds() == 0) { - log.info("Graceful Shutdown is not enabled. Server is shutting down immediately."); + log.severe("Graceful Shutdown is not enabled. Server is shutting down immediately."); } else { try { log.info( @@ -96,7 +96,7 @@ public void prepareServerForGracefulShutdown() { configs.getServer().getGracefulShutdownSeconds())); SECONDS.sleep(configs.getServer().getGracefulShutdownSeconds()); } catch (InterruptedException e) { - log.info( + log.severe( "Graceful Shutdown - The server graceful shutdown is interrupted: " + e.getMessage()); } finally { log.info( From f76893ed0690367003223605a53242d14383a1dc Mon Sep 17 00:00:00 2001 From: George Gensure Date: Sat, 16 Dec 2023 11:09:23 -0500 Subject: [PATCH 174/311] Remove orphaned DequeueResults (#1575) --- .../buildfarm/worker/DequeueResults.java | 38 ------------------- 1 file changed, 38 deletions(-) delete mode 100644 src/main/java/build/buildfarm/worker/DequeueResults.java diff --git a/src/main/java/build/buildfarm/worker/DequeueResults.java b/src/main/java/build/buildfarm/worker/DequeueResults.java deleted file mode 100644 index f449907db0..0000000000 --- a/src/main/java/build/buildfarm/worker/DequeueResults.java +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2021 The Bazel Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package build.buildfarm.worker; - -/** - * @class DequeueResults - * @brief The results of evaluating a dequeued operation. - * @details Contains information about whether the operation should be kept and if resources were - * claimed. - */ -public class DequeueResults { - /** - * @field keep - * @brief Whether the operation should be kept. - * @details Operations not kept should be put back on the queue. - */ - public boolean keep = false; - - /** - * @field resourcesClaimed - * @brief Whether resources have been claimed while deciding to keep operation. - * @details If resources are claimed but the operation is not kept, the resources should be - * released. - */ - public boolean resourcesClaimed = false; -} From 1fa3c43d79838e3e4f5f757654c338a8fed7a807 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Sat, 16 Dec 2023 11:09:43 -0500 Subject: [PATCH 175/311] Clean up bf-mount usage/refactor (#1576) --- .../java/build/buildfarm/tools/Mount.java | 34 +++++++++++++++---- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/src/main/java/build/buildfarm/tools/Mount.java b/src/main/java/build/buildfarm/tools/Mount.java index a0a4528d22..acd61f1f11 100644 --- a/src/main/java/build/buildfarm/tools/Mount.java +++ b/src/main/java/build/buildfarm/tools/Mount.java @@ -37,10 +37,14 @@ class Mount { @SuppressWarnings("BusyWait") - public static void main(String[] args) throws Exception { - String host = args[0]; - String instanceName = args[1]; - DigestUtil digestUtil = DigestUtil.forHash(args[2]); + public static void mount( + String host, + String instanceName, + DigestUtil digestUtil, + String root, + Digest inputRoot, + String name) + throws IOException, InterruptedException { ManagedChannel channel = createChannel(host); Instance instance = new StubInstance(instanceName, digestUtil, channel); @@ -48,7 +52,7 @@ public static void main(String[] args) throws Exception { FuseCAS fuse = new FuseCAS( - cwd.resolve(args[3]), + cwd.resolve(root), new InputStreamFactory() { final Map cache = new HashMap<>(); @@ -75,8 +79,7 @@ public synchronized InputStream newInput( } }); - // FIXME make bettar - fuse.createInputRoot(args[5], DigestUtil.parseDigest(args[4])); + fuse.createInputRoot(name, inputRoot); try { //noinspection InfiniteLoopStatement @@ -89,4 +92,21 @@ public synchronized InputStream newInput( fuse.stop(); } } + + public static void main(String[] args) throws Exception { + if (args.length != 6) { + System.err.println( + "Usage: bf-mount "); + System.err.println("\nMount an REAPI directory specified by 'digest' at 'name' under 'root'"); + System.exit(1); + } + + String host = args[0]; + String instanceName = args[1]; + DigestUtil digestUtil = DigestUtil.forHash(args[2]); + String root = args[3]; + Digest inputRoot = DigestUtil.parseDigest(args[4]); + String name = args[5]; + mount(host, instanceName, digestUtil, root, inputRoot, name); + } } From cf3ac777ebb7e801ff09889fd588a97be75e5686 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Sat, 16 Dec 2023 11:10:17 -0500 Subject: [PATCH 176/311] Clean up bf-mount usage/refactor (#1577) From ce31446defdcc90db2971f787c1d79403b5310b4 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Sat, 16 Dec 2023 11:10:32 -0500 Subject: [PATCH 177/311] Refactor WriteStreamObserver logging (#1578) --- .../common/services/WriteStreamObserver.java | 40 +++++++++++++------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java b/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java index c2518921a0..e1e23fa5b8 100644 --- a/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java +++ b/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java @@ -178,19 +178,11 @@ synchronized void commitSynchronized(long committedSize) { } commitActive(committedSize); } catch (RuntimeException e) { - RequestMetadata requestMetadata = TracingMetadataUtils.fromCurrentContext(); Status status = Status.fromThrowable(e); if (errorResponse(status.asException())) { - log.log( + logWriteActivity( status.getCode() == Status.Code.CANCELLED ? Level.FINER : Level.SEVERE, - format( - "%s-%s: %s -> %s -> %s: error committing %s", - requestMetadata.getToolDetails().getToolName(), - requestMetadata.getToolDetails().getToolVersion(), - requestMetadata.getCorrelatedInvocationsId(), - requestMetadata.getToolInvocationId(), - requestMetadata.getActionId(), - name), + "committing", e); } } @@ -240,7 +232,9 @@ public void onSuccess(Long committedSize) { @SuppressWarnings("NullableProblems") @Override public void onFailure(Throwable t) { - errorResponse(t); + if (errorResponse(t)) { + logWriteActivity("completing", t); + } } }, withCancellation.fixedContextExecutor(directExecutor())); @@ -258,6 +252,26 @@ public void onFailure(Throwable t) { } } + private void logWriteActivity(String activity, Throwable t) { + logWriteActivity(Level.SEVERE, activity, t); + } + + private void logWriteActivity(Level level, String activity, Throwable t) { + RequestMetadata requestMetadata = TracingMetadataUtils.fromCurrentContext(); + log.log( + level, + format( + "%s-%s: %s -> %s -> %s: error %s %s", + requestMetadata.getToolDetails().getToolName(), + requestMetadata.getToolDetails().getToolVersion(), + requestMetadata.getCorrelatedInvocationsId(), + requestMetadata.getToolInvocationId(), + requestMetadata.getActionId(), + activity, + name), + t); + } + private void logWriteRequest(WriteRequest request, Exception e) { log.log( Level.WARNING, @@ -331,7 +345,9 @@ private void handleWrite(String resourceName, long offset, ByteString data, bool } committedSize = getCommittedSizeForWrite(); } catch (IOException e) { - errorResponse(e); + if (errorResponse(e)) { + logWriteActivity("querying", e); + } return; } if (offset != 0 && offset > committedSize) { From 2a6f68c80abd94a72665d18a38cf8ab757d53d13 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Sat, 16 Dec 2023 11:10:54 -0500 Subject: [PATCH 178/311] Determine PipelineStage exception severity (#1579) Select pipeline stage terminations based on exception type. InterruptedExceptions are terminable. Errors are uncaught and will terminate the stage. All others are logged with the pipeline continuing. --- .../build/buildfarm/worker/PipelineStage.java | 51 +++++++--- .../build/buildfarm/worker/PipelineTest.java | 95 +++++++++++++++++++ 2 files changed, 131 insertions(+), 15 deletions(-) diff --git a/src/main/java/build/buildfarm/worker/PipelineStage.java b/src/main/java/build/buildfarm/worker/PipelineStage.java index ecc78f8e7e..49bd392a2e 100644 --- a/src/main/java/build/buildfarm/worker/PipelineStage.java +++ b/src/main/java/build/buildfarm/worker/PipelineStage.java @@ -46,7 +46,7 @@ public String getName() { return name; } - private void runInterruptible() throws InterruptedException { + protected void runInterruptible() throws InterruptedException { while (!output.isClosed() || isClaimed()) { iterate(); } @@ -58,23 +58,44 @@ private void runInterruptible() throws InterruptedException { @Override public void run() { - try { - runInterruptible(); - } catch (InterruptedException e) { - // ignore - } catch (Exception e) { - getLogger() - .log(Level.SEVERE, format("%s::run(): stage terminated due to exception", name), e); - } finally { - boolean wasInterrupted = Thread.interrupted(); + boolean keepRunningStage = true; + while (keepRunningStage) { try { - close(); - } finally { - if (wasInterrupted) { - Thread.currentThread().interrupt(); - } + runInterruptible(); + + // If the run finishes without exception, the stage can also stop running. + keepRunningStage = false; + + } catch (Exception e) { + keepRunningStage = decideTermination(e); } } + + close(); + } + + /** + * @brief When the stage has an uncaught exception, this method determines whether the pipeline + * stage should terminate. + * @details This is a customization of the pipeline stage to allow logging exceptions but keeping + * the pipeline stage running. + * @return Whether the stage should terminate or continue running. + */ + private boolean decideTermination(Exception e) { + // This is a normal way for the pipeline stage to terminate. + // If an interrupt is received, there is no reason to continue the pipeline stage. + if (e instanceof InterruptedException) { + getLogger() + .log(Level.INFO, String.format("%s::run(): stage terminated due to interrupt", name)); + return false; + } + + // On the other hand, this is an abnormal way for a pipeline stage to terminate. + // For robustness of the distributed system, we may want to log the error but continue the + // pipeline stage. + getLogger() + .log(Level.SEVERE, String.format("%s::run(): stage terminated due to exception", name), e); + return true; } public String name() { diff --git a/src/test/java/build/buildfarm/worker/PipelineTest.java b/src/test/java/build/buildfarm/worker/PipelineTest.java index f414b8cefe..866f6f19e3 100644 --- a/src/test/java/build/buildfarm/worker/PipelineTest.java +++ b/src/test/java/build/buildfarm/worker/PipelineTest.java @@ -14,6 +14,11 @@ package build.buildfarm.worker; +import static com.google.common.truth.Truth.assertThat; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.logging.Logger; import lombok.extern.java.Log; import org.junit.Test; @@ -71,4 +76,94 @@ public void run() { pipeline.start(); pipeline.join(); } + + // Create a test stage that exists because of an interrupt. + // This proves the stage can be interupted. + public class TestStage extends PipelineStage { + public TestStage(String name) { + super(name, null, null, null); + } + + @Override + protected void runInterruptible() throws InterruptedException { + throw new InterruptedException("Interrupt"); + } + + @Override + public void put(OperationContext operationContext) throws InterruptedException {} + + @Override + OperationContext take() { + throw new UnsupportedOperationException(); + } + + @Override + public Logger getLogger() { + return log; + } + } + + // This test demonstrates that the stage will end and the pipeline will finish because it was + // interrupted. + @Test + public void stageExitsOnInterrupt() throws InterruptedException { + Pipeline pipeline = new Pipeline(); + TestStage stage = new TestStage("test"); + pipeline.add(stage, 1); + pipeline.start(); + pipeline.join(); + } + + // Create a test stage that doesn't exit because of an a non-interrupt exception. + // This proves the stage is robust enough continue running when experiencing an exception. + public class ContinueStage extends PipelineStage { + public ContinueStage(String name) { + super(name, null, null, null); + } + + @Override + protected void runInterruptible() throws InterruptedException { + throw new RuntimeException("Exception"); + } + + @Override + public void put(OperationContext operationContext) throws InterruptedException {} + + @Override + OperationContext take() { + throw new UnsupportedOperationException(); + } + + @Override + public Logger getLogger() { + return log; + } + } + + // This test demonstrates that the stage will NOT end and the pipeline will NOT finish because a + // non-interrupt exception was thrown. + @Test + public void stageContinuesOnException() throws InterruptedException { + Pipeline pipeline = new Pipeline(); + ContinueStage stage = new ContinueStage("test"); + pipeline.add(stage, 1); + pipeline.start(); + + boolean didNotThrow = false; + try { + CompletableFuture.runAsync( + () -> { + try { + pipeline.join(); + } catch (InterruptedException e) { + } + return; + }) + .get(1, TimeUnit.SECONDS); + } catch (TimeoutException e) { + didNotThrow = true; + } catch (Exception e) { + } + assertThat(didNotThrow).isTrue(); + } } From a0ec481d0c1635552bbe949be015064b549068da Mon Sep 17 00:00:00 2001 From: George Gensure Date: Sat, 16 Dec 2023 11:11:10 -0500 Subject: [PATCH 179/311] Authored sandbox asNobody behavior (#1580) Describe a boolean authored to supply the as-nobody wrapper published with buildfarm deployments that should serve as a quick mechanism for any install to use non-buildfarm (typically root) uids for actions. --- .../build/buildfarm/common/config/SandboxSettings.java | 7 +++++++ .../build/buildfarm/worker/shard/ShardWorkerContext.java | 6 ++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/java/build/buildfarm/common/config/SandboxSettings.java b/src/main/java/build/buildfarm/common/config/SandboxSettings.java index f432989015..f9873faf2b 100644 --- a/src/main/java/build/buildfarm/common/config/SandboxSettings.java +++ b/src/main/java/build/buildfarm/common/config/SandboxSettings.java @@ -32,6 +32,13 @@ public class SandboxSettings { */ public boolean alwaysUseSandbox = false; + /** + * @field alwaysUseAsNobody + * @brief Whether or not to always use the as-nobody wrapper when running actions. + * @details It may be preferred to enforce this wrapper instead of relying on client selection. + */ + public boolean alwaysUseAsNobody = false; + /** * @field alwaysUseCgroups * @brief Whether or not to use cgroups when sandboxing actions. diff --git a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java index 37e46a5892..d6b2d54145 100644 --- a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java +++ b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java @@ -979,6 +979,10 @@ IOResource limitSpecifiedExecution( addLinuxSandboxCli(arguments, options); } + if (configs.getWorker().getSandboxSettings().isAlwaysUseAsNobody() || limits.fakeUsername) { + arguments.add(configs.getExecutionWrappers().getAsNobody()); + } + if (limits.time.skipSleep) { arguments.add(configs.getExecutionWrappers().getSkipSleep()); @@ -1043,8 +1047,6 @@ private LinuxSandboxOptions decideLinuxSandboxOptions( private void addLinuxSandboxCli( ImmutableList.Builder arguments, LinuxSandboxOptions options) { - arguments.add(configs.getExecutionWrappers().getAsNobody()); - // Choose the sandbox which is built and deployed with the worker image. arguments.add(configs.getExecutionWrappers().getLinuxSandbox()); From 915612379e5e658076e4b95b6ee432ec5ab01d25 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Sat, 16 Dec 2023 11:11:28 -0500 Subject: [PATCH 180/311] Provide Additional sandbox write paths in config (#1581) Deployments may specify the paths that should be writable in sandbox --- .../buildfarm/common/config/SandboxSettings.java | 16 ++++++++++++++++ .../worker/shard/ShardWorkerContext.java | 8 +++----- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/main/java/build/buildfarm/common/config/SandboxSettings.java b/src/main/java/build/buildfarm/common/config/SandboxSettings.java index f9873faf2b..db198b7c8e 100644 --- a/src/main/java/build/buildfarm/common/config/SandboxSettings.java +++ b/src/main/java/build/buildfarm/common/config/SandboxSettings.java @@ -14,6 +14,8 @@ package build.buildfarm.common.config; +import java.util.ArrayList; +import java.util.List; import lombok.Data; /** @@ -53,6 +55,20 @@ public class SandboxSettings { */ public boolean alwaysUseTmpFs = false; + /** + * @field additionalWritePaths + * @brief Additional paths the sandbox is allowed to write to. + * @details Suggestions may include: /tmp, /dev/shm + */ + public List additionalWritePaths = new ArrayList(); + + /** + * @field tmpFsPaths + * @brief Additional paths the sandbox uses for tmpfs + * @details Suggestions may include: /tmp + */ + public List tmpFsPaths = new ArrayList(); + /** * @field selectForBlockNetwork * @brief If the action requires "block network" use the sandbox to fulfill this request. diff --git a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java index d6b2d54145..71bc76e9e4 100644 --- a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java +++ b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java @@ -1021,13 +1021,11 @@ private LinuxSandboxOptions decideLinuxSandboxOptions( // TODO: provide proper support for bazel sandbox's fakeUsername "-U" flag. // options.fakeUsername = limits.fakeUsername; - // these were hardcoded in bazel based on a filesystem configuration typical to ours - // TODO: they may be incorrect for say Windows, and support will need adjusted in the future. - options.writableFiles.add("/tmp"); - options.writableFiles.add("/dev/shm"); + options.writableFiles.addAll( + configs.getWorker().getSandboxSettings().getAdditionalWritePaths()); if (limits.tmpFs) { - options.tmpfsDirs.add("/tmp"); + options.writableFiles.addAll(configs.getWorker().getSandboxSettings().getTmpFsPaths()); } if (limits.debugAfterExecution) { From b48032ba7e1f98867f044d3e2289da69108308a4 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Mon, 18 Dec 2023 14:40:55 -0500 Subject: [PATCH 181/311] Declare stat block information for FuseCAS (#1582) Useful so that a `du` and other block related tools work on the mounted directory. --- src/main/java/build/buildfarm/worker/FuseCAS.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/build/buildfarm/worker/FuseCAS.java b/src/main/java/build/buildfarm/worker/FuseCAS.java index 68489cbe2e..b9697d0133 100644 --- a/src/main/java/build/buildfarm/worker/FuseCAS.java +++ b/src/main/java/build/buildfarm/worker/FuseCAS.java @@ -547,6 +547,9 @@ public int getattr(String path, FileStat stat) { return -ErrorCodes.ENOENT(); } + // stock block size + stat.st_blksize.set(4096); + if (entry.isSymlink()) { stat.st_mode.set(FileStat.S_IFLNK | 0777); } else if (entry.isDirectory()) { @@ -554,9 +557,13 @@ public int getattr(String path, FileStat stat) { } else { int mode = entry.isExecutable() ? 0555 : 0444; stat.st_mode.set(FileStat.S_IFREG | mode); - stat.st_nlink.set(1); - stat.st_size.set(entry.size()); + stat.st_nlink.set(1); // should fix this for number of digests pointing to it } + long size = entry.size(); + long blksize = stat.st_blksize.get(); + long blocks = (size + blksize - 1) / blksize; + stat.st_size.set(size); + stat.st_blocks.set(blocks); return 0; } From 2097ef997a0d42a3c0290deb104b3660d697de1d Mon Sep 17 00:00:00 2001 From: George Gensure Date: Mon, 18 Dec 2023 16:06:24 -0500 Subject: [PATCH 182/311] Try a new version of jekyll (#1583) Current version is failing with a gem bundler error --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 064cde87fe..a4facca3c2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -20,7 +20,7 @@ jobs: ${{ runner.os }}-gems- # Use GitHub Deploy Action to build and deploy to Github - - uses: jeffreytse/jekyll-deploy-action@v0.4.0 + - uses: jeffreytse/jekyll-deploy-action@v0.5.0 with: provider: 'github' token: ${{ secrets.GH_TOKEN }} # It's your Personal Access Token(PAT) From d4de791d62046f8f0479e6d53091365e03e9d647 Mon Sep 17 00:00:00 2001 From: Andrew Rothstein Date: Thu, 21 Dec 2023 14:46:24 -0500 Subject: [PATCH 183/311] include (un)zip in images (#1590) --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 11c3379edc..6b843cc0be 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,7 +7,7 @@ FROM ubuntu:18.04 RUN echo 'APT::Acquire::Retries "5";' > /etc/apt/apt.conf.d/80retries RUN apt-get update -RUN apt-get -y install wget git python gcc openjdk-8-jdk g++ redis redis-server +RUN apt-get -y install wget git zip python gcc openjdk-8-jdk g++ redis redis-server RUN wget --tries=10 -O get-pip.py https://bootstrap.pypa.io/pip/2.7/get-pip.py RUN python2 get-pip.py RUN pip install python-dateutil From f320a8145312052e42c8f5fe672ec8f392e07d5c Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Thu, 21 Dec 2023 12:07:01 -0800 Subject: [PATCH 184/311] Remove rules k8s (#1587) * build: remove rules_k8s The repo was archived May 12, 2023. * chore: remove unused k8s templates Please use the helm chart instead. * chore: Tiltfile updates to use helm chart instead --- Tiltfile | 24 +- defs.bzl | 3 - deps.bzl | 8 - kubernetes/deployments/BUILD | 25 -- kubernetes/deployments/kubernetes.yaml | 303 --------------------- kubernetes/deployments/redis-cluster.yaml | 22 -- kubernetes/deployments/server.yaml | 28 -- kubernetes/deployments/shard-worker.yaml | 32 --- kubernetes/services/BUILD | 31 --- kubernetes/services/grafana.yaml | 82 ------ kubernetes/services/jaeger.yaml | 305 ---------------------- kubernetes/services/open-telemetry.yaml | 218 ---------------- kubernetes/services/redis-cluster.yaml | 11 - kubernetes/services/shard-worker.yaml | 17 -- 14 files changed, 3 insertions(+), 1106 deletions(-) delete mode 100644 kubernetes/deployments/BUILD delete mode 100644 kubernetes/deployments/kubernetes.yaml delete mode 100644 kubernetes/deployments/redis-cluster.yaml delete mode 100644 kubernetes/deployments/server.yaml delete mode 100644 kubernetes/deployments/shard-worker.yaml delete mode 100644 kubernetes/services/BUILD delete mode 100644 kubernetes/services/grafana.yaml delete mode 100644 kubernetes/services/jaeger.yaml delete mode 100644 kubernetes/services/open-telemetry.yaml delete mode 100644 kubernetes/services/redis-cluster.yaml delete mode 100644 kubernetes/services/shard-worker.yaml diff --git a/Tiltfile b/Tiltfile index 454f13253b..b706a79122 100644 --- a/Tiltfile +++ b/Tiltfile @@ -34,7 +34,7 @@ def server_deps(): # Inform tilt about the custom images built within the repository. # When you change code, these images will be re-built and re-deployed. custom_build( - ref='buildfarm-shard-worker-image', + ref='bazelbuild/buildfarm-worker', command=( 'bazelisk build --javabase=@bazel_tools//tools/jdk:remote_jdk11 //:buildfarm-shard-worker.tar && ' + 'docker load < bazel-bin/buildfarm-shard-worker.tar && ' + @@ -44,7 +44,7 @@ custom_build( deps = worker_deps() ) custom_build( - ref='buildfarm-server-image', + ref='bazelbuild/buildfarm-server', command=( 'bazelisk build --javabase=@bazel_tools//tools/jdk:remote_jdk11 //:buildfarm-server.tar && ' + 'docker load < bazel-bin/buildfarm-server.tar && ' + @@ -58,22 +58,4 @@ local_resource("unit tests",'bazelisk test --javabase=@bazel_tools//tools/jdk:re # Object definitions for kubernetes. # Tilt will automatically correlate them to any above docker images. -k8s_yaml(local('bazelisk run //kubernetes/deployments:kubernetes')) -k8s_yaml(local('bazelisk run //kubernetes/deployments:server')) -k8s_yaml(local('bazelisk run //kubernetes/deployments:shard-worker')) -k8s_yaml(local('bazelisk run //kubernetes/deployments:redis-cluster')) -k8s_yaml(local('bazelisk run //kubernetes/services:grafana')) -k8s_yaml(local('bazelisk run //kubernetes/services:redis-cluster')) -k8s_yaml(local('bazelisk run //kubernetes/services:shard-worker')) -k8s_yaml(local('bazelisk run //kubernetes/services:open-telemetry')) -k8s_yaml(local('bazelisk run //kubernetes/services:jaeger')) - -# Expose endpoints outside the kubernetes cluster. -k8s_resource('server', port_forwards=[8980,9092], labels="buildfarm-cluster") -k8s_resource('shard-worker', port_forwards=[8981,9091], labels="buildfarm-cluster") -k8s_resource('redis-cluster', port_forwards=6379, labels="buildfarm-cluster") -k8s_resource('otel-agent', labels="tracing") -k8s_resource('otel-collector', port_forwards=[4317,4318], labels="tracing") -k8s_resource('simplest', port_forwards=[14269,16686], labels="tracing") -k8s_resource('kubernetes-dashboard', port_forwards=8443) -k8s_resource('grafana', port_forwards=3000, labels="metrics") +k8s_yaml(helm('kubernetes/helm-charts/buildfarm')) diff --git a/defs.bzl b/defs.bzl index ad0790593e..a6114caa27 100644 --- a/defs.bzl +++ b/defs.bzl @@ -11,7 +11,6 @@ load( load("@io_grpc_grpc_java//:repositories.bzl", "IO_GRPC_GRPC_JAVA_OVERRIDE_TARGETS", "grpc_java_repositories") load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") load("@com_grail_bazel_toolchain//toolchain:rules.bzl", "llvm_toolchain") -load("@io_bazel_rules_k8s//k8s:k8s.bzl", "k8s_repositories") IO_NETTY_MODULES = [ "buffer", @@ -133,8 +132,6 @@ def buildfarm_init(name = "buildfarm"): grpc_java_repositories() - k8s_repositories() - native.bind( name = "jar/redis/clients/jedis", actual = "@jedis//jar", diff --git a/deps.bzl b/deps.bzl index 51dfbb953b..1d9f015226 100644 --- a/deps.bzl +++ b/deps.bzl @@ -25,14 +25,6 @@ def archive_dependencies(third_party): "url": "https://github.com/bazelbuild/rules_jvm_external/releases/download/%s/rules_jvm_external-%s.tar.gz" % (RULES_JVM_EXTERNAL_TAG, RULES_JVM_EXTERNAL_TAG), }, - # Kubernetes rules. Useful for local development with tilt. - { - "name": "io_bazel_rules_k8s", - "strip_prefix": "rules_k8s-0.7", - "url": "https://github.com/bazelbuild/rules_k8s/archive/refs/tags/v0.7.tar.gz", - "sha256": "ce5b9bc0926681e2e7f2147b49096f143e6cbc783e71bc1d4f36ca76b00e6f4a", - }, - # Needed for "well-known protos" and @com_google_protobuf//:protoc. { "name": "com_google_protobuf", diff --git a/kubernetes/deployments/BUILD b/kubernetes/deployments/BUILD deleted file mode 100644 index cd2051dce8..0000000000 --- a/kubernetes/deployments/BUILD +++ /dev/null @@ -1,25 +0,0 @@ -load("@io_bazel_rules_k8s//k8s:object.bzl", "k8s_object") - -k8s_object( - name = "kubernetes", - kind = "deployment", - template = ":kubernetes.yaml", -) - -k8s_object( - name = "server", - kind = "deployment", - template = ":server.yaml", -) - -k8s_object( - name = "shard-worker", - kind = "deployment", - template = ":shard-worker.yaml", -) - -k8s_object( - name = "redis-cluster", - kind = "deployment", - template = ":redis-cluster.yaml", -) diff --git a/kubernetes/deployments/kubernetes.yaml b/kubernetes/deployments/kubernetes.yaml deleted file mode 100644 index 5bc400448e..0000000000 --- a/kubernetes/deployments/kubernetes.yaml +++ /dev/null @@ -1,303 +0,0 @@ -# Copyright 2017 The Kubernetes Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -apiVersion: v1 -kind: Namespace -metadata: - name: kubernetes-dashboard - ---- - -apiVersion: v1 -kind: ServiceAccount -metadata: - labels: - k8s-app: kubernetes-dashboard - name: kubernetes-dashboard - namespace: kubernetes-dashboard - ---- - -kind: Service -apiVersion: v1 -metadata: - labels: - k8s-app: kubernetes-dashboard - name: kubernetes-dashboard - namespace: kubernetes-dashboard -spec: - ports: - - port: 443 - targetPort: 8443 - selector: - k8s-app: kubernetes-dashboard - ---- - -apiVersion: v1 -kind: Secret -metadata: - labels: - k8s-app: kubernetes-dashboard - name: kubernetes-dashboard-certs - namespace: kubernetes-dashboard -type: Opaque - ---- - -apiVersion: v1 -kind: Secret -metadata: - labels: - k8s-app: kubernetes-dashboard - name: kubernetes-dashboard-csrf - namespace: kubernetes-dashboard -type: Opaque -data: - csrf: "" - ---- - -apiVersion: v1 -kind: Secret -metadata: - labels: - k8s-app: kubernetes-dashboard - name: kubernetes-dashboard-key-holder - namespace: kubernetes-dashboard -type: Opaque - ---- - -kind: ConfigMap -apiVersion: v1 -metadata: - labels: - k8s-app: kubernetes-dashboard - name: kubernetes-dashboard-settings - namespace: kubernetes-dashboard - ---- - -kind: Role -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - labels: - k8s-app: kubernetes-dashboard - name: kubernetes-dashboard - namespace: kubernetes-dashboard -rules: - # Allow Dashboard to get, update and delete Dashboard exclusive secrets. - - apiGroups: [""] - resources: ["secrets"] - resourceNames: ["kubernetes-dashboard-key-holder", "kubernetes-dashboard-certs", "kubernetes-dashboard-csrf"] - verbs: ["get", "update", "delete"] - # Allow Dashboard to get and update 'kubernetes-dashboard-settings' config map. - - apiGroups: [""] - resources: ["configmaps"] - resourceNames: ["kubernetes-dashboard-settings"] - verbs: ["get", "update"] - # Allow Dashboard to get metrics. - - apiGroups: [""] - resources: ["services"] - resourceNames: ["heapster", "dashboard-metrics-scraper"] - verbs: ["proxy"] - - apiGroups: [""] - resources: ["services/proxy"] - resourceNames: ["heapster", "http:heapster:", "https:heapster:", "dashboard-metrics-scraper", "http:dashboard-metrics-scraper"] - verbs: ["get"] - ---- - -kind: ClusterRole -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - labels: - k8s-app: kubernetes-dashboard - name: kubernetes-dashboard -rules: - # Allow Metrics Scraper to get metrics from the Metrics server - - apiGroups: ["metrics.k8s.io"] - resources: ["pods", "nodes"] - verbs: ["get", "list", "watch"] - ---- - -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - labels: - k8s-app: kubernetes-dashboard - name: kubernetes-dashboard - namespace: kubernetes-dashboard -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: kubernetes-dashboard -subjects: - - kind: ServiceAccount - name: kubernetes-dashboard - namespace: kubernetes-dashboard - ---- - -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: kubernetes-dashboard -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: kubernetes-dashboard -subjects: - - kind: ServiceAccount - name: kubernetes-dashboard - namespace: kubernetes-dashboard - ---- - -kind: Deployment -apiVersion: apps/v1 -metadata: - labels: - k8s-app: kubernetes-dashboard - name: kubernetes-dashboard - namespace: kubernetes-dashboard -spec: - replicas: 1 - revisionHistoryLimit: 10 - selector: - matchLabels: - k8s-app: kubernetes-dashboard - template: - metadata: - labels: - k8s-app: kubernetes-dashboard - spec: - containers: - - name: kubernetes-dashboard - image: kubernetesui/dashboard:v2.4.0 - imagePullPolicy: Always - ports: - - containerPort: 8443 - protocol: TCP - args: - - --auto-generate-certificates - - --namespace=kubernetes-dashboard - # Uncomment the following line to manually specify Kubernetes API server Host - # If not specified, Dashboard will attempt to auto discover the API server and connect - # to it. Uncomment only if the default does not work. - # - --apiserver-host=http://my-address:port - volumeMounts: - - name: kubernetes-dashboard-certs - mountPath: /certs - # Create on-disk volume to store exec logs - - mountPath: /tmp - name: tmp-volume - livenessProbe: - httpGet: - scheme: HTTPS - path: / - port: 8443 - initialDelaySeconds: 30 - timeoutSeconds: 30 - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - runAsUser: 1001 - runAsGroup: 2001 - volumes: - - name: kubernetes-dashboard-certs - secret: - secretName: kubernetes-dashboard-certs - - name: tmp-volume - emptyDir: {} - serviceAccountName: kubernetes-dashboard - nodeSelector: - "kubernetes.io/os": linux - # Comment the following tolerations if Dashboard must not be deployed on master - tolerations: - - key: node-role.kubernetes.io/master - effect: NoSchedule - ---- - -kind: Service -apiVersion: v1 -metadata: - labels: - k8s-app: dashboard-metrics-scraper - name: dashboard-metrics-scraper - namespace: kubernetes-dashboard -spec: - ports: - - port: 8000 - targetPort: 8000 - selector: - k8s-app: dashboard-metrics-scraper - ---- - -kind: Deployment -apiVersion: apps/v1 -metadata: - labels: - k8s-app: dashboard-metrics-scraper - name: dashboard-metrics-scraper - namespace: kubernetes-dashboard -spec: - replicas: 1 - revisionHistoryLimit: 10 - selector: - matchLabels: - k8s-app: dashboard-metrics-scraper - template: - metadata: - labels: - k8s-app: dashboard-metrics-scraper - spec: - securityContext: - seccompProfile: - type: RuntimeDefault - containers: - - name: dashboard-metrics-scraper - image: kubernetesui/metrics-scraper:v1.0.7 - ports: - - containerPort: 8000 - protocol: TCP - livenessProbe: - httpGet: - scheme: HTTP - path: / - port: 8000 - initialDelaySeconds: 30 - timeoutSeconds: 30 - volumeMounts: - - mountPath: /tmp - name: tmp-volume - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - runAsUser: 1001 - runAsGroup: 2001 - serviceAccountName: kubernetes-dashboard - nodeSelector: - "kubernetes.io/os": linux - # Comment the following tolerations if Dashboard must not be deployed on master - tolerations: - - key: node-role.kubernetes.io/master - effect: NoSchedule - volumes: - - name: tmp-volume - emptyDir: {} diff --git a/kubernetes/deployments/redis-cluster.yaml b/kubernetes/deployments/redis-cluster.yaml deleted file mode 100644 index 9cd6263d45..0000000000 --- a/kubernetes/deployments/redis-cluster.yaml +++ /dev/null @@ -1,22 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: redis-cluster - labels: - name: redis-cluster -spec: - replicas: 1 - selector: - matchLabels: - name: redis-cluster - template: - metadata: - labels: - name: redis-cluster - spec: - #subdomain: primary - containers: - - name: redis-cluster - image: redis:5.0.4 - ports: - - containerPort: 6379 diff --git a/kubernetes/deployments/server.yaml b/kubernetes/deployments/server.yaml deleted file mode 100644 index 163f65697f..0000000000 --- a/kubernetes/deployments/server.yaml +++ /dev/null @@ -1,28 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: server - labels: - name: server -spec: - replicas: 1 - selector: - matchLabels: - name: server - template: - metadata: - labels: - name: server - spec: - containers: - - name: server - image: buildfarm-server-image - ports: - - containerPort: 8980 - name: "server-comm" - - containerPort: 9092 - name: "server-metrics" - env: - - name: REDIS_URI - value: "redis://redis-cluster-service:6379" - diff --git a/kubernetes/deployments/shard-worker.yaml b/kubernetes/deployments/shard-worker.yaml deleted file mode 100644 index 7a914b6db0..0000000000 --- a/kubernetes/deployments/shard-worker.yaml +++ /dev/null @@ -1,32 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: shard-worker - labels: - name: shard-worker -spec: - replicas: 1 - selector: - matchLabels: - name: shard-worker - template: - metadata: - labels: - name: shard-worker - spec: - containers: - - name: shard-worker - image: buildfarm-shard-worker-image - resources: - limits: - cpu: "2" - requests: - cpu: "2" - ports: - - containerPort: 8981 - name: "worker-comm" - - containerPort: 9091 - name: "worker-metrics" - env: - - name: REDIS_URI - value: "redis://redis-cluster-service:6379" diff --git a/kubernetes/services/BUILD b/kubernetes/services/BUILD deleted file mode 100644 index 071e6344f7..0000000000 --- a/kubernetes/services/BUILD +++ /dev/null @@ -1,31 +0,0 @@ -load("@io_bazel_rules_k8s//k8s:object.bzl", "k8s_object") - -k8s_object( - name = "redis-cluster", - kind = "service", - template = ":redis-cluster.yaml", -) - -k8s_object( - name = "shard-worker", - kind = "service", - template = ":shard-worker.yaml", -) - -k8s_object( - name = "open-telemetry", - kind = "service", - template = ":open-telemetry.yaml", -) - -k8s_object( - name = "jaeger", - kind = "service", - template = ":jaeger.yaml", -) - -k8s_object( - name = "grafana", - kind = "service", - template = ":grafana.yaml", -) diff --git a/kubernetes/services/grafana.yaml b/kubernetes/services/grafana.yaml deleted file mode 100644 index b87cbef235..0000000000 --- a/kubernetes/services/grafana.yaml +++ /dev/null @@ -1,82 +0,0 @@ ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: grafana-pvc -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 1Gi ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - app: grafana - name: grafana -spec: - selector: - matchLabels: - app: grafana - template: - metadata: - labels: - app: grafana - spec: - securityContext: - fsGroup: 472 - supplementalGroups: - - 0 - containers: - - name: grafana - image: grafana/grafana:8.2.5 - imagePullPolicy: IfNotPresent - ports: - - containerPort: 3000 - name: http-grafana - protocol: TCP - readinessProbe: - failureThreshold: 3 - httpGet: - path: /robots.txt - port: 3000 - scheme: HTTP - initialDelaySeconds: 10 - periodSeconds: 30 - successThreshold: 1 - timeoutSeconds: 2 - livenessProbe: - failureThreshold: 3 - initialDelaySeconds: 30 - periodSeconds: 10 - successThreshold: 1 - tcpSocket: - port: 3000 - timeoutSeconds: 1 - resources: - requests: - cpu: 250m - memory: 750Mi - volumeMounts: - - mountPath: /var/lib/grafana - name: grafana-pv - volumes: - - name: grafana-pv - persistentVolumeClaim: - claimName: grafana-pvc ---- -apiVersion: v1 -kind: Service -metadata: - name: grafana -spec: - ports: - - port: 3000 - protocol: TCP - targetPort: http-grafana - selector: - app: grafana - sessionAffinity: None - type: LoadBalancer \ No newline at end of file diff --git a/kubernetes/services/jaeger.yaml b/kubernetes/services/jaeger.yaml deleted file mode 100644 index d5900caf6b..0000000000 --- a/kubernetes/services/jaeger.yaml +++ /dev/null @@ -1,305 +0,0 @@ ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - creationTimestamp: null - labels: - app: jaeger - app.kubernetes.io/component: service-account - app.kubernetes.io/instance: simplest - app.kubernetes.io/managed-by: jaeger-operator - app.kubernetes.io/name: simplest - app.kubernetes.io/part-of: jaeger - name: simplest ---- -apiVersion: v1 -data: - sampling: '{"default_strategy":{"param":1,"type":"probabilistic"}}' -kind: ConfigMap -metadata: - creationTimestamp: null - labels: - app: jaeger - app.kubernetes.io/component: sampling-configuration - app.kubernetes.io/instance: simplest - app.kubernetes.io/managed-by: jaeger-operator - app.kubernetes.io/name: simplest-sampling-configuration - app.kubernetes.io/part-of: jaeger - name: simplest-sampling-configuration ---- -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - creationTimestamp: null - labels: - app: jaeger - app.kubernetes.io/component: query-ingress - app.kubernetes.io/instance: simplest - app.kubernetes.io/managed-by: jaeger-operator - app.kubernetes.io/name: simplest-query - app.kubernetes.io/part-of: jaeger - name: simplest-query -spec: - defaultBackend: - service: - name: simplest-query - port: - number: 16686 -status: - loadBalancer: {} ---- -apiVersion: v1 -kind: Service -metadata: - annotations: - prometheus.io/scrape: "false" - service.beta.openshift.io/serving-cert-secret-name: simplest-collector-headless-tls - creationTimestamp: null - labels: - app: jaeger - app.kubernetes.io/component: service-collector - app.kubernetes.io/instance: simplest - app.kubernetes.io/managed-by: jaeger-operator - app.kubernetes.io/name: simplest-collector - app.kubernetes.io/part-of: jaeger - name: simplest-collector-headless -spec: - clusterIP: None - ports: - - name: http-zipkin - port: 9411 - targetPort: 0 - - name: grpc-http - port: 14250 - targetPort: 0 - - name: c-tchan-trft - port: 14267 - targetPort: 0 - - name: http-c-binary-trft - port: 14268 - targetPort: 0 - selector: - app: jaeger - app.kubernetes.io/component: all-in-one - app.kubernetes.io/instance: simplest - app.kubernetes.io/managed-by: jaeger-operator - app.kubernetes.io/name: simplest - app.kubernetes.io/part-of: jaeger -status: - loadBalancer: {} ---- -apiVersion: v1 -kind: Service -metadata: - creationTimestamp: null - labels: - app: jaeger - app.kubernetes.io/component: service-collector - app.kubernetes.io/instance: simplest - app.kubernetes.io/managed-by: jaeger-operator - app.kubernetes.io/name: simplest-collector - app.kubernetes.io/part-of: jaeger - name: simplest-collector -spec: - ports: - - name: http-zipkin - port: 9411 - targetPort: 0 - - name: grpc-http - port: 14250 - targetPort: 0 - - name: c-tchan-trft - port: 14267 - targetPort: 0 - - name: http-c-binary-trft - port: 14268 - targetPort: 0 - selector: - app: jaeger - app.kubernetes.io/component: all-in-one - app.kubernetes.io/instance: simplest - app.kubernetes.io/managed-by: jaeger-operator - app.kubernetes.io/name: simplest - app.kubernetes.io/part-of: jaeger - type: ClusterIP -status: - loadBalancer: {} ---- -apiVersion: v1 -kind: Service -metadata: - creationTimestamp: null - labels: - app: jaeger - app.kubernetes.io/component: service-query - app.kubernetes.io/instance: simplest - app.kubernetes.io/managed-by: jaeger-operator - app.kubernetes.io/name: simplest-query - app.kubernetes.io/part-of: jaeger - name: simplest-query -spec: - ports: - - name: http-query - port: 16686 - targetPort: 16686 - - name: grpc-query - port: 16685 - targetPort: 16685 - selector: - app: jaeger - app.kubernetes.io/component: all-in-one - app.kubernetes.io/instance: simplest - app.kubernetes.io/managed-by: jaeger-operator - app.kubernetes.io/name: simplest - app.kubernetes.io/part-of: jaeger - type: ClusterIP -status: - loadBalancer: {} ---- -apiVersion: v1 -kind: Service -metadata: - creationTimestamp: null - labels: - app: jaeger - app.kubernetes.io/component: service-agent - app.kubernetes.io/instance: simplest - app.kubernetes.io/managed-by: jaeger-operator - app.kubernetes.io/name: simplest-agent - app.kubernetes.io/part-of: jaeger - name: simplest-agent -spec: - clusterIP: None - ports: - - name: zk-compact-trft - port: 5775 - protocol: UDP - targetPort: 0 - - name: config-rest - port: 5778 - targetPort: 0 - - name: jg-compact-trft - port: 6831 - protocol: UDP - targetPort: 0 - - name: jg-binary-trft - port: 6832 - protocol: UDP - targetPort: 0 - selector: - app: jaeger - app.kubernetes.io/component: all-in-one - app.kubernetes.io/instance: simplest - app.kubernetes.io/managed-by: jaeger-operator - app.kubernetes.io/name: simplest - app.kubernetes.io/part-of: jaeger -status: - loadBalancer: {} ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - annotations: - linkerd.io/inject: disabled - prometheus.io/port: "14269" - prometheus.io/scrape: "true" - sidecar.istio.io/inject: "false" - creationTimestamp: null - labels: - app: jaeger - app.kubernetes.io/component: all-in-one - app.kubernetes.io/instance: simplest - app.kubernetes.io/managed-by: jaeger-operator - app.kubernetes.io/name: simplest - app.kubernetes.io/part-of: jaeger - name: simplest -spec: - selector: - matchLabels: - app: jaeger - app.kubernetes.io/component: all-in-one - app.kubernetes.io/instance: simplest - app.kubernetes.io/managed-by: jaeger-operator - app.kubernetes.io/name: simplest - app.kubernetes.io/part-of: jaeger - strategy: - type: Recreate - template: - metadata: - annotations: - linkerd.io/inject: disabled - prometheus.io/port: "14269" - prometheus.io/scrape: "true" - sidecar.istio.io/inject: "false" - creationTimestamp: null - labels: - app: jaeger - app.kubernetes.io/component: all-in-one - app.kubernetes.io/instance: simplest - app.kubernetes.io/managed-by: jaeger-operator - app.kubernetes.io/name: simplest - app.kubernetes.io/part-of: jaeger - spec: - containers: - - args: - - --sampling.strategies-file=/etc/jaeger/sampling/sampling.json - env: - - name: SPAN_STORAGE_TYPE - value: memory - - name: COLLECTOR_ZIPKIN_HOST_PORT - value: :9411 - - name: JAEGER_DISABLED - value: "false" - image: jaegertracing/all-in-one:1.30.0 - livenessProbe: - failureThreshold: 5 - httpGet: - path: / - port: 14269 - initialDelaySeconds: 5 - periodSeconds: 15 - name: jaeger - ports: - - containerPort: 5775 - name: zk-compact-trft - protocol: UDP - - containerPort: 5778 - name: config-rest - - containerPort: 6831 - name: jg-compact-trft - protocol: UDP - - containerPort: 6832 - name: jg-binary-trft - protocol: UDP - - containerPort: 9411 - name: zipkin - - containerPort: 14267 - name: c-tchan-trft - - containerPort: 14268 - name: c-binary-trft - - containerPort: 16686 - name: query - - containerPort: 14269 - name: admin-http - - containerPort: 14250 - name: grpc - readinessProbe: - httpGet: - path: / - port: 14269 - initialDelaySeconds: 1 - resources: {} - volumeMounts: - - mountPath: /etc/jaeger/sampling - name: simplest-sampling-configuration-volume - readOnly: true - enableServiceLinks: false - serviceAccountName: simplest - volumes: - - configMap: - items: - - key: sampling - path: sampling.json - name: simplest-sampling-configuration - name: simplest-sampling-configuration-volume -status: {} diff --git a/kubernetes/services/open-telemetry.yaml b/kubernetes/services/open-telemetry.yaml deleted file mode 100644 index 494b8504e5..0000000000 --- a/kubernetes/services/open-telemetry.yaml +++ /dev/null @@ -1,218 +0,0 @@ ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: otel-agent-conf - labels: - app: opentelemetry - component: otel-agent-conf -data: - otel-agent-config: | - receivers: - otlp: - protocols: - grpc: - http: - exporters: - otlp: - endpoint: "otel-collector.default:4317" - tls: - insecure: true - sending_queue: - num_consumers: 4 - queue_size: 100 - retry_on_failure: - enabled: true - processors: - batch: - memory_limiter: - # 80% of maximum memory up to 2G - limit_mib: 400 - # 25% of limit up to 2G - spike_limit_mib: 100 - check_interval: 5s - extensions: - zpages: {} - memory_ballast: - # Memory Ballast size should be max 1/3 to 1/2 of memory. - size_mib: 165 - service: - extensions: [zpages, memory_ballast] - pipelines: - traces: - receivers: [otlp] - processors: [memory_limiter, batch] - exporters: [otlp] ---- -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: otel-agent - labels: - app: opentelemetry - component: otel-agent -spec: - selector: - matchLabels: - app: opentelemetry - component: otel-agent - template: - metadata: - labels: - app: opentelemetry - component: otel-agent - spec: - containers: - - command: - - "/otelcol" - - "--config=/conf/otel-agent-config.yaml" - image: otel/opentelemetry-collector:0.38.0 - name: otel-agent - resources: - limits: - cpu: 500m - memory: 500Mi - requests: - cpu: 100m - memory: 100Mi - ports: - - containerPort: 55679 # ZPages endpoint. - - containerPort: 4317 # Default OpenTelemetry receiver port. - - containerPort: 8888 # Metrics. - volumeMounts: - - name: otel-agent-config-vol - mountPath: /conf - volumes: - - configMap: - name: otel-agent-conf - items: - - key: otel-agent-config - path: otel-agent-config.yaml - name: otel-agent-config-vol ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: otel-collector-conf - labels: - app: opentelemetry - component: otel-collector-conf -data: - otel-collector-config: | - receivers: - otlp: - protocols: - grpc: - http: - processors: - batch: - memory_limiter: - # 80% of maximum memory up to 2G - limit_mib: 1500 - # 25% of limit up to 2G - spike_limit_mib: 512 - check_interval: 5s - extensions: - zpages: {} - memory_ballast: - # Memory Ballast size should be max 1/3 to 1/2 of memory. - size_mib: 683 - exporters: - otlp: - endpoint: "http://someotlp.target.com:4317" # Replace with a real endpoint. - tls: - insecure: true - jaeger: - endpoint: "simplest-collector:14250" - tls: - insecure: true - service: - extensions: [zpages, memory_ballast] - pipelines: - traces/1: - receivers: [otlp] - processors: [memory_limiter, batch] - exporters: [jaeger] ---- -apiVersion: v1 -kind: Service -metadata: - name: otel-collector - labels: - app: opentelemetry - component: otel-collector -spec: - ports: - - name: otlp-grpc # Default endpoint for OpenTelemetry gRPC receiver. - port: 4317 - protocol: TCP - targetPort: 4317 - - name: otlp-http # Default endpoint for OpenTelemetry HTTP receiver. - port: 4318 - protocol: TCP - targetPort: 4318 - - name: metrics # Default endpoint for querying metrics. - port: 8888 - selector: - component: otel-collector ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: otel-collector - labels: - app: opentelemetry - component: otel-collector -spec: - selector: - matchLabels: - app: opentelemetry - component: otel-collector - minReadySeconds: 5 - progressDeadlineSeconds: 120 - replicas: 1 #TODO - adjust this to your own requirements - template: - metadata: - labels: - app: opentelemetry - component: otel-collector - spec: - containers: - - command: - - "/otelcol" - - "--config=/conf/otel-collector-config.yaml" - image: otel/opentelemetry-collector:0.38.0 - name: otel-collector - resources: - limits: - cpu: 1 - memory: 2Gi - requests: - cpu: 200m - memory: 400Mi - ports: - - containerPort: 55679 # Default endpoint for ZPages. - - containerPort: 4317 # Default endpoint for OpenTelemetry receiver. - - containerPort: 14250 # Default endpoint for Jaeger gRPC receiver. - - containerPort: 14268 # Default endpoint for Jaeger HTTP receiver. - - containerPort: 9411 # Default endpoint for Zipkin receiver. - - containerPort: 8888 # Default endpoint for querying metrics. - volumeMounts: - - name: otel-collector-config-vol - mountPath: /conf -# - name: otel-collector-secrets -# mountPath: /secrets - volumes: - - configMap: - name: otel-collector-conf - items: - - key: otel-collector-config - path: otel-collector-config.yaml - name: otel-collector-config-vol -# - secret: -# name: otel-collector-secrets -# items: -# - key: cert.pem -# path: cert.pem -# - key: key.pem -# path: key.pem \ No newline at end of file diff --git a/kubernetes/services/redis-cluster.yaml b/kubernetes/services/redis-cluster.yaml deleted file mode 100644 index 116dbcea39..0000000000 --- a/kubernetes/services/redis-cluster.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: redis-cluster-service -spec: - selector: - name: redis-cluster - ports: - - protocol: TCP - port: 6379 - targetPort: 6379 diff --git a/kubernetes/services/shard-worker.yaml b/kubernetes/services/shard-worker.yaml deleted file mode 100644 index 0e89e0f313..0000000000 --- a/kubernetes/services/shard-worker.yaml +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: shard-worker-service -spec: - selector: - name: shard-worker - ports: - - name: "communication" - protocol: TCP - port: 8981 - targetPort: 8981 - - name: "metrics" - protocol: TCP - port: 9091 - targetPort: 9091 - From 2870a3ffd68a255d26eaa8f066a2d4b13d2701b8 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Thu, 21 Dec 2023 12:08:03 -0800 Subject: [PATCH 185/311] chore: bump rules_license to 0.0.7 (#1585) Updating rules_license https://github.com/bazelbuild/rules_license/releases/tag/0.0.7 --- deps.bzl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deps.bzl b/deps.bzl index 1d9f015226..00260e5ccd 100644 --- a/deps.bzl +++ b/deps.bzl @@ -56,10 +56,10 @@ def archive_dependencies(third_party): }, { "name": "rules_license", - "sha256": "6157e1e68378532d0241ecd15d3c45f6e5cfd98fc10846045509fb2a7cc9e381", + "sha256": "4531deccb913639c30e5c7512a054d5d875698daeb75d8cf90f284375fe7c360", "urls": [ - "https://github.com/bazelbuild/rules_license/releases/download/0.0.4/rules_license-0.0.4.tar.gz", - "https://mirror.bazel.build/github.com/bazelbuild/rules_license/releases/download/0.0.4/rules_license-0.0.4.tar.gz", + "https://mirror.bazel.build/github.com/bazelbuild/rules_license/releases/download/0.0.7/rules_license-0.0.7.tar.gz", + "https://github.com/bazelbuild/rules_license/releases/download/0.0.7/rules_license-0.0.7.tar.gz", ], }, From 1b52ac01a4e6869f9015e39cb7b0cc423236264d Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Thu, 21 Dec 2023 12:10:32 -0800 Subject: [PATCH 186/311] Bump rules_go and gazelle (#1584) * deps: bump rules_go Updating to 0.43.0 https://github.com/bazelbuild/rules_go/releases/tag/v0.43.0 * deps: bump gazelle Updating to 0.34.0 https://github.com/bazelbuild/bazel-gazelle/releases/tag/v0.34.0 --- deps.bzl | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/deps.bzl b/deps.bzl index 00260e5ccd..a289610b23 100644 --- a/deps.bzl +++ b/deps.bzl @@ -111,16 +111,19 @@ def archive_dependencies(third_party): # Updated versions of io_bazel_rules_docker dependencies for bazel compatibility { "name": "io_bazel_rules_go", - "sha256": "278b7ff5a826f3dc10f04feaf0b70d48b68748ccd512d7f98bf442077f043fe3", + "sha256": "d6ab6b57e48c09523e93050f13698f708428cfd5e619252e369d377af6597707", "urls": [ - "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.41.0/rules_go-v0.41.0.zip", - "https://github.com/bazelbuild/rules_go/releases/download/v0.41.0/rules_go-v0.41.0.zip", + "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.43.0/rules_go-v0.43.0.zip", + "https://github.com/bazelbuild/rules_go/releases/download/v0.43.0/rules_go-v0.43.0.zip", ], }, { "name": "bazel_gazelle", - "sha256": "d3fa66a39028e97d76f9e2db8f1b0c11c099e8e01bf363a923074784e451f809", - "urls": ["https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.33.0/bazel-gazelle-v0.33.0.tar.gz"], + "sha256": "b7387f72efb59f876e4daae42f1d3912d0d45563eac7cb23d1de0b094ab588cf", + "urls": [ + "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.34.0/bazel-gazelle-v0.34.0.tar.gz", + "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.34.0/bazel-gazelle-v0.34.0.tar.gz", + ], }, # Bazel is referenced as a dependency so that buildfarm can access the linux-sandbox as a potential execution wrapper. From 78b001c06f08d97b8e9f2b25399b852fd013988b Mon Sep 17 00:00:00 2001 From: Trevor Hickey Date: Tue, 2 Jan 2024 08:29:04 -0500 Subject: [PATCH 187/311] [CI] skip server/worker audit on mac (#1592) * do not audit server/worker jars on mac Avoid python dependencies on mac unit test CI * Update presubmit.yml comment reference to underlying issue --------- Co-authored-by: George Gensure --- .bazelci/presubmit.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index dfdf37f892..43aeba5380 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -63,7 +63,8 @@ tasks: USE_BAZEL_VERSION: 17be878292730359c9c90efdceabed26126df7ae build_flags: - "--cxxopt=-std=c++14" - - "--build_tag_filters=-container" + # FIXME: remove audit subtraction when https://github.com/bazelbuild/bazel-buildfarm/issues/1595 fixed + - "--build_tag_filters=-container,-audit" build_targets: - "..." test_flags: From b5425e0045d65b266bcee5991c0b8cbf9ee7a35b Mon Sep 17 00:00:00 2001 From: Andrew Rothstein Date: Tue, 2 Jan 2024 10:22:39 -0500 Subject: [PATCH 188/311] Helm Chart: latest image tags not v-prefixed (#1591) * latest images with versions not v-prefixed * stage 0.2.0 of the Helm chart --- README.md | 2 +- kubernetes/helm-charts/buildfarm/Chart.yaml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ab861d609e..fa66df79c8 100644 --- a/README.md +++ b/README.md @@ -142,5 +142,5 @@ helm install \ -n bazel-buildfarm \ --create-namespace \ bazel-buildfarm \ - "https://github.com/bazelbuild/bazel-buildfarm/releases/download/${BUILDFARM_VERSION:-2.7.1}/buildfarm-${CHART_VERSION:-0.1.0}.tgz" + "https://github.com/bazelbuild/bazel-buildfarm/releases/download/${BUILDFARM_VERSION:-2.8.0}/buildfarm-${CHART_VERSION:-0.2.0}.tgz" ``` diff --git a/kubernetes/helm-charts/buildfarm/Chart.yaml b/kubernetes/helm-charts/buildfarm/Chart.yaml index ce443957dd..dc92b0f61b 100644 --- a/kubernetes/helm-charts/buildfarm/Chart.yaml +++ b/kubernetes/helm-charts/buildfarm/Chart.yaml @@ -15,16 +15,16 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.0 +version: 0.2.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "v2.5.0" +appVersion: 2.8.0 dependencies: - condition: redis.enabled name: redis repository: https://charts.helm.sh/stable - version: 10.5.7 \ No newline at end of file + version: 10.5.7 From 41b44945751a6fe9ab5de93f5288f2310ae08b48 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Tue, 2 Jan 2024 16:23:58 -0500 Subject: [PATCH 189/311] Update helm values to use safe defaults (#1597) Removed values which will likely cause problems for execution and CFC saturation from helm chart: inputFetchStage_width and execute_stage_width both can be discovered from available processors maxSizeBytes for filesystem cas is automatically 90% of underlying file storage, down from a value 10x the actual bytes on storage requested below. path, names, and configuration for root, filesystem, and publicName can all be defaulted/derived safely. --- kubernetes/helm-charts/buildfarm/values.yaml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/kubernetes/helm-charts/buildfarm/values.yaml b/kubernetes/helm-charts/buildfarm/values.yaml index 3bb2994b7a..f1e21a97c9 100644 --- a/kubernetes/helm-charts/buildfarm/values.yaml +++ b/kubernetes/helm-charts/buildfarm/values.yaml @@ -27,16 +27,6 @@ config: recordBesEvents: true worker: port: 8982 - publicName: "localhost:8982" - executeStageWidth: 80 - inputFetchStageWidth: 8 - realInputDirectories: - - "external" - root: "/tmp/worker" - storages: - - type: FILESYSTEM - path: "cache" - maxSizeBytes: 536870912000 # 500 * 1024 * 1024 * 1024 server: image: From 088b8e12f2a5ec8fbfde33f73a1e3077eb2622fe Mon Sep 17 00:00:00 2001 From: George Gensure Date: Tue, 2 Jan 2024 20:56:51 -0500 Subject: [PATCH 190/311] Properly balance over nodes, not slot ranges (#1598) Slot ranges must not associate multiple times on a single node for use with balanced queues designed to be load balanced. --- .../common/redis/RedisNodeHashes.java | 18 +++++++++++++----- .../common/redis/RedisNodeHashesMockTest.java | 10 ++++++++-- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/main/java/build/buildfarm/common/redis/RedisNodeHashes.java b/src/main/java/build/buildfarm/common/redis/RedisNodeHashes.java index 5588ba8adf..689c7d46f4 100644 --- a/src/main/java/build/buildfarm/common/redis/RedisNodeHashes.java +++ b/src/main/java/build/buildfarm/common/redis/RedisNodeHashes.java @@ -15,8 +15,10 @@ package build.buildfarm.common.redis; import com.google.common.collect.ImmutableList; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisCluster; import redis.clients.jedis.JedisPool; @@ -41,7 +43,7 @@ public class RedisNodeHashes { @SuppressWarnings({"unchecked", "rawtypes"}) public static List getEvenlyDistributedHashes(JedisCluster jedis) { try { - List> slotRanges = getSlotRanges(jedis); + List> slotRanges = getNodeSlotRanges(jedis); ImmutableList.Builder hashTags = ImmutableList.builder(); for (List slotRange : slotRanges) { // we can use any slot that is in range for the node. @@ -66,7 +68,7 @@ public static List getEvenlyDistributedHashes(JedisCluster jedis) { public static List getEvenlyDistributedHashesWithPrefix( JedisCluster jedis, String prefix) { try { - List> slotRanges = getSlotRanges(jedis); + List> slotRanges = getNodeSlotRanges(jedis); ImmutableList.Builder hashTags = ImmutableList.builder(); for (List slotRange : slotRanges) { // we can use any slot that is in range for the node. @@ -88,16 +90,22 @@ public static List getEvenlyDistributedHashesWithPrefix( * @note Suggested return identifier: slotRanges. */ @SuppressWarnings("unchecked") - private static List> getSlotRanges(JedisCluster jedis) { + private static List> getNodeSlotRanges(JedisCluster jedis) { // get slot information for each node List slots = getClusterSlots(jedis); + Set nodes = new HashSet<>(); // convert slot information into a list of slot ranges ImmutableList.Builder> slotRanges = ImmutableList.builder(); for (Object slotInfoObj : slots) { List slotInfo = (List) slotInfoObj; - List slotNums = slotInfoToSlotRange(slotInfo); - slotRanges.add(slotNums); + List slotRangeNodes = (List) slotInfo.get(2); + // 2 is primary node id + String nodeId = (String) slotRangeNodes.get(2); + if (nodes.add(nodeId)) { + List slotNums = slotInfoToSlotRange(slotInfo); + slotRanges.add(slotNums); + } } return slotRanges.build(); diff --git a/src/test/java/build/buildfarm/common/redis/RedisNodeHashesMockTest.java b/src/test/java/build/buildfarm/common/redis/RedisNodeHashesMockTest.java index 3d421e6afa..f6627d37e3 100644 --- a/src/test/java/build/buildfarm/common/redis/RedisNodeHashesMockTest.java +++ b/src/test/java/build/buildfarm/common/redis/RedisNodeHashesMockTest.java @@ -47,7 +47,10 @@ public class RedisNodeHashesMockTest { public void getEvenlyDistributedHashesCanRetrieveDistributedHashes() throws Exception { // ARRANGE Jedis node = mock(Jedis.class); - when(node.clusterSlots()).thenReturn(Collections.singletonList(Arrays.asList(0L, 100L))); + when(node.clusterSlots()) + .thenReturn( + Collections.singletonList( + Arrays.asList(0L, 100L, Arrays.asList(null, null, "nodeId")))); JedisPool pool = mock(JedisPool.class); when(pool.getResource()).thenReturn(node); @@ -97,7 +100,10 @@ public void getEvenlyDistributedHashesWithPrefixExpectedPrefixHashes() throws Ex // ARRANGE Jedis node = mock(Jedis.class); when(node.clusterSlots()) - .thenReturn(Arrays.asList(Arrays.asList(0L, 100L), Arrays.asList(101L, 200L))); + .thenReturn( + Arrays.asList( + Arrays.asList(0L, 100L, Arrays.asList(null, null, "nodeId1")), + Arrays.asList(101L, 200L, Arrays.asList(null, null, "nodeId2")))); JedisPool pool = mock(JedisPool.class); when(pool.getResource()).thenReturn(node); From 6b5db62f75b506ab603c262eec24b3ccedb03483 Mon Sep 17 00:00:00 2001 From: Andrew Rothstein Date: Wed, 3 Jan 2024 09:52:01 -0500 Subject: [PATCH 191/311] fix the shard-worker HPA. it is a StatefulSet and not a Deployment (#1596) --- .../buildfarm/templates/shard-worker/autoscaler.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kubernetes/helm-charts/buildfarm/templates/shard-worker/autoscaler.yaml b/kubernetes/helm-charts/buildfarm/templates/shard-worker/autoscaler.yaml index 4389c793b6..5cdfe05e1f 100644 --- a/kubernetes/helm-charts/buildfarm/templates/shard-worker/autoscaler.yaml +++ b/kubernetes/helm-charts/buildfarm/templates/shard-worker/autoscaler.yaml @@ -15,7 +15,7 @@ spec: minReplicas: {{ .Values.shardWorker.autoscaling.minReplicas }} scaleTargetRef: apiVersion: apps/v1 - kind: Deployment + kind: StatefulSet name: {{ include "buildfarm.fullname" . }}-shard-worker targetCPUUtilizationPercentage: {{ .Values.shardWorker.autoscaling.targetCPUUtilizationPercentage }} {{- end }} From 413021d940da9d2f0569fb5a3823548030e66dc8 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Wed, 3 Jan 2024 09:52:12 -0500 Subject: [PATCH 192/311] Use integer ids for Sqlite bidirectional index (#1599) The cost in size for a single table bidirectional index is vast compared to the use of 3nf integer keys. Experimental estimates offer a decrease in file size of 90%. --- .../cas/cfc/SqliteFileDirectoriesIndex.java | 65 +++++++++++++++---- .../cas/cfc/DirectoriesIndexTest.java | 1 + 2 files changed, 55 insertions(+), 11 deletions(-) diff --git a/src/main/java/build/buildfarm/cas/cfc/SqliteFileDirectoriesIndex.java b/src/main/java/build/buildfarm/cas/cfc/SqliteFileDirectoriesIndex.java index 030c749037..e634616660 100644 --- a/src/main/java/build/buildfarm/cas/cfc/SqliteFileDirectoriesIndex.java +++ b/src/main/java/build/buildfarm/cas/cfc/SqliteFileDirectoriesIndex.java @@ -57,13 +57,19 @@ private void open() { throw new RuntimeException(e); } + String createDirectoriesSql = + "CREATE TABLE directories (id INTEGER PRIMARY KEY, name VARCHAR UNIQUE)"; + String createFilesSql = "CREATE TABLE files (id INTEGER PRIMARY KEY, name VARCHAR UNIQUE)"; String createEntriesSql = "CREATE TABLE entries (\n" - + " path TEXT NOT NULL,\n" - + " directory TEXT NOT NULL\n" + + " file_id INTEGER NOT NULL REFERENCES files(id) ON DELETE CASCADE,\n" + + " directory_id INTEGER NOT NULL REFERENCES directories(id) ON DELETE CASCADE,\n" + + " PRIMARY KEY (file_id, directory_id)\n" + ")"; try (Statement stmt = conn.createStatement()) { + stmt.execute(createDirectoriesSql); + stmt.execute(createFilesSql); stmt.execute(createEntriesSql); } catch (SQLException e) { throw new RuntimeException(e); @@ -77,11 +83,13 @@ private void open() { public synchronized void start() { open(); - String createPathIndexSql = "CREATE INDEX path_idx ON entries (path)"; - String createDirectoryIndexSql = "CREATE INDEX directory_idx ON entries (directory)"; + String createPathIndexSql = "CREATE INDEX file_idx ON entries (file_id)"; + String createDirectoryIndexSql = "CREATE INDEX directory_idx ON entries (directory_id)"; + String enforceForeignKeys = "PRAGMA foreign_keys=ON"; try (Statement stmt = conn.createStatement()) { stmt.execute(createPathIndexSql); stmt.execute(createDirectoryIndexSql); + stmt.execute(enforceForeignKeys); } catch (SQLException e) { throw new RuntimeException(e); } @@ -101,7 +109,8 @@ public void close() { private Set removeEntryDirectories(String entry) { open(); - String selectSql = "SELECT directory FROM entries WHERE path = ?"; + String selectSql = + "SELECT d.name as directory FROM files f INNER JOIN entries e ON f.id = e.file_id INNER JOIN directories d ON d.id = e.directory_id WHERE f.name = ?"; ImmutableSet.Builder directoriesBuilder = ImmutableSet.builder(); try (PreparedStatement selectStatement = conn.prepareStatement(selectSql)) { @@ -116,7 +125,7 @@ private Set removeEntryDirectories(String entry) { } // all directories featuring this entry are now invalid ImmutableSet directories = directoriesBuilder.build(); - String deleteSql = "DELETE FROM entries where directory = ?"; + String deleteSql = "DELETE FROM directories where name = ?"; try (PreparedStatement deleteStatement = conn.prepareStatement(deleteSql)) { conn.setAutoCommit(false); for (Digest directory : directories) { @@ -128,6 +137,14 @@ private Set removeEntryDirectories(String entry) { } catch (SQLException e) { throw new RuntimeException(e); } + // clear out orphaned files + try (Statement orphanStatement = conn.createStatement()) { + String deleteOrphanSql = + "DELETE FROM files WHERE id NOT IN (SELECT DISTINCT file_id FROM entries)"; + orphanStatement.execute(deleteOrphanSql); + } catch (SQLException e) { + throw new RuntimeException(e); + } return directories; } @@ -138,16 +155,41 @@ public synchronized Set removeEntry(String entry) throws IOException { return directories; } + // inserts here specifically avoids integer key maintenance in java private synchronized void addEntriesDirectory(Set entries, Digest directory) { open(); - String digest = DigestUtil.toString(directory); - String insertSql = "INSERT INTO entries (path, directory) VALUES (?,?)"; - try (PreparedStatement insertStatement = conn.prepareStatement(insertSql)) { + String directoryName = DigestUtil.toString(directory); + String filesInsertSql = "INSERT OR IGNORE INTO files (name) VALUES (?)"; + try (PreparedStatement filesInsertStatement = conn.prepareStatement(filesInsertSql)) { + conn.setAutoCommit(false); + for (String entry : entries) { + filesInsertStatement.setString(1, entry); + filesInsertStatement.addBatch(); + } + filesInsertStatement.executeBatch(); + conn.commit(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + // should be novel directory + String directoriesInsertSql = "INSERT INTO directories (name) VALUES (?)"; + try (PreparedStatement directoriesInsertStatement = + conn.prepareStatement(directoriesInsertSql)) { + conn.setAutoCommit(false); + directoriesInsertStatement.setString(1, directoryName); + directoriesInsertStatement.executeUpdate(); + conn.commit(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + String entriesInsertSql = + "INSERT INTO entries (file_id, directory_id) SELECT f.id, d.id FROM files f, directories d WHERE f.name = ? AND d.name = ?"; + try (PreparedStatement insertStatement = conn.prepareStatement(entriesInsertSql)) { conn.setAutoCommit(false); - insertStatement.setString(2, digest); for (String entry : entries) { insertStatement.setString(1, entry); + insertStatement.setString(2, directoryName); insertStatement.addBatch(); } insertStatement.executeBatch(); @@ -168,8 +210,9 @@ private void removeEntriesDirectory(Digest directory) { open(); String digest = DigestUtil.toString(directory); - String deleteSql = "DELETE FROM entries WHERE directory = ?"; + String deleteSql = "DELETE FROM directories WHERE name = ?"; try (PreparedStatement deleteStatement = conn.prepareStatement(deleteSql)) { + conn.setAutoCommit(true); deleteStatement.setString(1, digest); deleteStatement.executeUpdate(); } catch (SQLException e) { diff --git a/src/test/java/build/buildfarm/cas/cfc/DirectoriesIndexTest.java b/src/test/java/build/buildfarm/cas/cfc/DirectoriesIndexTest.java index 3eec66def7..b4effa2bc8 100644 --- a/src/test/java/build/buildfarm/cas/cfc/DirectoriesIndexTest.java +++ b/src/test/java/build/buildfarm/cas/cfc/DirectoriesIndexTest.java @@ -51,6 +51,7 @@ protected DirectoriesIndexTest(Path root, DirectoriesIndexType type) { } else { throw new IllegalArgumentException("DirectoriesIndex type is not supported."); } + directoriesIndex.start(); } @Before From 16b3aeaf99a6687bd67dc62abe29e17b2c7eae34 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Wed, 3 Jan 2024 10:50:01 -0500 Subject: [PATCH 193/311] Write cleanups (#1600) * Guard against writeObserver null race * Avoid cancellation log for StubWriteOutputStream Cancels will happen for all server->worker uploads on context cancels initiated by clients, and are normal behaviors. * Guarantee null write response for onCompleted Avoid a complaint by gRPC that a client-streaming request was completed without a response * Reset remote CAS write on initial Prevents the StubWriteOutputStream from issuing an unnecessary initial queryWriteStatus. --- .../common/grpc/StubWriteOutputStream.java | 35 ++++++++++++------- .../common/services/WriteStreamObserver.java | 8 ++++- .../worker/shard/RemoteCasWriter.java | 1 + 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/main/java/build/buildfarm/common/grpc/StubWriteOutputStream.java b/src/main/java/build/buildfarm/common/grpc/StubWriteOutputStream.java index 855b650ff9..0b2b7199f0 100644 --- a/src/main/java/build/buildfarm/common/grpc/StubWriteOutputStream.java +++ b/src/main/java/build/buildfarm/common/grpc/StubWriteOutputStream.java @@ -15,6 +15,7 @@ package build.buildfarm.common.grpc; import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; import static com.google.common.util.concurrent.Futures.immediateFuture; import static java.lang.String.format; import static java.util.logging.Level.WARNING; @@ -164,12 +165,18 @@ private void flushSome(boolean finishWrite) { request.setResourceName(resourceName); } synchronized (this) { - writeObserver.onNext(request.build()); + // writeObserver can be nulled by a completion race + // expect that we are completed in this case + if (writeObserver != null) { + writeObserver.onNext(request.build()); + wasReset = false; + writtenBytes += offset; + offset = 0; + sentResourceName = true; + } else { + checkState(writeFuture.isDone(), "writeObserver nulled without completion"); + } } - wasReset = false; - writtenBytes += offset; - offset = 0; - sentResourceName = true; } @Override @@ -231,14 +238,16 @@ public void onNext(WriteResponse response) { @Override public void onError(Throwable t) { - log.log( - WARNING, - format( - "%s: write(%s) on worker %s after %d bytes of content", - Status.fromThrowable(t).getCode().name(), - resourceName, - bsStub.get().getChannel().authority(), - writtenBytes)); + if (Status.fromThrowable(t).getCode() != Code.CANCELLED) { + log.log( + WARNING, + format( + "%s: write(%s) on worker %s after %d bytes of content", + Status.fromThrowable(t).getCode().name(), + resourceName, + bsStub.get().getChannel().authority(), + writtenBytes)); + } writeFuture.setException(exceptionTranslator.apply(t)); } diff --git a/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java b/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java index e1e23fa5b8..2eba90eba5 100644 --- a/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java +++ b/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java @@ -72,6 +72,8 @@ public class WriteStreamObserver implements StreamObserver { private boolean initialized = false; private volatile boolean committed = false; private String name = null; + + @GuardedBy("this") private Write write = null; @GuardedBy("this") @@ -492,9 +494,13 @@ public void onError(Throwable t) { } @Override - public void onCompleted() { + public synchronized void onCompleted() { log.log(Level.FINER, format("write completed for %s", name)); if (write == null) { + // we must return with a response lest we emit a grpc warning + // there can be no meaningful response at this point, as we + // have no idea what the size was + responseObserver.onNext(WriteResponse.getDefaultInstance()); responseObserver.onCompleted(); } } diff --git a/src/main/java/build/buildfarm/worker/shard/RemoteCasWriter.java b/src/main/java/build/buildfarm/worker/shard/RemoteCasWriter.java index b03c2794e7..7c379077a6 100644 --- a/src/main/java/build/buildfarm/worker/shard/RemoteCasWriter.java +++ b/src/main/java/build/buildfarm/worker/shard/RemoteCasWriter.java @@ -84,6 +84,7 @@ private long writeToCasMember(Digest digest, InputStream in) String workerName = getRandomWorker(); Write write = getCasMemberWrite(digest, workerName); + write.reset(); try { return streamIntoWriteFuture(in, write, digest).get(); } catch (ExecutionException e) { From 51608f7dccf4edc8c2b2d285287f13eda09e6fe5 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Wed, 3 Jan 2024 09:32:24 -0800 Subject: [PATCH 194/311] fix: format without placeholders (#1586) These instances of `format(...)` do not have placeholders and there's nothing to format. --- .../java/build/buildfarm/server/services/FetchService.java | 2 +- src/main/java/build/buildfarm/worker/shard/Worker.java | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/build/buildfarm/server/services/FetchService.java b/src/main/java/build/buildfarm/server/services/FetchService.java index 35be1784e2..17a33c68ca 100644 --- a/src/main/java/build/buildfarm/server/services/FetchService.java +++ b/src/main/java/build/buildfarm/server/services/FetchService.java @@ -72,7 +72,7 @@ private void fetchBlob( if (expectedDigest == null) { responseObserver.onError( Status.INVALID_ARGUMENT - .withDescription(format("Missing qualifier 'checksum.sri'")) + .withDescription("Missing qualifier 'checksum.sri'") .asException()); } else if (request.getUrisCount() != 0) { addCallback( diff --git a/src/main/java/build/buildfarm/worker/shard/Worker.java b/src/main/java/build/buildfarm/worker/shard/Worker.java index 6b175e1350..ecfd68e15f 100644 --- a/src/main/java/build/buildfarm/worker/shard/Worker.java +++ b/src/main/java/build/buildfarm/worker/shard/Worker.java @@ -144,8 +144,7 @@ public final class Worker extends LoggingMain { public void prepareWorkerForGracefulShutdown() { if (configs.getWorker().getGracefulShutdownSeconds() == 0) { log.info( - String.format( - "Graceful Shutdown is not enabled. Worker is shutting down without finishing executions in progress.")); + "Graceful Shutdown is not enabled. Worker is shutting down without finishing executions in progress."); } else { inGracefulShutdown = true; log.info( @@ -158,7 +157,7 @@ public void prepareWorkerForGracefulShutdown() { if (pipeline.isEmpty()) { log.info("Graceful Shutdown - no work in the pipeline."); } else { - log.info(String.format("Graceful Shutdown - waiting for executions to finish.")); + log.info("Graceful Shutdown - waiting for executions to finish."); } while (!pipeline.isEmpty() && timeWaited < timeOut) { SECONDS.sleep(scanRate); From 74b1f5685ebb43fca9a3b018469107c6ff82abca Mon Sep 17 00:00:00 2001 From: amishra-u <119983081+amishra-u@users.noreply.github.com> Date: Wed, 3 Jan 2024 10:18:30 -0800 Subject: [PATCH 195/311] chore: Update proto file styling (#1594) * chore: Update proto file styling * fix path * move protp styling to file * add new line at eof --- .bazelci/format.sh | 5 +-- .clang-format | 2 + .../resources/proto/build_event_stream.proto | 24 ++++++++--- .../src/main/resources/proto/buildfarm.proto | 40 ++++++++++++++----- .../main/resources/proto/command_line.proto | 8 +++- .../src/main/resources/proto/descriptor.proto | 4 +- .../resources/proto/remote_execution.proto | 4 +- defs.bzl | 2 +- deps.bzl | 6 +-- .../build/buildfarm/v1test/buildfarm.proto | 24 ++++++++--- third_party/clang_toolchain.patch | 15 +++---- 11 files changed, 94 insertions(+), 40 deletions(-) create mode 100644 .clang-format diff --git a/.bazelci/format.sh b/.bazelci/format.sh index 8b096d0890..f1255c9c2e 100755 --- a/.bazelci/format.sh +++ b/.bazelci/format.sh @@ -72,18 +72,17 @@ run_java_formatter () { } run_proto_formatter () { - # Check whether any formatting changes need to be made. # This is intended to be done by the CI. if [[ "$@" == "--check" ]] then - find . -name '*.proto' -exec $BAZEL run $CLANG_FORMAT -- -i --dry-run --Werror {} + + find $PWD -name '*.proto' -exec $BAZEL run $CLANG_FORMAT -- -i --dry-run --Werror {} + handle_format_error_check return fi # Fixes formatting issues - find . -name '*.proto' -exec $BAZEL run $CLANG_FORMAT -- -i {} + + find $PWD -name '*.proto' -exec $BAZEL run $CLANG_FORMAT -- -i {} + } run_buildifier () { diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000..455f9ec9dc --- /dev/null +++ b/.clang-format @@ -0,0 +1,2 @@ +Language: Proto +AllowShortFunctionsOnASingleLine: Empty diff --git a/admin/main/src/main/resources/proto/build_event_stream.proto b/admin/main/src/main/resources/proto/build_event_stream.proto index 133b9fffea..9c4cbcee58 100644 --- a/admin/main/src/main/resources/proto/build_event_stream.proto +++ b/admin/main/src/main/resources/proto/build_event_stream.proto @@ -34,7 +34,9 @@ message BuildEventId { // Generic identifier for a build event. This is the default type of // BuildEventId, but should not be used outside testing; nevertheless, // tools should handle build events with this kind of id gracefully. - message UnknownBuildEventId { string details = 1; } + message UnknownBuildEventId { + string details = 1; + } // Identifier of an event reporting progress. Those events are also used to // chain in events that come early. @@ -82,7 +84,9 @@ message BuildEventId { // have been skipped for some reason, if the actual expansion was still // carried out (e.g., if keep_going is set). In this case, the // pattern_skipped choice in the id field is to be made. - message PatternExpandedId { repeated string pattern = 1; } + message PatternExpandedId { + repeated string pattern = 1; + } message WorkspaceConfigId {} @@ -141,7 +145,9 @@ message BuildEventId { // any case, it will report some form of error (i.e., the payload will be an // Aborted event); there are no regular events using this identifier. The // purpose of those events is to serve as the root cause of a failed target. - message UnconfiguredLabelId { string label = 1; } + message UnconfiguredLabelId { + string label = 1; + } // Identifier of an event reporting an event associated with a configured // label, usually a visibility error. In any case, an event with such an @@ -313,7 +319,9 @@ message WorkspaceConfig { // like name and relevant entries of rc-files and client environment variables. // However, it does contain enough information to reproduce the build // invocation. -message UnstructuredCommandLine { repeated string args = 1; } +message UnstructuredCommandLine { + repeated string args = 1; +} // Payload of an event reporting on the parsed options, grouped in various ways. message OptionsParsed { @@ -328,7 +336,9 @@ message OptionsParsed { // Payload of an event indicating that an external resource was fetched. This // event will only occur in streams where an actual fetch happened, not in ones // where a cached copy of the entity to be fetched was used. -message Fetch { bool success = 1; } +message Fetch { + bool success = 1; +} // Payload of an event reporting the workspace status. Key-value pairs can be // provided by specifying the workspace_status_command to an executable that @@ -664,7 +674,9 @@ message BuildMetrics { } // Event providing additional statistics/logs after completion of the build. -message BuildToolLogs { repeated File log = 1; } +message BuildToolLogs { + repeated File log = 1; +} // Message describing a build event. Events will have an identifier that // is unique within a given build invocation; they also announce follow-up diff --git a/admin/main/src/main/resources/proto/buildfarm.proto b/admin/main/src/main/resources/proto/buildfarm.proto index d391847cb9..4349babc16 100644 --- a/admin/main/src/main/resources/proto/buildfarm.proto +++ b/admin/main/src/main/resources/proto/buildfarm.proto @@ -77,7 +77,9 @@ message ShutDownWorkerGracefullyRequest { message ShutDownWorkerGracefullyRequestResults {} -message DisableScaleInProtectionRequest { string instance_name = 1; } +message DisableScaleInProtectionRequest { + string instance_name = 1; +} message DisableScaleInProtectionRequestResults {} @@ -200,7 +202,9 @@ service OperationQueue { } } -message OperationsStatusRequest { string instance_name = 1; } +message OperationsStatusRequest { + string instance_name = 1; +} message TakeOperationRequest { // The instance of the execution system to operate against. A server may @@ -262,9 +266,13 @@ message AwsMetricsConfig { string region = 4; } -message GcpMetricsConfig { string operations_metrics_topic = 1; } +message GcpMetricsConfig { + string operations_metrics_topic = 1; +} -message LogMetricsConfig { string log_level = 1; } +message LogMetricsConfig { + string log_level = 1; +} message AdminConfig { string deployment_environment = 1; @@ -279,7 +287,9 @@ message AdminConfig { bool enable_graceful_shutdown = 5; } -message AwsAdminConfig { string region = 1; } +message AwsAdminConfig { + string region = 1; +} message GcpAdminConfig {} @@ -404,7 +414,9 @@ message ProvisionedQueue { build.bazel.remote.execution.v2.Platform platform = 2; } -message ProvisionedQueuesConfig { repeated ProvisionedQueue queues = 1; } +message ProvisionedQueuesConfig { + repeated ProvisionedQueue queues = 1; +} message RedisShardBackplaneConfig { // the uri endpoint of the redis target. This must be a single host entry @@ -681,7 +693,9 @@ message OperationChange { google.longrunning.Operation operation = 2; } - message Expire { bool force = 1; } + message Expire { + bool force = 1; + } google.protobuf.Timestamp effectiveAt = 1; @@ -870,7 +884,9 @@ message ExecutionWrapper { message ExecutionPolicy { string name = 1; - oneof policy { ExecutionWrapper wrapper = 2; } + oneof policy { + ExecutionWrapper wrapper = 2; + } } message WorkerConfig { @@ -964,7 +980,9 @@ message TreeIteratorToken { repeated build.bazel.remote.execution.v2.Digest directories = 1; } -message OperationIteratorToken { string operation_name = 1; } +message OperationIteratorToken { + string operation_name = 1; +} message BlobWriteKey { build.bazel.remote.execution.v2.Digest digest = 1; @@ -1040,7 +1058,9 @@ message WorkerProfileRequest {} message WorkerListRequest {} -message WorkerListMessage { repeated string workers = 1; } +message WorkerListMessage { + repeated string workers = 1; +} service WorkerProfile { rpc GetWorkerProfile(WorkerProfileRequest) returns (WorkerProfileMessage) {} diff --git a/admin/main/src/main/resources/proto/command_line.proto b/admin/main/src/main/resources/proto/command_line.proto index 628ac3c8ba..181f5d6314 100644 --- a/admin/main/src/main/resources/proto/command_line.proto +++ b/admin/main/src/main/resources/proto/command_line.proto @@ -53,10 +53,14 @@ message CommandLineSection { } // Wrapper to allow a list of strings in the "oneof" section_type. -message ChunkList { repeated string chunk = 1; } +message ChunkList { + repeated string chunk = 1; +} // Wrapper to allow a list of options in the "oneof" section_type. -message OptionList { repeated Option option = 1; } +message OptionList { + repeated Option option = 1; +} // A single command line option. // diff --git a/admin/main/src/main/resources/proto/descriptor.proto b/admin/main/src/main/resources/proto/descriptor.proto index 7316bc3d6e..f68b49bd33 100644 --- a/admin/main/src/main/resources/proto/descriptor.proto +++ b/admin/main/src/main/resources/proto/descriptor.proto @@ -53,7 +53,9 @@ option optimize_for = SPEED; // The protocol compiler can output a FileDescriptorSet containing the .proto // files it parses. -message FileDescriptorSet { repeated FileDescriptorProto file = 1; } +message FileDescriptorSet { + repeated FileDescriptorProto file = 1; +} // Describes a complete .proto file. message FileDescriptorProto { diff --git a/admin/main/src/main/resources/proto/remote_execution.proto b/admin/main/src/main/resources/proto/remote_execution.proto index f6ceaca5b5..3d5ae35cb6 100644 --- a/admin/main/src/main/resources/proto/remote_execution.proto +++ b/admin/main/src/main/resources/proto/remote_execution.proto @@ -1532,7 +1532,9 @@ message DigestFunction { } // Describes the server/instance capabilities for updating the action cache. -message ActionCacheUpdateCapabilities { bool update_enabled = 1; } +message ActionCacheUpdateCapabilities { + bool update_enabled = 1; +} // Allowed values for priority in // [ResultsCachePolicy][google.devtools.remoteexecution.v2.ResultsCachePolicy] diff --git a/defs.bzl b/defs.bzl index a6114caa27..9ca4aec502 100644 --- a/defs.bzl +++ b/defs.bzl @@ -139,5 +139,5 @@ def buildfarm_init(name = "buildfarm"): llvm_toolchain( name = "llvm_toolchain", - llvm_version = "10.0.0", + llvm_version = "16.0.0", ) diff --git a/deps.bzl b/deps.bzl index a289610b23..ff66198bc9 100644 --- a/deps.bzl +++ b/deps.bzl @@ -92,9 +92,9 @@ def archive_dependencies(third_party): # Used to format proto files { "name": "com_grail_bazel_toolchain", - "sha256": "ee74a364a978fa3c85ea56d736010bfc44ea22b439691e9cefdf72284d6c9b93", - "strip_prefix": "bazel-toolchain-d46339675a83e3517d955f5456e525501c3e05b8", - "url": "https://github.com/grailbio/bazel-toolchain/archive/d46339675a83e3517d955f5456e525501c3e05b8.tar.gz", + "sha256": "95f0bab6982c7e5a83447e08bf32fa7a47f210169da5e5ec62411fef0d8e7f59", + "strip_prefix": "bazel-toolchain-0.9", + "url": "https://github.com/grailbio/bazel-toolchain/archive/refs/tags/0.9.tar.gz", "patch_args": ["-p1"], "patches": ["%s:clang_toolchain.patch" % third_party], }, diff --git a/src/main/protobuf/build/buildfarm/v1test/buildfarm.proto b/src/main/protobuf/build/buildfarm/v1test/buildfarm.proto index 9632593f11..798f6fc9b1 100644 --- a/src/main/protobuf/build/buildfarm/v1test/buildfarm.proto +++ b/src/main/protobuf/build/buildfarm/v1test/buildfarm.proto @@ -77,7 +77,9 @@ message ShutDownWorkerGracefullyRequest { message ShutDownWorkerGracefullyRequestResults {} -message DisableScaleInProtectionRequest { string instance_name = 1; } +message DisableScaleInProtectionRequest { + string instance_name = 1; +} message DisableScaleInProtectionRequestResults {} @@ -200,7 +202,9 @@ service OperationQueue { } } -message BackplaneStatusRequest { string instance_name = 1; } +message BackplaneStatusRequest { + string instance_name = 1; +} message TakeOperationRequest { // The instance of the execution system to operate against. A server may @@ -301,7 +305,9 @@ message OperationChange { google.longrunning.Operation operation = 2; } - message Expire { bool force = 1; } + message Expire { + bool force = 1; + } google.protobuf.Timestamp effectiveAt = 1; @@ -556,14 +562,18 @@ message ExecutionWrapper { message ExecutionPolicy { string name = 1; - oneof policy { ExecutionWrapper wrapper = 2; } + oneof policy { + ExecutionWrapper wrapper = 2; + } } message TreeIteratorToken { repeated build.bazel.remote.execution.v2.Digest directories = 1; } -message OperationIteratorToken { string operation_name = 1; } +message OperationIteratorToken { + string operation_name = 1; +} message BlobWriteKey { build.bazel.remote.execution.v2.Digest digest = 1; @@ -643,7 +653,9 @@ message WorkerProfileRequest {} message WorkerListRequest {} -message WorkerListMessage { repeated string workers = 1; } +message WorkerListMessage { + repeated string workers = 1; +} service WorkerProfile { rpc GetWorkerProfile(WorkerProfileRequest) returns (WorkerProfileMessage) {} diff --git a/third_party/clang_toolchain.patch b/third_party/clang_toolchain.patch index a3921abf32..0c4176768c 100644 --- a/third_party/clang_toolchain.patch +++ b/third_party/clang_toolchain.patch @@ -1,12 +1,13 @@ diff --git a/toolchain/BUILD.llvm_repo b/toolchain/BUILD.llvm_repo -index 4158551..7bd9c54 100644 +index 94a1a98..922e6de 100644 --- a/toolchain/BUILD.llvm_repo +++ b/toolchain/BUILD.llvm_repo -@@ -70,6 +70,7 @@ filegroup( - "lib/lib*.dylib", - "lib/clang/*/lib/**/*.dylib", +@@ -61,6 +61,7 @@ filegroup( + # clang_rt.*.o supply crtbegin and crtend sections. + "lib/**/clang_rt.*.o", ], -+ allow_empty = True, - ), - ) ++ allow_empty = True, + exclude = [ + "lib/libLLVM*.a", + "lib/libclang*.a", From e51f1e16aa04a924675d0dd649387067ab9fbd1e Mon Sep 17 00:00:00 2001 From: amishra-u <119983081+amishra-u@users.noreply.github.com> Date: Wed, 3 Jan 2024 13:12:15 -0800 Subject: [PATCH 196/311] fix: Periodically Refresh Active Storage Workers With StartTime (#1549) * fix: Periodically Refresh Active Storage Workers With startTime --- .../instance/shard/RedisShardBackplane.java | 90 +++++++++---------- .../instance/shard/RedisShardSubscriber.java | 25 ++++-- .../build/buildfarm/v1test/buildfarm.proto | 4 +- .../shard/RedisShardBackplaneTest.java | 40 +++++++-- 4 files changed, 93 insertions(+), 66 deletions(-) diff --git a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java index 535473f2a9..382f2a8f5c 100644 --- a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java +++ b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java @@ -15,6 +15,7 @@ package build.buildfarm.instance.shard; import static java.lang.String.format; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.SECONDS; import build.bazel.remote.execution.v2.ActionResult; @@ -79,15 +80,14 @@ import io.grpc.Deadline; import java.io.IOException; import java.time.Instant; -import java.util.AbstractMap; import java.util.ArrayList; -import java.util.Collections; import java.util.Date; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.function.Consumer; import java.util.function.Function; @@ -144,7 +144,7 @@ public class RedisShardBackplane implements Backplane { private @Nullable RedisClient client = null; private Deadline storageWorkersDeadline = null; - private final Set storageWorkerSet = Collections.synchronizedSet(new HashSet<>()); + private final Map storageWorkers = new ConcurrentHashMap<>(); private final Supplier> recentExecuteWorkers; private DistributedState state = new DistributedState(); @@ -182,7 +182,7 @@ public RedisShardBackplane( Suppliers.memoizeWithExpiration( () -> { try { - return client.call(this::fetchAndExpireExecuteWorkers); + return client.call(this::fetchAndExpireExecuteWorkers).keySet(); } catch (IOException e) { throw new RuntimeException(e); } @@ -478,10 +478,7 @@ private void startSubscriptionThread() { subscriberService = BuildfarmExecutors.getSubscriberPool(); subscriber = new RedisShardSubscriber( - watchers, - storageWorkerSet, - configs.getBackplane().getWorkerChannel(), - subscriberService); + watchers, storageWorkers, configs.getBackplane().getWorkerChannel(), subscriberService); operationSubscription = new RedisShardSubscription( @@ -594,13 +591,14 @@ public void observe(Operation operation) { @Override public void addWorker(ShardWorker shardWorker) throws IOException { String json = JsonFormat.printer().print(shardWorker); + Timestamp effectiveAt = Timestamps.fromMillis(shardWorker.getFirstRegisteredAt()); String workerChangeJson = JsonFormat.printer() .print( WorkerChange.newBuilder() .setEffectiveAt(toTimestamp(Instant.now())) .setName(shardWorker.getEndpoint()) - .setAdd(WorkerChange.Add.getDefaultInstance()) + .setAdd(WorkerChange.Add.newBuilder().setEffectiveAt(effectiveAt).build()) .build()); client.call( jedis -> { @@ -648,7 +646,7 @@ public boolean removeWorker(String name, String reason) throws IOException { .setRemove(WorkerChange.Remove.newBuilder().setSource(source).setReason(reason).build()) .build(); String workerChangeJson = JsonFormat.printer().print(workerChange); - return storageWorkerSet.remove(name) + return storageWorkers.remove(name) != null && client.call( jedis -> removeWorkerAndPublish(jedis, name, workerChangeJson, /* storage=*/ true)); } @@ -697,45 +695,41 @@ public void deregisterWorker(String workerName) throws IOException { removeWorker(workerName, "Requested shutdown"); } - @SuppressWarnings("ConstantConditions") + /** + * Returns a new set containing copies of the storage workers. Note: This method does not grant + * access to the shared storage set. + */ @Override - public synchronized Set getStorageWorkers() throws IOException { - if (storageWorkersDeadline == null || storageWorkersDeadline.isExpired()) { - synchronized (storageWorkerSet) { - Set newWorkerSet = client.call(this::fetchAndExpireStorageWorkers); - storageWorkerSet.clear(); - storageWorkerSet.addAll(newWorkerSet); - } - storageWorkersDeadline = Deadline.after(workerSetMaxAge, SECONDS); - } - return new HashSet<>(storageWorkerSet); + public Set getStorageWorkers() throws IOException { + refreshStorageWorkersIfExpired(); + return new HashSet<>(storageWorkers.keySet()); } @Override public Map getWorkersStartTimeInEpochSecs(Set workerNames) throws IOException { - if (workerNames.isEmpty()) { - return Collections.emptyMap(); - } - List workerList = client.call(jedis -> state.storageWorkers.mget(jedis, workerNames)); + refreshStorageWorkersIfExpired(); + Map workerAndStartTime = new HashMap<>(); + workerNames.forEach( + worker -> { + ShardWorker workerInfo = storageWorkers.get(worker); + if (workerInfo != null) { + workerAndStartTime.put( + worker, MILLISECONDS.toSeconds(workerInfo.getFirstRegisteredAt())); + } + }); + return workerAndStartTime; + } - return workerList.stream() - .filter(Objects::nonNull) - .map( - workerJson -> { - try { - ShardWorker.Builder builder = ShardWorker.newBuilder(); - JsonFormat.parser().merge(workerJson, builder); - ShardWorker worker = builder.build(); - return new AbstractMap.SimpleEntry<>( - worker.getEndpoint(), worker.getFirstRegisteredAt() / 1000L); - } catch (InvalidProtocolBufferException e) { - return null; - } - }) - .filter(Objects::nonNull) - .collect( - Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue)); + private synchronized void refreshStorageWorkersIfExpired() throws IOException { + if (storageWorkersDeadline == null || storageWorkersDeadline.isExpired()) { + synchronized (storageWorkers) { + Map newWorkers = client.call(this::fetchAndExpireStorageWorkers); + storageWorkers.clear(); + storageWorkers.putAll(newWorkers); + } + storageWorkersDeadline = Deadline.after(workerSetMaxAge, SECONDS); + } } @Override @@ -798,18 +792,18 @@ private void removeInvalidWorkers( } } - private Set fetchAndExpireStorageWorkers(JedisCluster jedis) { + private Map fetchAndExpireStorageWorkers(JedisCluster jedis) { return fetchAndExpireWorkers(jedis, state.storageWorkers.asMap(jedis), /* storage=*/ true); } - private Set fetchAndExpireExecuteWorkers(JedisCluster jedis) { + private Map fetchAndExpireExecuteWorkers(JedisCluster jedis) { return fetchAndExpireWorkers(jedis, state.executeWorkers.asMap(jedis), /* storage=*/ false); } - private Set fetchAndExpireWorkers( + private Map fetchAndExpireWorkers( JedisCluster jedis, Map workers, boolean publish) { long now = System.currentTimeMillis(); - Set returnWorkers = Sets.newConcurrentHashSet(); + Map returnWorkers = Maps.newConcurrentMap(); ImmutableList.Builder invalidWorkers = ImmutableList.builder(); for (Map.Entry entry : workers.entrySet()) { String json = entry.getValue(); @@ -824,7 +818,7 @@ private Set fetchAndExpireWorkers( if (worker.getExpireAt() <= now) { invalidWorkers.add(worker); } else { - returnWorkers.add(worker.getEndpoint()); + returnWorkers.put(worker.getEndpoint(), worker); } } } catch (InvalidProtocolBufferException e) { diff --git a/src/main/java/build/buildfarm/instance/shard/RedisShardSubscriber.java b/src/main/java/build/buildfarm/instance/shard/RedisShardSubscriber.java index 637be2a383..9e68f0f41a 100644 --- a/src/main/java/build/buildfarm/instance/shard/RedisShardSubscriber.java +++ b/src/main/java/build/buildfarm/instance/shard/RedisShardSubscriber.java @@ -20,6 +20,7 @@ import build.buildfarm.instance.server.WatchFuture; import build.buildfarm.v1test.OperationChange; +import build.buildfarm.v1test.ShardWorker; import build.buildfarm.v1test.WorkerChange; import com.google.common.collect.ImmutableList; import com.google.common.collect.ListMultimap; @@ -27,9 +28,10 @@ import com.google.longrunning.Operation; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.Timestamp; +import com.google.protobuf.util.Timestamps; import java.time.Instant; import java.util.List; -import java.util.Set; +import java.util.Map; import java.util.concurrent.Executor; import java.util.function.Consumer; import java.util.function.Predicate; @@ -59,13 +61,13 @@ void complete() { } private final ListMultimap watchers; - private final Set workers; + private final Map workers; private final String workerChannel; private final Executor executor; RedisShardSubscriber( ListMultimap watchers, - Set workers, + Map workers, String workerChannel, Executor executor) { this.watchers = watchers; @@ -250,23 +252,28 @@ void onWorkerChange(WorkerChange workerChange) { workerChange.getName(), workerChange.getEffectiveAt())); break; case ADD: - addWorker(workerChange.getName()); + addWorker(workerChange); break; case REMOVE: - removeWorker(workerChange.getName()); + removeWorker(workerChange); break; } } - void addWorker(String worker) { + void addWorker(WorkerChange workerChange) { synchronized (workers) { - workers.add(worker); + workers.put( + workerChange.getName(), + ShardWorker.newBuilder() + .setEndpoint(workerChange.getName()) + .setFirstRegisteredAt(Timestamps.toMillis(workerChange.getAdd().getEffectiveAt())) + .build()); } } - boolean removeWorker(String worker) { + boolean removeWorker(WorkerChange workerChange) { synchronized (workers) { - return workers.remove(worker); + return workers.remove(workerChange.getName()) != null; } } diff --git a/src/main/protobuf/build/buildfarm/v1test/buildfarm.proto b/src/main/protobuf/build/buildfarm/v1test/buildfarm.proto index 798f6fc9b1..2785b27b70 100644 --- a/src/main/protobuf/build/buildfarm/v1test/buildfarm.proto +++ b/src/main/protobuf/build/buildfarm/v1test/buildfarm.proto @@ -279,7 +279,9 @@ message ShardWorker { } message WorkerChange { - message Add {} + message Add { + google.protobuf.Timestamp effectiveAt = 1; + } message Remove { string source = 1; diff --git a/src/test/java/build/buildfarm/instance/shard/RedisShardBackplaneTest.java b/src/test/java/build/buildfarm/instance/shard/RedisShardBackplaneTest.java index 3772459cf7..bf7360eeee 100644 --- a/src/test/java/build/buildfarm/instance/shard/RedisShardBackplaneTest.java +++ b/src/test/java/build/buildfarm/instance/shard/RedisShardBackplaneTest.java @@ -16,6 +16,7 @@ import static build.buildfarm.instance.shard.RedisShardBackplane.parseOperationChange; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.any; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; @@ -32,6 +33,7 @@ import build.buildfarm.v1test.ExecuteEntry; import build.buildfarm.v1test.OperationChange; import build.buildfarm.v1test.QueueEntry; +import build.buildfarm.v1test.ShardWorker; import build.buildfarm.v1test.WorkerChange; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; @@ -40,7 +42,6 @@ import java.io.IOException; import java.time.Instant; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Set; @@ -364,13 +365,13 @@ public void testGetWorkersStartTime() throws IOException { Set workerNames = ImmutableSet.of("worker1", "worker2", "missing_worker"); String storageWorkerKey = configs.getBackplane().getWorkersHashName() + "_storage"; - List workersJson = - Arrays.asList( - "{\"endpoint\": \"worker1\", \"expireAt\": \"1686981022917\", \"workerType\": 3, \"firstRegisteredAt\": \"1685292624000\"}", - "{\"endpoint\": \"worker2\", \"expireAt\": \"1686981022917\", \"workerType\": 3, \"firstRegisteredAt\": \"1685282624000\"}", - null); - when(jedisCluster.hmget(storageWorkerKey, "worker1", "worker2", "missing_worker")) - .thenReturn(workersJson); + Map workersJson = + Map.of( + "worker1", + "{\"endpoint\": \"worker1\", \"expireAt\": \"9999999999999\", \"workerType\": 3, \"firstRegisteredAt\": \"1685292624000\"}", + "worker2", + "{\"endpoint\": \"worker2\", \"expireAt\": \"9999999999999\", \"workerType\": 3, \"firstRegisteredAt\": \"1685282624000\"}"); + when(jedisCluster.hgetAll(storageWorkerKey)).thenReturn(workersJson); Map workersStartTime = backplane.getWorkersStartTimeInEpochSecs(workerNames); assertThat(workersStartTime.size()).isEqualTo(2); assertThat(workersStartTime.get("worker1")).isEqualTo(1685292624L); @@ -398,4 +399,27 @@ public void getDigestInsertTime() throws IOException { .isGreaterThan(Instant.now().getEpochSecond() - expirationInSecs + ttl - 2); assertThat(insertTimeInSecs).isAtMost(Instant.now().getEpochSecond() - expirationInSecs + ttl); } + + @Test + public void testAddWorker() throws IOException { + ShardWorker shardWorker = + ShardWorker.newBuilder().setWorkerType(3).setFirstRegisteredAt(1703065913000L).build(); + JedisCluster jedisCluster = mock(JedisCluster.class); + when(mockJedisClusterFactory.get()).thenReturn(jedisCluster); + when(jedisCluster.hset(anyString(), anyString(), anyString())).thenReturn(1L); + RedisShardBackplane backplane = createBackplane("add-worker-test"); + backplane.start("addWorker/test:0000"); + backplane.addWorker(shardWorker); + verify(jedisCluster, times(1)) + .hset( + configs.getBackplane().getWorkersHashName() + "_storage", + "", + JsonFormat.printer().print(shardWorker)); + verify(jedisCluster, times(1)) + .hset( + configs.getBackplane().getWorkersHashName() + "_execute", + "", + JsonFormat.printer().print(shardWorker)); + verify(jedisCluster, times(1)).publish(anyString(), anyString()); + } } From c79b213be32f40e1f592c0a055876586d069082a Mon Sep 17 00:00:00 2001 From: George Gensure Date: Thu, 4 Jan 2024 11:47:25 -0500 Subject: [PATCH 197/311] Revert "Use integer ids for Sqlite bidirectional index (#1599)" (#1603) This reverts commit 413021d940da9d2f0569fb5a3823548030e66dc8. --- .../cas/cfc/SqliteFileDirectoriesIndex.java | 65 ++++--------------- .../cas/cfc/DirectoriesIndexTest.java | 1 - 2 files changed, 11 insertions(+), 55 deletions(-) diff --git a/src/main/java/build/buildfarm/cas/cfc/SqliteFileDirectoriesIndex.java b/src/main/java/build/buildfarm/cas/cfc/SqliteFileDirectoriesIndex.java index e634616660..030c749037 100644 --- a/src/main/java/build/buildfarm/cas/cfc/SqliteFileDirectoriesIndex.java +++ b/src/main/java/build/buildfarm/cas/cfc/SqliteFileDirectoriesIndex.java @@ -57,19 +57,13 @@ private void open() { throw new RuntimeException(e); } - String createDirectoriesSql = - "CREATE TABLE directories (id INTEGER PRIMARY KEY, name VARCHAR UNIQUE)"; - String createFilesSql = "CREATE TABLE files (id INTEGER PRIMARY KEY, name VARCHAR UNIQUE)"; String createEntriesSql = "CREATE TABLE entries (\n" - + " file_id INTEGER NOT NULL REFERENCES files(id) ON DELETE CASCADE,\n" - + " directory_id INTEGER NOT NULL REFERENCES directories(id) ON DELETE CASCADE,\n" - + " PRIMARY KEY (file_id, directory_id)\n" + + " path TEXT NOT NULL,\n" + + " directory TEXT NOT NULL\n" + ")"; try (Statement stmt = conn.createStatement()) { - stmt.execute(createDirectoriesSql); - stmt.execute(createFilesSql); stmt.execute(createEntriesSql); } catch (SQLException e) { throw new RuntimeException(e); @@ -83,13 +77,11 @@ private void open() { public synchronized void start() { open(); - String createPathIndexSql = "CREATE INDEX file_idx ON entries (file_id)"; - String createDirectoryIndexSql = "CREATE INDEX directory_idx ON entries (directory_id)"; - String enforceForeignKeys = "PRAGMA foreign_keys=ON"; + String createPathIndexSql = "CREATE INDEX path_idx ON entries (path)"; + String createDirectoryIndexSql = "CREATE INDEX directory_idx ON entries (directory)"; try (Statement stmt = conn.createStatement()) { stmt.execute(createPathIndexSql); stmt.execute(createDirectoryIndexSql); - stmt.execute(enforceForeignKeys); } catch (SQLException e) { throw new RuntimeException(e); } @@ -109,8 +101,7 @@ public void close() { private Set removeEntryDirectories(String entry) { open(); - String selectSql = - "SELECT d.name as directory FROM files f INNER JOIN entries e ON f.id = e.file_id INNER JOIN directories d ON d.id = e.directory_id WHERE f.name = ?"; + String selectSql = "SELECT directory FROM entries WHERE path = ?"; ImmutableSet.Builder directoriesBuilder = ImmutableSet.builder(); try (PreparedStatement selectStatement = conn.prepareStatement(selectSql)) { @@ -125,7 +116,7 @@ private Set removeEntryDirectories(String entry) { } // all directories featuring this entry are now invalid ImmutableSet directories = directoriesBuilder.build(); - String deleteSql = "DELETE FROM directories where name = ?"; + String deleteSql = "DELETE FROM entries where directory = ?"; try (PreparedStatement deleteStatement = conn.prepareStatement(deleteSql)) { conn.setAutoCommit(false); for (Digest directory : directories) { @@ -137,14 +128,6 @@ private Set removeEntryDirectories(String entry) { } catch (SQLException e) { throw new RuntimeException(e); } - // clear out orphaned files - try (Statement orphanStatement = conn.createStatement()) { - String deleteOrphanSql = - "DELETE FROM files WHERE id NOT IN (SELECT DISTINCT file_id FROM entries)"; - orphanStatement.execute(deleteOrphanSql); - } catch (SQLException e) { - throw new RuntimeException(e); - } return directories; } @@ -155,41 +138,16 @@ public synchronized Set removeEntry(String entry) throws IOException { return directories; } - // inserts here specifically avoids integer key maintenance in java private synchronized void addEntriesDirectory(Set entries, Digest directory) { open(); - String directoryName = DigestUtil.toString(directory); - String filesInsertSql = "INSERT OR IGNORE INTO files (name) VALUES (?)"; - try (PreparedStatement filesInsertStatement = conn.prepareStatement(filesInsertSql)) { - conn.setAutoCommit(false); - for (String entry : entries) { - filesInsertStatement.setString(1, entry); - filesInsertStatement.addBatch(); - } - filesInsertStatement.executeBatch(); - conn.commit(); - } catch (SQLException e) { - throw new RuntimeException(e); - } - // should be novel directory - String directoriesInsertSql = "INSERT INTO directories (name) VALUES (?)"; - try (PreparedStatement directoriesInsertStatement = - conn.prepareStatement(directoriesInsertSql)) { - conn.setAutoCommit(false); - directoriesInsertStatement.setString(1, directoryName); - directoriesInsertStatement.executeUpdate(); - conn.commit(); - } catch (SQLException e) { - throw new RuntimeException(e); - } - String entriesInsertSql = - "INSERT INTO entries (file_id, directory_id) SELECT f.id, d.id FROM files f, directories d WHERE f.name = ? AND d.name = ?"; - try (PreparedStatement insertStatement = conn.prepareStatement(entriesInsertSql)) { + String digest = DigestUtil.toString(directory); + String insertSql = "INSERT INTO entries (path, directory) VALUES (?,?)"; + try (PreparedStatement insertStatement = conn.prepareStatement(insertSql)) { conn.setAutoCommit(false); + insertStatement.setString(2, digest); for (String entry : entries) { insertStatement.setString(1, entry); - insertStatement.setString(2, directoryName); insertStatement.addBatch(); } insertStatement.executeBatch(); @@ -210,9 +168,8 @@ private void removeEntriesDirectory(Digest directory) { open(); String digest = DigestUtil.toString(directory); - String deleteSql = "DELETE FROM directories WHERE name = ?"; + String deleteSql = "DELETE FROM entries WHERE directory = ?"; try (PreparedStatement deleteStatement = conn.prepareStatement(deleteSql)) { - conn.setAutoCommit(true); deleteStatement.setString(1, digest); deleteStatement.executeUpdate(); } catch (SQLException e) { diff --git a/src/test/java/build/buildfarm/cas/cfc/DirectoriesIndexTest.java b/src/test/java/build/buildfarm/cas/cfc/DirectoriesIndexTest.java index b4effa2bc8..3eec66def7 100644 --- a/src/test/java/build/buildfarm/cas/cfc/DirectoriesIndexTest.java +++ b/src/test/java/build/buildfarm/cas/cfc/DirectoriesIndexTest.java @@ -51,7 +51,6 @@ protected DirectoriesIndexTest(Path root, DirectoriesIndexType type) { } else { throw new IllegalArgumentException("DirectoriesIndex type is not supported."); } - directoriesIndex.start(); } @Before From 044597e12210c8cbca6b0b71ba0062b1eba0243a Mon Sep 17 00:00:00 2001 From: amishra-u <119983081+amishra-u@users.noreply.github.com> Date: Sat, 6 Jan 2024 17:17:58 -0800 Subject: [PATCH 198/311] Separate fields for storage and execute workers in BackplaneStatus (#1605) --- .../build/buildfarm/instance/shard/RedisShardBackplane.java | 6 +++++- src/main/protobuf/build/buildfarm/v1test/buildfarm.proto | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java index 382f2a8f5c..84a9f2e525 100644 --- a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java +++ b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java @@ -1468,7 +1468,11 @@ public boolean canPrequeue() throws IOException { @Override public BackplaneStatus backplaneStatus() throws IOException { BackplaneStatus.Builder builder = BackplaneStatus.newBuilder(); - builder.addAllActiveWorkers(Sets.union(getExecuteWorkers(), getStorageWorkers())); + Set executeWorkers = getExecuteWorkers(); + Set storageWorkers = getStorageWorkers(); + builder.addAllActiveExecuteWorkers(executeWorkers); + builder.addAllActiveStorageWorkers(storageWorkers); + builder.addAllActiveWorkers(Sets.union(executeWorkers, storageWorkers)); builder.setDispatchedSize(client.call(jedis -> state.dispatchedOperations.size(jedis))); builder.setOperationQueue(state.operationQueue.status(client.call(jedis -> jedis))); builder.setPrequeue(state.prequeue.status(client.call(jedis -> jedis))); diff --git a/src/main/protobuf/build/buildfarm/v1test/buildfarm.proto b/src/main/protobuf/build/buildfarm/v1test/buildfarm.proto index 2785b27b70..a47f691438 100644 --- a/src/main/protobuf/build/buildfarm/v1test/buildfarm.proto +++ b/src/main/protobuf/build/buildfarm/v1test/buildfarm.proto @@ -448,8 +448,13 @@ message BackplaneStatus { DispatchedOperationsStatus dispatched_operations = 9; + // Maintained for backward compatibility. repeated string active_workers = 4; + repeated string active_storage_workers = 12; + + repeated string active_execute_workers = 13; + int64 cas_lookup_size = 5; int64 action_cache_size = 6; From 74316e707f068e7b81c1d00eb2c9e4d90da1caba Mon Sep 17 00:00:00 2001 From: George Gensure Date: Mon, 8 Jan 2024 15:59:24 -0500 Subject: [PATCH 199/311] Decode nodeId with jedis util SafeEncoder (#1607) Node name strings provided via `cluster slots` will be byte arrays that require decoding. Use the inbuilt SafeEncoder from jedis which is used to decode all other strings. --- .../build/buildfarm/common/redis/RedisNodeHashes.java | 3 ++- .../buildfarm/common/redis/RedisNodeHashesMockTest.java | 8 +++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/build/buildfarm/common/redis/RedisNodeHashes.java b/src/main/java/build/buildfarm/common/redis/RedisNodeHashes.java index 689c7d46f4..62eb957621 100644 --- a/src/main/java/build/buildfarm/common/redis/RedisNodeHashes.java +++ b/src/main/java/build/buildfarm/common/redis/RedisNodeHashes.java @@ -24,6 +24,7 @@ import redis.clients.jedis.JedisPool; import redis.clients.jedis.exceptions.JedisException; import redis.clients.jedis.exceptions.JedisNoReachableClusterNodeException; +import redis.clients.jedis.util.SafeEncoder; /** * @class RedisNodeHashes @@ -101,7 +102,7 @@ private static List> getNodeSlotRanges(JedisCluster jedis) { List slotInfo = (List) slotInfoObj; List slotRangeNodes = (List) slotInfo.get(2); // 2 is primary node id - String nodeId = (String) slotRangeNodes.get(2); + String nodeId = (String) SafeEncoder.encode((byte[]) slotRangeNodes.get(2)); if (nodes.add(nodeId)) { List slotNums = slotInfoToSlotRange(slotInfo); slotRanges.add(slotNums); diff --git a/src/test/java/build/buildfarm/common/redis/RedisNodeHashesMockTest.java b/src/test/java/build/buildfarm/common/redis/RedisNodeHashesMockTest.java index f6627d37e3..fe1e755f8b 100644 --- a/src/test/java/build/buildfarm/common/redis/RedisNodeHashesMockTest.java +++ b/src/test/java/build/buildfarm/common/redis/RedisNodeHashesMockTest.java @@ -29,6 +29,7 @@ import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisCluster; import redis.clients.jedis.JedisPool; +import redis.clients.jedis.util.SafeEncoder; /** * @class RedisNodeHashesMockTest @@ -50,7 +51,7 @@ public void getEvenlyDistributedHashesCanRetrieveDistributedHashes() throws Exce when(node.clusterSlots()) .thenReturn( Collections.singletonList( - Arrays.asList(0L, 100L, Arrays.asList(null, null, "nodeId")))); + Arrays.asList(0L, 100L, Arrays.asList(null, null, SafeEncoder.encode("nodeId"))))); JedisPool pool = mock(JedisPool.class); when(pool.getResource()).thenReturn(node); @@ -102,8 +103,9 @@ public void getEvenlyDistributedHashesWithPrefixExpectedPrefixHashes() throws Ex when(node.clusterSlots()) .thenReturn( Arrays.asList( - Arrays.asList(0L, 100L, Arrays.asList(null, null, "nodeId1")), - Arrays.asList(101L, 200L, Arrays.asList(null, null, "nodeId2")))); + Arrays.asList(0L, 100L, Arrays.asList(null, null, SafeEncoder.encode("nodeId1"))), + Arrays.asList( + 101L, 200L, Arrays.asList(null, null, SafeEncoder.encode("nodeId2"))))); JedisPool pool = mock(JedisPool.class); when(pool.getResource()).thenReturn(node); From b62a4ce976e0d932cec52a4adadec7d573a324a0 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Tue, 9 Jan 2024 06:47:42 -0800 Subject: [PATCH 200/311] build: start adopting bzlmod (#1564) * build: start adopting bzlmod Only four bazel dependencies were found in the existing bzlmod registry (https://registry.bazel.build/) * build: swap io_bazel_rules_go for bzlmod * build: swap gazelle for bzlmod * tests: support bzlmod I don't know why. But it works. * build: leave breadcrumbs for bzlmod migration * build(chore): MODULE.bazel.lock * build: swap buildtools for buildifier_prebuilt There are conflicts with go tooling between buildtools and protobuf. --- .bazelrc | 4 +- BUILD | 2 +- MODULE.bazel | 19 +- MODULE.bazel.lock | 8484 +++++++++++++++++ deps.bzl | 60 +- .../examples/ExampleConfigsTest.java | 6 +- 6 files changed, 8507 insertions(+), 68 deletions(-) create mode 100644 MODULE.bazel.lock diff --git a/.bazelrc b/.bazelrc index 5cc10724d9..60199a4cbe 100644 --- a/.bazelrc +++ b/.bazelrc @@ -21,9 +21,7 @@ test --test_tag_filters=-redis,-integration # https://buildkite.com/bazel/bazelisk-plus-incompatible-flags common --incompatible_disallow_empty_glob -# TODO: migrate all dependencies from WORKSPACE to MODULE.bazel -# https://github.com/bazelbuild/bazel-buildfarm/issues/1479 -common --noenable_bzlmod +common --enable_bzlmod # Support protobuf on macOS with Xcode 15.x common:macos --host_cxxopt=-std=c++14 --cxxopt=-std=c++14 diff --git a/BUILD b/BUILD index c0400a6061..d82be09f83 100644 --- a/BUILD +++ b/BUILD @@ -1,4 +1,4 @@ -load("@com_github_bazelbuild_buildtools//buildifier:def.bzl", "buildifier") +load("@buildifier_prebuilt//:rules.bzl", "buildifier") load("@io_bazel_rules_docker//java:image.bzl", "java_image") load("@io_bazel_rules_docker//docker/package_managers:download_pkgs.bzl", "download_pkgs") load("@io_bazel_rules_docker//docker/package_managers:install_pkgs.bzl", "install_pkgs") diff --git a/MODULE.bazel b/MODULE.bazel index cabbbe697c..83268eda13 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,2 +1,17 @@ -# TODO: migrate all dependencies from WORKSPACE to MODULE.bazel -# https://github.com/bazelbuild/bazel-buildfarm/issues/1479 +module( + name = "build_buildfarm", + repo_name = "build_buildfarm", +) + +bazel_dep(name = "gazelle", version = "0.34.0", repo_name = "bazel_gazelle") +bazel_dep(name = "platforms", version = "0.0.7") +bazel_dep(name = "rules_cc", version = "0.0.9") +bazel_dep(name = "rules_go", version = "0.43.0", repo_name = "io_bazel_rules_go") +bazel_dep(name = "rules_jvm_external", version = "5.3") +bazel_dep(name = "rules_license", version = "0.0.7") + +bazel_dep( + name = "buildifier_prebuilt", + version = "6.4.0", + dev_dependency = True, +) diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock new file mode 100644 index 0000000000..a58ae1defb --- /dev/null +++ b/MODULE.bazel.lock @@ -0,0 +1,8484 @@ +{ + "lockFileVersion": 3, + "moduleFileHash": "3f11511a2b9a5f6fb04a3324b46b42a4fa6bcae5f2aed6e1f6f6cf980cfd218e", + "flags": { + "cmdRegistries": [ + "https://bcr.bazel.build/" + ], + "cmdModuleOverrides": {}, + "allowedYankedVersions": [], + "envVarAllowedYankedVersions": "", + "ignoreDevDependency": false, + "directDependenciesMode": "WARNING", + "compatibilityMode": "ERROR" + }, + "localOverrideHashes": { + "bazel_tools": "922ea6752dc9105de5af957f7a99a6933c0a6a712d23df6aad16a9c399f7e787" + }, + "moduleDepGraph": { + "": { + "name": "build_buildfarm", + "version": "", + "key": "", + "repoName": "build_buildfarm", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [ + { + "extensionBzlFile": "@rules_jvm_external//:extensions.bzl", + "extensionName": "maven", + "usingModule": "", + "location": { + "file": "@@//:MODULE.bazel", + "line": 47, + "column": 22 + }, + "imports": { + "maven": "maven", + "unpinned_maven": "unpinned_maven" + }, + "devImports": [], + "tags": [ + { + "tagName": "install", + "attributeValues": { + "artifacts": [ + "com.amazonaws:aws-java-sdk-s3:1.12.544", + "com.amazonaws:aws-java-sdk-secretsmanager:1.12.544", + "com.fasterxml.jackson.core:jackson-databind:2.15.0", + "com.github.ben-manes.caffeine:caffeine:2.9.0", + "com.github.docker-java:docker-java:3.3.3", + "com.github.fppt:jedis-mock:1.0.10", + "com.github.jnr:jffi:1.3.11", + "com.github.jnr:jffi:jar:native:1.3.11", + "com.github.jnr:jnr-constants:0.10.4", + "com.github.jnr:jnr-ffi:2.2.14", + "com.github.jnr:jnr-posix:3.1.17", + "com.github.pcj:google-options:1.0.0", + "com.github.serceman:jnr-fuse:0.5.7", + "com.github.luben:zstd-jni:1.5.5-7", + "com.github.oshi:oshi-core:6.4.5", + "com.google.auth:google-auth-library-credentials:1.19.0", + "com.google.auth:google-auth-library-oauth2-http:1.19.0", + "com.google.code.findbugs:jsr305:3.0.2", + "com.google.code.gson:gson:2.10.1", + "com.google.errorprone:error_prone_annotations:2.22.0", + "com.google.errorprone:error_prone_core:2.22.0", + "com.google.guava:failureaccess:1.0.1", + "com.google.guava:guava:32.1.1-jre", + "com.google.j2objc:j2objc-annotations:2.8", + "com.google.jimfs:jimfs:1.3.0", + "com.google.protobuf:protobuf-java-util:3.19.1", + "com.google.protobuf:protobuf-java:3.19.1", + "com.google.truth:truth:1.1.5", + "org.slf4j:slf4j-simple:2.0.9", + "com.googlecode.json-simple:json-simple:1.1.1", + "com.jayway.jsonpath:json-path:2.8.0", + "org.bouncycastle:bcprov-jdk15on:1.70", + "net.jcip:jcip-annotations:1.0", + "io.netty:netty-buffer:4.1.97.Final", + "io.netty:netty-codec:4.1.97.Final", + "io.netty:netty-codec-http:4.1.97.Final", + "io.netty:netty-codec-http2:4.1.97.Final", + "io.netty:netty-codec-socks:4.1.97.Final", + "io.netty:netty-common:4.1.97.Final", + "io.netty:netty-handler:4.1.97.Final", + "io.netty:netty-handler-proxy:4.1.97.Final", + "io.netty:netty-resolver:4.1.97.Final", + "io.netty:netty-transport:4.1.97.Final", + "io.netty:netty-transport-native-epoll:4.1.97.Final", + "io.netty:netty-transport-native-kqueue:4.1.97.Final", + "io.netty:netty-transport-native-unix-common:4.1.97.Final", + "io.grpc:grpc-api:1.56.1", + "io.grpc:grpc-auth:1.56.1", + "io.grpc:grpc-core:1.56.1", + "io.grpc:grpc-context:1.56.1", + "io.grpc:grpc-netty:1.56.1", + "io.grpc:grpc-stub:1.56.1", + "io.grpc:grpc-protobuf:1.56.1", + "io.grpc:grpc-testing:1.56.1", + "io.grpc:grpc-services:1.56.1", + "io.grpc:grpc-netty-shaded:1.56.1", + "io.prometheus:simpleclient:0.15.0", + "io.prometheus:simpleclient_hotspot:0.15.0", + "io.prometheus:simpleclient_httpserver:0.15.0", + "junit:junit:4.13.2", + "javax.annotation:javax.annotation-api:1.3.2", + "net.javacrumbs.future-converter:future-converter-java8-guava:1.2.0", + "org.apache.commons:commons-compress:1.23.0", + "org.apache.commons:commons-pool2:2.11.1", + "org.apache.commons:commons-lang3:3.13.0", + "commons-io:commons-io:2.13.0", + "me.dinowernli:java-grpc-prometheus:0.6.0", + "org.apache.tomcat:annotations-api:6.0.53", + "org.checkerframework:checker-qual:3.38.0", + "org.mockito:mockito-core:2.25.0", + "org.openjdk.jmh:jmh-core:1.37", + "org.openjdk.jmh:jmh-generator-annprocess:1.37", + "org.redisson:redisson:3.23.4", + "org.threeten:threetenbp:1.6.8", + "org.xerial:sqlite-jdbc:3.34.0", + "org.jetbrains:annotations:16.0.2", + "org.yaml:snakeyaml:2.2", + "org.projectlombok:lombok:1.18.30" + ], + "fail_if_repin_required": true, + "generate_compat_repositories": true, + "lock_file": "//:maven_install.json" + }, + "devDependency": false, + "location": { + "file": "@@//:MODULE.bazel", + "line": 48, + "column": 14 + } + } + ], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "bazel_gazelle": "gazelle@0.34.0", + "platforms": "platforms@0.0.7", + "rules_cc": "rules_cc@0.0.9", + "io_bazel_rules_go": "rules_go@0.43.0", + "rules_jvm_external": "rules_jvm_external@5.3", + "rules_license": "rules_license@0.0.7", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + } + }, + "gazelle@0.34.0": { + "name": "gazelle", + "version": "0.34.0", + "key": "gazelle@0.34.0", + "repoName": "bazel_gazelle", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [ + { + "extensionBzlFile": "@io_bazel_rules_go//go:extensions.bzl", + "extensionName": "go_sdk", + "usingModule": "gazelle@0.34.0", + "location": { + "file": "https://bcr.bazel.build/modules/gazelle/0.34.0/MODULE.bazel", + "line": 12, + "column": 23 + }, + "imports": { + "go_host_compatible_sdk_label": "go_host_compatible_sdk_label" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@bazel_gazelle//internal/bzlmod:non_module_deps.bzl", + "extensionName": "non_module_deps", + "usingModule": "gazelle@0.34.0", + "location": { + "file": "https://bcr.bazel.build/modules/gazelle/0.34.0/MODULE.bazel", + "line": 20, + "column": 32 + }, + "imports": { + "bazel_gazelle_go_repository_cache": "bazel_gazelle_go_repository_cache", + "bazel_gazelle_go_repository_tools": "bazel_gazelle_go_repository_tools", + "bazel_gazelle_is_bazel_module": "bazel_gazelle_is_bazel_module" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@bazel_gazelle//:extensions.bzl", + "extensionName": "go_deps", + "usingModule": "gazelle@0.34.0", + "location": { + "file": "https://bcr.bazel.build/modules/gazelle/0.34.0/MODULE.bazel", + "line": 28, + "column": 24 + }, + "imports": { + "com_github_bazelbuild_buildtools": "com_github_bazelbuild_buildtools", + "com_github_bmatcuk_doublestar_v4": "com_github_bmatcuk_doublestar_v4", + "com_github_fsnotify_fsnotify": "com_github_fsnotify_fsnotify", + "com_github_google_go_cmp": "com_github_google_go_cmp", + "com_github_pmezard_go_difflib": "com_github_pmezard_go_difflib", + "org_golang_x_mod": "org_golang_x_mod", + "org_golang_x_sync": "org_golang_x_sync", + "org_golang_x_tools": "org_golang_x_tools", + "org_golang_x_tools_go_vcs": "org_golang_x_tools_go_vcs", + "bazel_gazelle_go_repository_config": "bazel_gazelle_go_repository_config" + }, + "devImports": [], + "tags": [ + { + "tagName": "from_file", + "attributeValues": { + "go_mod": "//:go.mod" + }, + "devDependency": false, + "location": { + "file": "https://bcr.bazel.build/modules/gazelle/0.34.0/MODULE.bazel", + "line": 29, + "column": 18 + } + }, + { + "tagName": "module", + "attributeValues": { + "path": "golang.org/x/tools", + "sum": "h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=", + "version": "v0.13.0" + }, + "devDependency": false, + "location": { + "file": "https://bcr.bazel.build/modules/gazelle/0.34.0/MODULE.bazel", + "line": 33, + "column": 15 + } + } + ], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "bazel_skylib": "bazel_skylib@1.4.1", + "com_google_protobuf": "protobuf@3.19.6", + "io_bazel_rules_go": "rules_go@0.43.0", + "rules_proto": "rules_proto@4.0.0", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "gazelle~0.34.0", + "urls": [ + "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.34.0/bazel-gazelle-v0.34.0.tar.gz" + ], + "integrity": "sha256-tzh/cu+1n4duTarkLx05EtDUVWPqx8sj0d4LCUq1iM8=", + "strip_prefix": "", + "remote_patches": {}, + "remote_patch_strip": 0 + } + } + }, + "platforms@0.0.7": { + "name": "platforms", + "version": "0.0.7", + "key": "platforms@0.0.7", + "repoName": "platforms", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "rules_license": "rules_license@0.0.7", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "platforms", + "urls": [ + "https://github.com/bazelbuild/platforms/releases/download/0.0.7/platforms-0.0.7.tar.gz" + ], + "integrity": "sha256-OlYcmee9vpFzqmU/1Xn+hJ8djWc5V4CrR3Cx84FDHVE=", + "strip_prefix": "", + "remote_patches": {}, + "remote_patch_strip": 0 + } + } + }, + "rules_cc@0.0.9": { + "name": "rules_cc", + "version": "0.0.9", + "key": "rules_cc@0.0.9", + "repoName": "rules_cc", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [ + "@local_config_cc_toolchains//:all" + ], + "extensionUsages": [ + { + "extensionBzlFile": "@bazel_tools//tools/cpp:cc_configure.bzl", + "extensionName": "cc_configure_extension", + "usingModule": "rules_cc@0.0.9", + "location": { + "file": "https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel", + "line": 9, + "column": 29 + }, + "imports": { + "local_config_cc_toolchains": "local_config_cc_toolchains" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "platforms": "platforms@0.0.7", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_cc~0.0.9", + "urls": [ + "https://github.com/bazelbuild/rules_cc/releases/download/0.0.9/rules_cc-0.0.9.tar.gz" + ], + "integrity": "sha256-IDeHW5pEVtzkp50RKorohbvEqtlo5lh9ym5k86CQDN8=", + "strip_prefix": "rules_cc-0.0.9", + "remote_patches": { + "https://bcr.bazel.build/modules/rules_cc/0.0.9/patches/module_dot_bazel_version.patch": "sha256-mM+qzOI0SgAdaJBlWOSMwMPKpaA9b7R37Hj/tp5bb4g=" + }, + "remote_patch_strip": 0 + } + } + }, + "rules_go@0.43.0": { + "name": "rules_go", + "version": "0.43.0", + "key": "rules_go@0.43.0", + "repoName": "io_bazel_rules_go", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [ + "@go_toolchains//:all" + ], + "extensionUsages": [ + { + "extensionBzlFile": "@io_bazel_rules_go//go/private:extensions.bzl", + "extensionName": "non_module_dependencies", + "usingModule": "rules_go@0.43.0", + "location": { + "file": "https://bcr.bazel.build/modules/rules_go/0.43.0/MODULE.bazel", + "line": 14, + "column": 40 + }, + "imports": { + "io_bazel_rules_nogo": "io_bazel_rules_nogo" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@io_bazel_rules_go//go:extensions.bzl", + "extensionName": "go_sdk", + "usingModule": "rules_go@0.43.0", + "location": { + "file": "https://bcr.bazel.build/modules/rules_go/0.43.0/MODULE.bazel", + "line": 20, + "column": 23 + }, + "imports": { + "go_toolchains": "go_toolchains" + }, + "devImports": [], + "tags": [ + { + "tagName": "download", + "attributeValues": { + "name": "go_default_sdk", + "version": "1.21.1" + }, + "devDependency": false, + "location": { + "file": "https://bcr.bazel.build/modules/rules_go/0.43.0/MODULE.bazel", + "line": 21, + "column": 16 + } + } + ], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@gazelle//:extensions.bzl", + "extensionName": "go_deps", + "usingModule": "rules_go@0.43.0", + "location": { + "file": "https://bcr.bazel.build/modules/rules_go/0.43.0/MODULE.bazel", + "line": 31, + "column": 24 + }, + "imports": { + "com_github_gogo_protobuf": "com_github_gogo_protobuf", + "com_github_golang_mock": "com_github_golang_mock", + "com_github_golang_protobuf": "com_github_golang_protobuf", + "org_golang_google_genproto": "org_golang_google_genproto", + "org_golang_google_grpc": "org_golang_google_grpc", + "org_golang_google_protobuf": "org_golang_google_protobuf", + "org_golang_x_net": "org_golang_x_net" + }, + "devImports": [], + "tags": [ + { + "tagName": "from_file", + "attributeValues": { + "go_mod": "//:go.mod" + }, + "devDependency": false, + "location": { + "file": "https://bcr.bazel.build/modules/rules_go/0.43.0/MODULE.bazel", + "line": 32, + "column": 18 + } + }, + { + "tagName": "module", + "attributeValues": { + "path": "github.com/gogo/protobuf", + "sum": "h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=", + "version": "v1.3.2" + }, + "devDependency": false, + "location": { + "file": "https://bcr.bazel.build/modules/rules_go/0.43.0/MODULE.bazel", + "line": 33, + "column": 15 + } + } + ], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "bazel_features": "bazel_features@1.1.1", + "bazel_skylib": "bazel_skylib@1.4.1", + "platforms": "platforms@0.0.7", + "rules_proto": "rules_proto@4.0.0", + "com_google_protobuf": "protobuf@3.19.6", + "gazelle": "gazelle@0.34.0", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_go~0.43.0", + "urls": [ + "https://github.com/bazelbuild/rules_go/releases/download/v0.43.0/rules_go-v0.43.0.zip" + ], + "integrity": "sha256-1qtrV+SMCVI+kwUPE2mPcIQoz9XmGSUuNp03evZZdwc=", + "strip_prefix": "", + "remote_patches": {}, + "remote_patch_strip": 0 + } + } + }, + "rules_jvm_external@5.3": { + "name": "rules_jvm_external", + "version": "5.3", + "key": "rules_jvm_external@5.3", + "repoName": "rules_jvm_external", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [ + { + "extensionBzlFile": "@rules_jvm_external//:non-module-deps.bzl", + "extensionName": "non_module_deps", + "usingModule": "rules_jvm_external@5.3", + "location": { + "file": "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel", + "line": 9, + "column": 32 + }, + "imports": { + "io_bazel_rules_kotlin": "io_bazel_rules_kotlin" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": ":extensions.bzl", + "extensionName": "maven", + "usingModule": "rules_jvm_external@5.3", + "location": { + "file": "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel", + "line": 16, + "column": 22 + }, + "imports": { + "rules_jvm_external_deps": "rules_jvm_external_deps" + }, + "devImports": [], + "tags": [ + { + "tagName": "install", + "attributeValues": { + "name": "rules_jvm_external_deps", + "artifacts": [ + "com.google.auth:google-auth-library-credentials:1.17.0", + "com.google.auth:google-auth-library-oauth2-http:1.17.0", + "com.google.cloud:google-cloud-core:2.18.1", + "com.google.cloud:google-cloud-storage:2.22.3", + "com.google.code.gson:gson:2.10.1", + "com.google.googlejavaformat:google-java-format:1.17.0", + "com.google.guava:guava:32.0.0-jre", + "org.apache.maven:maven-artifact:3.9.2", + "software.amazon.awssdk:s3:2.20.78" + ], + "lock_file": "@rules_jvm_external//:rules_jvm_external_deps_install.json" + }, + "devDependency": false, + "location": { + "file": "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel", + "line": 18, + "column": 14 + } + } + ], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "bazel_skylib": "bazel_skylib@1.4.1", + "io_bazel_stardoc": "stardoc@0.5.3", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_jvm_external~5.3", + "urls": [ + "https://github.com/bazelbuild/rules_jvm_external/releases/download/5.3/rules_jvm_external-5.3.tar.gz" + ], + "integrity": "sha256-0x42m4VDIspQmOoSxp1xdd7ZcUNeVcGN2d1fKcxSSaw=", + "strip_prefix": "rules_jvm_external-5.3", + "remote_patches": {}, + "remote_patch_strip": 0 + } + } + }, + "rules_license@0.0.7": { + "name": "rules_license", + "version": "0.0.7", + "key": "rules_license@0.0.7", + "repoName": "rules_license", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_license~0.0.7", + "urls": [ + "https://github.com/bazelbuild/rules_license/releases/download/0.0.7/rules_license-0.0.7.tar.gz" + ], + "integrity": "sha256-RTHezLkTY5ww5cdRKgVNXYdWmNrrddjPkPKEN1/nw2A=", + "strip_prefix": "", + "remote_patches": {}, + "remote_patch_strip": 0 + } + } + }, + "bazel_tools@_": { + "name": "bazel_tools", + "version": "", + "key": "bazel_tools@_", + "repoName": "bazel_tools", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [ + "@local_config_cc_toolchains//:all", + "@local_config_sh//:local_sh_toolchain" + ], + "extensionUsages": [ + { + "extensionBzlFile": "@bazel_tools//tools/cpp:cc_configure.bzl", + "extensionName": "cc_configure_extension", + "usingModule": "bazel_tools@_", + "location": { + "file": "@@bazel_tools//:MODULE.bazel", + "line": 17, + "column": 29 + }, + "imports": { + "local_config_cc": "local_config_cc", + "local_config_cc_toolchains": "local_config_cc_toolchains" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@bazel_tools//tools/osx:xcode_configure.bzl", + "extensionName": "xcode_configure_extension", + "usingModule": "bazel_tools@_", + "location": { + "file": "@@bazel_tools//:MODULE.bazel", + "line": 21, + "column": 32 + }, + "imports": { + "local_config_xcode": "local_config_xcode" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@rules_java//java:extensions.bzl", + "extensionName": "toolchains", + "usingModule": "bazel_tools@_", + "location": { + "file": "@@bazel_tools//:MODULE.bazel", + "line": 24, + "column": 32 + }, + "imports": { + "local_jdk": "local_jdk", + "remote_java_tools": "remote_java_tools", + "remote_java_tools_linux": "remote_java_tools_linux", + "remote_java_tools_windows": "remote_java_tools_windows", + "remote_java_tools_darwin_x86_64": "remote_java_tools_darwin_x86_64", + "remote_java_tools_darwin_arm64": "remote_java_tools_darwin_arm64" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@bazel_tools//tools/sh:sh_configure.bzl", + "extensionName": "sh_configure_extension", + "usingModule": "bazel_tools@_", + "location": { + "file": "@@bazel_tools//:MODULE.bazel", + "line": 35, + "column": 39 + }, + "imports": { + "local_config_sh": "local_config_sh" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@bazel_tools//tools/test:extensions.bzl", + "extensionName": "remote_coverage_tools_extension", + "usingModule": "bazel_tools@_", + "location": { + "file": "@@bazel_tools//:MODULE.bazel", + "line": 39, + "column": 48 + }, + "imports": { + "remote_coverage_tools": "remote_coverage_tools" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@bazel_tools//tools/android:android_extensions.bzl", + "extensionName": "remote_android_tools_extensions", + "usingModule": "bazel_tools@_", + "location": { + "file": "@@bazel_tools//:MODULE.bazel", + "line": 42, + "column": 42 + }, + "imports": { + "android_gmaven_r8": "android_gmaven_r8", + "android_tools": "android_tools" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "rules_cc": "rules_cc@0.0.9", + "rules_java": "rules_java@7.1.0", + "rules_license": "rules_license@0.0.7", + "rules_proto": "rules_proto@4.0.0", + "rules_python": "rules_python@0.4.0", + "platforms": "platforms@0.0.7", + "com_google_protobuf": "protobuf@3.19.6", + "zlib": "zlib@1.3", + "build_bazel_apple_support": "apple_support@1.5.0", + "local_config_platform": "local_config_platform@_" + } + }, + "local_config_platform@_": { + "name": "local_config_platform", + "version": "", + "key": "local_config_platform@_", + "repoName": "local_config_platform", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "platforms": "platforms@0.0.7", + "bazel_tools": "bazel_tools@_" + } + }, + "bazel_skylib@1.4.1": { + "name": "bazel_skylib", + "version": "1.4.1", + "key": "bazel_skylib@1.4.1", + "repoName": "bazel_skylib", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [ + "//toolchains/unittest:cmd_toolchain", + "//toolchains/unittest:bash_toolchain" + ], + "extensionUsages": [], + "deps": { + "platforms": "platforms@0.0.7", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "bazel_skylib~1.4.1", + "urls": [ + "https://github.com/bazelbuild/bazel-skylib/releases/download/1.4.1/bazel-skylib-1.4.1.tar.gz" + ], + "integrity": "sha256-uKFSeQF3QYCvx5iusoxGNL3M8ZxNmOe90c550f6aqtc=", + "strip_prefix": "", + "remote_patches": {}, + "remote_patch_strip": 0 + } + } + }, + "protobuf@3.19.6": { + "name": "protobuf", + "version": "3.19.6", + "key": "protobuf@3.19.6", + "repoName": "protobuf", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "bazel_skylib": "bazel_skylib@1.4.1", + "zlib": "zlib@1.3", + "rules_python": "rules_python@0.4.0", + "rules_cc": "rules_cc@0.0.9", + "rules_proto": "rules_proto@4.0.0", + "rules_java": "rules_java@7.1.0", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "protobuf~3.19.6", + "urls": [ + "https://github.com/protocolbuffers/protobuf/archive/refs/tags/v3.19.6.zip" + ], + "integrity": "sha256-OH4sVZuyx8G8N5jE5s/wFTgaebJ1hpavy/johzC0c4k=", + "strip_prefix": "protobuf-3.19.6", + "remote_patches": { + "https://bcr.bazel.build/modules/protobuf/3.19.6/patches/relative_repo_names.patch": "sha256-w/5gw/zGv8NFId+669hcdw1Uus2lxgYpulATHIwIByI=", + "https://bcr.bazel.build/modules/protobuf/3.19.6/patches/remove_dependency_on_rules_jvm_external.patch": "sha256-THUTnVgEBmjA0W7fKzIyZOVG58DnW9HQTkr4D2zKUUc=", + "https://bcr.bazel.build/modules/protobuf/3.19.6/patches/add_module_dot_bazel_for_examples.patch": "sha256-s/b1gi3baK3LsXefI2rQilhmkb2R5jVJdnT6zEcdfHY=", + "https://bcr.bazel.build/modules/protobuf/3.19.6/patches/module_dot_bazel.patch": "sha256-S0DEni8zgx7rHscW3z/rCEubQnYec0XhNet640cw0h4=" + }, + "remote_patch_strip": 1 + } + } + }, + "rules_proto@4.0.0": { + "name": "rules_proto", + "version": "4.0.0", + "key": "rules_proto@4.0.0", + "repoName": "rules_proto", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "bazel_skylib": "bazel_skylib@1.4.1", + "rules_cc": "rules_cc@0.0.9", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_proto~4.0.0", + "urls": [ + "https://github.com/bazelbuild/rules_proto/archive/refs/tags/4.0.0.zip" + ], + "integrity": "sha256-Lr5z6xyuRA19pNtRYMGjKaynwQpck4H/lwYyVjyhoq4=", + "strip_prefix": "rules_proto-4.0.0", + "remote_patches": { + "https://bcr.bazel.build/modules/rules_proto/4.0.0/patches/module_dot_bazel.patch": "sha256-MclJO7tIAM2ElDAmscNId9pKTpOuDGHgVlW/9VBOIp0=" + }, + "remote_patch_strip": 0 + } + } + }, + "bazel_features@1.1.1": { + "name": "bazel_features", + "version": "1.1.1", + "key": "bazel_features@1.1.1", + "repoName": "bazel_features", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [ + { + "extensionBzlFile": "@bazel_features//private:extensions.bzl", + "extensionName": "version_extension", + "usingModule": "bazel_features@1.1.1", + "location": { + "file": "https://bcr.bazel.build/modules/bazel_features/1.1.1/MODULE.bazel", + "line": 6, + "column": 24 + }, + "imports": { + "bazel_features_globals": "bazel_features_globals", + "bazel_features_version": "bazel_features_version" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "bazel_features~1.1.1", + "urls": [ + "https://github.com/bazel-contrib/bazel_features/releases/download/v1.1.1/bazel_features-v1.1.1.tar.gz" + ], + "integrity": "sha256-YsJuQn5cvHUQJERpJ2IuOYqdzfMsZDJSOIFXCdEcEag=", + "strip_prefix": "bazel_features-1.1.1", + "remote_patches": { + "https://bcr.bazel.build/modules/bazel_features/1.1.1/patches/module_dot_bazel_version.patch": "sha256-+56MAEsc7bYN/Pzhn252ZQUxiRzZg9bynXj1qpsmCYs=" + }, + "remote_patch_strip": 1 + } + } + }, + "stardoc@0.5.3": { + "name": "stardoc", + "version": "0.5.3", + "key": "stardoc@0.5.3", + "repoName": "stardoc", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "bazel_skylib": "bazel_skylib@1.4.1", + "rules_java": "rules_java@7.1.0", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "stardoc~0.5.3", + "urls": [ + "https://github.com/bazelbuild/stardoc/releases/download/0.5.3/stardoc-0.5.3.tar.gz" + ], + "integrity": "sha256-P9j+xN3sPGcL2BCQTi4zFwvt/hL5Ct+UNQgYS+RYyLs=", + "strip_prefix": "", + "remote_patches": { + "https://bcr.bazel.build/modules/stardoc/0.5.3/patches/module_dot_bazel.patch": "sha256-Lgpy9OCr0zBWYuHoyM1rJJrgxn23X/bwgICEF7XiEug=" + }, + "remote_patch_strip": 0 + } + } + }, + "rules_java@7.1.0": { + "name": "rules_java", + "version": "7.1.0", + "key": "rules_java@7.1.0", + "repoName": "rules_java", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [ + "//toolchains:all", + "@local_jdk//:runtime_toolchain_definition", + "@local_jdk//:bootstrap_runtime_toolchain_definition", + "@remotejdk11_linux_toolchain_config_repo//:all", + "@remotejdk11_linux_aarch64_toolchain_config_repo//:all", + "@remotejdk11_linux_ppc64le_toolchain_config_repo//:all", + "@remotejdk11_linux_s390x_toolchain_config_repo//:all", + "@remotejdk11_macos_toolchain_config_repo//:all", + "@remotejdk11_macos_aarch64_toolchain_config_repo//:all", + "@remotejdk11_win_toolchain_config_repo//:all", + "@remotejdk11_win_arm64_toolchain_config_repo//:all", + "@remotejdk17_linux_toolchain_config_repo//:all", + "@remotejdk17_linux_aarch64_toolchain_config_repo//:all", + "@remotejdk17_linux_ppc64le_toolchain_config_repo//:all", + "@remotejdk17_linux_s390x_toolchain_config_repo//:all", + "@remotejdk17_macos_toolchain_config_repo//:all", + "@remotejdk17_macos_aarch64_toolchain_config_repo//:all", + "@remotejdk17_win_toolchain_config_repo//:all", + "@remotejdk17_win_arm64_toolchain_config_repo//:all", + "@remotejdk21_linux_toolchain_config_repo//:all", + "@remotejdk21_linux_aarch64_toolchain_config_repo//:all", + "@remotejdk21_macos_toolchain_config_repo//:all", + "@remotejdk21_macos_aarch64_toolchain_config_repo//:all", + "@remotejdk21_win_toolchain_config_repo//:all" + ], + "extensionUsages": [ + { + "extensionBzlFile": "@rules_java//java:extensions.bzl", + "extensionName": "toolchains", + "usingModule": "rules_java@7.1.0", + "location": { + "file": "https://bcr.bazel.build/modules/rules_java/7.1.0/MODULE.bazel", + "line": 19, + "column": 27 + }, + "imports": { + "remote_java_tools": "remote_java_tools", + "remote_java_tools_linux": "remote_java_tools_linux", + "remote_java_tools_windows": "remote_java_tools_windows", + "remote_java_tools_darwin_x86_64": "remote_java_tools_darwin_x86_64", + "remote_java_tools_darwin_arm64": "remote_java_tools_darwin_arm64", + "local_jdk": "local_jdk", + "remotejdk11_linux_toolchain_config_repo": "remotejdk11_linux_toolchain_config_repo", + "remotejdk11_linux_aarch64_toolchain_config_repo": "remotejdk11_linux_aarch64_toolchain_config_repo", + "remotejdk11_linux_ppc64le_toolchain_config_repo": "remotejdk11_linux_ppc64le_toolchain_config_repo", + "remotejdk11_linux_s390x_toolchain_config_repo": "remotejdk11_linux_s390x_toolchain_config_repo", + "remotejdk11_macos_toolchain_config_repo": "remotejdk11_macos_toolchain_config_repo", + "remotejdk11_macos_aarch64_toolchain_config_repo": "remotejdk11_macos_aarch64_toolchain_config_repo", + "remotejdk11_win_toolchain_config_repo": "remotejdk11_win_toolchain_config_repo", + "remotejdk11_win_arm64_toolchain_config_repo": "remotejdk11_win_arm64_toolchain_config_repo", + "remotejdk17_linux_toolchain_config_repo": "remotejdk17_linux_toolchain_config_repo", + "remotejdk17_linux_aarch64_toolchain_config_repo": "remotejdk17_linux_aarch64_toolchain_config_repo", + "remotejdk17_linux_ppc64le_toolchain_config_repo": "remotejdk17_linux_ppc64le_toolchain_config_repo", + "remotejdk17_linux_s390x_toolchain_config_repo": "remotejdk17_linux_s390x_toolchain_config_repo", + "remotejdk17_macos_toolchain_config_repo": "remotejdk17_macos_toolchain_config_repo", + "remotejdk17_macos_aarch64_toolchain_config_repo": "remotejdk17_macos_aarch64_toolchain_config_repo", + "remotejdk17_win_toolchain_config_repo": "remotejdk17_win_toolchain_config_repo", + "remotejdk17_win_arm64_toolchain_config_repo": "remotejdk17_win_arm64_toolchain_config_repo", + "remotejdk21_linux_toolchain_config_repo": "remotejdk21_linux_toolchain_config_repo", + "remotejdk21_linux_aarch64_toolchain_config_repo": "remotejdk21_linux_aarch64_toolchain_config_repo", + "remotejdk21_macos_toolchain_config_repo": "remotejdk21_macos_toolchain_config_repo", + "remotejdk21_macos_aarch64_toolchain_config_repo": "remotejdk21_macos_aarch64_toolchain_config_repo", + "remotejdk21_win_toolchain_config_repo": "remotejdk21_win_toolchain_config_repo" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "platforms": "platforms@0.0.7", + "rules_cc": "rules_cc@0.0.9", + "bazel_skylib": "bazel_skylib@1.4.1", + "rules_proto": "rules_proto@4.0.0", + "rules_license": "rules_license@0.0.7", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0", + "urls": [ + "https://github.com/bazelbuild/rules_java/releases/download/7.1.0/rules_java-7.1.0.tar.gz" + ], + "integrity": "sha256-o3pOX2OrgnFuXdau75iO2EYcegC46TYnImKJn1h81OE=", + "strip_prefix": "", + "remote_patches": {}, + "remote_patch_strip": 0 + } + } + }, + "rules_python@0.4.0": { + "name": "rules_python", + "version": "0.4.0", + "key": "rules_python@0.4.0", + "repoName": "rules_python", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [ + "@bazel_tools//tools/python:autodetecting_toolchain" + ], + "extensionUsages": [ + { + "extensionBzlFile": "@rules_python//bzlmod:extensions.bzl", + "extensionName": "pip_install", + "usingModule": "rules_python@0.4.0", + "location": { + "file": "https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel", + "line": 7, + "column": 28 + }, + "imports": { + "pypi__click": "pypi__click", + "pypi__pip": "pypi__pip", + "pypi__pip_tools": "pypi__pip_tools", + "pypi__pkginfo": "pypi__pkginfo", + "pypi__setuptools": "pypi__setuptools", + "pypi__wheel": "pypi__wheel" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_python~0.4.0", + "urls": [ + "https://github.com/bazelbuild/rules_python/releases/download/0.4.0/rules_python-0.4.0.tar.gz" + ], + "integrity": "sha256-lUqom0kb5KCDMEosuDgBnIuMNyCnq7nEy4GseiQjDOo=", + "strip_prefix": "", + "remote_patches": { + "https://bcr.bazel.build/modules/rules_python/0.4.0/patches/propagate_pip_install_dependencies.patch": "sha256-v7S/dem/mixg63MF4KoRGDA4KEol9ab/tIVp+6Xq0D0=", + "https://bcr.bazel.build/modules/rules_python/0.4.0/patches/module_dot_bazel.patch": "sha256-kG4VIfWxQazzTuh50mvsx6pmyoRVA4lfH5rkto/Oq+Y=" + }, + "remote_patch_strip": 1 + } + } + }, + "zlib@1.3": { + "name": "zlib", + "version": "1.3", + "key": "zlib@1.3", + "repoName": "zlib", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "platforms": "platforms@0.0.7", + "rules_cc": "rules_cc@0.0.9", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "zlib~1.3", + "urls": [ + "https://github.com/madler/zlib/releases/download/v1.3/zlib-1.3.tar.gz" + ], + "integrity": "sha256-/wukwpIBPbwnUws6geH5qBPNOd4Byl4Pi/NVcC76WT4=", + "strip_prefix": "zlib-1.3", + "remote_patches": { + "https://bcr.bazel.build/modules/zlib/1.3/patches/add_build_file.patch": "sha256-Ei+FYaaOo7A3jTKunMEodTI0Uw5NXQyZEcboMC8JskY=", + "https://bcr.bazel.build/modules/zlib/1.3/patches/module_dot_bazel.patch": "sha256-fPWLM+2xaF/kuy+kZc1YTfW6hNjrkG400Ho7gckuyJk=" + }, + "remote_patch_strip": 0 + } + } + }, + "apple_support@1.5.0": { + "name": "apple_support", + "version": "1.5.0", + "key": "apple_support@1.5.0", + "repoName": "build_bazel_apple_support", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [ + "@local_config_apple_cc_toolchains//:all" + ], + "extensionUsages": [ + { + "extensionBzlFile": "@build_bazel_apple_support//crosstool:setup.bzl", + "extensionName": "apple_cc_configure_extension", + "usingModule": "apple_support@1.5.0", + "location": { + "file": "https://bcr.bazel.build/modules/apple_support/1.5.0/MODULE.bazel", + "line": 17, + "column": 35 + }, + "imports": { + "local_config_apple_cc": "local_config_apple_cc", + "local_config_apple_cc_toolchains": "local_config_apple_cc_toolchains" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "bazel_skylib": "bazel_skylib@1.4.1", + "platforms": "platforms@0.0.7", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "apple_support~1.5.0", + "urls": [ + "https://github.com/bazelbuild/apple_support/releases/download/1.5.0/apple_support.1.5.0.tar.gz" + ], + "integrity": "sha256-miM41vja0yRPgj8txghKA+TQ+7J8qJLclw5okNW0gYQ=", + "strip_prefix": "", + "remote_patches": {}, + "remote_patch_strip": 0 + } + } + } + }, + "moduleExtensions": { + "@@apple_support~1.5.0//crosstool:setup.bzl%apple_cc_configure_extension": { + "general": { + "bzlTransitiveDigest": "pMLFCYaRPkgXPQ8vtuNkMfiHfPmRBy6QJfnid4sWfv0=", + "accumulatedFileDigests": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "local_config_apple_cc": { + "bzlFile": "@@apple_support~1.5.0//crosstool:setup.bzl", + "ruleClassName": "_apple_cc_autoconf", + "attributes": { + "name": "apple_support~1.5.0~apple_cc_configure_extension~local_config_apple_cc" + } + }, + "local_config_apple_cc_toolchains": { + "bzlFile": "@@apple_support~1.5.0//crosstool:setup.bzl", + "ruleClassName": "_apple_cc_autoconf_toolchains", + "attributes": { + "name": "apple_support~1.5.0~apple_cc_configure_extension~local_config_apple_cc_toolchains" + } + } + } + } + }, + "@@bazel_features~1.1.1//private:extensions.bzl%version_extension": { + "general": { + "bzlTransitiveDigest": "xm7Skm1Las5saxzFWt2hbS+e68BWi+MXyt6+lKIhjPA=", + "accumulatedFileDigests": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "bazel_features_version": { + "bzlFile": "@@bazel_features~1.1.1//private:version_repo.bzl", + "ruleClassName": "version_repo", + "attributes": { + "name": "bazel_features~1.1.1~version_extension~bazel_features_version" + } + }, + "bazel_features_globals": { + "bzlFile": "@@bazel_features~1.1.1//private:globals_repo.bzl", + "ruleClassName": "globals_repo", + "attributes": { + "name": "bazel_features~1.1.1~version_extension~bazel_features_globals", + "globals": { + "RunEnvironmentInfo": "5.3.0", + "DefaultInfo": "0.0.1", + "__TestingOnly_NeverAvailable": "1000000000.0.0" + } + } + } + } + } + }, + "@@bazel_tools//tools/cpp:cc_configure.bzl%cc_configure_extension": { + "general": { + "bzlTransitiveDigest": "O9sf6ilKWU9Veed02jG9o2HM/xgV/UAyciuFBuxrFRY=", + "accumulatedFileDigests": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "local_config_cc": { + "bzlFile": "@@bazel_tools//tools/cpp:cc_configure.bzl", + "ruleClassName": "cc_autoconf", + "attributes": { + "name": "bazel_tools~cc_configure_extension~local_config_cc" + } + }, + "local_config_cc_toolchains": { + "bzlFile": "@@bazel_tools//tools/cpp:cc_configure.bzl", + "ruleClassName": "cc_autoconf_toolchains", + "attributes": { + "name": "bazel_tools~cc_configure_extension~local_config_cc_toolchains" + } + } + } + } + }, + "@@bazel_tools//tools/osx:xcode_configure.bzl%xcode_configure_extension": { + "general": { + "bzlTransitiveDigest": "Qh2bWTU6QW6wkrd87qrU4YeY+SG37Nvw3A0PR4Y0L2Y=", + "accumulatedFileDigests": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "local_config_xcode": { + "bzlFile": "@@bazel_tools//tools/osx:xcode_configure.bzl", + "ruleClassName": "xcode_autoconf", + "attributes": { + "name": "bazel_tools~xcode_configure_extension~local_config_xcode", + "xcode_locator": "@bazel_tools//tools/osx:xcode_locator.m", + "remote_xcode": "" + } + } + } + } + }, + "@@bazel_tools//tools/sh:sh_configure.bzl%sh_configure_extension": { + "general": { + "bzlTransitiveDigest": "hp4NgmNjEg5+xgvzfh6L83bt9/aiiWETuNpwNuF1MSU=", + "accumulatedFileDigests": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "local_config_sh": { + "bzlFile": "@@bazel_tools//tools/sh:sh_configure.bzl", + "ruleClassName": "sh_config", + "attributes": { + "name": "bazel_tools~sh_configure_extension~local_config_sh" + } + } + } + } + }, + "@@rules_go~0.43.0//go:extensions.bzl%go_sdk": { + "os:osx,arch:aarch64": { + "bzlTransitiveDigest": "X7FY+0kUDFpsa3ulS9IPEJAqEW8vwFdmD7u4epims+M=", + "accumulatedFileDigests": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "go_default_sdk": { + "bzlFile": "@@rules_go~0.43.0//go/private:sdk.bzl", + "ruleClassName": "go_download_sdk_rule", + "attributes": { + "name": "rules_go~0.43.0~go_sdk~go_default_sdk", + "goos": "", + "goarch": "", + "sdks": {}, + "experiments": [], + "patches": [], + "patch_strip": 0, + "urls": [ + "https://dl.google.com/go/{}" + ], + "version": "1.21.1", + "strip_prefix": "go" + } + }, + "go_host_compatible_sdk_label": { + "bzlFile": "@@rules_go~0.43.0//go/private:extensions.bzl", + "ruleClassName": "host_compatible_toolchain", + "attributes": { + "name": "rules_go~0.43.0~go_sdk~go_host_compatible_sdk_label", + "toolchain": "@go_default_sdk//:ROOT" + } + }, + "go_toolchains": { + "bzlFile": "@@rules_go~0.43.0//go/private:sdk.bzl", + "ruleClassName": "go_multiple_toolchains", + "attributes": { + "name": "rules_go~0.43.0~go_sdk~go_toolchains", + "prefixes": [ + "_0000_go_default_sdk_" + ], + "geese": [ + "" + ], + "goarchs": [ + "" + ], + "sdk_repos": [ + "go_default_sdk" + ], + "sdk_types": [ + "remote" + ], + "sdk_versions": [ + "1.21.1" + ] + } + } + } + } + }, + "@@rules_java~7.1.0//java:extensions.bzl%toolchains": { + "general": { + "bzlTransitiveDigest": "iUIRqCK7tkhvcDJCAfPPqSd06IHG0a8HQD0xeQyVAqw=", + "accumulatedFileDigests": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "remotejdk21_linux_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk21_linux_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_linux//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_linux//:jdk\",\n)\n" + } + }, + "remotejdk17_linux_s390x_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_s390x_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:s390x\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_s390x//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:s390x\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_s390x//:jdk\",\n)\n" + } + }, + "remotejdk17_macos_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_macos_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_macos//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_macos//:jdk\",\n)\n" + } + }, + "remotejdk21_macos_aarch64_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk21_macos_aarch64_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_macos_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_macos_aarch64//:jdk\",\n)\n" + } + }, + "remotejdk17_linux_aarch64_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_aarch64_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_aarch64//:jdk\",\n)\n" + } + }, + "remotejdk21_macos_aarch64": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk21_macos_aarch64", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n", + "sha256": "2a7a99a3ea263dbd8d32a67d1e6e363ba8b25c645c826f5e167a02bbafaff1fa", + "strip_prefix": "zulu21.28.85-ca-jdk21.0.0-macosx_aarch64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-macosx_aarch64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-macosx_aarch64.tar.gz" + ] + } + }, + "remotejdk17_linux_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux//:jdk\",\n)\n" + } + }, + "remotejdk17_macos_aarch64": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_macos_aarch64", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", + "sha256": "314b04568ec0ae9b36ba03c9cbd42adc9e1265f74678923b19297d66eb84dcca", + "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-macosx_aarch64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-macosx_aarch64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-macosx_aarch64.tar.gz" + ] + } + }, + "remote_java_tools_windows": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remote_java_tools_windows", + "sha256": "c5c70c214a350f12cbf52da8270fa43ba629b795f3dd328028a38f8f0d39c2a1", + "urls": [ + "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.1/java_tools_windows-v13.1.zip", + "https://github.com/bazelbuild/java_tools/releases/download/java_v13.1/java_tools_windows-v13.1.zip" + ] + } + }, + "remotejdk11_win": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_win", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", + "sha256": "43408193ce2fa0862819495b5ae8541085b95660153f2adcf91a52d3a1710e83", + "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-win_x64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-win_x64.zip", + "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-win_x64.zip" + ] + } + }, + "remotejdk11_win_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_win_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_win//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_win//:jdk\",\n)\n" + } + }, + "remotejdk11_linux_aarch64": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_aarch64", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", + "sha256": "54174439f2b3fddd11f1048c397fe7bb45d4c9d66d452d6889b013d04d21c4de", + "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-linux_aarch64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-linux_aarch64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-linux_aarch64.tar.gz" + ] + } + }, + "remotejdk17_linux": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_linux", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", + "sha256": "b9482f2304a1a68a614dfacddcf29569a72f0fac32e6c74f83dc1b9a157b8340", + "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-linux_x64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-linux_x64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-linux_x64.tar.gz" + ] + } + }, + "remotejdk11_linux_s390x_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_s390x_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:s390x\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_s390x//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:s390x\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_s390x//:jdk\",\n)\n" + } + }, + "remotejdk11_linux_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux//:jdk\",\n)\n" + } + }, + "remotejdk11_macos": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_macos", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", + "sha256": "bcaab11cfe586fae7583c6d9d311c64384354fb2638eb9a012eca4c3f1a1d9fd", + "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-macosx_x64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-macosx_x64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-macosx_x64.tar.gz" + ] + } + }, + "remotejdk11_win_arm64": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_win_arm64", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", + "sha256": "b8a28e6e767d90acf793ea6f5bed0bb595ba0ba5ebdf8b99f395266161e53ec2", + "strip_prefix": "jdk-11.0.13+8", + "urls": [ + "https://mirror.bazel.build/aka.ms/download-jdk/microsoft-jdk-11.0.13.8.1-windows-aarch64.zip" + ] + } + }, + "remotejdk17_macos": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_macos", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", + "sha256": "640453e8afe8ffe0fb4dceb4535fb50db9c283c64665eebb0ba68b19e65f4b1f", + "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-macosx_x64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-macosx_x64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-macosx_x64.tar.gz" + ] + } + }, + "remotejdk21_macos": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk21_macos", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n", + "sha256": "9639b87db586d0c89f7a9892ae47f421e442c64b97baebdff31788fbe23265bd", + "strip_prefix": "zulu21.28.85-ca-jdk21.0.0-macosx_x64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-macosx_x64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-macosx_x64.tar.gz" + ] + } + }, + "remotejdk21_macos_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk21_macos_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_macos//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_macos//:jdk\",\n)\n" + } + }, + "remotejdk17_macos_aarch64_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_macos_aarch64_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_macos_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_macos_aarch64//:jdk\",\n)\n" + } + }, + "remotejdk17_win": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_win", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", + "sha256": "192f2afca57701de6ec496234f7e45d971bf623ff66b8ee4a5c81582054e5637", + "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-win_x64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-win_x64.zip", + "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-win_x64.zip" + ] + } + }, + "remotejdk11_macos_aarch64_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_macos_aarch64_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_macos_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_macos_aarch64//:jdk\",\n)\n" + } + }, + "remotejdk11_linux_ppc64le_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_ppc64le_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:ppc\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_ppc64le//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:ppc\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_ppc64le//:jdk\",\n)\n" + } + }, + "remotejdk21_linux": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk21_linux", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n", + "sha256": "0c0eadfbdc47a7ca64aeab51b9c061f71b6e4d25d2d87674512e9b6387e9e3a6", + "strip_prefix": "zulu21.28.85-ca-jdk21.0.0-linux_x64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-linux_x64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-linux_x64.tar.gz" + ] + } + }, + "remote_java_tools_linux": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remote_java_tools_linux", + "sha256": "d134da9b04c9023fb6e56a5d4bffccee73f7bc9572ddc4e747778dacccd7a5a7", + "urls": [ + "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.1/java_tools_linux-v13.1.zip", + "https://github.com/bazelbuild/java_tools/releases/download/java_v13.1/java_tools_linux-v13.1.zip" + ] + } + }, + "remotejdk21_win": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk21_win", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n", + "sha256": "e9959d500a0d9a7694ac243baf657761479da132f0f94720cbffd092150bd802", + "strip_prefix": "zulu21.28.85-ca-jdk21.0.0-win_x64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-win_x64.zip", + "https://cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-win_x64.zip" + ] + } + }, + "remotejdk21_linux_aarch64": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk21_linux_aarch64", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n", + "sha256": "1fb64b8036c5d463d8ab59af06bf5b6b006811e6012e3b0eb6bccf57f1c55835", + "strip_prefix": "zulu21.28.85-ca-jdk21.0.0-linux_aarch64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-linux_aarch64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-linux_aarch64.tar.gz" + ] + } + }, + "remotejdk11_linux_aarch64_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_aarch64_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_aarch64//:jdk\",\n)\n" + } + }, + "remotejdk11_linux_s390x": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_s390x", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", + "sha256": "a58fc0361966af0a5d5a31a2d8a208e3c9bb0f54f345596fd80b99ea9a39788b", + "strip_prefix": "jdk-11.0.15+10", + "urls": [ + "https://mirror.bazel.build/github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.15+10/OpenJDK11U-jdk_s390x_linux_hotspot_11.0.15_10.tar.gz", + "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.15+10/OpenJDK11U-jdk_s390x_linux_hotspot_11.0.15_10.tar.gz" + ] + } + }, + "remotejdk17_linux_aarch64": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_aarch64", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", + "sha256": "6531cef61e416d5a7b691555c8cf2bdff689201b8a001ff45ab6740062b44313", + "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-linux_aarch64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-linux_aarch64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-linux_aarch64.tar.gz" + ] + } + }, + "remotejdk17_win_arm64_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_win_arm64_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:arm64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_win_arm64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:arm64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_win_arm64//:jdk\",\n)\n" + } + }, + "remotejdk11_linux": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_linux", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", + "sha256": "a34b404f87a08a61148b38e1416d837189e1df7a040d949e743633daf4695a3c", + "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-linux_x64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-linux_x64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-linux_x64.tar.gz" + ] + } + }, + "remotejdk11_macos_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_macos_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_macos//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_macos//:jdk\",\n)\n" + } + }, + "remotejdk17_linux_ppc64le_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_ppc64le_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:ppc\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_ppc64le//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:ppc\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_ppc64le//:jdk\",\n)\n" + } + }, + "remotejdk17_win_arm64": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_win_arm64", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", + "sha256": "6802c99eae0d788e21f52d03cab2e2b3bf42bc334ca03cbf19f71eb70ee19f85", + "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-win_aarch64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-win_aarch64.zip", + "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-win_aarch64.zip" + ] + } + }, + "remote_java_tools_darwin_arm64": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remote_java_tools_darwin_arm64", + "sha256": "dab5bb87ec43e980faea6e1cec14bafb217b8e2f5346f53aa784fd715929a930", + "urls": [ + "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.1/java_tools_darwin_arm64-v13.1.zip", + "https://github.com/bazelbuild/java_tools/releases/download/java_v13.1/java_tools_darwin_arm64-v13.1.zip" + ] + } + }, + "remotejdk17_linux_ppc64le": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_ppc64le", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", + "sha256": "00a4c07603d0218cd678461b5b3b7e25b3253102da4022d31fc35907f21a2efd", + "strip_prefix": "jdk-17.0.8.1+1", + "urls": [ + "https://mirror.bazel.build/github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.8.1%2B1/OpenJDK17U-jdk_ppc64le_linux_hotspot_17.0.8.1_1.tar.gz", + "https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.8.1%2B1/OpenJDK17U-jdk_ppc64le_linux_hotspot_17.0.8.1_1.tar.gz" + ] + } + }, + "remotejdk21_linux_aarch64_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk21_linux_aarch64_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_linux_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_linux_aarch64//:jdk\",\n)\n" + } + }, + "remotejdk11_win_arm64_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_win_arm64_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:arm64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_win_arm64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:arm64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_win_arm64//:jdk\",\n)\n" + } + }, + "local_jdk": { + "bzlFile": "@@rules_java~7.1.0//toolchains:local_java_repository.bzl", + "ruleClassName": "_local_java_repository_rule", + "attributes": { + "name": "rules_java~7.1.0~toolchains~local_jdk", + "java_home": "", + "version": "", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = {RUNTIME_VERSION},\n)\n" + } + }, + "remote_java_tools_darwin_x86_64": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remote_java_tools_darwin_x86_64", + "sha256": "0db40d8505a2b65ef0ed46e4256757807db8162f7acff16225be57c1d5726dbc", + "urls": [ + "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.1/java_tools_darwin_x86_64-v13.1.zip", + "https://github.com/bazelbuild/java_tools/releases/download/java_v13.1/java_tools_darwin_x86_64-v13.1.zip" + ] + } + }, + "remote_java_tools": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remote_java_tools", + "sha256": "286bdbbd66e616fc4ed3f90101418729a73baa7e8c23a98ffbef558f74c0ad14", + "urls": [ + "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.1/java_tools-v13.1.zip", + "https://github.com/bazelbuild/java_tools/releases/download/java_v13.1/java_tools-v13.1.zip" + ] + } + }, + "remotejdk17_linux_s390x": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_s390x", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", + "sha256": "ffacba69c6843d7ca70d572489d6cc7ab7ae52c60f0852cedf4cf0d248b6fc37", + "strip_prefix": "jdk-17.0.8.1+1", + "urls": [ + "https://mirror.bazel.build/github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.8.1%2B1/OpenJDK17U-jdk_s390x_linux_hotspot_17.0.8.1_1.tar.gz", + "https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.8.1%2B1/OpenJDK17U-jdk_s390x_linux_hotspot_17.0.8.1_1.tar.gz" + ] + } + }, + "remotejdk17_win_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_win_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_win//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_win//:jdk\",\n)\n" + } + }, + "remotejdk11_linux_ppc64le": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_ppc64le", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", + "sha256": "a8fba686f6eb8ae1d1a9566821dbd5a85a1108b96ad857fdbac5c1e4649fc56f", + "strip_prefix": "jdk-11.0.15+10", + "urls": [ + "https://mirror.bazel.build/github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.15+10/OpenJDK11U-jdk_ppc64le_linux_hotspot_11.0.15_10.tar.gz", + "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.15+10/OpenJDK11U-jdk_ppc64le_linux_hotspot_11.0.15_10.tar.gz" + ] + } + }, + "remotejdk11_macos_aarch64": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_macos_aarch64", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", + "sha256": "7632bc29f8a4b7d492b93f3bc75a7b61630894db85d136456035ab2a24d38885", + "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-macosx_aarch64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-macosx_aarch64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-macosx_aarch64.tar.gz" + ] + } + }, + "remotejdk21_win_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk21_win_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_win//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_win//:jdk\",\n)\n" + } + } + } + } + }, + "@@rules_jvm_external~5.3//:extensions.bzl%maven": { + "general": { + "bzlTransitiveDigest": "9VQBVBpk1BYX8MlZX/v6yoWpeoWbbeIDc8bZ2kiueLI=", + "accumulatedFileDigests": { + "@@//:maven_install.json": "a5ee74885480c4e38f70dd8ca3e8ef2b7d89c81a581bbc196965d22aabd9b2ab", + "@@rules_jvm_external~5.3//:rules_jvm_external_deps_install.json": "741ab2ef3843a43eaacb45d1448835c9deb99c95162279f513096eface8acd44" + }, + "envVariables": {}, + "generatedRepoSpecs": { + "io_grpc_grpc_netty_shaded_jar_sources_1_56_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_netty_shaded_jar_sources_1_56_1", + "sha256": "4a7dd3517fc4540e926cd958b3a48ffc561f42ad9dfe31e3f2ccc13ba1742939", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-netty-shaded/1.56.1/grpc-netty-shaded-1.56.1-sources.jar" + ], + "downloaded_file_path": "io/grpc/grpc-netty-shaded/1.56.1/grpc-netty-shaded-1.56.1-sources.jar" + } + }, + "me_dinowernli_java_grpc_prometheus": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~me_dinowernli_java_grpc_prometheus", + "generating_repository": "maven", + "target_name": "me_dinowernli_java_grpc_prometheus" + } + }, + "com_sun_activation_jakarta_activation_1_2_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_sun_activation_jakarta_activation_1_2_1", + "sha256": "d84d4ba8b55cdb7fdcbb885e6939386367433f56f5ab8cfdc302a7c3587fa92b", + "urls": [ + "https://repo1.maven.org/maven2/com/sun/activation/jakarta.activation/1.2.1/jakarta.activation-1.2.1.jar" + ], + "downloaded_file_path": "com/sun/activation/jakarta.activation/1.2.1/jakarta.activation-1.2.1.jar" + } + }, + "io_netty_netty_resolver_dns_jar_sources_4_1_96_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_resolver_dns_jar_sources_4_1_96_Final", + "sha256": "77eeef5ac81bf4b1ad919dc0e7b44bd4f2a4f71418c57beb341685f299fdc963", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-resolver-dns/4.1.96.Final/netty-resolver-dns-4.1.96.Final-sources.jar" + ], + "downloaded_file_path": "io/netty/netty-resolver-dns/4.1.96.Final/netty-resolver-dns-4.1.96.Final-sources.jar" + } + }, + "io_grpc_grpc_alts_1_55_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_alts_1_55_1", + "sha256": "9ab78b042d55cb501a2126c831896f3223e39c65085351b40a588b085ed6d431", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-alts/1.55.1/grpc-alts-1.55.1.jar", + "https://maven.google.com/io/grpc/grpc-alts/1.55.1/grpc-alts-1.55.1.jar" + ], + "downloaded_file_path": "io/grpc/grpc-alts/1.55.1/grpc-alts-1.55.1.jar" + } + }, + "com_github_jnr_jffi_1_3_11": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_jnr_jffi_1_3_11", + "sha256": "74d3bce7397b4872ccb6a6fd84b8f260503f76509adc9548029f665852ad38d7", + "urls": [ + "https://repo1.maven.org/maven2/com/github/jnr/jffi/1.3.11/jffi-1.3.11.jar" + ], + "downloaded_file_path": "com/github/jnr/jffi/1.3.11/jffi-1.3.11.jar" + } + }, + "io_prometheus_simpleclient_tracer_common_jar_sources_0_15_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_tracer_common_jar_sources_0_15_0", + "sha256": "ad5a691dc6b1b5096de0a209530c07a8f98d31d51895730136699a74caa1145a", + "urls": [ + "https://repo1.maven.org/maven2/io/prometheus/simpleclient_tracer_common/0.15.0/simpleclient_tracer_common-0.15.0-sources.jar" + ], + "downloaded_file_path": "io/prometheus/simpleclient_tracer_common/0.15.0/simpleclient_tracer_common-0.15.0-sources.jar" + } + }, + "com_google_truth_truth": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_truth_truth", + "generating_repository": "maven", + "target_name": "com_google_truth_truth" + } + }, + "io_opencensus_opencensus_api_jar_sources_0_31_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_opencensus_opencensus_api_jar_sources_0_31_1", + "sha256": "6748d57aaae81995514ad3e2fb11a95aa88e158b3f93450288018eaccf31e86b", + "urls": [ + "https://repo1.maven.org/maven2/io/opencensus/opencensus-api/0.31.1/opencensus-api-0.31.1-sources.jar" + ], + "downloaded_file_path": "io/opencensus/opencensus-api/0.31.1/opencensus-api-0.31.1-sources.jar" + } + }, + "com_github_kevinstern_software_and_algorithms_1_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_kevinstern_software_and_algorithms_1_0", + "sha256": "61ab82439cef37343b14f53154c461619375373a56b9338e895709fb54e0864c", + "urls": [ + "https://repo1.maven.org/maven2/com/github/kevinstern/software-and-algorithms/1.0/software-and-algorithms-1.0.jar" + ], + "downloaded_file_path": "com/github/kevinstern/software-and-algorithms/1.0/software-and-algorithms-1.0.jar" + } + }, + "com_google_protobuf_protobuf_java_util": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_protobuf_protobuf_java_util", + "generating_repository": "maven", + "target_name": "com_google_protobuf_protobuf_java_util" + } + }, + "io_grpc_grpc_api_1_56_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_api_1_56_1", + "sha256": "b090b1bb5a3b066f7f2ef14b9ba68e3304de80ba34f90414aed3b519c30999e8", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-api/1.56.1/grpc-api-1.56.1.jar" + ], + "downloaded_file_path": "io/grpc/grpc-api/1.56.1/grpc-api-1.56.1.jar" + } + }, + "org_apache_commons_commons_compress_1_23_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_apache_commons_commons_compress_1_23_0", + "sha256": "c267f17160e9ef662b4d78b7f29dca7c82b15c5cff2cb6a9865ef4ab3dd5b787", + "urls": [ + "https://repo1.maven.org/maven2/org/apache/commons/commons-compress/1.23.0/commons-compress-1.23.0.jar" + ], + "downloaded_file_path": "org/apache/commons/commons-compress/1.23.0/commons-compress-1.23.0.jar" + } + }, + "org_reactivestreams_reactive_streams_1_0_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_reactivestreams_reactive_streams_1_0_3", + "sha256": "1dee0481072d19c929b623e155e14d2f6085dc011529a0a0dbefc84cf571d865", + "urls": [ + "https://repo1.maven.org/maven2/org/reactivestreams/reactive-streams/1.0.3/reactive-streams-1.0.3.jar", + "https://maven.google.com/org/reactivestreams/reactive-streams/1.0.3/reactive-streams-1.0.3.jar" + ], + "downloaded_file_path": "org/reactivestreams/reactive-streams/1.0.3/reactive-streams-1.0.3.jar" + } + }, + "com_google_protobuf_protobuf_java_util_3_22_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_protobuf_protobuf_java_util_3_22_3", + "sha256": "c615f76879dc5c303e4df5b94a6afa39534058c7545db2d483fd95d9f63c8bfe", + "urls": [ + "https://repo1.maven.org/maven2/com/google/protobuf/protobuf-java-util/3.22.3/protobuf-java-util-3.22.3.jar" + ], + "downloaded_file_path": "com/google/protobuf/protobuf-java-util/3.22.3/protobuf-java-util-3.22.3.jar" + } + }, + "org_reactivestreams_reactive_streams_1_0_4": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_reactivestreams_reactive_streams_1_0_4", + "sha256": "f75ca597789b3dac58f61857b9ac2e1034a68fa672db35055a8fb4509e325f28", + "urls": [ + "https://repo1.maven.org/maven2/org/reactivestreams/reactive-streams/1.0.4/reactive-streams-1.0.4.jar" + ], + "downloaded_file_path": "org/reactivestreams/reactive-streams/1.0.4/reactive-streams-1.0.4.jar" + } + }, + "com_amazonaws_aws_java_sdk_s3_1_12_544": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_amazonaws_aws_java_sdk_s3_1_12_544", + "sha256": "817b2fac490d3e02ecaf3253c2e2ab0bf6d2291a841574cec70464312d669230", + "urls": [ + "https://repo1.maven.org/maven2/com/amazonaws/aws-java-sdk-s3/1.12.544/aws-java-sdk-s3-1.12.544.jar" + ], + "downloaded_file_path": "com/amazonaws/aws-java-sdk-s3/1.12.544/aws-java-sdk-s3-1.12.544.jar" + } + }, + "joda_time_joda_time_2_8_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~joda_time_joda_time_2_8_1", + "sha256": "b4670b95f75957c974284c5f3ada966040be2578f643c5c6083d262162061fa2", + "urls": [ + "https://repo1.maven.org/maven2/joda-time/joda-time/2.8.1/joda-time-2.8.1.jar" + ], + "downloaded_file_path": "joda-time/joda-time/2.8.1/joda-time-2.8.1.jar" + } + }, + "com_amazonaws_aws_java_sdk_s3": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_amazonaws_aws_java_sdk_s3", + "generating_repository": "maven", + "target_name": "com_amazonaws_aws_java_sdk_s3" + } + }, + "com_github_fppt_jedis_mock": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_fppt_jedis_mock", + "generating_repository": "maven", + "target_name": "com_github_fppt_jedis_mock" + } + }, + "com_jayway_jsonpath_json_path_2_8_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_jayway_jsonpath_json_path_2_8_0", + "sha256": "9601707e95cd79fb98570a01ea8cfb857b5cde948744d6e0edf733c11002c95b", + "urls": [ + "https://repo1.maven.org/maven2/com/jayway/jsonpath/json-path/2.8.0/json-path-2.8.0.jar" + ], + "downloaded_file_path": "com/jayway/jsonpath/json-path/2.8.0/json-path-2.8.0.jar" + } + }, + "com_google_errorprone_error_prone_annotations_jar_sources_2_22_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_errorprone_error_prone_annotations_jar_sources_2_22_0", + "sha256": "c989d7144e4b3313514972df85f8f9dfd53b300e1359e13ca5e6453965c8fcef", + "urls": [ + "https://repo1.maven.org/maven2/com/google/errorprone/error_prone_annotations/2.22.0/error_prone_annotations-2.22.0-sources.jar" + ], + "downloaded_file_path": "com/google/errorprone/error_prone_annotations/2.22.0/error_prone_annotations-2.22.0-sources.jar" + } + }, + "io_prometheus_simpleclient_tracer_otel_agent_jar_sources_0_15_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_tracer_otel_agent_jar_sources_0_15_0", + "sha256": "9071a9ecf1473fd9c71c27082c549dd4e5686039444efb662392b1f3391a5d36", + "urls": [ + "https://repo1.maven.org/maven2/io/prometheus/simpleclient_tracer_otel_agent/0.15.0/simpleclient_tracer_otel_agent-0.15.0-sources.jar" + ], + "downloaded_file_path": "io/prometheus/simpleclient_tracer_otel_agent/0.15.0/simpleclient_tracer_otel_agent-0.15.0-sources.jar" + } + }, + "com_github_serceman_jnr_fuse": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_serceman_jnr_fuse", + "generating_repository": "maven", + "target_name": "com_github_serceman_jnr_fuse" + } + }, + "org_checkerframework_checker_qual_jar_sources_3_38_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_checkerframework_checker_qual_jar_sources_3_38_0", + "sha256": "c1184779ca27c09efe55b54109bf8a2b654112c6e8b28105c0c2dcc5a84465b1", + "urls": [ + "https://repo1.maven.org/maven2/org/checkerframework/checker-qual/3.38.0/checker-qual-3.38.0-sources.jar" + ], + "downloaded_file_path": "org/checkerframework/checker-qual/3.38.0/checker-qual-3.38.0-sources.jar" + } + }, + "org_bouncycastle_bcprov_jdk15on_1_70": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_bouncycastle_bcprov_jdk15on_1_70", + "sha256": "8f3c20e3e2d565d26f33e8d4857a37d0d7f8ac39b62a7026496fcab1bdac30d4", + "urls": [ + "https://repo1.maven.org/maven2/org/bouncycastle/bcprov-jdk15on/1.70/bcprov-jdk15on-1.70.jar" + ], + "downloaded_file_path": "org/bouncycastle/bcprov-jdk15on/1.70/bcprov-jdk15on-1.70.jar" + } + }, + "com_google_code_gson_gson_2_10_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_code_gson_gson_2_10_1", + "sha256": "4241c14a7727c34feea6507ec801318a3d4a90f070e4525681079fb94ee4c593", + "urls": [ + "https://repo1.maven.org/maven2/com/google/code/gson/gson/2.10.1/gson-2.10.1.jar" + ], + "downloaded_file_path": "com/google/code/gson/gson/2.10.1/gson-2.10.1.jar" + } + }, + "io_netty_netty_handler_jar_sources_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_handler_jar_sources_4_1_97_Final", + "sha256": "905739df92b7fe6468504e1e91b964654381eb3d162766f39552d06a0cbf4cd3", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-handler/4.1.97.Final/netty-handler-4.1.97.Final-sources.jar" + ], + "downloaded_file_path": "io/netty/netty-handler/4.1.97.Final/netty-handler-4.1.97.Final-sources.jar" + } + }, + "io_netty_netty_codec_dns_4_1_96_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_dns_4_1_96_Final", + "sha256": "857d0213bd4e504ad897a7c0f967ef3f728f120feea3e824729dad525b44bbce", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-codec-dns/4.1.96.Final/netty-codec-dns-4.1.96.Final.jar" + ], + "downloaded_file_path": "io/netty/netty-codec-dns/4.1.96.Final/netty-codec-dns-4.1.96.Final.jar" + } + }, + "com_google_errorprone_error_prone_core_2_22_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_errorprone_error_prone_core_2_22_0", + "sha256": "32a3df226a9a47f48dd895a9a89678d50ac404282c33400781c38757e8143f2c", + "urls": [ + "https://repo1.maven.org/maven2/com/google/errorprone/error_prone_core/2.22.0/error_prone_core-2.22.0.jar" + ], + "downloaded_file_path": "com/google/errorprone/error_prone_core/2.22.0/error_prone_core-2.22.0.jar" + } + }, + "com_fasterxml_jackson_core_jackson_databind": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_core_jackson_databind", + "generating_repository": "maven", + "target_name": "com_fasterxml_jackson_core_jackson_databind" + } + }, + "io_prometheus_simpleclient_jar_sources_0_15_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_jar_sources_0_15_0", + "sha256": "996c0ae2c1f6fe658865f8b3b3d073d136bd60de1a37fa78db2d52db328d1adb", + "urls": [ + "https://repo1.maven.org/maven2/io/prometheus/simpleclient/0.15.0/simpleclient-0.15.0-sources.jar" + ], + "downloaded_file_path": "io/prometheus/simpleclient/0.15.0/simpleclient-0.15.0-sources.jar" + } + }, + "org_ow2_asm_asm_tree_jar_sources_9_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_ow2_asm_asm_tree_jar_sources_9_2", + "sha256": "c35bc5b4b6c54bf15abec34ab821cf9d0801a64451f4f6070d93dcb87122aa08", + "urls": [ + "https://repo1.maven.org/maven2/org/ow2/asm/asm-tree/9.2/asm-tree-9.2-sources.jar" + ], + "downloaded_file_path": "org/ow2/asm/asm-tree/9.2/asm-tree-9.2-sources.jar" + } + }, + "io_netty_netty_transport_jar_sources_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_jar_sources_4_1_97_Final", + "sha256": "2ee8b4402c42f9bbbb3b4a14cce1f80d0b48f2115c718ea464f3050f58c70b2e", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-transport/4.1.97.Final/netty-transport-4.1.97.Final-sources.jar" + ], + "downloaded_file_path": "io/netty/netty-transport/4.1.97.Final/netty-transport-4.1.97.Final-sources.jar" + } + }, + "org_apache_commons_commons_math3_3_6_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_apache_commons_commons_math3_3_6_1", + "sha256": "1e56d7b058d28b65abd256b8458e3885b674c1d588fa43cd7d1cbb9c7ef2b308", + "urls": [ + "https://repo1.maven.org/maven2/org/apache/commons/commons-math3/3.6.1/commons-math3-3.6.1.jar" + ], + "downloaded_file_path": "org/apache/commons/commons-math3/3.6.1/commons-math3-3.6.1.jar" + } + }, + "org_jboss_marshalling_jboss_marshalling_river_jar_sources_2_0_11_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_jboss_marshalling_jboss_marshalling_river_jar_sources_2_0_11_Final", + "sha256": "c3cb3209f18c0d1fec289669426b105d5247ad53ae98326369c9b4db4b80ceac", + "urls": [ + "https://repo1.maven.org/maven2/org/jboss/marshalling/jboss-marshalling-river/2.0.11.Final/jboss-marshalling-river-2.0.11.Final-sources.jar" + ], + "downloaded_file_path": "org/jboss/marshalling/jboss-marshalling-river/2.0.11.Final/jboss-marshalling-river-2.0.11.Final-sources.jar" + } + }, + "jakarta_annotation_jakarta_annotation_api_jar_sources_1_3_5": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~jakarta_annotation_jakarta_annotation_api_jar_sources_1_3_5", + "sha256": "aa27e9291dce4ddbb0aea52a1cbef41c6330b96b0ae387a995ed412b68a3af7c", + "urls": [ + "https://repo1.maven.org/maven2/jakarta/annotation/jakarta.annotation-api/1.3.5/jakarta.annotation-api-1.3.5-sources.jar" + ], + "downloaded_file_path": "jakarta/annotation/jakarta.annotation-api/1.3.5/jakarta.annotation-api-1.3.5-sources.jar" + } + }, + "org_apache_commons_commons_compress_jar_sources_1_23_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_apache_commons_commons_compress_jar_sources_1_23_0", + "sha256": "2ba017aee1a90ebd2b27ba245c2338f37bf23948f035a2bd75becf623906b709", + "urls": [ + "https://repo1.maven.org/maven2/org/apache/commons/commons-compress/1.23.0/commons-compress-1.23.0-sources.jar" + ], + "downloaded_file_path": "org/apache/commons/commons-compress/1.23.0/commons-compress-1.23.0-sources.jar" + } + }, + "com_github_docker_java_docker_java_transport_netty_3_3_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_docker_java_docker_java_transport_netty_3_3_3", + "sha256": "30152706a19f46f97bea55e85182762d8b5d2d23bea5e465af403537677f879b", + "urls": [ + "https://repo1.maven.org/maven2/com/github/docker-java/docker-java-transport-netty/3.3.3/docker-java-transport-netty-3.3.3.jar" + ], + "downloaded_file_path": "com/github/docker-java/docker-java-transport-netty/3.3.3/docker-java-transport-netty-3.3.3.jar" + } + }, + "io_netty_netty_transport_native_epoll_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_native_epoll_4_1_97_Final", + "sha256": "418a0d0d66d2d52a63a0e2cd5377f8c3186db47c09e3b8af39a43fec39c077fe", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-transport-native-epoll/4.1.97.Final/netty-transport-native-epoll-4.1.97.Final.jar" + ], + "downloaded_file_path": "io/netty/netty-transport-native-epoll/4.1.97.Final/netty-transport-native-epoll-4.1.97.Final.jar" + } + }, + "net_javacrumbs_future_converter_future_converter_common_jar_sources_1_2_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~net_javacrumbs_future_converter_future_converter_common_jar_sources_1_2_0", + "sha256": "24f849eb33ef57a4ea597052f8fa78cbe14076cb36160e7b37a6373d1f162a70", + "urls": [ + "https://repo1.maven.org/maven2/net/javacrumbs/future-converter/future-converter-common/1.2.0/future-converter-common-1.2.0-sources.jar" + ], + "downloaded_file_path": "net/javacrumbs/future-converter/future-converter-common/1.2.0/future-converter-common-1.2.0-sources.jar" + } + }, + "com_google_errorprone_error_prone_type_annotations_2_22_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_errorprone_error_prone_type_annotations_2_22_0", + "sha256": "6618b1d28df562622b77187b5c6dfc9c4c97851af73bd64dc0300efe9a439b20", + "urls": [ + "https://repo1.maven.org/maven2/com/google/errorprone/error_prone_type_annotations/2.22.0/error_prone_type_annotations-2.22.0.jar" + ], + "downloaded_file_path": "com/google/errorprone/error_prone_type_annotations/2.22.0/error_prone_type_annotations-2.22.0.jar" + } + }, + "com_fasterxml_jackson_jaxrs_jackson_jaxrs_json_provider_jar_sources_2_10_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_jaxrs_jackson_jaxrs_json_provider_jar_sources_2_10_3", + "sha256": "b15fd7237ceb93aa289e22bb21335249e3cd33cd6a0fd1be769e6fc63b1513b5", + "urls": [ + "https://repo1.maven.org/maven2/com/fasterxml/jackson/jaxrs/jackson-jaxrs-json-provider/2.10.3/jackson-jaxrs-json-provider-2.10.3-sources.jar" + ], + "downloaded_file_path": "com/fasterxml/jackson/jaxrs/jackson-jaxrs-json-provider/2.10.3/jackson-jaxrs-json-provider-2.10.3-sources.jar" + } + }, + "net_java_dev_jna_jna_platform_jar_sources_5_13_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~net_java_dev_jna_jna_platform_jar_sources_5_13_0", + "sha256": "2f39937649df7e74f36f2b56ee2f15c15d4f9218fde43369c48a6b51e3cc087e", + "urls": [ + "https://repo1.maven.org/maven2/net/java/dev/jna/jna-platform/5.13.0/jna-platform-5.13.0-sources.jar" + ], + "downloaded_file_path": "net/java/dev/jna/jna-platform/5.13.0/jna-platform-5.13.0-sources.jar" + } + }, + "net_javacrumbs_future_converter_future_converter_java8_common_1_2_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~net_javacrumbs_future_converter_future_converter_java8_common_1_2_0", + "sha256": "bed25293fabbf59e048f67f88e55140ebc1cfa4fa899e397545d0193e866a65c", + "urls": [ + "https://repo1.maven.org/maven2/net/javacrumbs/future-converter/future-converter-java8-common/1.2.0/future-converter-java8-common-1.2.0.jar" + ], + "downloaded_file_path": "net/javacrumbs/future-converter/future-converter-java8-common/1.2.0/future-converter-java8-common-1.2.0.jar" + } + }, + "io_prometheus_simpleclient_hotspot": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_hotspot", + "generating_repository": "maven", + "target_name": "io_prometheus_simpleclient_hotspot" + } + }, + "io_netty_netty_codec": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec", + "generating_repository": "maven", + "target_name": "io_netty_netty_codec" + } + }, + "net_javacrumbs_future_converter_future_converter_guava_common_jar_sources_1_2_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~net_javacrumbs_future_converter_future_converter_guava_common_jar_sources_1_2_0", + "sha256": "f5a6c226632ab0c4225962146c8b4dbbfd8db75f1b573c2da29268ac1beecc57", + "urls": [ + "https://repo1.maven.org/maven2/net/javacrumbs/future-converter/future-converter-guava-common/1.2.0/future-converter-guava-common-1.2.0-sources.jar" + ], + "downloaded_file_path": "net/javacrumbs/future-converter/future-converter-guava-common/1.2.0/future-converter-guava-common-1.2.0-sources.jar" + } + }, + "io_grpc_grpc_api_1_55_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_api_1_55_1", + "sha256": "9f21b1585b1c578cf905fb4c926ce895494207cb5bf456a64a24c458850f51d3", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-api/1.55.1/grpc-api-1.55.1.jar", + "https://maven.google.com/io/grpc/grpc-api/1.55.1/grpc-api-1.55.1.jar" + ], + "downloaded_file_path": "io/grpc/grpc-api/1.55.1/grpc-api-1.55.1.jar" + } + }, + "com_fasterxml_jackson_module_jackson_module_jaxb_annotations_jar_sources_2_10_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_module_jackson_module_jaxb_annotations_jar_sources_2_10_3", + "sha256": "81e7738e3a836c465e3170cab143e1c3182c3ca5dd3cfabfceb9a23fe0939a34", + "urls": [ + "https://repo1.maven.org/maven2/com/fasterxml/jackson/module/jackson-module-jaxb-annotations/2.10.3/jackson-module-jaxb-annotations-2.10.3-sources.jar" + ], + "downloaded_file_path": "com/fasterxml/jackson/module/jackson-module-jaxb-annotations/2.10.3/jackson-module-jaxb-annotations-2.10.3-sources.jar" + } + }, + "com_google_errorprone_error_prone_core_jar_sources_2_22_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_errorprone_error_prone_core_jar_sources_2_22_0", + "sha256": "98c52d46fe499a61eea86234f5463bba6968c595dacddb38d89c161e354c62b4", + "urls": [ + "https://repo1.maven.org/maven2/com/google/errorprone/error_prone_core/2.22.0/error_prone_core-2.22.0-sources.jar" + ], + "downloaded_file_path": "com/google/errorprone/error_prone_core/2.22.0/error_prone_core-2.22.0-sources.jar" + } + }, + "net_bytebuddy_byte_buddy_jar_sources_1_14_5": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~net_bytebuddy_byte_buddy_jar_sources_1_14_5", + "sha256": "143dd9fe73f0566cc703934b7fd15abbb97bfab045064c2f176067e70456a136", + "urls": [ + "https://repo1.maven.org/maven2/net/bytebuddy/byte-buddy/1.14.5/byte-buddy-1.14.5-sources.jar" + ], + "downloaded_file_path": "net/bytebuddy/byte-buddy/1.14.5/byte-buddy-1.14.5-sources.jar" + } + }, + "com_google_protobuf_protobuf_java_util_3_23_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_protobuf_protobuf_java_util_3_23_1", + "sha256": "35d78f70fcba8ecaad6b2025a4879099a27997079158500a08fafebad8918c8c", + "urls": [ + "https://repo1.maven.org/maven2/com/google/protobuf/protobuf-java-util/3.23.1/protobuf-java-util-3.23.1.jar", + "https://maven.google.com/com/google/protobuf/protobuf-java-util/3.23.1/protobuf-java-util-3.23.1.jar" + ], + "downloaded_file_path": "com/google/protobuf/protobuf-java-util/3.23.1/protobuf-java-util-3.23.1.jar" + } + }, + "org_ow2_asm_asm_9_5": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_ow2_asm_asm_9_5", + "sha256": "b62e84b5980729751b0458c534cf1366f727542bb8d158621335682a460f0353", + "urls": [ + "https://repo1.maven.org/maven2/org/ow2/asm/asm/9.5/asm-9.5.jar" + ], + "downloaded_file_path": "org/ow2/asm/asm/9.5/asm-9.5.jar" + } + }, + "software_amazon_ion_ion_java_jar_sources_1_0_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~software_amazon_ion_ion_java_jar_sources_1_0_2", + "sha256": "d827fc9775443697bbcdfeb8ea2d3d75bf5ad7f2ca540dabda1a5f83cd0a39de", + "urls": [ + "https://repo1.maven.org/maven2/software/amazon/ion/ion-java/1.0.2/ion-java-1.0.2-sources.jar" + ], + "downloaded_file_path": "software/amazon/ion/ion-java/1.0.2/ion-java-1.0.2-sources.jar" + } + }, + "io_netty_netty_resolver_jar_sources_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_resolver_jar_sources_4_1_97_Final", + "sha256": "dd687a7b2016d38d92d988172b787c713d786e5b8c37896796b156e6798cbd95", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-resolver/4.1.97.Final/netty-resolver-4.1.97.Final-sources.jar" + ], + "downloaded_file_path": "io/netty/netty-resolver/4.1.97.Final/netty-resolver-4.1.97.Final-sources.jar" + } + }, + "org_pcollections_pcollections_jar_sources_3_1_4": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_pcollections_pcollections_jar_sources_3_1_4", + "sha256": "38d91b91467dedcedfd36b6b5f577008fd51748ce74150ebe11ec1227acce218", + "urls": [ + "https://repo1.maven.org/maven2/org/pcollections/pcollections/3.1.4/pcollections-3.1.4-sources.jar" + ], + "downloaded_file_path": "org/pcollections/pcollections/3.1.4/pcollections-3.1.4-sources.jar" + } + }, + "com_google_guava_listenablefuture_9999_0_empty_to_avoid_conflict_with_guava": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_guava_listenablefuture_9999_0_empty_to_avoid_conflict_with_guava", + "sha256": "b372a037d4230aa57fbeffdef30fd6123f9c0c2db85d0aced00c91b974f33f99", + "urls": [ + "https://repo1.maven.org/maven2/com/google/guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar" + ], + "downloaded_file_path": "com/google/guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar" + } + }, + "com_jayway_jsonpath_json_path_jar_sources_2_8_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_jayway_jsonpath_json_path_jar_sources_2_8_0", + "sha256": "ce1d02241b445abf7f4c067b94d77c917fa06fbcbb048519b932a2197a2cc3fd", + "urls": [ + "https://repo1.maven.org/maven2/com/jayway/jsonpath/json-path/2.8.0/json-path-2.8.0-sources.jar" + ], + "downloaded_file_path": "com/jayway/jsonpath/json-path/2.8.0/json-path-2.8.0-sources.jar" + } + }, + "com_google_code_gson_gson": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_code_gson_gson", + "generating_repository": "maven", + "target_name": "com_google_code_gson_gson" + } + }, + "org_json_json_20220320": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_json_json_20220320", + "sha256": "1edf7fcea79a16b8dfdd3bc988ddec7f8908b1f7762fdf00d39acb037542747a", + "urls": [ + "https://repo1.maven.org/maven2/org/json/json/20220320/json-20220320.jar" + ], + "downloaded_file_path": "org/json/json/20220320/json-20220320.jar" + } + }, + "com_fasterxml_jackson_jaxrs_jackson_jaxrs_base_2_10_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_jaxrs_jackson_jaxrs_base_2_10_3", + "sha256": "3b6b74311d094990e6d8de356363988050fb2bf5389138b198b01a0ceb9a9668", + "urls": [ + "https://repo1.maven.org/maven2/com/fasterxml/jackson/jaxrs/jackson-jaxrs-base/2.10.3/jackson-jaxrs-base-2.10.3.jar" + ], + "downloaded_file_path": "com/fasterxml/jackson/jaxrs/jackson-jaxrs-base/2.10.3/jackson-jaxrs-base-2.10.3.jar" + } + }, + "com_google_api_grpc_gapic_google_cloud_storage_v2_2_22_3_alpha": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_api_grpc_gapic_google_cloud_storage_v2_2_22_3_alpha", + "sha256": "2843f647000e82fe1d3b89eff32a15aab7671d917c90b739f31c9aa895bf957a", + "urls": [ + "https://repo1.maven.org/maven2/com/google/api/grpc/gapic-google-cloud-storage-v2/2.22.3-alpha/gapic-google-cloud-storage-v2-2.22.3-alpha.jar", + "https://maven.google.com/com/google/api/grpc/gapic-google-cloud-storage-v2/2.22.3-alpha/gapic-google-cloud-storage-v2-2.22.3-alpha.jar" + ], + "downloaded_file_path": "com/google/api/grpc/gapic-google-cloud-storage-v2/2.22.3-alpha/gapic-google-cloud-storage-v2-2.22.3-alpha.jar" + } + }, + "com_github_ben_manes_caffeine_caffeine_3_0_5": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_ben_manes_caffeine_caffeine_3_0_5", + "sha256": "8a9b54d3506a3b92ee46b217bcee79196b21ca6d52dc2967c686a205fb2f9c15", + "urls": [ + "https://repo1.maven.org/maven2/com/github/ben-manes/caffeine/caffeine/3.0.5/caffeine-3.0.5.jar" + ], + "downloaded_file_path": "com/github/ben-manes/caffeine/caffeine/3.0.5/caffeine-3.0.5.jar" + } + }, + "org_jodd_jodd_core_jar_sources_5_1_6": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_jodd_jodd_core_jar_sources_5_1_6", + "sha256": "2eb5a3af95296bc941767870bf5cb242ba7ee59a5eb0524c73e734578f6c6c16", + "urls": [ + "https://repo1.maven.org/maven2/org/jodd/jodd-core/5.1.6/jodd-core-5.1.6-sources.jar" + ], + "downloaded_file_path": "org/jodd/jodd-core/5.1.6/jodd-core-5.1.6-sources.jar" + } + }, + "org_jetbrains_annotations": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_jetbrains_annotations", + "generating_repository": "maven", + "target_name": "org_jetbrains_annotations" + } + }, + "com_amazonaws_aws_java_sdk_core_1_12_544": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_amazonaws_aws_java_sdk_core_1_12_544", + "sha256": "79682855ea21bd65094ad97109f9b3e4361d3e02926f5ee14ade3411c7ca43da", + "urls": [ + "https://repo1.maven.org/maven2/com/amazonaws/aws-java-sdk-core/1.12.544/aws-java-sdk-core-1.12.544.jar" + ], + "downloaded_file_path": "com/amazonaws/aws-java-sdk-core/1.12.544/aws-java-sdk-core-1.12.544.jar" + } + }, + "org_checkerframework_checker_qual_3_38_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_checkerframework_checker_qual_3_38_0", + "sha256": "9bd02cbe679a58afa0fba44c9621fe70130653e8c4564eb8d65e14bbfe26b7f8", + "urls": [ + "https://repo1.maven.org/maven2/org/checkerframework/checker-qual/3.38.0/checker-qual-3.38.0.jar" + ], + "downloaded_file_path": "org/checkerframework/checker-qual/3.38.0/checker-qual-3.38.0.jar" + } + }, + "org_glassfish_hk2_external_jakarta_inject_2_6_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_glassfish_hk2_external_jakarta_inject_2_6_1", + "sha256": "5e88c123b3e41bca788b2683118867d9b6dec714247ea91c588aed46a36ee24f", + "urls": [ + "https://repo1.maven.org/maven2/org/glassfish/hk2/external/jakarta.inject/2.6.1/jakarta.inject-2.6.1.jar" + ], + "downloaded_file_path": "org/glassfish/hk2/external/jakarta.inject/2.6.1/jakarta.inject-2.6.1.jar" + } + }, + "io_netty_netty_codec_socks_jar_sources_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_socks_jar_sources_4_1_97_Final", + "sha256": "2b48738f837dfc66833b811f6a4eab7fc3a75abd47fee3e7572de7653e5172de", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-codec-socks/4.1.97.Final/netty-codec-socks-4.1.97.Final-sources.jar" + ], + "downloaded_file_path": "io/netty/netty-codec-socks/4.1.97.Final/netty-codec-socks-4.1.97.Final-sources.jar" + } + }, + "com_google_http_client_google_http_client_apache_v2_1_43_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_http_client_google_http_client_apache_v2_1_43_1", + "sha256": "18b25a8bed630a7b90204b7020f72219fdda643935fca6405e6e3937ae92b361", + "urls": [ + "https://repo1.maven.org/maven2/com/google/http-client/google-http-client-apache-v2/1.43.1/google-http-client-apache-v2-1.43.1.jar", + "https://maven.google.com/com/google/http-client/google-http-client-apache-v2/1.43.1/google-http-client-apache-v2-1.43.1.jar" + ], + "downloaded_file_path": "com/google/http-client/google-http-client-apache-v2/1.43.1/google-http-client-apache-v2-1.43.1.jar" + } + }, + "io_netty_netty_transport_classes_epoll_4_1_86_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_classes_epoll_4_1_86_Final", + "sha256": "3cc7eb87d85d6b4bf3d596a172a92df09f8d746c2b283c85543c95795b51edda", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-transport-classes-epoll/4.1.86.Final/netty-transport-classes-epoll-4.1.86.Final.jar", + "https://maven.google.com/io/netty/netty-transport-classes-epoll/4.1.86.Final/netty-transport-classes-epoll-4.1.86.Final.jar" + ], + "downloaded_file_path": "io/netty/netty-transport-classes-epoll/4.1.86.Final/netty-transport-classes-epoll-4.1.86.Final.jar" + } + }, + "com_github_jnr_jnr_x86asm_jar_sources_1_0_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_jnr_jnr_x86asm_jar_sources_1_0_2", + "sha256": "3c983efd496f95ea5382ca014f96613786826136e0ce13d5c1cbc3097ea92ca0", + "urls": [ + "https://repo1.maven.org/maven2/com/github/jnr/jnr-x86asm/1.0.2/jnr-x86asm-1.0.2-sources.jar" + ], + "downloaded_file_path": "com/github/jnr/jnr-x86asm/1.0.2/jnr-x86asm-1.0.2-sources.jar" + } + }, + "io_netty_netty_codec_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_4_1_97_Final", + "sha256": "bcc96737a0f912fcf031cf8c45ebda352a90a40437db0832caad3d5a63618b38", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-codec/4.1.97.Final/netty-codec-4.1.97.Final.jar" + ], + "downloaded_file_path": "io/netty/netty-codec/4.1.97.Final/netty-codec-4.1.97.Final.jar" + } + }, + "com_google_code_gson_gson_jar_sources_2_10_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_code_gson_gson_jar_sources_2_10_1", + "sha256": "eee1cc5c1f4267ee194cc245777e68084738ef390acd763354ce0ff6bfb7bcc1", + "urls": [ + "https://repo1.maven.org/maven2/com/google/code/gson/gson/2.10.1/gson-2.10.1-sources.jar" + ], + "downloaded_file_path": "com/google/code/gson/gson/2.10.1/gson-2.10.1-sources.jar" + } + }, + "org_threeten_threetenbp": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_threeten_threetenbp", + "generating_repository": "maven", + "target_name": "org_threeten_threetenbp" + } + }, + "com_github_jnr_jnr_ffi_2_2_14": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_jnr_jnr_ffi_2_2_14", + "sha256": "01fafe177b1e3136b3789aeb0ff0884ae1e24b5ada711192f67084103697f2d4", + "urls": [ + "https://repo1.maven.org/maven2/com/github/jnr/jnr-ffi/2.2.14/jnr-ffi-2.2.14.jar" + ], + "downloaded_file_path": "com/github/jnr/jnr-ffi/2.2.14/jnr-ffi-2.2.14.jar" + } + }, + "com_google_auto_value_auto_value_annotations_1_10_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_auto_value_auto_value_annotations_1_10_1", + "sha256": "a4fe0a211925e938a8510d741763ee1171a11bf931f5891ef4d4ee84fca72be2", + "urls": [ + "https://repo1.maven.org/maven2/com/google/auto/value/auto-value-annotations/1.10.1/auto-value-annotations-1.10.1.jar" + ], + "downloaded_file_path": "com/google/auto/value/auto-value-annotations/1.10.1/auto-value-annotations-1.10.1.jar" + } + }, + "org_ow2_asm_asm_tree_9_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_ow2_asm_asm_tree_9_2", + "sha256": "aabf9bd23091a4ebfc109c1f3ee7cf3e4b89f6ba2d3f51c5243f16b3cffae011", + "urls": [ + "https://repo1.maven.org/maven2/org/ow2/asm/asm-tree/9.2/asm-tree-9.2.jar" + ], + "downloaded_file_path": "org/ow2/asm/asm-tree/9.2/asm-tree-9.2.jar" + } + }, + "com_google_inject_guice_jar_sources_5_1_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_inject_guice_jar_sources_5_1_0", + "sha256": "79484227656350f8ea315198ed2ebdc8583e7ba42ecd90d367d66a7e491de52e", + "urls": [ + "https://repo1.maven.org/maven2/com/google/inject/guice/5.1.0/guice-5.1.0-sources.jar" + ], + "downloaded_file_path": "com/google/inject/guice/5.1.0/guice-5.1.0-sources.jar" + } + }, + "com_google_api_client_google_api_client_2_2_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_api_client_google_api_client_2_2_0", + "sha256": "58eca9fb0a869391689ffc828b3bd0b19ac76042ff9fab4881eddf7fde76903f", + "urls": [ + "https://repo1.maven.org/maven2/com/google/api-client/google-api-client/2.2.0/google-api-client-2.2.0.jar", + "https://maven.google.com/com/google/api-client/google-api-client/2.2.0/google-api-client-2.2.0.jar" + ], + "downloaded_file_path": "com/google/api-client/google-api-client/2.2.0/google-api-client-2.2.0.jar" + } + }, + "rules_jvm_external_deps": { + "bzlFile": "@@rules_jvm_external~5.3//:coursier.bzl", + "ruleClassName": "pinned_coursier_fetch", + "attributes": { + "name": "rules_jvm_external~5.3~maven~rules_jvm_external_deps", + "repositories": [ + "{ \"repo_url\": \"https://repo1.maven.org/maven2\" }" + ], + "artifacts": [ + "{ \"group\": \"com.google.auth\", \"artifact\": \"google-auth-library-credentials\", \"version\": \"1.17.0\" }", + "{ \"group\": \"com.google.auth\", \"artifact\": \"google-auth-library-oauth2-http\", \"version\": \"1.17.0\" }", + "{ \"group\": \"com.google.cloud\", \"artifact\": \"google-cloud-core\", \"version\": \"2.18.1\" }", + "{ \"group\": \"com.google.cloud\", \"artifact\": \"google-cloud-storage\", \"version\": \"2.22.3\" }", + "{ \"group\": \"com.google.code.gson\", \"artifact\": \"gson\", \"version\": \"2.10.1\" }", + "{ \"group\": \"com.google.googlejavaformat\", \"artifact\": \"google-java-format\", \"version\": \"1.17.0\" }", + "{ \"group\": \"com.google.guava\", \"artifact\": \"guava\", \"version\": \"32.0.0-jre\" }", + "{ \"group\": \"org.apache.maven\", \"artifact\": \"maven-artifact\", \"version\": \"3.9.2\" }", + "{ \"group\": \"software.amazon.awssdk\", \"artifact\": \"s3\", \"version\": \"2.20.78\" }" + ], + "fetch_sources": true, + "fetch_javadoc": false, + "generate_compat_repositories": false, + "maven_install_json": "@@rules_jvm_external~5.3//:rules_jvm_external_deps_install.json", + "override_targets": {}, + "strict_visibility": false, + "strict_visibility_value": [ + "@@//visibility:private" + ], + "jetify": false, + "jetify_include_list": [ + "*" + ], + "additional_netrc_lines": [], + "fail_if_repin_required": false, + "use_starlark_android_rules": false, + "aar_import_bzl_label": "@build_bazel_rules_android//android:rules.bzl", + "duplicate_version_warning": "warn" + } + }, + "net_javacrumbs_future_converter_future_converter_java8_guava": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~net_javacrumbs_future_converter_future_converter_java8_guava", + "generating_repository": "maven", + "target_name": "net_javacrumbs_future_converter_future_converter_java8_guava" + } + }, + "com_google_http_client_google_http_client_appengine_1_43_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_http_client_google_http_client_appengine_1_43_1", + "sha256": "93762484a9324f824455b24da0cb698a7e3467e2e4962ee541a14ff1922c3a88", + "urls": [ + "https://repo1.maven.org/maven2/com/google/http-client/google-http-client-appengine/1.43.1/google-http-client-appengine-1.43.1.jar", + "https://maven.google.com/com/google/http-client/google-http-client-appengine/1.43.1/google-http-client-appengine-1.43.1.jar" + ], + "downloaded_file_path": "com/google/http-client/google-http-client-appengine/1.43.1/google-http-client-appengine-1.43.1.jar" + } + }, + "io_grpc_grpc_auth_1_56_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_auth_1_56_1", + "sha256": "ac365e11532a4b779a2ac80ecc64dcbd3bafbdd666e08e22ffdb5c855069e3f9", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-auth/1.56.1/grpc-auth-1.56.1.jar" + ], + "downloaded_file_path": "io/grpc/grpc-auth/1.56.1/grpc-auth-1.56.1.jar" + } + }, + "com_google_auto_service_auto_service_annotations_1_0_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_auto_service_auto_service_annotations_1_0_1", + "sha256": "c7bec54b7b5588b5967e870341091c5691181d954cf2039f1bf0a6eeb837473b", + "urls": [ + "https://repo1.maven.org/maven2/com/google/auto/service/auto-service-annotations/1.0.1/auto-service-annotations-1.0.1.jar" + ], + "downloaded_file_path": "com/google/auto/service/auto-service-annotations/1.0.1/auto-service-annotations-1.0.1.jar" + } + }, + "io_grpc_grpc_xds_1_55_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_xds_1_55_1", + "sha256": "08e618b3e166981f86d8bd1623f161d6432923183c55338db77df49a2fb23893", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-xds/1.55.1/grpc-xds-1.55.1.jar", + "https://maven.google.com/io/grpc/grpc-xds/1.55.1/grpc-xds-1.55.1.jar" + ], + "downloaded_file_path": "io/grpc/grpc-xds/1.55.1/grpc-xds-1.55.1.jar" + } + }, + "com_fasterxml_jackson_core_jackson_annotations_jar_sources_2_15_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_core_jackson_annotations_jar_sources_2_15_2", + "sha256": "ce8e910f66e0c60d0beec66ccfe308a2426d606c85e67c76a5377dafb52eb4da", + "urls": [ + "https://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-annotations/2.15.2/jackson-annotations-2.15.2-sources.jar" + ], + "downloaded_file_path": "com/fasterxml/jackson/core/jackson-annotations/2.15.2/jackson-annotations-2.15.2-sources.jar" + } + }, + "junit_junit_4_13_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~junit_junit_4_13_2", + "sha256": "8e495b634469d64fb8acfa3495a065cbacc8a0fff55ce1e31007be4c16dc57d3", + "urls": [ + "https://repo1.maven.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar" + ], + "downloaded_file_path": "junit/junit/4.13.2/junit-4.13.2.jar" + } + }, + "com_google_guava_guava_32_1_1_jre": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_guava_guava_32_1_1_jre", + "sha256": "91fbba37f1c8b251cf9ea9e7d3a369eb79eb1e6a5df1d4bbf483dd0380740281", + "urls": [ + "https://repo1.maven.org/maven2/com/google/guava/guava/32.1.1-jre/guava-32.1.1-jre.jar" + ], + "downloaded_file_path": "com/google/guava/guava/32.1.1-jre/guava-32.1.1-jre.jar" + } + }, + "com_googlecode_json_simple_json_simple": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_googlecode_json_simple_json_simple", + "generating_repository": "maven", + "target_name": "com_googlecode_json_simple_json_simple" + } + }, + "io_netty_netty_codec_socks_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_socks_4_1_97_Final", + "sha256": "24081cae8a9685ff3fcde141f5050f28589c22e2ae6c447854e044df6d308028", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-codec-socks/4.1.97.Final/netty-codec-socks-4.1.97.Final.jar" + ], + "downloaded_file_path": "io/netty/netty-codec-socks/4.1.97.Final/netty-codec-socks-4.1.97.Final.jar" + } + }, + "com_esotericsoftware_minlog_1_3_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_esotericsoftware_minlog_1_3_1", + "sha256": "5d4d632cfbebfe0a7644501cc303570b691406181bee65e9916b921c767d7c72", + "urls": [ + "https://repo1.maven.org/maven2/com/esotericsoftware/minlog/1.3.1/minlog-1.3.1.jar" + ], + "downloaded_file_path": "com/esotericsoftware/minlog/1.3.1/minlog-1.3.1.jar" + } + }, + "org_hamcrest_hamcrest_core_1_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_hamcrest_hamcrest_core_1_3", + "sha256": "66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9", + "urls": [ + "https://repo1.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar" + ], + "downloaded_file_path": "org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar" + } + }, + "com_google_http_client_google_http_client_1_42_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_http_client_google_http_client_1_42_3", + "sha256": "e395dd1765e3e6bceb0c610706bcf4128de84bd6e65cf1d4adbf998b4114161c", + "urls": [ + "https://repo1.maven.org/maven2/com/google/http-client/google-http-client/1.42.3/google-http-client-1.42.3.jar" + ], + "downloaded_file_path": "com/google/http-client/google-http-client/1.42.3/google-http-client-1.42.3.jar" + } + }, + "org_jodd_jodd_bean_5_1_6": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_jodd_jodd_bean_5_1_6", + "sha256": "d07d805fe0d59b5d2dbc85d0ebfcf30f52d7fd5a3ff89ff4fbea1e46b1319705", + "urls": [ + "https://repo1.maven.org/maven2/org/jodd/jodd-bean/5.1.6/jodd-bean-5.1.6.jar" + ], + "downloaded_file_path": "org/jodd/jodd-bean/5.1.6/jodd-bean-5.1.6.jar" + } + }, + "me_dinowernli_java_grpc_prometheus_0_6_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~me_dinowernli_java_grpc_prometheus_0_6_0", + "sha256": "badf9c84d9ea4b598bfa3fc690c85a8f6d863265829b9cb79f33884d48729ed8", + "urls": [ + "https://repo1.maven.org/maven2/me/dinowernli/java-grpc-prometheus/0.6.0/java-grpc-prometheus-0.6.0.jar" + ], + "downloaded_file_path": "me/dinowernli/java-grpc-prometheus/0.6.0/java-grpc-prometheus-0.6.0.jar" + } + }, + "org_mockito_mockito_core_jar_sources_2_25_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_mockito_mockito_core_jar_sources_2_25_0", + "sha256": "2230169d4ffad6f6c1b07bba0e81e30fa734941faf073e847839c695907645ff", + "urls": [ + "https://repo1.maven.org/maven2/org/mockito/mockito-core/2.25.0/mockito-core-2.25.0-sources.jar" + ], + "downloaded_file_path": "org/mockito/mockito-core/2.25.0/mockito-core-2.25.0-sources.jar" + } + }, + "org_slf4j_jcl_over_slf4j_1_7_30": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_slf4j_jcl_over_slf4j_1_7_30", + "sha256": "71e9ee37b9e4eb7802a2acc5f41728a4cf3915e7483d798db3b4ff2ec8847c50", + "urls": [ + "https://repo1.maven.org/maven2/org/slf4j/jcl-over-slf4j/1.7.30/jcl-over-slf4j-1.7.30.jar" + ], + "downloaded_file_path": "org/slf4j/jcl-over-slf4j/1.7.30/jcl-over-slf4j-1.7.30.jar" + } + }, + "org_json_json_jar_sources_20220320": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_json_json_jar_sources_20220320", + "sha256": "741ba87153d52919259b085e9a066a603b7efe41ede242336f4e3232d230a899", + "urls": [ + "https://repo1.maven.org/maven2/org/json/json/20220320/json-20220320-sources.jar" + ], + "downloaded_file_path": "org/json/json/20220320/json-20220320-sources.jar" + } + }, + "io_grpc_grpc_stub": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_stub", + "generating_repository": "maven", + "target_name": "io_grpc_grpc_stub" + } + }, + "com_google_errorprone_error_prone_check_api_2_22_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_errorprone_error_prone_check_api_2_22_0", + "sha256": "1717bbf65757b8e1a83f3b0aa78c5ac25a6493008bc730091d404cf798fc0639", + "urls": [ + "https://repo1.maven.org/maven2/com/google/errorprone/error_prone_check_api/2.22.0/error_prone_check_api-2.22.0.jar" + ], + "downloaded_file_path": "com/google/errorprone/error_prone_check_api/2.22.0/error_prone_check_api-2.22.0.jar" + } + }, + "com_github_pcj_google_options_1_0_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_pcj_google_options_1_0_0", + "sha256": "f1f84449b46390a7fa73aac0b5acdec4312d6174146af0db1c92425c7005fdce", + "urls": [ + "https://repo1.maven.org/maven2/com/github/pcj/google-options/1.0.0/google-options-1.0.0.jar" + ], + "downloaded_file_path": "com/github/pcj/google-options/1.0.0/google-options-1.0.0.jar" + } + }, + "com_github_luben_zstd_jni": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_luben_zstd_jni", + "generating_repository": "maven", + "target_name": "com_github_luben_zstd_jni" + } + }, + "com_github_jnr_jnr_posix_3_1_17": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_jnr_jnr_posix_3_1_17", + "sha256": "9e24abedd700a1d8f0a2787566f2d0c4f3e4fbdb8be543d4b434ce445923c757", + "urls": [ + "https://repo1.maven.org/maven2/com/github/jnr/jnr-posix/3.1.17/jnr-posix-3.1.17.jar" + ], + "downloaded_file_path": "com/github/jnr/jnr-posix/3.1.17/jnr-posix-3.1.17.jar" + } + }, + "net_bytebuddy_byte_buddy_agent_1_9_7": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~net_bytebuddy_byte_buddy_agent_1_9_7", + "sha256": "145ce0fab5390374e69b2b4070d65fedaa2b07c3cfad06b330bea1b6dcfa826f", + "urls": [ + "https://repo1.maven.org/maven2/net/bytebuddy/byte-buddy-agent/1.9.7/byte-buddy-agent-1.9.7.jar" + ], + "downloaded_file_path": "net/bytebuddy/byte-buddy-agent/1.9.7/byte-buddy-agent-1.9.7.jar" + } + }, + "io_github_eisop_dataflow_errorprone_jar_sources_3_34_0_eisop1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_github_eisop_dataflow_errorprone_jar_sources_3_34_0_eisop1", + "sha256": "ec56c0f0a96c5e22a3608f2cf9f41c11b5698fee92dd665c21c2dc918e65ef9f", + "urls": [ + "https://repo1.maven.org/maven2/io/github/eisop/dataflow-errorprone/3.34.0-eisop1/dataflow-errorprone-3.34.0-eisop1-sources.jar" + ], + "downloaded_file_path": "io/github/eisop/dataflow-errorprone/3.34.0-eisop1/dataflow-errorprone-3.34.0-eisop1-sources.jar" + } + }, + "io_netty_netty_transport_native_kqueue": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_native_kqueue", + "generating_repository": "maven", + "target_name": "io_netty_netty_transport_native_kqueue" + } + }, + "org_jboss_marshalling_jboss_marshalling_2_0_11_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_jboss_marshalling_jboss_marshalling_2_0_11_Final", + "sha256": "93d6257e1ac0f93ba6ff85827c9ef65b5efabf7bd2241fb3b4caf6c426f4f149", + "urls": [ + "https://repo1.maven.org/maven2/org/jboss/marshalling/jboss-marshalling/2.0.11.Final/jboss-marshalling-2.0.11.Final.jar" + ], + "downloaded_file_path": "org/jboss/marshalling/jboss-marshalling/2.0.11.Final/jboss-marshalling-2.0.11.Final.jar" + } + }, + "com_google_truth_truth_1_1_5": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_truth_truth_1_1_5", + "sha256": "7f6d50d6f43a102942ef2c5a05f37a84f77788bb448cf33cceebf86d34e575c0", + "urls": [ + "https://repo1.maven.org/maven2/com/google/truth/truth/1.1.5/truth-1.1.5.jar" + ], + "downloaded_file_path": "com/google/truth/truth/1.1.5/truth-1.1.5.jar" + } + }, + "io_netty_netty_transport_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_4_1_97_Final", + "sha256": "197fd2d6c6b4afe677d9e95bf2e36b49a0bcabdfce0583683fb73f29a3f5a407", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-transport/4.1.97.Final/netty-transport-4.1.97.Final.jar" + ], + "downloaded_file_path": "io/netty/netty-transport/4.1.97.Final/netty-transport-4.1.97.Final.jar" + } + }, + "io_grpc_grpc_context_jar_sources_1_56_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_context_jar_sources_1_56_1", + "sha256": "315a2c4145c3362131d4af25c27ae9cd4924f8f84e661a31402c56b223bcb956", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-context/1.56.1/grpc-context-1.56.1-sources.jar" + ], + "downloaded_file_path": "io/grpc/grpc-context/1.56.1/grpc-context-1.56.1-sources.jar" + } + }, + "org_slf4j_slf4j_api_2_0_9": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_slf4j_slf4j_api_2_0_9", + "sha256": "0818930dc8d7debb403204611691da58e49d42c50b6ffcfdce02dadb7c3c2b6c", + "urls": [ + "https://repo1.maven.org/maven2/org/slf4j/slf4j-api/2.0.9/slf4j-api-2.0.9.jar" + ], + "downloaded_file_path": "org/slf4j/slf4j-api/2.0.9/slf4j-api-2.0.9.jar" + } + }, + "com_google_j2objc_j2objc_annotations_2_8": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_j2objc_j2objc_annotations_2_8", + "sha256": "f02a95fa1a5e95edb3ed859fd0fb7df709d121a35290eff8b74dce2ab7f4d6ed", + "urls": [ + "https://repo1.maven.org/maven2/com/google/j2objc/j2objc-annotations/2.8/j2objc-annotations-2.8.jar" + ], + "downloaded_file_path": "com/google/j2objc/j2objc-annotations/2.8/j2objc-annotations-2.8.jar" + } + }, + "io_netty_netty_codec_http2_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_http2_4_1_97_Final", + "sha256": "51fabf675563b59dc51dde22d29dbc5a20f836469cf48b8d53a07d3db0d775ad", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-codec-http2/4.1.97.Final/netty-codec-http2-4.1.97.Final.jar" + ], + "downloaded_file_path": "io/netty/netty-codec-http2/4.1.97.Final/netty-codec-http2-4.1.97.Final.jar" + } + }, + "io_prometheus_simpleclient_common_0_15_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_common_0_15_0", + "sha256": "8d2fa21b5c7959010818245788bd43131633dea989d3facb28cec45b2da37918", + "urls": [ + "https://repo1.maven.org/maven2/io/prometheus/simpleclient_common/0.15.0/simpleclient_common-0.15.0.jar" + ], + "downloaded_file_path": "io/prometheus/simpleclient_common/0.15.0/simpleclient_common-0.15.0.jar" + } + }, + "net_java_dev_jna_jna_jar_sources_5_13_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~net_java_dev_jna_jna_jar_sources_5_13_0", + "sha256": "a4c45843e8f60df141c4f37602365a421bb278ca1ef30ba0a043d6a871dd29f4", + "urls": [ + "https://repo1.maven.org/maven2/net/java/dev/jna/jna/5.13.0/jna-5.13.0-sources.jar" + ], + "downloaded_file_path": "net/java/dev/jna/jna/5.13.0/jna-5.13.0-sources.jar" + } + }, + "io_prometheus_simpleclient_hotspot_0_15_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_hotspot_0_15_0", + "sha256": "3c99768b090065bc0b25219061f94970aa569a2e363488d9120c79769d78c1a6", + "urls": [ + "https://repo1.maven.org/maven2/io/prometheus/simpleclient_hotspot/0.15.0/simpleclient_hotspot-0.15.0.jar" + ], + "downloaded_file_path": "io/prometheus/simpleclient_hotspot/0.15.0/simpleclient_hotspot-0.15.0.jar" + } + }, + "org_jboss_marshalling_jboss_marshalling_river_2_0_11_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_jboss_marshalling_jboss_marshalling_river_2_0_11_Final", + "sha256": "f3fa6545d15163468e1639fe3087de22234a9fd027a52be6e532bfe7bde6c554", + "urls": [ + "https://repo1.maven.org/maven2/org/jboss/marshalling/jboss-marshalling-river/2.0.11.Final/jboss-marshalling-river-2.0.11.Final.jar" + ], + "downloaded_file_path": "org/jboss/marshalling/jboss-marshalling-river/2.0.11.Final/jboss-marshalling-river-2.0.11.Final.jar" + } + }, + "org_luaj_luaj_jse_jar_sources_3_0_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_luaj_luaj_jse_jar_sources_3_0_1", + "sha256": "e9fc8eb5593ef489bafb79b5561b49114e8a233834f160c4657efe927a613f53", + "urls": [ + "https://repo1.maven.org/maven2/org/luaj/luaj-jse/3.0.1/luaj-jse-3.0.1-sources.jar" + ], + "downloaded_file_path": "org/luaj/luaj-jse/3.0.1/luaj-jse-3.0.1-sources.jar" + } + }, + "io_netty_netty_resolver_4_1_86_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_resolver_4_1_86_Final", + "sha256": "7628a1309d7f2443dc41d8923a7f269e2981b9616f80a999eb7264ae6bcbfdba", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-resolver/4.1.86.Final/netty-resolver-4.1.86.Final.jar", + "https://maven.google.com/io/netty/netty-resolver/4.1.86.Final/netty-resolver-4.1.86.Final.jar" + ], + "downloaded_file_path": "io/netty/netty-resolver/4.1.86.Final/netty-resolver-4.1.86.Final.jar" + } + }, + "net_javacrumbs_future_converter_future_converter_java8_guava_jar_sources_1_2_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~net_javacrumbs_future_converter_future_converter_java8_guava_jar_sources_1_2_0", + "sha256": "3e209e1d6e80d1cde253ac0e28d50588112d0128a9bf05dae7f4aea3a36bdc03", + "urls": [ + "https://repo1.maven.org/maven2/net/javacrumbs/future-converter/future-converter-java8-guava/1.2.0/future-converter-java8-guava-1.2.0-sources.jar" + ], + "downloaded_file_path": "net/javacrumbs/future-converter/future-converter-java8-guava/1.2.0/future-converter-java8-guava-1.2.0-sources.jar" + } + }, + "org_jetbrains_annotations_jar_sources_16_0_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_jetbrains_annotations_jar_sources_16_0_2", + "sha256": "699c2e6786e86fa5df5c82ffd0490d829107daa6225c0cffa290860abe4c1a80", + "urls": [ + "https://repo1.maven.org/maven2/org/jetbrains/annotations/16.0.2/annotations-16.0.2-sources.jar" + ], + "downloaded_file_path": "org/jetbrains/annotations/16.0.2/annotations-16.0.2-sources.jar" + } + }, + "software_amazon_awssdk_crt_core_2_20_78": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_crt_core_2_20_78", + "sha256": "f83ba65ea519cfcc2306994527d6432a969ac8efb418abfcf38128d08467f7cf", + "urls": [ + "https://repo1.maven.org/maven2/software/amazon/awssdk/crt-core/2.20.78/crt-core-2.20.78.jar", + "https://maven.google.com/software/amazon/awssdk/crt-core/2.20.78/crt-core-2.20.78.jar" + ], + "downloaded_file_path": "software/amazon/awssdk/crt-core/2.20.78/crt-core-2.20.78.jar" + } + }, + "com_google_guava_failureaccess": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_guava_failureaccess", + "generating_repository": "maven", + "target_name": "com_google_guava_failureaccess" + } + }, + "com_google_cloud_google_cloud_core_http_2_18_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_cloud_google_cloud_core_http_2_18_1", + "sha256": "52466ba755e309ae43977209897aac76f40103115cf37ca755a428dae5a190ae", + "urls": [ + "https://repo1.maven.org/maven2/com/google/cloud/google-cloud-core-http/2.18.1/google-cloud-core-http-2.18.1.jar", + "https://maven.google.com/com/google/cloud/google-cloud-core-http/2.18.1/google-cloud-core-http-2.18.1.jar" + ], + "downloaded_file_path": "com/google/cloud/google-cloud-core-http/2.18.1/google-cloud-core-http-2.18.1.jar" + } + }, + "javax_annotation_javax_annotation_api": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~javax_annotation_javax_annotation_api", + "generating_repository": "maven", + "target_name": "javax_annotation_javax_annotation_api" + } + }, + "io_opencensus_opencensus_api_0_31_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_opencensus_opencensus_api_0_31_1", + "sha256": "f1474d47f4b6b001558ad27b952e35eda5cc7146788877fc52938c6eba24b382", + "urls": [ + "https://repo1.maven.org/maven2/io/opencensus/opencensus-api/0.31.1/opencensus-api-0.31.1.jar" + ], + "downloaded_file_path": "io/opencensus/opencensus-api/0.31.1/opencensus-api-0.31.1.jar" + } + }, + "io_netty_netty_transport_classes_epoll_jar_sources_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_classes_epoll_jar_sources_4_1_97_Final", + "sha256": "96e2dbe0d3d8d4dae3ddc23443c174388373c1f6dd76401e23a26bd952bf4d08", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-transport-classes-epoll/4.1.97.Final/netty-transport-classes-epoll-4.1.97.Final-sources.jar" + ], + "downloaded_file_path": "io/netty/netty-transport-classes-epoll/4.1.97.Final/netty-transport-classes-epoll-4.1.97.Final-sources.jar" + } + }, + "io_netty_netty_codec_http2_4_1_86_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_http2_4_1_86_Final", + "sha256": "e8e8e28e6ab6bb989aed904778922045f388cfb420bc1eb37abf4df8801db167", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-codec-http2/4.1.86.Final/netty-codec-http2-4.1.86.Final.jar", + "https://maven.google.com/io/netty/netty-codec-http2/4.1.86.Final/netty-codec-http2-4.1.86.Final.jar" + ], + "downloaded_file_path": "io/netty/netty-codec-http2/4.1.86.Final/netty-codec-http2-4.1.86.Final.jar" + } + }, + "commons_io_commons_io": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~commons_io_commons_io", + "generating_repository": "maven", + "target_name": "commons_io_commons_io" + } + }, + "io_netty_netty_transport_native_unix_common": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_native_unix_common", + "generating_repository": "maven", + "target_name": "io_netty_netty_transport_native_unix_common" + } + }, + "org_javassist_javassist_jar_sources_3_28_0_GA": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_javassist_javassist_jar_sources_3_28_0_GA", + "sha256": "0b6cf0d138dc208263a2a0a39b1daae217707d58d79d7a4973a68ce62f8c2d1f", + "urls": [ + "https://repo1.maven.org/maven2/org/javassist/javassist/3.28.0-GA/javassist-3.28.0-GA-sources.jar" + ], + "downloaded_file_path": "org/javassist/javassist/3.28.0-GA/javassist-3.28.0-GA-sources.jar" + } + }, + "me_dinowernli_java_grpc_prometheus_jar_sources_0_6_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~me_dinowernli_java_grpc_prometheus_jar_sources_0_6_0", + "sha256": "a9029bdc0712ee294862aaa0c65e1308705472bb9fe429095b346a964be7b731", + "urls": [ + "https://repo1.maven.org/maven2/me/dinowernli/java-grpc-prometheus/0.6.0/java-grpc-prometheus-0.6.0-sources.jar" + ], + "downloaded_file_path": "me/dinowernli/java-grpc-prometheus/0.6.0/java-grpc-prometheus-0.6.0-sources.jar" + } + }, + "org_apache_maven_maven_artifact_3_9_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_apache_maven_maven_artifact_3_9_2", + "sha256": "f2174221d412a79572817b5aa77125348f43266670b6329a9881cdccf7bbc4b1", + "urls": [ + "https://repo1.maven.org/maven2/org/apache/maven/maven-artifact/3.9.2/maven-artifact-3.9.2.jar", + "https://maven.google.com/org/apache/maven/maven-artifact/3.9.2/maven-artifact-3.9.2.jar" + ], + "downloaded_file_path": "org/apache/maven/maven-artifact/3.9.2/maven-artifact-3.9.2.jar" + } + }, + "io_netty_netty_common": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_common", + "generating_repository": "maven", + "target_name": "io_netty_netty_common" + } + }, + "com_google_j2objc_j2objc_annotations_jar_sources_2_8": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_j2objc_j2objc_annotations_jar_sources_2_8", + "sha256": "7413eed41f111453a08837f5ac680edded7faed466cbd35745e402e13f4cc3f5", + "urls": [ + "https://repo1.maven.org/maven2/com/google/j2objc/j2objc-annotations/2.8/j2objc-annotations-2.8-sources.jar" + ], + "downloaded_file_path": "com/google/j2objc/j2objc-annotations/2.8/j2objc-annotations-2.8-sources.jar" + } + }, + "com_github_jnr_jffi_jar_sources_1_3_11": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_jnr_jffi_jar_sources_1_3_11", + "sha256": "df7dcc8843d61e60c5fe606e860646f1a82d11d2dc41a3d230da87fc0bcf4291", + "urls": [ + "https://repo1.maven.org/maven2/com/github/jnr/jffi/1.3.11/jffi-1.3.11-sources.jar" + ], + "downloaded_file_path": "com/github/jnr/jffi/1.3.11/jffi-1.3.11-sources.jar" + } + }, + "org_apache_commons_commons_lang3_jar_sources_3_13_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_apache_commons_commons_lang3_jar_sources_3_13_0", + "sha256": "6152e03a6c29e0d9dd1415aaa42cb13f6fab5fc5b2333077c29b498927535453", + "urls": [ + "https://repo1.maven.org/maven2/org/apache/commons/commons-lang3/3.13.0/commons-lang3-3.13.0-sources.jar" + ], + "downloaded_file_path": "org/apache/commons/commons-lang3/3.13.0/commons-lang3-3.13.0-sources.jar" + } + }, + "software_amazon_eventstream_eventstream_1_0_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~software_amazon_eventstream_eventstream_1_0_1", + "sha256": "0c37d8e696117f02c302191b8110b0d0eb20fa412fce34c3a269ec73c16ce822", + "urls": [ + "https://repo1.maven.org/maven2/software/amazon/eventstream/eventstream/1.0.1/eventstream-1.0.1.jar", + "https://maven.google.com/software/amazon/eventstream/eventstream/1.0.1/eventstream-1.0.1.jar" + ], + "downloaded_file_path": "software/amazon/eventstream/eventstream/1.0.1/eventstream-1.0.1.jar" + } + }, + "com_github_docker_java_docker_java_transport_jersey_3_3_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_docker_java_docker_java_transport_jersey_3_3_3", + "sha256": "7574d831272a56268f4468b901059cafdca6e10176c87fec83f65d26d28c6fb0", + "urls": [ + "https://repo1.maven.org/maven2/com/github/docker-java/docker-java-transport-jersey/3.3.3/docker-java-transport-jersey-3.3.3.jar" + ], + "downloaded_file_path": "com/github/docker-java/docker-java-transport-jersey/3.3.3/docker-java-transport-jersey-3.3.3.jar" + } + }, + "org_glassfish_hk2_hk2_utils_jar_sources_2_6_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_glassfish_hk2_hk2_utils_jar_sources_2_6_1", + "sha256": "36552a965412a1d5a9eb2ee0282fd224151e79ac5dc42ae794f0bac67e523dc5", + "urls": [ + "https://repo1.maven.org/maven2/org/glassfish/hk2/hk2-utils/2.6.1/hk2-utils-2.6.1-sources.jar" + ], + "downloaded_file_path": "org/glassfish/hk2/hk2-utils/2.6.1/hk2-utils-2.6.1-sources.jar" + } + }, + "io_netty_netty_handler": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_handler", + "generating_repository": "maven", + "target_name": "io_netty_netty_handler" + } + }, + "com_google_api_grpc_proto_google_common_protos_jar_sources_2_17_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_api_grpc_proto_google_common_protos_jar_sources_2_17_0", + "sha256": "cadaaa7232e1469abf515b99f2642b120fed9f68d6f36899ee493058b2159f18", + "urls": [ + "https://repo1.maven.org/maven2/com/google/api/grpc/proto-google-common-protos/2.17.0/proto-google-common-protos-2.17.0-sources.jar" + ], + "downloaded_file_path": "com/google/api/grpc/proto-google-common-protos/2.17.0/proto-google-common-protos-2.17.0-sources.jar" + } + }, + "net_minidev_accessors_smart_jar_sources_2_4_9": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~net_minidev_accessors_smart_jar_sources_2_4_9", + "sha256": "4b6022d773826980f124e7a2aed243cea6541238bc1bed785e2ce86076567f50", + "urls": [ + "https://repo1.maven.org/maven2/net/minidev/accessors-smart/2.4.9/accessors-smart-2.4.9-sources.jar" + ], + "downloaded_file_path": "net/minidev/accessors-smart/2.4.9/accessors-smart-2.4.9-sources.jar" + } + }, + "com_fasterxml_jackson_core_jackson_core_jar_sources_2_15_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_core_jackson_core_jar_sources_2_15_2", + "sha256": "4b29fe878549425194521d5c3270fae13f9c82cfcad639ebffea0963431bef45", + "urls": [ + "https://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-core/2.15.2/jackson-core-2.15.2-sources.jar" + ], + "downloaded_file_path": "com/fasterxml/jackson/core/jackson-core/2.15.2/jackson-core-2.15.2-sources.jar" + } + }, + "net_java_dev_jna_jna_platform_5_13_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~net_java_dev_jna_jna_platform_5_13_0", + "sha256": "474d7b88f6e97009b6ec1d98c3024dd95c23187c65dabfbc35331bcac3d173dd", + "urls": [ + "https://repo1.maven.org/maven2/net/java/dev/jna/jna-platform/5.13.0/jna-platform-5.13.0.jar" + ], + "downloaded_file_path": "net/java/dev/jna/jna-platform/5.13.0/jna-platform-5.13.0.jar" + } + }, + "io_grpc_grpc_protobuf_1_56_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_protobuf_1_56_1", + "sha256": "46185731a718d723d853723610a77e9062da9a6fc8b4ff14f370ba10cf097893", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-protobuf/1.56.1/grpc-protobuf-1.56.1.jar" + ], + "downloaded_file_path": "io/grpc/grpc-protobuf/1.56.1/grpc-protobuf-1.56.1.jar" + } + }, + "org_openjdk_jmh_jmh_core": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_openjdk_jmh_jmh_core", + "generating_repository": "maven", + "target_name": "org_openjdk_jmh_jmh_core" + } + }, + "com_github_serceman_jnr_fuse_jar_sources_0_5_7": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_serceman_jnr_fuse_jar_sources_0_5_7", + "sha256": "68a7003b43945ec3083fe2b8a5b882ff515449075122fcd6fb85f0c30bb750ab", + "urls": [ + "https://repo1.maven.org/maven2/com/github/serceman/jnr-fuse/0.5.7/jnr-fuse-0.5.7-sources.jar" + ], + "downloaded_file_path": "com/github/serceman/jnr-fuse/0.5.7/jnr-fuse-0.5.7-sources.jar" + } + }, + "com_google_truth_truth_jar_sources_1_1_5": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_truth_truth_jar_sources_1_1_5", + "sha256": "f1a94449ed48392525626f4e5edeff5c6e66af21c4c009ebb49b5109ac5db6b2", + "urls": [ + "https://repo1.maven.org/maven2/com/google/truth/truth/1.1.5/truth-1.1.5-sources.jar" + ], + "downloaded_file_path": "com/google/truth/truth/1.1.5/truth-1.1.5-sources.jar" + } + }, + "org_jodd_jodd_core_5_1_6": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_jodd_jodd_core_5_1_6", + "sha256": "4b504519263a98202480d3cf73562dff8245edc582350cc5f37d5965a0298122", + "urls": [ + "https://repo1.maven.org/maven2/org/jodd/jodd-core/5.1.6/jodd-core-5.1.6.jar" + ], + "downloaded_file_path": "org/jodd/jodd-core/5.1.6/jodd-core-5.1.6.jar" + } + }, + "org_objenesis_objenesis_jar_sources_3_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_objenesis_objenesis_jar_sources_3_3", + "sha256": "d06164f8ca002c8ef193cef2d682822014dd330505616af93a3fb64226fc131d", + "urls": [ + "https://repo1.maven.org/maven2/org/objenesis/objenesis/3.3/objenesis-3.3-sources.jar" + ], + "downloaded_file_path": "org/objenesis/objenesis/3.3/objenesis-3.3-sources.jar" + } + }, + "io_grpc_grpc_core": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_core", + "generating_repository": "maven", + "target_name": "io_grpc_grpc_core" + } + }, + "com_google_guava_guava_32_0_0_jre": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_guava_guava_32_0_0_jre", + "sha256": "39f3550b0343d8d19dd4e83bd165b58ea3389d2ddb9f2148e63903f79ecdb114", + "urls": [ + "https://repo1.maven.org/maven2/com/google/guava/guava/32.0.0-jre/guava-32.0.0-jre.jar", + "https://maven.google.com/com/google/guava/guava/32.0.0-jre/guava-32.0.0-jre.jar" + ], + "downloaded_file_path": "com/google/guava/guava/32.0.0-jre/guava-32.0.0-jre.jar" + } + }, + "io_netty_netty_codec_socks": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_socks", + "generating_repository": "maven", + "target_name": "io_netty_netty_codec_socks" + } + }, + "org_apache_httpcomponents_httpcore_jar_sources_4_4_15": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_apache_httpcomponents_httpcore_jar_sources_4_4_15", + "sha256": "1510fc72cf2858244bdeb0d7f5d266fe584ecbd2ffe0d91b10a6d80641cd1985", + "urls": [ + "https://repo1.maven.org/maven2/org/apache/httpcomponents/httpcore/4.4.15/httpcore-4.4.15-sources.jar" + ], + "downloaded_file_path": "org/apache/httpcomponents/httpcore/4.4.15/httpcore-4.4.15-sources.jar" + } + }, + "com_github_jnr_jnr_x86asm_1_0_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_jnr_jnr_x86asm_1_0_2", + "sha256": "39f3675b910e6e9b93825f8284bec9f4ad3044cd20a6f7c8ff9e2f8695ebf21e", + "urls": [ + "https://repo1.maven.org/maven2/com/github/jnr/jnr-x86asm/1.0.2/jnr-x86asm-1.0.2.jar" + ], + "downloaded_file_path": "com/github/jnr/jnr-x86asm/1.0.2/jnr-x86asm-1.0.2.jar" + } + }, + "software_amazon_awssdk_annotations_2_20_78": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_annotations_2_20_78", + "sha256": "90ce2bb257ffa63942831f7329e28cf22fa4caf0cc96ee4f2f4557b7554eae1e", + "urls": [ + "https://repo1.maven.org/maven2/software/amazon/awssdk/annotations/2.20.78/annotations-2.20.78.jar", + "https://maven.google.com/software/amazon/awssdk/annotations/2.20.78/annotations-2.20.78.jar" + ], + "downloaded_file_path": "software/amazon/awssdk/annotations/2.20.78/annotations-2.20.78.jar" + } + }, + "io_grpc_grpc_netty": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_netty", + "generating_repository": "maven", + "target_name": "io_grpc_grpc_netty" + } + }, + "io_grpc_grpc_testing": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_testing", + "generating_repository": "maven", + "target_name": "io_grpc_grpc_testing" + } + }, + "io_grpc_grpc_api_jar_sources_1_56_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_api_jar_sources_1_56_1", + "sha256": "e5e58482c95a332706d6c12a758d55ec195b01a3e54e2a38a6239ed7a3de26c0", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-api/1.56.1/grpc-api-1.56.1-sources.jar" + ], + "downloaded_file_path": "io/grpc/grpc-api/1.56.1/grpc-api-1.56.1-sources.jar" + } + }, + "org_ow2_asm_asm_jar_sources_9_5": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_ow2_asm_asm_jar_sources_9_5", + "sha256": "11214bbba797e0615402b8d57fd4be83c93a65244c5a88778015520d61078376", + "urls": [ + "https://repo1.maven.org/maven2/org/ow2/asm/asm/9.5/asm-9.5-sources.jar" + ], + "downloaded_file_path": "org/ow2/asm/asm/9.5/asm-9.5-sources.jar" + } + }, + "io_prometheus_simpleclient": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient", + "generating_repository": "maven", + "target_name": "io_prometheus_simpleclient" + } + }, + "com_google_jimfs_jimfs_jar_sources_1_3_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_jimfs_jimfs_jar_sources_1_3_0", + "sha256": "aa30e127e68ddba8e76395d14806f838f22c9ef904b07ff0266dfc5de7163059", + "urls": [ + "https://repo1.maven.org/maven2/com/google/jimfs/jimfs/1.3.0/jimfs-1.3.0-sources.jar" + ], + "downloaded_file_path": "com/google/jimfs/jimfs/1.3.0/jimfs-1.3.0-sources.jar" + } + }, + "com_google_apis_google_api_services_storage_v1_rev20230301_2_0_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_apis_google_api_services_storage_v1_rev20230301_2_0_0", + "sha256": "857ac102129477c55487ed94fd7e021b6093bd88370f9ccac799456a0ff86af9", + "urls": [ + "https://repo1.maven.org/maven2/com/google/apis/google-api-services-storage/v1-rev20230301-2.0.0/google-api-services-storage-v1-rev20230301-2.0.0.jar", + "https://maven.google.com/com/google/apis/google-api-services-storage/v1-rev20230301-2.0.0/google-api-services-storage-v1-rev20230301-2.0.0.jar" + ], + "downloaded_file_path": "com/google/apis/google-api-services-storage/v1-rev20230301-2.0.0/google-api-services-storage-v1-rev20230301-2.0.0.jar" + } + }, + "io_netty_netty_codec_http2": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_http2", + "generating_repository": "maven", + "target_name": "io_netty_netty_codec_http2" + } + }, + "io_grpc_grpc_auth_1_55_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_auth_1_55_1", + "sha256": "45d9bfaf837c41abf01e087773f535ea5afa6faad1faecbc6f32cb9ae423adef", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-auth/1.55.1/grpc-auth-1.55.1.jar", + "https://maven.google.com/io/grpc/grpc-auth/1.55.1/grpc-auth-1.55.1.jar" + ], + "downloaded_file_path": "io/grpc/grpc-auth/1.55.1/grpc-auth-1.55.1.jar" + } + }, + "com_google_auth_google_auth_library_credentials_1_17_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_auth_google_auth_library_credentials_1_17_0", + "sha256": "5de364ee7a9ce95d8715bf124bdb0d949d37649914db846cc7005584fba7ce4d", + "urls": [ + "https://repo1.maven.org/maven2/com/google/auth/google-auth-library-credentials/1.17.0/google-auth-library-credentials-1.17.0.jar", + "https://maven.google.com/com/google/auth/google-auth-library-credentials/1.17.0/google-auth-library-credentials-1.17.0.jar" + ], + "downloaded_file_path": "com/google/auth/google-auth-library-credentials/1.17.0/google-auth-library-credentials-1.17.0.jar" + } + }, + "com_github_jnr_jnr_constants_jar_sources_0_10_4": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_jnr_jnr_constants_jar_sources_0_10_4", + "sha256": "696f737f76a29d900401e52277274c3c12a47cb70d00eb9e3619f3ff0b261a5f", + "urls": [ + "https://repo1.maven.org/maven2/com/github/jnr/jnr-constants/0.10.4/jnr-constants-0.10.4-sources.jar" + ], + "downloaded_file_path": "com/github/jnr/jnr-constants/0.10.4/jnr-constants-0.10.4-sources.jar" + } + }, + "io_grpc_grpc_services_1_56_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_services_1_56_1", + "sha256": "0d14ece28e97b30aa9ef1b63782d48261dd63738ef1c5615afefb8b963c121c8", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-services/1.56.1/grpc-services-1.56.1.jar" + ], + "downloaded_file_path": "io/grpc/grpc-services/1.56.1/grpc-services-1.56.1.jar" + } + }, + "net_javacrumbs_future_converter_future_converter_common_1_2_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~net_javacrumbs_future_converter_future_converter_common_1_2_0", + "sha256": "567aeb2907088298fe5e67fd0fb1843571c24b46ef5b369f495c3d52c654b67b", + "urls": [ + "https://repo1.maven.org/maven2/net/javacrumbs/future-converter/future-converter-common/1.2.0/future-converter-common-1.2.0.jar" + ], + "downloaded_file_path": "net/javacrumbs/future-converter/future-converter-common/1.2.0/future-converter-common-1.2.0.jar" + } + }, + "org_codehaus_plexus_plexus_utils_3_5_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_codehaus_plexus_plexus_utils_3_5_1", + "sha256": "86e0255d4c879c61b4833ed7f13124e8bb679df47debb127326e7db7dd49a07b", + "urls": [ + "https://repo1.maven.org/maven2/org/codehaus/plexus/plexus-utils/3.5.1/plexus-utils-3.5.1.jar", + "https://maven.google.com/org/codehaus/plexus/plexus-utils/3.5.1/plexus-utils-3.5.1.jar" + ], + "downloaded_file_path": "org/codehaus/plexus/plexus-utils/3.5.1/plexus-utils-3.5.1.jar" + } + }, + "com_github_fppt_jedis_mock_jar_sources_1_0_10": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_fppt_jedis_mock_jar_sources_1_0_10", + "sha256": "315cd23d9c010ceee598fc594d4674b63f4bcd0375fe8c2b90d79ce50a12bb7e", + "urls": [ + "https://repo1.maven.org/maven2/com/github/fppt/jedis-mock/1.0.10/jedis-mock-1.0.10-sources.jar" + ], + "downloaded_file_path": "com/github/fppt/jedis-mock/1.0.10/jedis-mock-1.0.10-sources.jar" + } + }, + "io_grpc_grpc_protobuf_1_55_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_protobuf_1_55_1", + "sha256": "a170ef578cd94bf81c57f46cca9328e2db5136f45e18da80af26bbebcca9618c", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-protobuf/1.55.1/grpc-protobuf-1.55.1.jar", + "https://maven.google.com/io/grpc/grpc-protobuf/1.55.1/grpc-protobuf-1.55.1.jar" + ], + "downloaded_file_path": "io/grpc/grpc-protobuf/1.55.1/grpc-protobuf-1.55.1.jar" + } + }, + "org_glassfish_jersey_inject_jersey_hk2_2_30_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_glassfish_jersey_inject_jersey_hk2_2_30_1", + "sha256": "cd5f4c10cf4915d1c217c295fc8b4eadceda7a28f9488b1d01de6b8792b33496", + "urls": [ + "https://repo1.maven.org/maven2/org/glassfish/jersey/inject/jersey-hk2/2.30.1/jersey-hk2-2.30.1.jar" + ], + "downloaded_file_path": "org/glassfish/jersey/inject/jersey-hk2/2.30.1/jersey-hk2-2.30.1.jar" + } + }, + "net_java_dev_jna_jna_5_13_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~net_java_dev_jna_jna_5_13_0", + "sha256": "66d4f819a062a51a1d5627bffc23fac55d1677f0e0a1feba144aabdd670a64bb", + "urls": [ + "https://repo1.maven.org/maven2/net/java/dev/jna/jna/5.13.0/jna-5.13.0.jar" + ], + "downloaded_file_path": "net/java/dev/jna/jna/5.13.0/jna-5.13.0.jar" + } + }, + "com_google_http_client_google_http_client_1_43_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_http_client_google_http_client_1_43_1", + "sha256": "834e37b0af2cfe80b297be4d6a5c8fd0ccab1d0b13e9b8d7ac921e8dd2f251ec", + "urls": [ + "https://repo1.maven.org/maven2/com/google/http-client/google-http-client/1.43.1/google-http-client-1.43.1.jar", + "https://maven.google.com/com/google/http-client/google-http-client/1.43.1/google-http-client-1.43.1.jar" + ], + "downloaded_file_path": "com/google/http-client/google-http-client/1.43.1/google-http-client-1.43.1.jar" + } + }, + "io_opencensus_opencensus_proto_0_2_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_opencensus_opencensus_proto_0_2_0", + "sha256": "0c192d451e9dd74e98721b27d02f0e2b6bca44b51563b5dabf2e211f7a3ebf13", + "urls": [ + "https://repo1.maven.org/maven2/io/opencensus/opencensus-proto/0.2.0/opencensus-proto-0.2.0.jar", + "https://maven.google.com/io/opencensus/opencensus-proto/0.2.0/opencensus-proto-0.2.0.jar" + ], + "downloaded_file_path": "io/opencensus/opencensus-proto/0.2.0/opencensus-proto-0.2.0.jar" + } + }, + "com_fasterxml_jackson_core_jackson_databind_2_15_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_core_jackson_databind_2_15_2", + "sha256": "0eb2fdad6e40ab8832a78c9b22f58196dd970594e8d3d5a26ead87847c4f3a96", + "urls": [ + "https://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-databind/2.15.2/jackson-databind-2.15.2.jar" + ], + "downloaded_file_path": "com/fasterxml/jackson/core/jackson-databind/2.15.2/jackson-databind-2.15.2.jar" + } + }, + "org_slf4j_slf4j_api_1_7_30": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_slf4j_slf4j_api_1_7_30", + "sha256": "cdba07964d1bb40a0761485c6b1e8c2f8fd9eb1d19c53928ac0d7f9510105c57", + "urls": [ + "https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.30/slf4j-api-1.7.30.jar", + "https://maven.google.com/org/slf4j/slf4j-api/1.7.30/slf4j-api-1.7.30.jar" + ], + "downloaded_file_path": "org/slf4j/slf4j-api/1.7.30/slf4j-api-1.7.30.jar" + } + }, + "io_grpc_grpc_grpclb_1_55_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_grpclb_1_55_1", + "sha256": "9d0dcf87d99a1042a3a2343e96d394220c6be07cf1a5082d5df066e2077b3428", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-grpclb/1.55.1/grpc-grpclb-1.55.1.jar", + "https://maven.google.com/io/grpc/grpc-grpclb/1.55.1/grpc-grpclb-1.55.1.jar" + ], + "downloaded_file_path": "io/grpc/grpc-grpclb/1.55.1/grpc-grpclb-1.55.1.jar" + } + }, + "com_esotericsoftware_minlog_jar_sources_1_3_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_esotericsoftware_minlog_jar_sources_1_3_1", + "sha256": "fdaf83a8c51295eff3a8109473ce7b213582738f71593e16b1efa012ff1f99b5", + "urls": [ + "https://repo1.maven.org/maven2/com/esotericsoftware/minlog/1.3.1/minlog-1.3.1-sources.jar" + ], + "downloaded_file_path": "com/esotericsoftware/minlog/1.3.1/minlog-1.3.1-sources.jar" + } + }, + "net_javacrumbs_future_converter_future_converter_java8_guava_1_2_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~net_javacrumbs_future_converter_future_converter_java8_guava_1_2_0", + "sha256": "3b47ae8e2b2bfad810586c37537f002273c05237bd3adecafe9f9f57a2b18fde", + "urls": [ + "https://repo1.maven.org/maven2/net/javacrumbs/future-converter/future-converter-java8-guava/1.2.0/future-converter-java8-guava-1.2.0.jar" + ], + "downloaded_file_path": "net/javacrumbs/future-converter/future-converter-java8-guava/1.2.0/future-converter-java8-guava-1.2.0.jar" + } + }, + "com_google_errorprone_error_prone_annotations_2_18_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_errorprone_error_prone_annotations_2_18_0", + "sha256": "9e6814cb71816988a4fd1b07a993a8f21bb7058d522c162b1de849e19bea54ae", + "urls": [ + "https://repo1.maven.org/maven2/com/google/errorprone/error_prone_annotations/2.18.0/error_prone_annotations-2.18.0.jar", + "https://maven.google.com/com/google/errorprone/error_prone_annotations/2.18.0/error_prone_annotations-2.18.0.jar" + ], + "downloaded_file_path": "com/google/errorprone/error_prone_annotations/2.18.0/error_prone_annotations-2.18.0.jar" + } + }, + "com_google_cloud_google_cloud_core_2_18_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_cloud_google_cloud_core_2_18_1", + "sha256": "8a8da77a17193fae86012722237736db7d08cb6fac8df50a311427c95b26d4a6", + "urls": [ + "https://repo1.maven.org/maven2/com/google/cloud/google-cloud-core/2.18.1/google-cloud-core-2.18.1.jar", + "https://maven.google.com/com/google/cloud/google-cloud-core/2.18.1/google-cloud-core-2.18.1.jar" + ], + "downloaded_file_path": "com/google/cloud/google-cloud-core/2.18.1/google-cloud-core-2.18.1.jar" + } + }, + "com_github_jnr_jffi_jar_native_1_3_11": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_jnr_jffi_jar_native_1_3_11", + "sha256": "f4c26c0a4a3eddfdbaaf4dda77d4d9f7d148ba4208798f32ce475ce4d6778744", + "urls": [ + "https://repo1.maven.org/maven2/com/github/jnr/jffi/1.3.11/jffi-1.3.11-native.jar" + ], + "downloaded_file_path": "com/github/jnr/jffi/1.3.11/jffi-1.3.11-native.jar" + } + }, + "com_google_errorprone_error_prone_annotations": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_errorprone_error_prone_annotations", + "generating_repository": "maven", + "target_name": "com_google_errorprone_error_prone_annotations" + } + }, + "io_netty_netty_codec_dns_jar_sources_4_1_96_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_dns_jar_sources_4_1_96_Final", + "sha256": "080f78aa2451386f7c0ac993ed4b3eae28ea3b337c606aee29b0c723e01f9588", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-codec-dns/4.1.96.Final/netty-codec-dns-4.1.96.Final-sources.jar" + ], + "downloaded_file_path": "io/netty/netty-codec-dns/4.1.96.Final/netty-codec-dns-4.1.96.Final-sources.jar" + } + }, + "io_netty_netty_handler_proxy_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_handler_proxy_4_1_97_Final", + "sha256": "c789f30d0905a09b2a17c4cf397e1b57b0d63db714624eb0dec2282b9619e206", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-handler-proxy/4.1.97.Final/netty-handler-proxy-4.1.97.Final.jar" + ], + "downloaded_file_path": "io/netty/netty-handler-proxy/4.1.97.Final/netty-handler-proxy-4.1.97.Final.jar" + } + }, + "io_projectreactor_reactor_core_jar_sources_3_5_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_projectreactor_reactor_core_jar_sources_3_5_3", + "sha256": "c4193dbe135cc2a1db71c55771249158f611d3663e0f42b3ede5ab9e4302bce4", + "urls": [ + "https://repo1.maven.org/maven2/io/projectreactor/reactor-core/3.5.3/reactor-core-3.5.3-sources.jar" + ], + "downloaded_file_path": "io/projectreactor/reactor-core/3.5.3/reactor-core-3.5.3-sources.jar" + } + }, + "com_google_errorprone_error_prone_type_annotations_jar_sources_2_22_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_errorprone_error_prone_type_annotations_jar_sources_2_22_0", + "sha256": "84bbb947f3de91d97eee9abb6c5648c5b61d0fb4d132f86c4d7c80e4357e5da6", + "urls": [ + "https://repo1.maven.org/maven2/com/google/errorprone/error_prone_type_annotations/2.22.0/error_prone_type_annotations-2.22.0-sources.jar" + ], + "downloaded_file_path": "com/google/errorprone/error_prone_type_annotations/2.22.0/error_prone_type_annotations-2.22.0-sources.jar" + } + }, + "com_google_api_grpc_proto_google_common_protos_2_17_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_api_grpc_proto_google_common_protos_2_17_0", + "sha256": "4ef1fe0c327fc1521d1d753b0b1c4a875a54bd14ebded3afff0ca395320b6ea9", + "urls": [ + "https://repo1.maven.org/maven2/com/google/api/grpc/proto-google-common-protos/2.17.0/proto-google-common-protos-2.17.0.jar" + ], + "downloaded_file_path": "com/google/api/grpc/proto-google-common-protos/2.17.0/proto-google-common-protos-2.17.0.jar" + } + }, + "io_netty_netty_codec_http_jar_sources_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_http_jar_sources_4_1_97_Final", + "sha256": "fd45d71121285bed020b3cc2515288d252b9c07cbc4934a63615d7d8c8855289", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-codec-http/4.1.97.Final/netty-codec-http-4.1.97.Final-sources.jar" + ], + "downloaded_file_path": "io/netty/netty-codec-http/4.1.97.Final/netty-codec-http-4.1.97.Final-sources.jar" + } + }, + "io_netty_netty_transport_native_epoll": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_native_epoll", + "generating_repository": "maven", + "target_name": "io_netty_netty_transport_native_epoll" + } + }, + "software_amazon_awssdk_aws_xml_protocol_2_20_78": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_aws_xml_protocol_2_20_78", + "sha256": "c7977c61aeb3f74e471bedde0ab6ca44447af4cbff309c63f5e7d2a26dbcba7a", + "urls": [ + "https://repo1.maven.org/maven2/software/amazon/awssdk/aws-xml-protocol/2.20.78/aws-xml-protocol-2.20.78.jar", + "https://maven.google.com/software/amazon/awssdk/aws-xml-protocol/2.20.78/aws-xml-protocol-2.20.78.jar" + ], + "downloaded_file_path": "software/amazon/awssdk/aws-xml-protocol/2.20.78/aws-xml-protocol-2.20.78.jar" + } + }, + "com_sun_activation_jakarta_activation_jar_sources_1_2_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_sun_activation_jakarta_activation_jar_sources_1_2_1", + "sha256": "d254da455b0e1e36c7a9db2f0910fea9e8a012cbc85160207328e16bd3aea753", + "urls": [ + "https://repo1.maven.org/maven2/com/sun/activation/jakarta.activation/1.2.1/jakarta.activation-1.2.1-sources.jar" + ], + "downloaded_file_path": "com/sun/activation/jakarta.activation/1.2.1/jakarta.activation-1.2.1-sources.jar" + } + }, + "io_grpc_grpc_testing_1_56_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_testing_1_56_1", + "sha256": "b4cd4f2c410040fb097108eb6b7fa84826365b4d91844bd30b21f4e97eee906d", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-testing/1.56.1/grpc-testing-1.56.1.jar" + ], + "downloaded_file_path": "io/grpc/grpc-testing/1.56.1/grpc-testing-1.56.1.jar" + } + }, + "org_glassfish_hk2_external_aopalliance_repackaged_2_6_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_glassfish_hk2_external_aopalliance_repackaged_2_6_1", + "sha256": "bad77f9278d753406360af9e4747bd9b3161554ea9cd3d62411a0ae1f2c141fd", + "urls": [ + "https://repo1.maven.org/maven2/org/glassfish/hk2/external/aopalliance-repackaged/2.6.1/aopalliance-repackaged-2.6.1.jar" + ], + "downloaded_file_path": "org/glassfish/hk2/external/aopalliance-repackaged/2.6.1/aopalliance-repackaged-2.6.1.jar" + } + }, + "org_openjdk_jmh_jmh_core_1_37": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_openjdk_jmh_jmh_core_1_37", + "sha256": "dc0eaf2bbf0036a70b60798c785d6e03a9daf06b68b8edb0f1ba9eb3421baeb3", + "urls": [ + "https://repo1.maven.org/maven2/org/openjdk/jmh/jmh-core/1.37/jmh-core-1.37.jar" + ], + "downloaded_file_path": "org/openjdk/jmh/jmh-core/1.37/jmh-core-1.37.jar" + } + }, + "io_netty_netty_codec_http_4_1_86_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_http_4_1_86_Final", + "sha256": "3f6ceb3112cfcf7b70545eb5111220ce57db54d593f23f64c38333bb22c40b84", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-codec-http/4.1.86.Final/netty-codec-http-4.1.86.Final.jar", + "https://maven.google.com/io/netty/netty-codec-http/4.1.86.Final/netty-codec-http-4.1.86.Final.jar" + ], + "downloaded_file_path": "io/netty/netty-codec-http/4.1.86.Final/netty-codec-http-4.1.86.Final.jar" + } + }, + "aopalliance_aopalliance_1_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~aopalliance_aopalliance_1_0", + "sha256": "0addec670fedcd3f113c5c8091d783280d23f75e3acb841b61a9cdb079376a08", + "urls": [ + "https://repo1.maven.org/maven2/aopalliance/aopalliance/1.0/aopalliance-1.0.jar" + ], + "downloaded_file_path": "aopalliance/aopalliance/1.0/aopalliance-1.0.jar" + } + }, + "org_reactivestreams_reactive_streams_jar_sources_1_0_4": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_reactivestreams_reactive_streams_jar_sources_1_0_4", + "sha256": "5a7a36ae9536698c434ebe119feb374d721210fee68eb821a37ef3859b64b708", + "urls": [ + "https://repo1.maven.org/maven2/org/reactivestreams/reactive-streams/1.0.4/reactive-streams-1.0.4-sources.jar" + ], + "downloaded_file_path": "org/reactivestreams/reactive-streams/1.0.4/reactive-streams-1.0.4-sources.jar" + } + }, + "com_google_http_client_google_http_client_jackson2_1_43_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_http_client_google_http_client_jackson2_1_43_1", + "sha256": "1d41fa103da432dc49b41a321effc3e2fda722a3dc896a89dcdc3a4d5fe82255", + "urls": [ + "https://repo1.maven.org/maven2/com/google/http-client/google-http-client-jackson2/1.43.1/google-http-client-jackson2-1.43.1.jar", + "https://maven.google.com/com/google/http-client/google-http-client-jackson2/1.43.1/google-http-client-jackson2-1.43.1.jar" + ], + "downloaded_file_path": "com/google/http-client/google-http-client-jackson2/1.43.1/google-http-client-jackson2-1.43.1.jar" + } + }, + "io_netty_netty_transport_4_1_86_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_4_1_86_Final", + "sha256": "f6726dcd54e4922b46b3b4f4467b443a70a30eb08a62620c8fe502d8cb802c9f", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-transport/4.1.86.Final/netty-transport-4.1.86.Final.jar", + "https://maven.google.com/io/netty/netty-transport/4.1.86.Final/netty-transport-4.1.86.Final.jar" + ], + "downloaded_file_path": "io/netty/netty-transport/4.1.86.Final/netty-transport-4.1.86.Final.jar" + } + }, + "com_amazonaws_jmespath_java_jar_sources_1_12_544": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_amazonaws_jmespath_java_jar_sources_1_12_544", + "sha256": "496d7f1c237d107b3c4c766ff603ba6b3e773e59c590e3ed0156f56fdb3d0b4a", + "urls": [ + "https://repo1.maven.org/maven2/com/amazonaws/jmespath-java/1.12.544/jmespath-java-1.12.544-sources.jar" + ], + "downloaded_file_path": "com/amazonaws/jmespath-java/1.12.544/jmespath-java-1.12.544-sources.jar" + } + }, + "com_github_kevinstern_software_and_algorithms_jar_sources_1_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_kevinstern_software_and_algorithms_jar_sources_1_0", + "sha256": "37a46c7f8f6c5064ceb398be472c17507b1e7e7bfc72399c57efb5fa5310a8ae", + "urls": [ + "https://repo1.maven.org/maven2/com/github/kevinstern/software-and-algorithms/1.0/software-and-algorithms-1.0-sources.jar" + ], + "downloaded_file_path": "com/github/kevinstern/software-and-algorithms/1.0/software-and-algorithms-1.0-sources.jar" + } + }, + "com_github_pcj_google_options": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_pcj_google_options", + "generating_repository": "maven", + "target_name": "com_github_pcj_google_options" + } + }, + "io_github_eisop_dataflow_errorprone_3_34_0_eisop1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_github_eisop_dataflow_errorprone_3_34_0_eisop1", + "sha256": "89b4f5d2bd5059f067c5982a0e5988b87dfc8a8234795d68c6f3178846de3319", + "urls": [ + "https://repo1.maven.org/maven2/io/github/eisop/dataflow-errorprone/3.34.0-eisop1/dataflow-errorprone-3.34.0-eisop1.jar" + ], + "downloaded_file_path": "io/github/eisop/dataflow-errorprone/3.34.0-eisop1/dataflow-errorprone-3.34.0-eisop1.jar" + } + }, + "com_github_docker_java_docker_java_jar_sources_3_3_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_docker_java_docker_java_jar_sources_3_3_3", + "sha256": "ddc2c925a8b58cc47e5d683c770c9f261f6a6b7db028b38dd289be0e51a7c3df", + "urls": [ + "https://repo1.maven.org/maven2/com/github/docker-java/docker-java/3.3.3/docker-java-3.3.3-sources.jar" + ], + "downloaded_file_path": "com/github/docker-java/docker-java/3.3.3/docker-java-3.3.3-sources.jar" + } + }, + "io_prometheus_simpleclient_tracer_otel_jar_sources_0_15_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_tracer_otel_jar_sources_0_15_0", + "sha256": "f83fcb43addcd77adeb34ff00ee27141060ac103597272eb44f2d73aea4addea", + "urls": [ + "https://repo1.maven.org/maven2/io/prometheus/simpleclient_tracer_otel/0.15.0/simpleclient_tracer_otel-0.15.0-sources.jar" + ], + "downloaded_file_path": "io/prometheus/simpleclient_tracer_otel/0.15.0/simpleclient_tracer_otel-0.15.0-sources.jar" + } + }, + "io_reactivex_rxjava3_rxjava_3_1_6": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_reactivex_rxjava3_rxjava_3_1_6", + "sha256": "34682bd3ec6f043c5defb589a2d18113ba3e2d2372dd401744f8e4815c1db638", + "urls": [ + "https://repo1.maven.org/maven2/io/reactivex/rxjava3/rxjava/3.1.6/rxjava-3.1.6.jar" + ], + "downloaded_file_path": "io/reactivex/rxjava3/rxjava/3.1.6/rxjava-3.1.6.jar" + } + }, + "com_github_jnr_jnr_a64asm_jar_sources_1_0_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_jnr_jnr_a64asm_jar_sources_1_0_0", + "sha256": "2106b98c7d794fb01237e7243d975b9bc8450aa87bf34f93d7b5fcc651af7ff1", + "urls": [ + "https://repo1.maven.org/maven2/com/github/jnr/jnr-a64asm/1.0.0/jnr-a64asm-1.0.0-sources.jar" + ], + "downloaded_file_path": "com/github/jnr/jnr-a64asm/1.0.0/jnr-a64asm-1.0.0-sources.jar" + } + }, + "io_netty_netty_transport_classes_kqueue_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_classes_kqueue_4_1_97_Final", + "sha256": "964ef63eb24a5c979f0af473da13f9574497e11bd41543a66d10609d34013b9f", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-transport-classes-kqueue/4.1.97.Final/netty-transport-classes-kqueue-4.1.97.Final.jar" + ], + "downloaded_file_path": "io/netty/netty-transport-classes-kqueue/4.1.97.Final/netty-transport-classes-kqueue-4.1.97.Final.jar" + } + }, + "commons_io_commons_io_jar_sources_2_13_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~commons_io_commons_io_jar_sources_2_13_0", + "sha256": "1c7bece2e87ac49b24f09ec3c5ceb51560edd7a259889fceef96dda9c046a1b3", + "urls": [ + "https://repo1.maven.org/maven2/commons-io/commons-io/2.13.0/commons-io-2.13.0-sources.jar" + ], + "downloaded_file_path": "commons-io/commons-io/2.13.0/commons-io-2.13.0-sources.jar" + } + }, + "org_codehaus_mojo_animal_sniffer_annotations_jar_sources_1_23": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_codehaus_mojo_animal_sniffer_annotations_jar_sources_1_23", + "sha256": "4878fcc6808dbc88085a4622db670e703867754bc4bc40312c52bf3a3510d019", + "urls": [ + "https://repo1.maven.org/maven2/org/codehaus/mojo/animal-sniffer-annotations/1.23/animal-sniffer-annotations-1.23-sources.jar" + ], + "downloaded_file_path": "org/codehaus/mojo/animal-sniffer-annotations/1.23/animal-sniffer-annotations-1.23-sources.jar" + } + }, + "com_google_inject_guice_5_1_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_inject_guice_5_1_0", + "sha256": "4130e50bfac48099c860f0d903b91860c81a249c90f38245f8fed58fc817bc26", + "urls": [ + "https://repo1.maven.org/maven2/com/google/inject/guice/5.1.0/guice-5.1.0.jar" + ], + "downloaded_file_path": "com/google/inject/guice/5.1.0/guice-5.1.0.jar" + } + }, + "org_slf4j_slf4j_simple_jar_sources_2_0_9": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_slf4j_slf4j_simple_jar_sources_2_0_9", + "sha256": "45423388e9fc51af94ac936842211353dbde78c29350d1ed97445ed3e37416cd", + "urls": [ + "https://repo1.maven.org/maven2/org/slf4j/slf4j-simple/2.0.9/slf4j-simple-2.0.9-sources.jar" + ], + "downloaded_file_path": "org/slf4j/slf4j-simple/2.0.9/slf4j-simple-2.0.9-sources.jar" + } + }, + "org_apache_commons_commons_pool2_jar_sources_2_11_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_apache_commons_commons_pool2_jar_sources_2_11_1", + "sha256": "00f8a2910e6c36784384f382fb6edc61a0e856c550ee866e8d285cdd3c167111", + "urls": [ + "https://repo1.maven.org/maven2/org/apache/commons/commons-pool2/2.11.1/commons-pool2-2.11.1-sources.jar" + ], + "downloaded_file_path": "org/apache/commons/commons-pool2/2.11.1/commons-pool2-2.11.1-sources.jar" + } + }, + "com_amazonaws_aws_java_sdk_core_jar_sources_1_12_544": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_amazonaws_aws_java_sdk_core_jar_sources_1_12_544", + "sha256": "e1cc8b011d35e4d71ba452fbf0c2777a6dc2a2a4668ea8c9e72a610f77f1a71d", + "urls": [ + "https://repo1.maven.org/maven2/com/amazonaws/aws-java-sdk-core/1.12.544/aws-java-sdk-core-1.12.544-sources.jar" + ], + "downloaded_file_path": "com/amazonaws/aws-java-sdk-core/1.12.544/aws-java-sdk-core-1.12.544-sources.jar" + } + }, + "com_github_jnr_jnr_constants": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_jnr_jnr_constants", + "generating_repository": "maven", + "target_name": "com_github_jnr_jnr_constants" + } + }, + "com_google_auto_auto_common_1_2_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_auto_auto_common_1_2_1", + "sha256": "f43f29fe2a6ebaf04b2598cdeec32a4e346d49a9404e990f5fc19c19f3a28d0e", + "urls": [ + "https://repo1.maven.org/maven2/com/google/auto/auto-common/1.2.1/auto-common-1.2.1.jar" + ], + "downloaded_file_path": "com/google/auto/auto-common/1.2.1/auto-common-1.2.1.jar" + } + }, + "io_grpc_grpc_protobuf": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_protobuf", + "generating_repository": "maven", + "target_name": "io_grpc_grpc_protobuf" + } + }, + "io_prometheus_simpleclient_tracer_otel_agent_0_15_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_tracer_otel_agent_0_15_0", + "sha256": "0cbb4c29d17e9fe71bb2cec013c2999ae8a9050f237ad33211761b40d2586e0b", + "urls": [ + "https://repo1.maven.org/maven2/io/prometheus/simpleclient_tracer_otel_agent/0.15.0/simpleclient_tracer_otel_agent-0.15.0.jar" + ], + "downloaded_file_path": "io/prometheus/simpleclient_tracer_otel_agent/0.15.0/simpleclient_tracer_otel_agent-0.15.0.jar" + } + }, + "io_netty_netty_buffer_4_1_86_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_buffer_4_1_86_Final", + "sha256": "e42e15f47c865266b1faa6e038ebfd7ddadcf9f4ae9e6617edd4881dbd4abe88", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-buffer/4.1.86.Final/netty-buffer-4.1.86.Final.jar", + "https://maven.google.com/io/netty/netty-buffer/4.1.86.Final/netty-buffer-4.1.86.Final.jar" + ], + "downloaded_file_path": "io/netty/netty-buffer/4.1.86.Final/netty-buffer-4.1.86.Final.jar" + } + }, + "io_netty_netty_codec_4_1_86_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_4_1_86_Final", + "sha256": "0456840b5c851dad6cab881cd1a9ad5d916db65d81048145df1d9a6d03325bea", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-codec/4.1.86.Final/netty-codec-4.1.86.Final.jar", + "https://maven.google.com/io/netty/netty-codec/4.1.86.Final/netty-codec-4.1.86.Final.jar" + ], + "downloaded_file_path": "io/netty/netty-codec/4.1.86.Final/netty-codec-4.1.86.Final.jar" + } + }, + "org_openjdk_jmh_jmh_generator_annprocess_1_37": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_openjdk_jmh_jmh_generator_annprocess_1_37", + "sha256": "6a5604b5b804e0daca1145df1077609321687734a8b49387e49f10557c186c77", + "urls": [ + "https://repo1.maven.org/maven2/org/openjdk/jmh/jmh-generator-annprocess/1.37/jmh-generator-annprocess-1.37.jar" + ], + "downloaded_file_path": "org/openjdk/jmh/jmh-generator-annprocess/1.37/jmh-generator-annprocess-1.37.jar" + } + }, + "org_projectlombok_lombok_jar_sources_1_18_30": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_projectlombok_lombok_jar_sources_1_18_30", + "sha256": "d41c3ab349c0ec484449b545d2ac5c26ccc9c8b23f2dbbd6176382469f9eac71", + "urls": [ + "https://repo1.maven.org/maven2/org/projectlombok/lombok/1.18.30/lombok-1.18.30-sources.jar" + ], + "downloaded_file_path": "org/projectlombok/lombok/1.18.30/lombok-1.18.30-sources.jar" + } + }, + "org_apache_tomcat_annotations_api_6_0_53": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_apache_tomcat_annotations_api_6_0_53", + "sha256": "253829d3c12b7381d1044fc22c6436cff025fe0d459e4a329413e560a7d0dd13", + "urls": [ + "https://repo1.maven.org/maven2/org/apache/tomcat/annotations-api/6.0.53/annotations-api-6.0.53.jar" + ], + "downloaded_file_path": "org/apache/tomcat/annotations-api/6.0.53/annotations-api-6.0.53.jar" + } + }, + "io_perfmark_perfmark_api_jar_sources_0_26_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_perfmark_perfmark_api_jar_sources_0_26_0", + "sha256": "7379e0fef0c32d69f3ebae8f271f426fc808613f1cfbc29e680757f348ba8aa4", + "urls": [ + "https://repo1.maven.org/maven2/io/perfmark/perfmark-api/0.26.0/perfmark-api-0.26.0-sources.jar" + ], + "downloaded_file_path": "io/perfmark/perfmark-api/0.26.0/perfmark-api-0.26.0-sources.jar" + } + }, + "software_amazon_awssdk_aws_query_protocol_2_20_78": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_aws_query_protocol_2_20_78", + "sha256": "74c9b42046e3829836d2351a3a0bb06ae54f7e4f0c3d319c9b68166f245db549", + "urls": [ + "https://repo1.maven.org/maven2/software/amazon/awssdk/aws-query-protocol/2.20.78/aws-query-protocol-2.20.78.jar", + "https://maven.google.com/software/amazon/awssdk/aws-query-protocol/2.20.78/aws-query-protocol-2.20.78.jar" + ], + "downloaded_file_path": "software/amazon/awssdk/aws-query-protocol/2.20.78/aws-query-protocol-2.20.78.jar" + } + }, + "org_projectlombok_lombok_1_18_30": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_projectlombok_lombok_1_18_30", + "sha256": "14151b47582d570b4de16a147ece3bdbd19ace4aee5bde3a5578c87db9ecb998", + "urls": [ + "https://repo1.maven.org/maven2/org/projectlombok/lombok/1.18.30/lombok-1.18.30.jar" + ], + "downloaded_file_path": "org/projectlombok/lombok/1.18.30/lombok-1.18.30.jar" + } + }, + "org_apache_tomcat_annotations_api": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_apache_tomcat_annotations_api", + "generating_repository": "maven", + "target_name": "org_apache_tomcat_annotations_api" + } + }, + "io_netty_netty_resolver_dns_4_1_96_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_resolver_dns_4_1_96_Final", + "sha256": "09a4f0cc4fc7af083515cfb84d6e70af4223dfe129858274cf506cc626f5175e", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-resolver-dns/4.1.96.Final/netty-resolver-dns-4.1.96.Final.jar" + ], + "downloaded_file_path": "io/netty/netty-resolver-dns/4.1.96.Final/netty-resolver-dns-4.1.96.Final.jar" + } + }, + "com_google_api_grpc_proto_google_common_protos_2_19_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_api_grpc_proto_google_common_protos_2_19_1", + "sha256": "5557ee1b7f44a80fa595cdcedcc52ed3be143ce25408181c3ad136006cdd749f", + "urls": [ + "https://repo1.maven.org/maven2/com/google/api/grpc/proto-google-common-protos/2.19.1/proto-google-common-protos-2.19.1.jar", + "https://maven.google.com/com/google/api/grpc/proto-google-common-protos/2.19.1/proto-google-common-protos-2.19.1.jar" + ], + "downloaded_file_path": "com/google/api/grpc/proto-google-common-protos/2.19.1/proto-google-common-protos-2.19.1.jar" + } + }, + "com_github_oshi_oshi_core_jar_sources_6_4_5": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_oshi_oshi_core_jar_sources_6_4_5", + "sha256": "1ff5c3475458db16fce29e1aabce48242fe80221144de4b2a1dc62bd18f15062", + "urls": [ + "https://repo1.maven.org/maven2/com/github/oshi/oshi-core/6.4.5/oshi-core-6.4.5-sources.jar" + ], + "downloaded_file_path": "com/github/oshi/oshi-core/6.4.5/oshi-core-6.4.5-sources.jar" + } + }, + "javax_inject_javax_inject_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~javax_inject_javax_inject_1", + "sha256": "91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff", + "urls": [ + "https://repo1.maven.org/maven2/javax/inject/javax.inject/1/javax.inject-1.jar" + ], + "downloaded_file_path": "javax/inject/javax.inject/1/javax.inject-1.jar" + } + }, + "org_jodd_jodd_bean_jar_sources_5_1_6": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_jodd_jodd_bean_jar_sources_5_1_6", + "sha256": "961cff0114d349d3491293eea0c74a910b8676326c1af682f07e500782180160", + "urls": [ + "https://repo1.maven.org/maven2/org/jodd/jodd-bean/5.1.6/jodd-bean-5.1.6-sources.jar" + ], + "downloaded_file_path": "org/jodd/jodd-bean/5.1.6/jodd-bean-5.1.6-sources.jar" + } + }, + "software_amazon_awssdk_s3_2_20_78": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_s3_2_20_78", + "sha256": "0a21d9d740f20e8d65985b8e31154a6603f4f15a7c5acea5a70957745519327b", + "urls": [ + "https://repo1.maven.org/maven2/software/amazon/awssdk/s3/2.20.78/s3-2.20.78.jar", + "https://maven.google.com/software/amazon/awssdk/s3/2.20.78/s3-2.20.78.jar" + ], + "downloaded_file_path": "software/amazon/awssdk/s3/2.20.78/s3-2.20.78.jar" + } + }, + "com_google_android_annotations_jar_sources_4_1_1_4": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_android_annotations_jar_sources_4_1_1_4", + "sha256": "e9b667aa958df78ea1ad115f7bbac18a5869c3128b1d5043feb360b0cfce9d40", + "urls": [ + "https://repo1.maven.org/maven2/com/google/android/annotations/4.1.1.4/annotations-4.1.1.4-sources.jar" + ], + "downloaded_file_path": "com/google/android/annotations/4.1.1.4/annotations-4.1.1.4-sources.jar" + } + }, + "org_glassfish_hk2_hk2_utils_2_6_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_glassfish_hk2_hk2_utils_2_6_1", + "sha256": "30727f79086452fdefdab08451d982c2082aa239d9f75cdeb1ba271e3c887036", + "urls": [ + "https://repo1.maven.org/maven2/org/glassfish/hk2/hk2-utils/2.6.1/hk2-utils-2.6.1.jar" + ], + "downloaded_file_path": "org/glassfish/hk2/hk2-utils/2.6.1/hk2-utils-2.6.1.jar" + } + }, + "com_google_android_annotations_4_1_1_4": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_android_annotations_4_1_1_4", + "sha256": "ba734e1e84c09d615af6a09d33034b4f0442f8772dec120efb376d86a565ae15", + "urls": [ + "https://repo1.maven.org/maven2/com/google/android/annotations/4.1.1.4/annotations-4.1.1.4.jar" + ], + "downloaded_file_path": "com/google/android/annotations/4.1.1.4/annotations-4.1.1.4.jar" + } + }, + "com_github_pcj_google_options_jar_sources_1_0_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_pcj_google_options_jar_sources_1_0_0", + "sha256": "3871275e5323aaa132ed043c3c3bf6620f5fe73c8aeb456ce992db9ce5d59768", + "urls": [ + "https://repo1.maven.org/maven2/com/github/pcj/google-options/1.0.0/google-options-1.0.0-sources.jar" + ], + "downloaded_file_path": "com/github/pcj/google-options/1.0.0/google-options-1.0.0-sources.jar" + } + }, + "com_google_guava_failureaccess_jar_sources_1_0_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_guava_failureaccess_jar_sources_1_0_1", + "sha256": "092346eebbb1657b51aa7485a246bf602bb464cc0b0e2e1c7e7201fadce1e98f", + "urls": [ + "https://repo1.maven.org/maven2/com/google/guava/failureaccess/1.0.1/failureaccess-1.0.1-sources.jar" + ], + "downloaded_file_path": "com/google/guava/failureaccess/1.0.1/failureaccess-1.0.1-sources.jar" + } + }, + "redis_clients_jedis_jar_sources_4_3_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~redis_clients_jedis_jar_sources_4_3_1", + "sha256": "8590d6ad29f6760424e5d832ee2f738b9790393c9986e6754a03427bfb8d5d04", + "urls": [ + "https://repo1.maven.org/maven2/redis/clients/jedis/4.3.1/jedis-4.3.1-sources.jar" + ], + "downloaded_file_path": "redis/clients/jedis/4.3.1/jedis-4.3.1-sources.jar" + } + }, + "com_google_api_grpc_proto_google_cloud_storage_v2_2_22_3_alpha": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_api_grpc_proto_google_cloud_storage_v2_2_22_3_alpha", + "sha256": "346cc208553f4b286868bd05ccf4558e3798609559ec2b8fc8b2ea5e15819d8b", + "urls": [ + "https://repo1.maven.org/maven2/com/google/api/grpc/proto-google-cloud-storage-v2/2.22.3-alpha/proto-google-cloud-storage-v2-2.22.3-alpha.jar", + "https://maven.google.com/com/google/api/grpc/proto-google-cloud-storage-v2/2.22.3-alpha/proto-google-cloud-storage-v2-2.22.3-alpha.jar" + ], + "downloaded_file_path": "com/google/api/grpc/proto-google-cloud-storage-v2/2.22.3-alpha/proto-google-cloud-storage-v2-2.22.3-alpha.jar" + } + }, + "com_google_auth_google_auth_library_oauth2_http": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_auth_google_auth_library_oauth2_http", + "generating_repository": "maven", + "target_name": "com_google_auth_google_auth_library_oauth2_http" + } + }, + "io_github_java_diff_utils_java_diff_utils_jar_sources_4_12": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_github_java_diff_utils_java_diff_utils_jar_sources_4_12", + "sha256": "fa24217b6eaa115a05d4a8f0003fe913c62716ca2184d2e4f17de4a7d42a8822", + "urls": [ + "https://repo1.maven.org/maven2/io/github/java-diff-utils/java-diff-utils/4.12/java-diff-utils-4.12-sources.jar" + ], + "downloaded_file_path": "io/github/java-diff-utils/java-diff-utils/4.12/java-diff-utils-4.12-sources.jar" + } + }, + "commons_io_commons_io_2_13_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~commons_io_commons_io_2_13_0", + "sha256": "671eaa39688dac2ffaa4645b3c9980ae2d0ea2471e4ae6a5da199cd15ae23666", + "urls": [ + "https://repo1.maven.org/maven2/commons-io/commons-io/2.13.0/commons-io-2.13.0.jar" + ], + "downloaded_file_path": "commons-io/commons-io/2.13.0/commons-io-2.13.0.jar" + } + }, + "commons_logging_commons_logging_jar_sources_1_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~commons_logging_commons_logging_jar_sources_1_2", + "sha256": "44347acfe5860461728e9cb33251e97345be36f8a0dfd5c5130c172559455f41", + "urls": [ + "https://repo1.maven.org/maven2/commons-logging/commons-logging/1.2/commons-logging-1.2-sources.jar" + ], + "downloaded_file_path": "commons-logging/commons-logging/1.2/commons-logging-1.2-sources.jar" + } + }, + "jakarta_activation_jakarta_activation_api_jar_sources_1_2_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~jakarta_activation_jakarta_activation_api_jar_sources_1_2_1", + "sha256": "e9638b764202c0def1b4d54bd37a984c681b2ed46a548ae94ef3f7e4a4b58a31", + "urls": [ + "https://repo1.maven.org/maven2/jakarta/activation/jakarta.activation-api/1.2.1/jakarta.activation-api-1.2.1-sources.jar" + ], + "downloaded_file_path": "jakarta/activation/jakarta.activation-api/1.2.1/jakarta.activation-api-1.2.1-sources.jar" + } + }, + "io_grpc_grpc_netty_shaded_1_55_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_netty_shaded_1_55_1", + "sha256": "3dc035ea13bf854d4218bc6370ba8d786077a9e0d76337e61df7597a78a03c61", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-netty-shaded/1.55.1/grpc-netty-shaded-1.55.1.jar", + "https://maven.google.com/io/grpc/grpc-netty-shaded/1.55.1/grpc-netty-shaded-1.55.1.jar" + ], + "downloaded_file_path": "io/grpc/grpc-netty-shaded/1.55.1/grpc-netty-shaded-1.55.1.jar" + } + }, + "com_github_luben_zstd_jni_jar_sources_1_5_5_7": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_luben_zstd_jni_jar_sources_1_5_5_7", + "sha256": "6560c8d5e307feebb75630032c3e16c07e079907cf0238cc45647495af704599", + "urls": [ + "https://repo1.maven.org/maven2/com/github/luben/zstd-jni/1.5.5-7/zstd-jni-1.5.5-7-sources.jar" + ], + "downloaded_file_path": "com/github/luben/zstd-jni/1.5.5-7/zstd-jni-1.5.5-7-sources.jar" + } + }, + "com_github_luben_zstd_jni_1_5_5_7": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_luben_zstd_jni_1_5_5_7", + "sha256": "edd7fc60c2aaa6b77d3436f667bf30b06202633761ec20d683638b40e8f11426", + "urls": [ + "https://repo1.maven.org/maven2/com/github/luben/zstd-jni/1.5.5-7/zstd-jni-1.5.5-7.jar" + ], + "downloaded_file_path": "com/github/luben/zstd-jni/1.5.5-7/zstd-jni-1.5.5-7.jar" + } + }, + "io_netty_netty_resolver": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_resolver", + "generating_repository": "maven", + "target_name": "io_netty_netty_resolver" + } + }, + "org_redisson_redisson_3_23_4": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_redisson_redisson_3_23_4", + "sha256": "fe59768d63419b0073c0cbd6029d0be864ad5c9d233dd1337945f9edfe3df3ca", + "urls": [ + "https://repo1.maven.org/maven2/org/redisson/redisson/3.23.4/redisson-3.23.4.jar" + ], + "downloaded_file_path": "org/redisson/redisson/3.23.4/redisson-3.23.4.jar" + } + }, + "net_javacrumbs_future_converter_future_converter_guava_common_1_2_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~net_javacrumbs_future_converter_future_converter_guava_common_1_2_0", + "sha256": "82bfab706005ea51c3e76958a62564367cf9cae207c0b1d55b9734876b9780c1", + "urls": [ + "https://repo1.maven.org/maven2/net/javacrumbs/future-converter/future-converter-guava-common/1.2.0/future-converter-guava-common-1.2.0.jar" + ], + "downloaded_file_path": "net/javacrumbs/future-converter/future-converter-guava-common/1.2.0/future-converter-guava-common-1.2.0.jar" + } + }, + "org_ow2_asm_asm_util_9_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_ow2_asm_asm_util_9_2", + "sha256": "ff5b3cd331ae8a9a804768280da98f50f424fef23dd3c788bb320e08c94ee598", + "urls": [ + "https://repo1.maven.org/maven2/org/ow2/asm/asm-util/9.2/asm-util-9.2.jar" + ], + "downloaded_file_path": "org/ow2/asm/asm-util/9.2/asm-util-9.2.jar" + } + }, + "io_grpc_grpc_stub_1_55_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_stub_1_55_1", + "sha256": "58c114817d42237ce50a5f7677cf142564df64200e59c956e49302b6c8af616a", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-stub/1.55.1/grpc-stub-1.55.1.jar", + "https://maven.google.com/io/grpc/grpc-stub/1.55.1/grpc-stub-1.55.1.jar" + ], + "downloaded_file_path": "io/grpc/grpc-stub/1.55.1/grpc-stub-1.55.1.jar" + } + }, + "org_apache_commons_commons_lang3_3_12_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_apache_commons_commons_lang3_3_12_0", + "sha256": "d919d904486c037f8d193412da0c92e22a9fa24230b9d67a57855c5c31c7e94e", + "urls": [ + "https://repo1.maven.org/maven2/org/apache/commons/commons-lang3/3.12.0/commons-lang3-3.12.0.jar", + "https://maven.google.com/org/apache/commons/commons-lang3/3.12.0/commons-lang3-3.12.0.jar" + ], + "downloaded_file_path": "org/apache/commons/commons-lang3/3.12.0/commons-lang3-3.12.0.jar" + } + }, + "com_github_docker_java_docker_java_transport_3_3_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_docker_java_docker_java_transport_3_3_3", + "sha256": "103b94685f398b036cf9243cb8899680bcdb4e54c32340a32b2b5737a87a33ba", + "urls": [ + "https://repo1.maven.org/maven2/com/github/docker-java/docker-java-transport/3.3.3/docker-java-transport-3.3.3.jar" + ], + "downloaded_file_path": "com/github/docker-java/docker-java-transport/3.3.3/docker-java-transport-3.3.3.jar" + } + }, + "software_amazon_awssdk_auth_2_20_78": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_auth_2_20_78", + "sha256": "9eb0c3d97668b318ae5dcd127f434186a73d8e2552ad0fdd1fb71e3ffa5f0bec", + "urls": [ + "https://repo1.maven.org/maven2/software/amazon/awssdk/auth/2.20.78/auth-2.20.78.jar", + "https://maven.google.com/software/amazon/awssdk/auth/2.20.78/auth-2.20.78.jar" + ], + "downloaded_file_path": "software/amazon/awssdk/auth/2.20.78/auth-2.20.78.jar" + } + }, + "io_grpc_grpc_core_jar_sources_1_56_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_core_jar_sources_1_56_1", + "sha256": "9fd5eb82e115bcfc3babadb486d37d1096e86ce869ae0d1ccc4270aec60351ef", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-core/1.56.1/grpc-core-1.56.1-sources.jar" + ], + "downloaded_file_path": "io/grpc/grpc-core/1.56.1/grpc-core-1.56.1-sources.jar" + } + }, + "com_github_docker_java_docker_java_3_3_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_docker_java_docker_java_3_3_3", + "sha256": "3afb208216a17d8ce26a8f689303292701c87b974d43780cfba47bb2199a4467", + "urls": [ + "https://repo1.maven.org/maven2/com/github/docker-java/docker-java/3.3.3/docker-java-3.3.3.jar" + ], + "downloaded_file_path": "com/github/docker-java/docker-java/3.3.3/docker-java-3.3.3.jar" + } + }, + "org_apache_commons_commons_math3_jar_sources_3_6_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_apache_commons_commons_math3_jar_sources_3_6_1", + "sha256": "e2ff85a3c360d56c51a7021614a194f3fbaf224054642ac535016f118322934d", + "urls": [ + "https://repo1.maven.org/maven2/org/apache/commons/commons-math3/3.6.1/commons-math3-3.6.1-sources.jar" + ], + "downloaded_file_path": "org/apache/commons/commons-math3/3.6.1/commons-math3-3.6.1-sources.jar" + } + }, + "com_fasterxml_jackson_core_jackson_core_2_15_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_core_jackson_core_2_15_2", + "sha256": "303c99e82b1faa91a0bae5d8fbeb56f7e2adf9b526a900dd723bf140d62bd4b4", + "urls": [ + "https://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-core/2.15.2/jackson-core-2.15.2.jar" + ], + "downloaded_file_path": "com/fasterxml/jackson/core/jackson-core/2.15.2/jackson-core-2.15.2.jar" + } + }, + "io_netty_netty_transport_native_epoll_jar_linux_x86_64_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_native_epoll_jar_linux_x86_64_4_1_97_Final", + "sha256": "1e83fc9f82e5415cdbb688c6a5c6bbbd7d198e9fdd6fdf64b3dc5d54dd1acfd0", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-transport-native-epoll/4.1.97.Final/netty-transport-native-epoll-4.1.97.Final-linux-x86_64.jar" + ], + "downloaded_file_path": "io/netty/netty-transport-native-epoll/4.1.97.Final/netty-transport-native-epoll-4.1.97.Final-linux-x86_64.jar" + } + }, + "org_bouncycastle_bcpkix_jdk18on_1_75": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_bouncycastle_bcpkix_jdk18on_1_75", + "sha256": "9e2c1db5a6ed29fbc36b438d39ca9feb901bb69bad0ce8d7bc735264bea79bd3", + "urls": [ + "https://repo1.maven.org/maven2/org/bouncycastle/bcpkix-jdk18on/1.75/bcpkix-jdk18on-1.75.jar" + ], + "downloaded_file_path": "org/bouncycastle/bcpkix-jdk18on/1.75/bcpkix-jdk18on-1.75.jar" + } + }, + "org_reflections_reflections_0_10_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_reflections_reflections_0_10_2", + "sha256": "938a2d08fe54050d7610b944d8ddc3a09355710d9e6be0aac838dbc04e9a2825", + "urls": [ + "https://repo1.maven.org/maven2/org/reflections/reflections/0.10.2/reflections-0.10.2.jar" + ], + "downloaded_file_path": "org/reflections/reflections/0.10.2/reflections-0.10.2.jar" + } + }, + "com_github_fppt_jedis_mock_1_0_10": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_fppt_jedis_mock_1_0_10", + "sha256": "118684813167330681c6f1bebea2c1b67e3ed96bb862867437c0e4270d1fc88d", + "urls": [ + "https://repo1.maven.org/maven2/com/github/fppt/jedis-mock/1.0.10/jedis-mock-1.0.10.jar" + ], + "downloaded_file_path": "com/github/fppt/jedis-mock/1.0.10/jedis-mock-1.0.10.jar" + } + }, + "org_javassist_javassist_3_28_0_GA": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_javassist_javassist_3_28_0_GA", + "sha256": "57d0a9e9286f82f4eaa851125186997f811befce0e2060ff0a15a77f5a9dd9a7", + "urls": [ + "https://repo1.maven.org/maven2/org/javassist/javassist/3.28.0-GA/javassist-3.28.0-GA.jar" + ], + "downloaded_file_path": "org/javassist/javassist/3.28.0-GA/javassist-3.28.0-GA.jar" + } + }, + "com_google_http_client_google_http_client_gson_1_43_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_http_client_google_http_client_gson_1_43_1", + "sha256": "017406e5105a33147ab13baf7b491ff53d99e54a5e2b61b7ccd651e164229698", + "urls": [ + "https://repo1.maven.org/maven2/com/google/http-client/google-http-client-gson/1.43.1/google-http-client-gson-1.43.1.jar", + "https://maven.google.com/com/google/http-client/google-http-client-gson/1.43.1/google-http-client-gson-1.43.1.jar" + ], + "downloaded_file_path": "com/google/http-client/google-http-client-gson/1.43.1/google-http-client-gson-1.43.1.jar" + } + }, + "net_minidev_json_smart_2_4_10": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~net_minidev_json_smart_2_4_10", + "sha256": "70cab5e9488630dc631b1fc6e7fa550d95cddd19ba14db39ceca7cabfbd4e5ae", + "urls": [ + "https://repo1.maven.org/maven2/net/minidev/json-smart/2.4.10/json-smart-2.4.10.jar" + ], + "downloaded_file_path": "net/minidev/json-smart/2.4.10/json-smart-2.4.10.jar" + } + }, + "org_apache_httpcomponents_httpcore_4_4_15": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_apache_httpcomponents_httpcore_4_4_15", + "sha256": "3cbaed088c499a10f96dde58f39dc0e7985171abd88138ca1655a872011bb142", + "urls": [ + "https://repo1.maven.org/maven2/org/apache/httpcomponents/httpcore/4.4.15/httpcore-4.4.15.jar" + ], + "downloaded_file_path": "org/apache/httpcomponents/httpcore/4.4.15/httpcore-4.4.15.jar" + } + }, + "io_grpc_grpc_protobuf_lite_1_56_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_protobuf_lite_1_56_1", + "sha256": "5605030f1668edf93ade7f24b0bfe5ecf943774e02cf0ac5cac02387ac910185", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-protobuf-lite/1.56.1/grpc-protobuf-lite-1.56.1.jar" + ], + "downloaded_file_path": "io/grpc/grpc-protobuf-lite/1.56.1/grpc-protobuf-lite-1.56.1.jar" + } + }, + "org_apache_httpcomponents_httpcore_4_4_16": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_apache_httpcomponents_httpcore_4_4_16", + "sha256": "6c9b3dd142a09dc468e23ad39aad6f75a0f2b85125104469f026e52a474e464f", + "urls": [ + "https://repo1.maven.org/maven2/org/apache/httpcomponents/httpcore/4.4.16/httpcore-4.4.16.jar", + "https://maven.google.com/org/apache/httpcomponents/httpcore/4.4.16/httpcore-4.4.16.jar" + ], + "downloaded_file_path": "org/apache/httpcomponents/httpcore/4.4.16/httpcore-4.4.16.jar" + } + }, + "org_slf4j_slf4j_simple": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_slf4j_slf4j_simple", + "generating_repository": "maven", + "target_name": "org_slf4j_slf4j_simple" + } + }, + "io_netty_netty_codec_jar_sources_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_jar_sources_4_1_97_Final", + "sha256": "3f512c1a7ffa112ce3f8a8fec9545017063ae06583e80e841bdee76477f891f4", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-codec/4.1.97.Final/netty-codec-4.1.97.Final-sources.jar" + ], + "downloaded_file_path": "io/netty/netty-codec/4.1.97.Final/netty-codec-4.1.97.Final-sources.jar" + } + }, + "org_xerial_sqlite_jdbc_3_34_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_xerial_sqlite_jdbc_3_34_0", + "sha256": "605979c94e7fe00437f1e10dcfa657a23f125c8eb4d2f0ec17e3f84613894cc3", + "urls": [ + "https://repo1.maven.org/maven2/org/xerial/sqlite-jdbc/3.34.0/sqlite-jdbc-3.34.0.jar" + ], + "downloaded_file_path": "org/xerial/sqlite-jdbc/3.34.0/sqlite-jdbc-3.34.0.jar" + } + }, + "org_slf4j_jcl_over_slf4j_jar_sources_1_7_30": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_slf4j_jcl_over_slf4j_jar_sources_1_7_30", + "sha256": "e746bd5e537c8ceeb0c815a4edbaa4169444f74e658038e1966d8a3596eb8d05", + "urls": [ + "https://repo1.maven.org/maven2/org/slf4j/jcl-over-slf4j/1.7.30/jcl-over-slf4j-1.7.30-sources.jar" + ], + "downloaded_file_path": "org/slf4j/jcl-over-slf4j/1.7.30/jcl-over-slf4j-1.7.30-sources.jar" + } + }, + "io_grpc_grpc_netty_shaded_1_56_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_netty_shaded_1_56_1", + "sha256": "b15257e1137d609a7e8eb9bf4f0cec06b78ee69c030282db0a66d17cc9c3eaf1", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-netty-shaded/1.56.1/grpc-netty-shaded-1.56.1.jar" + ], + "downloaded_file_path": "io/grpc/grpc-netty-shaded/1.56.1/grpc-netty-shaded-1.56.1.jar" + } + }, + "com_google_protobuf_protobuf_java": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_protobuf_protobuf_java", + "generating_repository": "maven", + "target_name": "com_google_protobuf_protobuf_java" + } + }, + "unpinned_maven": { + "bzlFile": "@@rules_jvm_external~5.3//:coursier.bzl", + "ruleClassName": "coursier_fetch", + "attributes": { + "name": "rules_jvm_external~5.3~maven~unpinned_maven", + "repositories": [ + "{ \"repo_url\": \"https://repo1.maven.org/maven2\" }" + ], + "artifacts": [ + "{ \"group\": \"com.amazonaws\", \"artifact\": \"aws-java-sdk-s3\", \"version\": \"1.12.544\" }", + "{ \"group\": \"com.amazonaws\", \"artifact\": \"aws-java-sdk-secretsmanager\", \"version\": \"1.12.544\" }", + "{ \"group\": \"com.fasterxml.jackson.core\", \"artifact\": \"jackson-databind\", \"version\": \"2.15.0\" }", + "{ \"group\": \"com.github.ben-manes.caffeine\", \"artifact\": \"caffeine\", \"version\": \"2.9.0\" }", + "{ \"group\": \"com.github.docker-java\", \"artifact\": \"docker-java\", \"version\": \"3.3.3\" }", + "{ \"group\": \"com.github.fppt\", \"artifact\": \"jedis-mock\", \"version\": \"1.0.10\" }", + "{ \"group\": \"com.github.jnr\", \"artifact\": \"jffi\", \"version\": \"1.3.11\" }", + "{ \"group\": \"com.github.jnr\", \"artifact\": \"jffi\", \"version\": \"1.3.11\", \"packaging\": \"jar\", \"classifier\": \"native\" }", + "{ \"group\": \"com.github.jnr\", \"artifact\": \"jnr-constants\", \"version\": \"0.10.4\" }", + "{ \"group\": \"com.github.jnr\", \"artifact\": \"jnr-ffi\", \"version\": \"2.2.14\" }", + "{ \"group\": \"com.github.jnr\", \"artifact\": \"jnr-posix\", \"version\": \"3.1.17\" }", + "{ \"group\": \"com.github.pcj\", \"artifact\": \"google-options\", \"version\": \"1.0.0\" }", + "{ \"group\": \"com.github.serceman\", \"artifact\": \"jnr-fuse\", \"version\": \"0.5.7\" }", + "{ \"group\": \"com.github.luben\", \"artifact\": \"zstd-jni\", \"version\": \"1.5.5-7\" }", + "{ \"group\": \"com.github.oshi\", \"artifact\": \"oshi-core\", \"version\": \"6.4.5\" }", + "{ \"group\": \"com.google.auth\", \"artifact\": \"google-auth-library-credentials\", \"version\": \"1.19.0\" }", + "{ \"group\": \"com.google.auth\", \"artifact\": \"google-auth-library-oauth2-http\", \"version\": \"1.19.0\" }", + "{ \"group\": \"com.google.code.findbugs\", \"artifact\": \"jsr305\", \"version\": \"3.0.2\" }", + "{ \"group\": \"com.google.code.gson\", \"artifact\": \"gson\", \"version\": \"2.10.1\" }", + "{ \"group\": \"com.google.errorprone\", \"artifact\": \"error_prone_annotations\", \"version\": \"2.22.0\" }", + "{ \"group\": \"com.google.errorprone\", \"artifact\": \"error_prone_core\", \"version\": \"2.22.0\" }", + "{ \"group\": \"com.google.guava\", \"artifact\": \"failureaccess\", \"version\": \"1.0.1\" }", + "{ \"group\": \"com.google.guava\", \"artifact\": \"guava\", \"version\": \"32.1.1-jre\" }", + "{ \"group\": \"com.google.j2objc\", \"artifact\": \"j2objc-annotations\", \"version\": \"2.8\" }", + "{ \"group\": \"com.google.jimfs\", \"artifact\": \"jimfs\", \"version\": \"1.3.0\" }", + "{ \"group\": \"com.google.protobuf\", \"artifact\": \"protobuf-java-util\", \"version\": \"3.19.1\" }", + "{ \"group\": \"com.google.protobuf\", \"artifact\": \"protobuf-java\", \"version\": \"3.19.1\" }", + "{ \"group\": \"com.google.truth\", \"artifact\": \"truth\", \"version\": \"1.1.5\" }", + "{ \"group\": \"org.slf4j\", \"artifact\": \"slf4j-simple\", \"version\": \"2.0.9\" }", + "{ \"group\": \"com.googlecode.json-simple\", \"artifact\": \"json-simple\", \"version\": \"1.1.1\" }", + "{ \"group\": \"com.jayway.jsonpath\", \"artifact\": \"json-path\", \"version\": \"2.8.0\" }", + "{ \"group\": \"org.bouncycastle\", \"artifact\": \"bcprov-jdk15on\", \"version\": \"1.70\" }", + "{ \"group\": \"net.jcip\", \"artifact\": \"jcip-annotations\", \"version\": \"1.0\" }", + "{ \"group\": \"io.netty\", \"artifact\": \"netty-buffer\", \"version\": \"4.1.97.Final\" }", + "{ \"group\": \"io.netty\", \"artifact\": \"netty-codec\", \"version\": \"4.1.97.Final\" }", + "{ \"group\": \"io.netty\", \"artifact\": \"netty-codec-http\", \"version\": \"4.1.97.Final\" }", + "{ \"group\": \"io.netty\", \"artifact\": \"netty-codec-http2\", \"version\": \"4.1.97.Final\" }", + "{ \"group\": \"io.netty\", \"artifact\": \"netty-codec-socks\", \"version\": \"4.1.97.Final\" }", + "{ \"group\": \"io.netty\", \"artifact\": \"netty-common\", \"version\": \"4.1.97.Final\" }", + "{ \"group\": \"io.netty\", \"artifact\": \"netty-handler\", \"version\": \"4.1.97.Final\" }", + "{ \"group\": \"io.netty\", \"artifact\": \"netty-handler-proxy\", \"version\": \"4.1.97.Final\" }", + "{ \"group\": \"io.netty\", \"artifact\": \"netty-resolver\", \"version\": \"4.1.97.Final\" }", + "{ \"group\": \"io.netty\", \"artifact\": \"netty-transport\", \"version\": \"4.1.97.Final\" }", + "{ \"group\": \"io.netty\", \"artifact\": \"netty-transport-native-epoll\", \"version\": \"4.1.97.Final\" }", + "{ \"group\": \"io.netty\", \"artifact\": \"netty-transport-native-kqueue\", \"version\": \"4.1.97.Final\" }", + "{ \"group\": \"io.netty\", \"artifact\": \"netty-transport-native-unix-common\", \"version\": \"4.1.97.Final\" }", + "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-api\", \"version\": \"1.56.1\" }", + "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-auth\", \"version\": \"1.56.1\" }", + "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-core\", \"version\": \"1.56.1\" }", + "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-context\", \"version\": \"1.56.1\" }", + "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-netty\", \"version\": \"1.56.1\" }", + "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-stub\", \"version\": \"1.56.1\" }", + "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-protobuf\", \"version\": \"1.56.1\" }", + "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-testing\", \"version\": \"1.56.1\" }", + "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-services\", \"version\": \"1.56.1\" }", + "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-netty-shaded\", \"version\": \"1.56.1\" }", + "{ \"group\": \"io.prometheus\", \"artifact\": \"simpleclient\", \"version\": \"0.15.0\" }", + "{ \"group\": \"io.prometheus\", \"artifact\": \"simpleclient_hotspot\", \"version\": \"0.15.0\" }", + "{ \"group\": \"io.prometheus\", \"artifact\": \"simpleclient_httpserver\", \"version\": \"0.15.0\" }", + "{ \"group\": \"junit\", \"artifact\": \"junit\", \"version\": \"4.13.2\" }", + "{ \"group\": \"javax.annotation\", \"artifact\": \"javax.annotation-api\", \"version\": \"1.3.2\" }", + "{ \"group\": \"net.javacrumbs.future-converter\", \"artifact\": \"future-converter-java8-guava\", \"version\": \"1.2.0\" }", + "{ \"group\": \"org.apache.commons\", \"artifact\": \"commons-compress\", \"version\": \"1.23.0\" }", + "{ \"group\": \"org.apache.commons\", \"artifact\": \"commons-pool2\", \"version\": \"2.11.1\" }", + "{ \"group\": \"org.apache.commons\", \"artifact\": \"commons-lang3\", \"version\": \"3.13.0\" }", + "{ \"group\": \"commons-io\", \"artifact\": \"commons-io\", \"version\": \"2.13.0\" }", + "{ \"group\": \"me.dinowernli\", \"artifact\": \"java-grpc-prometheus\", \"version\": \"0.6.0\" }", + "{ \"group\": \"org.apache.tomcat\", \"artifact\": \"annotations-api\", \"version\": \"6.0.53\" }", + "{ \"group\": \"org.checkerframework\", \"artifact\": \"checker-qual\", \"version\": \"3.38.0\" }", + "{ \"group\": \"org.mockito\", \"artifact\": \"mockito-core\", \"version\": \"2.25.0\" }", + "{ \"group\": \"org.openjdk.jmh\", \"artifact\": \"jmh-core\", \"version\": \"1.37\" }", + "{ \"group\": \"org.openjdk.jmh\", \"artifact\": \"jmh-generator-annprocess\", \"version\": \"1.37\" }", + "{ \"group\": \"org.redisson\", \"artifact\": \"redisson\", \"version\": \"3.23.4\" }", + "{ \"group\": \"org.threeten\", \"artifact\": \"threetenbp\", \"version\": \"1.6.8\" }", + "{ \"group\": \"org.xerial\", \"artifact\": \"sqlite-jdbc\", \"version\": \"3.34.0\" }", + "{ \"group\": \"org.jetbrains\", \"artifact\": \"annotations\", \"version\": \"16.0.2\" }", + "{ \"group\": \"org.yaml\", \"artifact\": \"snakeyaml\", \"version\": \"2.2\" }", + "{ \"group\": \"org.projectlombok\", \"artifact\": \"lombok\", \"version\": \"1.18.30\" }" + ], + "fail_on_missing_checksum": true, + "fetch_sources": true, + "fetch_javadoc": false, + "excluded_artifacts": [], + "generate_compat_repositories": false, + "version_conflict_policy": "default", + "override_targets": {}, + "strict_visibility": false, + "strict_visibility_value": [ + "@@//visibility:private" + ], + "maven_install_json": "@@//:maven_install.json", + "resolve_timeout": 600, + "jetify": false, + "jetify_include_list": [ + "*" + ], + "use_starlark_android_rules": false, + "aar_import_bzl_label": "@build_bazel_rules_android//android:rules.bzl", + "duplicate_version_warning": "warn" + } + }, + "io_netty_netty_transport_native_unix_common_4_1_86_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_native_unix_common_4_1_86_Final", + "sha256": "ec26d03a06565791d57e997f793677ee4d3fc47b290b7951898c2ecd0232f115", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-transport-native-unix-common/4.1.86.Final/netty-transport-native-unix-common-4.1.86.Final.jar", + "https://maven.google.com/io/netty/netty-transport-native-unix-common/4.1.86.Final/netty-transport-native-unix-common-4.1.86.Final.jar" + ], + "downloaded_file_path": "io/netty/netty-transport-native-unix-common/4.1.86.Final/netty-transport-native-unix-common-4.1.86.Final.jar" + } + }, + "com_github_oshi_oshi_core_6_4_5": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_oshi_oshi_core_6_4_5", + "sha256": "7e634fb57b8763b7803d5f9caaed46d19c3bdbe81ddd8a93e61528c700cdc09e", + "urls": [ + "https://repo1.maven.org/maven2/com/github/oshi/oshi-core/6.4.5/oshi-core-6.4.5.jar" + ], + "downloaded_file_path": "com/github/oshi/oshi-core/6.4.5/oshi-core-6.4.5.jar" + } + }, + "joda_time_joda_time_jar_sources_2_8_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~joda_time_joda_time_jar_sources_2_8_1", + "sha256": "59086b3e0608df2eac1b21063d6bae37851173e24efc4cacd6705326408723d9", + "urls": [ + "https://repo1.maven.org/maven2/joda-time/joda-time/2.8.1/joda-time-2.8.1-sources.jar" + ], + "downloaded_file_path": "joda-time/joda-time/2.8.1/joda-time-2.8.1-sources.jar" + } + }, + "com_google_protobuf_protobuf_java_3_22_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_protobuf_protobuf_java_3_22_3", + "sha256": "59d388ea6a2d2d76ae8efff7fd4d0c60c6f0f464c3d3ab9be8e5add092975708", + "urls": [ + "https://repo1.maven.org/maven2/com/google/protobuf/protobuf-java/3.22.3/protobuf-java-3.22.3.jar" + ], + "downloaded_file_path": "com/google/protobuf/protobuf-java/3.22.3/protobuf-java-3.22.3.jar" + } + }, + "org_apache_commons_commons_lang3_3_13_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_apache_commons_commons_lang3_3_13_0", + "sha256": "82f528cf718c7a3c2f30fc5bc784e3c6a0a10b17605dadb9e16c82ede11e6064", + "urls": [ + "https://repo1.maven.org/maven2/org/apache/commons/commons-lang3/3.13.0/commons-lang3-3.13.0.jar" + ], + "downloaded_file_path": "org/apache/commons/commons-lang3/3.13.0/commons-lang3-3.13.0.jar" + } + }, + "software_amazon_awssdk_profiles_2_20_78": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_profiles_2_20_78", + "sha256": "c54925f8710a63b545f272ad651b40fc4310c4d3f49df50257645604d6021f32", + "urls": [ + "https://repo1.maven.org/maven2/software/amazon/awssdk/profiles/2.20.78/profiles-2.20.78.jar", + "https://maven.google.com/software/amazon/awssdk/profiles/2.20.78/profiles-2.20.78.jar" + ], + "downloaded_file_path": "software/amazon/awssdk/profiles/2.20.78/profiles-2.20.78.jar" + } + }, + "io_grpc_grpc_stub_1_56_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_stub_1_56_1", + "sha256": "64ffca5dde4565c4c0f876deea3d105341d45ce605b29053e79dc86a22f7953b", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-stub/1.56.1/grpc-stub-1.56.1.jar" + ], + "downloaded_file_path": "io/grpc/grpc-stub/1.56.1/grpc-stub-1.56.1.jar" + } + }, + "io_grpc_grpc_protobuf_lite_jar_sources_1_56_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_protobuf_lite_jar_sources_1_56_1", + "sha256": "515018e2d65b852e0fa99c6dcb6c1e711070e02bdb926ca5b3e04ed35ae0a874", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-protobuf-lite/1.56.1/grpc-protobuf-lite-1.56.1-sources.jar" + ], + "downloaded_file_path": "io/grpc/grpc-protobuf-lite/1.56.1/grpc-protobuf-lite-1.56.1-sources.jar" + } + }, + "com_googlecode_json_simple_json_simple_1_1_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_googlecode_json_simple_json_simple_1_1_1", + "sha256": "4e69696892b88b41c55d49ab2fdcc21eead92bf54acc588c0050596c3b75199c", + "urls": [ + "https://repo1.maven.org/maven2/com/googlecode/json-simple/json-simple/1.1.1/json-simple-1.1.1.jar" + ], + "downloaded_file_path": "com/googlecode/json-simple/json-simple/1.1.1/json-simple-1.1.1.jar" + } + }, + "io_netty_netty_transport_native_kqueue_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_native_kqueue_4_1_97_Final", + "sha256": "85916dd7569148bb3d4bc831d45846807b39d2b6f593dc8794a42ca71a4086c9", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-transport-native-kqueue/4.1.97.Final/netty-transport-native-kqueue-4.1.97.Final.jar" + ], + "downloaded_file_path": "io/netty/netty-transport-native-kqueue/4.1.97.Final/netty-transport-native-kqueue-4.1.97.Final.jar" + } + }, + "io_grpc_grpc_auth_jar_sources_1_56_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_auth_jar_sources_1_56_1", + "sha256": "301967032288267e509448bdcd8ba42c726b5e58732b2d7d357f864e036f0e23", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-auth/1.56.1/grpc-auth-1.56.1-sources.jar" + ], + "downloaded_file_path": "io/grpc/grpc-auth/1.56.1/grpc-auth-1.56.1-sources.jar" + } + }, + "com_google_api_api_common_2_11_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_api_api_common_2_11_1", + "sha256": "21f67354fa308826395d2ed171d25416a8001d50ea70f82b68f2bdd17bb8947f", + "urls": [ + "https://repo1.maven.org/maven2/com/google/api/api-common/2.11.1/api-common-2.11.1.jar", + "https://maven.google.com/com/google/api/api-common/2.11.1/api-common-2.11.1.jar" + ], + "downloaded_file_path": "com/google/api/api-common/2.11.1/api-common-2.11.1.jar" + } + }, + "io_netty_netty_transport_native_unix_common_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_native_unix_common_4_1_97_Final", + "sha256": "412fe140257c2dda5a5e15bee911298bd61928d03ee6be4db588e82c196c5dc6", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-transport-native-unix-common/4.1.97.Final/netty-transport-native-unix-common-4.1.97.Final.jar" + ], + "downloaded_file_path": "io/netty/netty-transport-native-unix-common/4.1.97.Final/netty-transport-native-unix-common-4.1.97.Final.jar" + } + }, + "com_google_oauth_client_google_oauth_client_1_34_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_oauth_client_google_oauth_client_1_34_1", + "sha256": "193edf97aefa28b93c5892bdc598bac34fa4c396588030084f290b1440e8b98a", + "urls": [ + "https://repo1.maven.org/maven2/com/google/oauth-client/google-oauth-client/1.34.1/google-oauth-client-1.34.1.jar", + "https://maven.google.com/com/google/oauth-client/google-oauth-client/1.34.1/google-oauth-client-1.34.1.jar" + ], + "downloaded_file_path": "com/google/oauth-client/google-oauth-client/1.34.1/google-oauth-client-1.34.1.jar" + } + }, + "com_amazonaws_aws_java_sdk_secretsmanager": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_amazonaws_aws_java_sdk_secretsmanager", + "generating_repository": "maven", + "target_name": "com_amazonaws_aws_java_sdk_secretsmanager" + } + }, + "javax_cache_cache_api_jar_sources_1_1_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~javax_cache_cache_api_jar_sources_1_1_1", + "sha256": "2387f48682d3475fd214a6b9c2d1ef732ae8ce9313a3b8f69e72449ce33c6068", + "urls": [ + "https://repo1.maven.org/maven2/javax/cache/cache-api/1.1.1/cache-api-1.1.1-sources.jar" + ], + "downloaded_file_path": "javax/cache/cache-api/1.1.1/cache-api-1.1.1-sources.jar" + } + }, + "org_bouncycastle_bcutil_jdk18on_jar_sources_1_75": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_bouncycastle_bcutil_jdk18on_jar_sources_1_75", + "sha256": "bf827dd7283566804ba0583d02c80f43f0713896814e9dc56b1242ff5cc656a7", + "urls": [ + "https://repo1.maven.org/maven2/org/bouncycastle/bcutil-jdk18on/1.75/bcutil-jdk18on-1.75-sources.jar" + ], + "downloaded_file_path": "org/bouncycastle/bcutil-jdk18on/1.75/bcutil-jdk18on-1.75-sources.jar" + } + }, + "io_grpc_grpc_stub_jar_sources_1_56_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_stub_jar_sources_1_56_1", + "sha256": "da927063466a063aaee49ca7c43b8cd487d3f24d3b8bb694216304060f386b8c", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-stub/1.56.1/grpc-stub-1.56.1-sources.jar" + ], + "downloaded_file_path": "io/grpc/grpc-stub/1.56.1/grpc-stub-1.56.1-sources.jar" + } + }, + "net_sf_jopt_simple_jopt_simple_5_0_4": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~net_sf_jopt_simple_jopt_simple_5_0_4", + "sha256": "df26cc58f235f477db07f753ba5a3ab243ebe5789d9f89ecf68dd62ea9a66c28", + "urls": [ + "https://repo1.maven.org/maven2/net/sf/jopt-simple/jopt-simple/5.0.4/jopt-simple-5.0.4.jar" + ], + "downloaded_file_path": "net/sf/jopt-simple/jopt-simple/5.0.4/jopt-simple-5.0.4.jar" + } + }, + "jakarta_activation_jakarta_activation_api_1_2_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~jakarta_activation_jakarta_activation_api_1_2_1", + "sha256": "8b0a0f52fa8b05c5431921a063ed866efaa41dadf2e3a7ee3e1961f2b0d9645b", + "urls": [ + "https://repo1.maven.org/maven2/jakarta/activation/jakarta.activation-api/1.2.1/jakarta.activation-api-1.2.1.jar" + ], + "downloaded_file_path": "jakarta/activation/jakarta.activation-api/1.2.1/jakarta.activation-api-1.2.1.jar" + } + }, + "io_netty_netty_handler_proxy_jar_sources_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_handler_proxy_jar_sources_4_1_97_Final", + "sha256": "19e0dac14e5028af4c7068a0a2872f50ad06588a5140a065648f1ab3c31cf5bc", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-handler-proxy/4.1.97.Final/netty-handler-proxy-4.1.97.Final-sources.jar" + ], + "downloaded_file_path": "io/netty/netty-handler-proxy/4.1.97.Final/netty-handler-proxy-4.1.97.Final-sources.jar" + } + }, + "io_netty_netty_transport_classes_kqueue_jar_sources_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_classes_kqueue_jar_sources_4_1_97_Final", + "sha256": "1db14659fab815b08ed06a60553bebabd402687d35b204f1af5add7396a549f4", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-transport-classes-kqueue/4.1.97.Final/netty-transport-classes-kqueue-4.1.97.Final-sources.jar" + ], + "downloaded_file_path": "io/netty/netty-transport-classes-kqueue/4.1.97.Final/netty-transport-classes-kqueue-4.1.97.Final-sources.jar" + } + }, + "software_amazon_awssdk_regions_2_20_78": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_regions_2_20_78", + "sha256": "af2dd9874404ef3bda177000134b7d9e04279a24a726388175b4dff2590740d7", + "urls": [ + "https://repo1.maven.org/maven2/software/amazon/awssdk/regions/2.20.78/regions-2.20.78.jar", + "https://maven.google.com/software/amazon/awssdk/regions/2.20.78/regions-2.20.78.jar" + ], + "downloaded_file_path": "software/amazon/awssdk/regions/2.20.78/regions-2.20.78.jar" + } + }, + "com_github_docker_java_docker_java_transport_netty_jar_sources_3_3_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_docker_java_docker_java_transport_netty_jar_sources_3_3_3", + "sha256": "9c8e9b8e0bf0495470d19c22e27b832dc5f0025786106212b0de6a478b5abde3", + "urls": [ + "https://repo1.maven.org/maven2/com/github/docker-java/docker-java-transport-netty/3.3.3/docker-java-transport-netty-3.3.3-sources.jar" + ], + "downloaded_file_path": "com/github/docker-java/docker-java-transport-netty/3.3.3/docker-java-transport-netty-3.3.3-sources.jar" + } + }, + "io_grpc_grpc_protobuf_lite_1_55_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_protobuf_lite_1_55_1", + "sha256": "d0253390609c72ec09c31ae46e79b01cd72a2ce2ccae11176de550ffd475c853", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-protobuf-lite/1.55.1/grpc-protobuf-lite-1.55.1.jar", + "https://maven.google.com/io/grpc/grpc-protobuf-lite/1.55.1/grpc-protobuf-lite-1.55.1.jar" + ], + "downloaded_file_path": "io/grpc/grpc-protobuf-lite/1.55.1/grpc-protobuf-lite-1.55.1.jar" + } + }, + "io_grpc_grpc_services_jar_sources_1_56_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_services_jar_sources_1_56_1", + "sha256": "e9676fe1c41585babbe70c26a28b418b87a80e81ed49481a5dfaaace1a71162e", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-services/1.56.1/grpc-services-1.56.1-sources.jar" + ], + "downloaded_file_path": "io/grpc/grpc-services/1.56.1/grpc-services-1.56.1-sources.jar" + } + }, + "net_minidev_accessors_smart_2_4_9": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~net_minidev_accessors_smart_2_4_9", + "sha256": "accdd5c7ac4c49b155890aaea1ffca2a9ccd5826b562dd95a99fc1887003e031", + "urls": [ + "https://repo1.maven.org/maven2/net/minidev/accessors-smart/2.4.9/accessors-smart-2.4.9.jar" + ], + "downloaded_file_path": "net/minidev/accessors-smart/2.4.9/accessors-smart-2.4.9.jar" + } + }, + "com_fasterxml_jackson_core_jackson_annotations_2_15_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_core_jackson_annotations_2_15_2", + "sha256": "04e21f94dcfee4b078fa5a5f53047b785aaba69d19de392f616e7a7fe5d3882f", + "urls": [ + "https://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-annotations/2.15.2/jackson-annotations-2.15.2.jar" + ], + "downloaded_file_path": "com/fasterxml/jackson/core/jackson-annotations/2.15.2/jackson-annotations-2.15.2.jar" + } + }, + "aopalliance_aopalliance_jar_sources_1_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~aopalliance_aopalliance_jar_sources_1_0", + "sha256": "e6ef91d439ada9045f419c77543ebe0416c3cdfc5b063448343417a3e4a72123", + "urls": [ + "https://repo1.maven.org/maven2/aopalliance/aopalliance/1.0/aopalliance-1.0-sources.jar" + ], + "downloaded_file_path": "aopalliance/aopalliance/1.0/aopalliance-1.0-sources.jar" + } + }, + "org_threeten_threetenbp_1_6_8": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_threeten_threetenbp_1_6_8", + "sha256": "e4b1eb3d90c38a54c7f3384fda957e0b5bf0b41b40672a44ae8b03cb6c87ce06", + "urls": [ + "https://repo1.maven.org/maven2/org/threeten/threetenbp/1.6.8/threetenbp-1.6.8.jar" + ], + "downloaded_file_path": "org/threeten/threetenbp/1.6.8/threetenbp-1.6.8.jar" + } + }, + "io_netty_netty_handler_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_handler_4_1_97_Final", + "sha256": "bd4771d19149cbc9c7464ed2d58035d79cdfed7adb59d38718b0d8e7a3dcc2de", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-handler/4.1.97.Final/netty-handler-4.1.97.Final.jar" + ], + "downloaded_file_path": "io/netty/netty-handler/4.1.97.Final/netty-handler-4.1.97.Final.jar" + } + }, + "com_google_http_client_google_http_client_jar_sources_1_42_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_http_client_google_http_client_jar_sources_1_42_3", + "sha256": "60d3d16ff67d6a395a81560227f51d282d3c65235154a696cafafe9032f43d5f", + "urls": [ + "https://repo1.maven.org/maven2/com/google/http-client/google-http-client/1.42.3/google-http-client-1.42.3-sources.jar" + ], + "downloaded_file_path": "com/google/http-client/google-http-client/1.42.3/google-http-client-1.42.3-sources.jar" + } + }, + "javax_inject_javax_inject_jar_sources_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~javax_inject_javax_inject_jar_sources_1", + "sha256": "c4b87ee2911c139c3daf498a781967f1eb2e75bc1a8529a2e7b328a15d0e433e", + "urls": [ + "https://repo1.maven.org/maven2/javax/inject/javax.inject/1/javax.inject-1-sources.jar" + ], + "downloaded_file_path": "javax/inject/javax.inject/1/javax.inject-1-sources.jar" + } + }, + "io_netty_netty_handler_proxy": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_handler_proxy", + "generating_repository": "maven", + "target_name": "io_netty_netty_handler_proxy" + } + }, + "com_esotericsoftware_reflectasm_1_11_9": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_esotericsoftware_reflectasm_1_11_9", + "sha256": "712b44da79a5b7f47a28cbfcb3d8ecfc872fae349c48aa4d3e38a5d69956afce", + "urls": [ + "https://repo1.maven.org/maven2/com/esotericsoftware/reflectasm/1.11.9/reflectasm-1.11.9.jar" + ], + "downloaded_file_path": "com/esotericsoftware/reflectasm/1.11.9/reflectasm-1.11.9.jar" + } + }, + "com_google_re2j_re2j_1_6": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_re2j_re2j_1_6", + "sha256": "c8b5c3472d4db594a865b2e47f835d07fb8b1415eeba559dccfb0a6945f033cd", + "urls": [ + "https://repo1.maven.org/maven2/com/google/re2j/re2j/1.6/re2j-1.6.jar", + "https://maven.google.com/com/google/re2j/re2j/1.6/re2j-1.6.jar" + ], + "downloaded_file_path": "com/google/re2j/re2j/1.6/re2j-1.6.jar" + } + }, + "software_amazon_awssdk_apache_client_2_20_78": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_apache_client_2_20_78", + "sha256": "771923580e38678b7f66c3a63f4b5f79eef9ffb81027e2a422aed2713ce4138b", + "urls": [ + "https://repo1.maven.org/maven2/software/amazon/awssdk/apache-client/2.20.78/apache-client-2.20.78.jar", + "https://maven.google.com/software/amazon/awssdk/apache-client/2.20.78/apache-client-2.20.78.jar" + ], + "downloaded_file_path": "software/amazon/awssdk/apache-client/2.20.78/apache-client-2.20.78.jar" + } + }, + "com_jayway_jsonpath_json_path": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_jayway_jsonpath_json_path", + "generating_repository": "maven", + "target_name": "com_jayway_jsonpath_json_path" + } + }, + "com_fasterxml_jackson_dataformat_jackson_dataformat_cbor_jar_sources_2_12_6": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_dataformat_jackson_dataformat_cbor_jar_sources_2_12_6", + "sha256": "1e70fe124ab0a0c3e9a909e75735799e987fb71b4f7649eb10199f4f3b873287", + "urls": [ + "https://repo1.maven.org/maven2/com/fasterxml/jackson/dataformat/jackson-dataformat-cbor/2.12.6/jackson-dataformat-cbor-2.12.6-sources.jar" + ], + "downloaded_file_path": "com/fasterxml/jackson/dataformat/jackson-dataformat-cbor/2.12.6/jackson-dataformat-cbor-2.12.6-sources.jar" + } + }, + "org_bouncycastle_bcpkix_jdk18on_jar_sources_1_75": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_bouncycastle_bcpkix_jdk18on_jar_sources_1_75", + "sha256": "bd621657020f859beff0c8279aef31380c18438596964da2c77a0542126bf780", + "urls": [ + "https://repo1.maven.org/maven2/org/bouncycastle/bcpkix-jdk18on/1.75/bcpkix-jdk18on-1.75-sources.jar" + ], + "downloaded_file_path": "org/bouncycastle/bcpkix-jdk18on/1.75/bcpkix-jdk18on-1.75-sources.jar" + } + }, + "org_redisson_redisson_jar_sources_3_23_4": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_redisson_redisson_jar_sources_3_23_4", + "sha256": "7701f55b848adeb366af2461e1323f50f2d8701e983b133b34f5085803cbbab6", + "urls": [ + "https://repo1.maven.org/maven2/org/redisson/redisson/3.23.4/redisson-3.23.4-sources.jar" + ], + "downloaded_file_path": "org/redisson/redisson/3.23.4/redisson-3.23.4-sources.jar" + } + }, + "org_threeten_threetenbp_jar_sources_1_6_8": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_threeten_threetenbp_jar_sources_1_6_8", + "sha256": "6b68e90399fd0d97ee7abbe3918c87a236d52a3fb3c434359a11942f9a1abc59", + "urls": [ + "https://repo1.maven.org/maven2/org/threeten/threetenbp/1.6.8/threetenbp-1.6.8-sources.jar" + ], + "downloaded_file_path": "org/threeten/threetenbp/1.6.8/threetenbp-1.6.8-sources.jar" + } + }, + "io_netty_netty_common_jar_sources_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_common_jar_sources_4_1_97_Final", + "sha256": "54e96a125cb58b3ac067fa59b4a97fb6f1aadbac3f3092e6cc7fa88684de9964", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-common/4.1.97.Final/netty-common-4.1.97.Final-sources.jar" + ], + "downloaded_file_path": "io/netty/netty-common/4.1.97.Final/netty-common-4.1.97.Final-sources.jar" + } + }, + "org_glassfish_hk2_external_jakarta_inject_jar_sources_2_6_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_glassfish_hk2_external_jakarta_inject_jar_sources_2_6_1", + "sha256": "fbbadf59b395bf326910de95682eaaa83dcc0f1d65cd4a077c6988deff6a527a", + "urls": [ + "https://repo1.maven.org/maven2/org/glassfish/hk2/external/jakarta.inject/2.6.1/jakarta.inject-2.6.1-sources.jar" + ], + "downloaded_file_path": "org/glassfish/hk2/external/jakarta.inject/2.6.1/jakarta.inject-2.6.1-sources.jar" + } + }, + "org_bouncycastle_bcprov_jdk18on_jar_sources_1_75": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_bouncycastle_bcprov_jdk18on_jar_sources_1_75", + "sha256": "72abfe335986c5f8d9f61489d5699dca7688303a7da60697cef77018187ac8bc", + "urls": [ + "https://repo1.maven.org/maven2/org/bouncycastle/bcprov-jdk18on/1.75/bcprov-jdk18on-1.75-sources.jar" + ], + "downloaded_file_path": "org/bouncycastle/bcprov-jdk18on/1.75/bcprov-jdk18on-1.75-sources.jar" + } + }, + "javax_annotation_javax_annotation_api_1_3_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~javax_annotation_javax_annotation_api_1_3_2", + "sha256": "e04ba5195bcd555dc95650f7cc614d151e4bcd52d29a10b8aa2197f3ab89ab9b", + "urls": [ + "https://repo1.maven.org/maven2/javax/annotation/javax.annotation-api/1.3.2/javax.annotation-api-1.3.2.jar" + ], + "downloaded_file_path": "javax/annotation/javax.annotation-api/1.3.2/javax.annotation-api-1.3.2.jar" + } + }, + "io_prometheus_simpleclient_httpserver_0_15_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_httpserver_0_15_0", + "sha256": "a1a16e1f804e3382ed8b400220ecb2913c96412d937e618f54a7088e6eb432b6", + "urls": [ + "https://repo1.maven.org/maven2/io/prometheus/simpleclient_httpserver/0.15.0/simpleclient_httpserver-0.15.0.jar" + ], + "downloaded_file_path": "io/prometheus/simpleclient_httpserver/0.15.0/simpleclient_httpserver-0.15.0.jar" + } + }, + "com_google_auth_google_auth_library_credentials": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_auth_google_auth_library_credentials", + "generating_repository": "maven", + "target_name": "com_google_auth_google_auth_library_credentials" + } + }, + "com_google_jimfs_jimfs": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_jimfs_jimfs", + "generating_repository": "maven", + "target_name": "com_google_jimfs_jimfs" + } + }, + "org_slf4j_slf4j_simple_2_0_9": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_slf4j_slf4j_simple_2_0_9", + "sha256": "71f9c6de6dbaec2d10caa303faf08c5e749be53b242896c64c96b7c6bb6d62dc", + "urls": [ + "https://repo1.maven.org/maven2/org/slf4j/slf4j-simple/2.0.9/slf4j-simple-2.0.9.jar" + ], + "downloaded_file_path": "org/slf4j/slf4j-simple/2.0.9/slf4j-simple-2.0.9.jar" + } + }, + "org_glassfish_jersey_core_jersey_client_jar_sources_2_30_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_glassfish_jersey_core_jersey_client_jar_sources_2_30_1", + "sha256": "44618799a585b0529c7b1fc63bdf4e0c5faa11c9cc8fb27621f3b24106be9ab7", + "urls": [ + "https://repo1.maven.org/maven2/org/glassfish/jersey/core/jersey-client/2.30.1/jersey-client-2.30.1-sources.jar" + ], + "downloaded_file_path": "org/glassfish/jersey/core/jersey-client/2.30.1/jersey-client-2.30.1-sources.jar" + } + }, + "com_github_docker_java_docker_java_core_jar_sources_3_3_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_docker_java_docker_java_core_jar_sources_3_3_3", + "sha256": "4858f9c8671cd792067fdaa4e99f04f6a660f546d08e03041664b754b79235f8", + "urls": [ + "https://repo1.maven.org/maven2/com/github/docker-java/docker-java-core/3.3.3/docker-java-core-3.3.3-sources.jar" + ], + "downloaded_file_path": "com/github/docker-java/docker-java-core/3.3.3/docker-java-core-3.3.3-sources.jar" + } + }, + "io_grpc_grpc_netty_shaded": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_netty_shaded", + "generating_repository": "maven", + "target_name": "io_grpc_grpc_netty_shaded" + } + }, + "io_netty_netty_common_4_1_86_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_common_4_1_86_Final", + "sha256": "a35a3f16e7cd45c5d8529aa3e7702d4ef3b36213ea332db59744ea348fc2ae99", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-common/4.1.86.Final/netty-common-4.1.86.Final.jar", + "https://maven.google.com/io/netty/netty-common/4.1.86.Final/netty-common-4.1.86.Final.jar" + ], + "downloaded_file_path": "io/netty/netty-common/4.1.86.Final/netty-common-4.1.86.Final.jar" + } + }, + "io_netty_netty_transport_native_kqueue_jar_sources_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_native_kqueue_jar_sources_4_1_97_Final", + "sha256": "2ea352ecbfc3cf601f98b0ffb06d30169ba40ed912fd68d66c0cd6f0bcf4d4b6", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-transport-native-kqueue/4.1.97.Final/netty-transport-native-kqueue-4.1.97.Final-sources.jar" + ], + "downloaded_file_path": "io/netty/netty-transport-native-kqueue/4.1.97.Final/netty-transport-native-kqueue-4.1.97.Final-sources.jar" + } + }, + "com_google_protobuf_protobuf_java_jar_sources_3_22_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_protobuf_protobuf_java_jar_sources_3_22_3", + "sha256": "49a699e1a696b4c6f681f4f0f9af5247fc97e0e665c5fbbbf797be7e7cd9c091", + "urls": [ + "https://repo1.maven.org/maven2/com/google/protobuf/protobuf-java/3.22.3/protobuf-java-3.22.3-sources.jar" + ], + "downloaded_file_path": "com/google/protobuf/protobuf-java/3.22.3/protobuf-java-3.22.3-sources.jar" + } + }, + "io_netty_netty_buffer_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_buffer_4_1_97_Final", + "sha256": "a4393f5b395486cc74d0325c9b41311abb9513ba0fd7ef8cf46e9345c3bffbea", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-buffer/4.1.97.Final/netty-buffer-4.1.97.Final.jar" + ], + "downloaded_file_path": "io/netty/netty-buffer/4.1.97.Final/netty-buffer-4.1.97.Final.jar" + } + }, + "software_amazon_awssdk_arns_2_20_78": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_arns_2_20_78", + "sha256": "83c9c5743f83375e1d4b5bedce3593107b4989beec96f809554f545feeae4f34", + "urls": [ + "https://repo1.maven.org/maven2/software/amazon/awssdk/arns/2.20.78/arns-2.20.78.jar", + "https://maven.google.com/software/amazon/awssdk/arns/2.20.78/arns-2.20.78.jar" + ], + "downloaded_file_path": "software/amazon/awssdk/arns/2.20.78/arns-2.20.78.jar" + } + }, + "io_netty_netty_buffer_jar_sources_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_buffer_jar_sources_4_1_97_Final", + "sha256": "0b691a25682115d65da9e565589e39ee272227a972ecf0de936b475d42a4be48", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-buffer/4.1.97.Final/netty-buffer-4.1.97.Final-sources.jar" + ], + "downloaded_file_path": "io/netty/netty-buffer/4.1.97.Final/netty-buffer-4.1.97.Final-sources.jar" + } + }, + "io_grpc_grpc_services_1_55_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_services_1_55_1", + "sha256": "324d773ca903ce13b67686c98f28f56a201ee75cbb859de071d05683d06d337b", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-services/1.55.1/grpc-services-1.55.1.jar", + "https://maven.google.com/io/grpc/grpc-services/1.55.1/grpc-services-1.55.1.jar" + ], + "downloaded_file_path": "io/grpc/grpc-services/1.55.1/grpc-services-1.55.1.jar" + } + }, + "com_kohlschutter_junixsocket_junixsocket_common_jar_sources_2_6_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_kohlschutter_junixsocket_junixsocket_common_jar_sources_2_6_1", + "sha256": "066422249c845d9a0439a91fd1035e2bdf13b7552f03e94d1caef795afe53612", + "urls": [ + "https://repo1.maven.org/maven2/com/kohlschutter/junixsocket/junixsocket-common/2.6.1/junixsocket-common-2.6.1-sources.jar" + ], + "downloaded_file_path": "com/kohlschutter/junixsocket/junixsocket-common/2.6.1/junixsocket-common-2.6.1-sources.jar" + } + }, + "com_github_jnr_jnr_posix": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_jnr_jnr_posix", + "generating_repository": "maven", + "target_name": "com_github_jnr_jnr_posix" + } + }, + "org_hamcrest_hamcrest_core_jar_sources_1_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_hamcrest_hamcrest_core_jar_sources_1_3", + "sha256": "e223d2d8fbafd66057a8848cc94222d63c3cedd652cc48eddc0ab5c39c0f84df", + "urls": [ + "https://repo1.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-sources.jar" + ], + "downloaded_file_path": "org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-sources.jar" + } + }, + "io_netty_netty_transport_native_epoll_jar_sources_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_native_epoll_jar_sources_4_1_97_Final", + "sha256": "a6e3591efc09729a68574bec1493bfc0d08019b6ed4a566b6cb4e8e45ab1e937", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-transport-native-epoll/4.1.97.Final/netty-transport-native-epoll-4.1.97.Final-sources.jar" + ], + "downloaded_file_path": "io/netty/netty-transport-native-epoll/4.1.97.Final/netty-transport-native-epoll-4.1.97.Final-sources.jar" + } + }, + "com_google_auto_auto_common_jar_sources_1_2_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_auto_auto_common_jar_sources_1_2_1", + "sha256": "6802fc6e48f84cacadab9418bc8eba732f4c6a4189fc8569b1f619cb88112b25", + "urls": [ + "https://repo1.maven.org/maven2/com/google/auto/auto-common/1.2.1/auto-common-1.2.1-sources.jar" + ], + "downloaded_file_path": "com/google/auto/auto-common/1.2.1/auto-common-1.2.1-sources.jar" + } + }, + "software_amazon_awssdk_aws_core_2_20_78": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_aws_core_2_20_78", + "sha256": "83d02aa3fc781288b73b5392ef870282788cdd552fdf6ad31b9038e20a452395", + "urls": [ + "https://repo1.maven.org/maven2/software/amazon/awssdk/aws-core/2.20.78/aws-core-2.20.78.jar", + "https://maven.google.com/software/amazon/awssdk/aws-core/2.20.78/aws-core-2.20.78.jar" + ], + "downloaded_file_path": "software/amazon/awssdk/aws-core/2.20.78/aws-core-2.20.78.jar" + } + }, + "net_jcip_jcip_annotations_1_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~net_jcip_jcip_annotations_1_0", + "sha256": "be5805392060c71474bf6c9a67a099471274d30b83eef84bfc4e0889a4f1dcc0", + "urls": [ + "https://repo1.maven.org/maven2/net/jcip/jcip-annotations/1.0/jcip-annotations-1.0.jar" + ], + "downloaded_file_path": "net/jcip/jcip-annotations/1.0/jcip-annotations-1.0.jar" + } + }, + "org_checkerframework_checker_qual_3_33_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_checkerframework_checker_qual_3_33_0", + "sha256": "e316255bbfcd9fe50d165314b85abb2b33cb2a66a93c491db648e498a82c2de1", + "urls": [ + "https://repo1.maven.org/maven2/org/checkerframework/checker-qual/3.33.0/checker-qual-3.33.0.jar", + "https://maven.google.com/org/checkerframework/checker-qual/3.33.0/checker-qual-3.33.0.jar" + ], + "downloaded_file_path": "org/checkerframework/checker-qual/3.33.0/checker-qual-3.33.0.jar" + } + }, + "software_amazon_awssdk_third_party_jackson_core_2_20_78": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_third_party_jackson_core_2_20_78", + "sha256": "3bc11fd8888ab3b8026dec0894e51dd76a7460f4baac4c1adead7a03a87f8a44", + "urls": [ + "https://repo1.maven.org/maven2/software/amazon/awssdk/third-party-jackson-core/2.20.78/third-party-jackson-core-2.20.78.jar", + "https://maven.google.com/software/amazon/awssdk/third-party-jackson-core/2.20.78/third-party-jackson-core-2.20.78.jar" + ], + "downloaded_file_path": "software/amazon/awssdk/third-party-jackson-core/2.20.78/third-party-jackson-core-2.20.78.jar" + } + }, + "com_github_docker_java_docker_java_core_3_3_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_docker_java_docker_java_core_3_3_3", + "sha256": "d1f60040b4666a6073d4a2e0b72fc86cfb1b77f36b093e46a4115ea255995267", + "urls": [ + "https://repo1.maven.org/maven2/com/github/docker-java/docker-java-core/3.3.3/docker-java-core-3.3.3.jar" + ], + "downloaded_file_path": "com/github/docker-java/docker-java-core/3.3.3/docker-java-core-3.3.3.jar" + } + }, + "net_minidev_json_smart_jar_sources_2_4_10": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~net_minidev_json_smart_jar_sources_2_4_10", + "sha256": "e2ece85df4e5489cf5644fd826d2875527a405233b02496b7520d871755f395d", + "urls": [ + "https://repo1.maven.org/maven2/net/minidev/json-smart/2.4.10/json-smart-2.4.10-sources.jar" + ], + "downloaded_file_path": "net/minidev/json-smart/2.4.10/json-smart-2.4.10-sources.jar" + } + }, + "com_google_j2objc_j2objc_annotations": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_j2objc_j2objc_annotations", + "generating_repository": "maven", + "target_name": "com_google_j2objc_j2objc_annotations" + } + }, + "org_projectlombok_lombok": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_projectlombok_lombok", + "generating_repository": "maven", + "target_name": "org_projectlombok_lombok" + } + }, + "software_amazon_awssdk_http_client_spi_2_20_78": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_http_client_spi_2_20_78", + "sha256": "a52f5fa04a3c7e5c15ae632e64c64c44d2d019a3ee609ddca38312039c7a5b24", + "urls": [ + "https://repo1.maven.org/maven2/software/amazon/awssdk/http-client-spi/2.20.78/http-client-spi-2.20.78.jar", + "https://maven.google.com/software/amazon/awssdk/http-client-spi/2.20.78/http-client-spi-2.20.78.jar" + ], + "downloaded_file_path": "software/amazon/awssdk/http-client-spi/2.20.78/http-client-spi-2.20.78.jar" + } + }, + "unpinned_rules_jvm_external_deps": { + "bzlFile": "@@rules_jvm_external~5.3//:coursier.bzl", + "ruleClassName": "coursier_fetch", + "attributes": { + "name": "rules_jvm_external~5.3~maven~unpinned_rules_jvm_external_deps", + "repositories": [ + "{ \"repo_url\": \"https://repo1.maven.org/maven2\" }" + ], + "artifacts": [ + "{ \"group\": \"com.google.auth\", \"artifact\": \"google-auth-library-credentials\", \"version\": \"1.17.0\" }", + "{ \"group\": \"com.google.auth\", \"artifact\": \"google-auth-library-oauth2-http\", \"version\": \"1.17.0\" }", + "{ \"group\": \"com.google.cloud\", \"artifact\": \"google-cloud-core\", \"version\": \"2.18.1\" }", + "{ \"group\": \"com.google.cloud\", \"artifact\": \"google-cloud-storage\", \"version\": \"2.22.3\" }", + "{ \"group\": \"com.google.code.gson\", \"artifact\": \"gson\", \"version\": \"2.10.1\" }", + "{ \"group\": \"com.google.googlejavaformat\", \"artifact\": \"google-java-format\", \"version\": \"1.17.0\" }", + "{ \"group\": \"com.google.guava\", \"artifact\": \"guava\", \"version\": \"32.0.0-jre\" }", + "{ \"group\": \"org.apache.maven\", \"artifact\": \"maven-artifact\", \"version\": \"3.9.2\" }", + "{ \"group\": \"software.amazon.awssdk\", \"artifact\": \"s3\", \"version\": \"2.20.78\" }" + ], + "fail_on_missing_checksum": true, + "fetch_sources": true, + "fetch_javadoc": false, + "excluded_artifacts": [], + "generate_compat_repositories": false, + "version_conflict_policy": "default", + "override_targets": {}, + "strict_visibility": false, + "strict_visibility_value": [ + "@@//visibility:private" + ], + "maven_install_json": "@@rules_jvm_external~5.3//:rules_jvm_external_deps_install.json", + "resolve_timeout": 600, + "jetify": false, + "jetify_include_list": [ + "*" + ], + "use_starlark_android_rules": false, + "aar_import_bzl_label": "@build_bazel_rules_android//android:rules.bzl", + "duplicate_version_warning": "warn" + } + }, + "org_bouncycastle_bcutil_jdk18on_1_75": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_bouncycastle_bcutil_jdk18on_1_75", + "sha256": "027f36578c1ffdf08878c1cc2aa1e191f4b9da119c1e8f113299c53f298fa664", + "urls": [ + "https://repo1.maven.org/maven2/org/bouncycastle/bcutil-jdk18on/1.75/bcutil-jdk18on-1.75.jar" + ], + "downloaded_file_path": "org/bouncycastle/bcutil-jdk18on/1.75/bcutil-jdk18on-1.75.jar" + } + }, + "org_jetbrains_annotations_16_0_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_jetbrains_annotations_16_0_2", + "sha256": "245abad9a39eab1266ac9a8796980f462577e708ef3f6d43be2e008e4b72b9b4", + "urls": [ + "https://repo1.maven.org/maven2/org/jetbrains/annotations/16.0.2/annotations-16.0.2.jar" + ], + "downloaded_file_path": "org/jetbrains/annotations/16.0.2/annotations-16.0.2.jar" + } + }, + "com_google_http_client_google_http_client_gson_jar_sources_1_42_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_http_client_google_http_client_gson_jar_sources_1_42_3", + "sha256": "9e476cdfe8cd02f6691a3549ccc2016a3d2de4ad1d3ef5234145e73b2e61f732", + "urls": [ + "https://repo1.maven.org/maven2/com/google/http-client/google-http-client-gson/1.42.3/google-http-client-gson-1.42.3-sources.jar" + ], + "downloaded_file_path": "com/google/http-client/google-http-client-gson/1.42.3/google-http-client-gson-1.42.3-sources.jar" + } + }, + "software_amazon_awssdk_endpoints_spi_2_20_78": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_endpoints_spi_2_20_78", + "sha256": "9e20aaeb3dda2305bc04fea71d284a5ab53c562a896cc9206bcff52281585bb2", + "urls": [ + "https://repo1.maven.org/maven2/software/amazon/awssdk/endpoints-spi/2.20.78/endpoints-spi-2.20.78.jar", + "https://maven.google.com/software/amazon/awssdk/endpoints-spi/2.20.78/endpoints-spi-2.20.78.jar" + ], + "downloaded_file_path": "software/amazon/awssdk/endpoints-spi/2.20.78/endpoints-spi-2.20.78.jar" + } + }, + "software_amazon_awssdk_json_utils_2_20_78": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_json_utils_2_20_78", + "sha256": "a8f0752527d123de28ddea281ad5829bbe10bbb657fe96da32b454f976042f50", + "urls": [ + "https://repo1.maven.org/maven2/software/amazon/awssdk/json-utils/2.20.78/json-utils-2.20.78.jar", + "https://maven.google.com/software/amazon/awssdk/json-utils/2.20.78/json-utils-2.20.78.jar" + ], + "downloaded_file_path": "software/amazon/awssdk/json-utils/2.20.78/json-utils-2.20.78.jar" + } + }, + "io_grpc_grpc_netty_1_56_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_netty_1_56_1", + "sha256": "0f457ae74e16c8928c004c1f2086dfdd2905f05c75a8a02ca6750e7d7dc6c8cc", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-netty/1.56.1/grpc-netty-1.56.1.jar" + ], + "downloaded_file_path": "io/grpc/grpc-netty/1.56.1/grpc-netty-1.56.1.jar" + } + }, + "io_prometheus_simpleclient_common_jar_sources_0_15_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_common_jar_sources_0_15_0", + "sha256": "4b43be524ff3b9e00dc3859170700d0a74194625586a49eef03ea616365d1bf8", + "urls": [ + "https://repo1.maven.org/maven2/io/prometheus/simpleclient_common/0.15.0/simpleclient_common-0.15.0-sources.jar" + ], + "downloaded_file_path": "io/prometheus/simpleclient_common/0.15.0/simpleclient_common-0.15.0-sources.jar" + } + }, + "org_bouncycastle_bcprov_jdk15on_jar_sources_1_70": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_bouncycastle_bcprov_jdk15on_jar_sources_1_70", + "sha256": "0252e39814e4403b5d91a7386c3a5ac3e1fe65d43c2d25fed8d45e8eebab2696", + "urls": [ + "https://repo1.maven.org/maven2/org/bouncycastle/bcprov-jdk15on/1.70/bcprov-jdk15on-1.70-sources.jar" + ], + "downloaded_file_path": "org/bouncycastle/bcprov-jdk15on/1.70/bcprov-jdk15on-1.70-sources.jar" + } + }, + "io_opencensus_opencensus_contrib_http_util_0_31_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_opencensus_opencensus_contrib_http_util_0_31_1", + "sha256": "3ea995b55a4068be22989b70cc29a4d788c2d328d1d50613a7a9afd13fdd2d0a", + "urls": [ + "https://repo1.maven.org/maven2/io/opencensus/opencensus-contrib-http-util/0.31.1/opencensus-contrib-http-util-0.31.1.jar" + ], + "downloaded_file_path": "io/opencensus/opencensus-contrib-http-util/0.31.1/opencensus-contrib-http-util-0.31.1.jar" + } + }, + "com_fasterxml_jackson_dataformat_jackson_dataformat_yaml_jar_sources_2_15_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_dataformat_jackson_dataformat_yaml_jar_sources_2_15_2", + "sha256": "fcc3d81d341c72284a59639185558fb1035414b6f42724ae0dac013673cf62e9", + "urls": [ + "https://repo1.maven.org/maven2/com/fasterxml/jackson/dataformat/jackson-dataformat-yaml/2.15.2/jackson-dataformat-yaml-2.15.2-sources.jar" + ], + "downloaded_file_path": "com/fasterxml/jackson/dataformat/jackson-dataformat-yaml/2.15.2/jackson-dataformat-yaml-2.15.2-sources.jar" + } + }, + "org_glassfish_jersey_inject_jersey_hk2_jar_sources_2_30_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_glassfish_jersey_inject_jersey_hk2_jar_sources_2_30_1", + "sha256": "e4a24b58b0a7fa5089ee3008356a2ee252766bb12516fc2eda27cc54e935bcd9", + "urls": [ + "https://repo1.maven.org/maven2/org/glassfish/jersey/inject/jersey-hk2/2.30.1/jersey-hk2-2.30.1-sources.jar" + ], + "downloaded_file_path": "org/glassfish/jersey/inject/jersey-hk2/2.30.1/jersey-hk2-2.30.1-sources.jar" + } + }, + "com_google_auth_google_auth_library_oauth2_http_1_19_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_auth_google_auth_library_oauth2_http_1_19_0", + "sha256": "01bdf5c5cd85e10b794e401775d9909b56a38ffce313fbd39510a5d87ed56f58", + "urls": [ + "https://repo1.maven.org/maven2/com/google/auth/google-auth-library-oauth2-http/1.19.0/google-auth-library-oauth2-http-1.19.0.jar" + ], + "downloaded_file_path": "com/google/auth/google-auth-library-oauth2-http/1.19.0/google-auth-library-oauth2-http-1.19.0.jar" + } + }, + "com_github_jnr_jnr_ffi": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_jnr_jnr_ffi", + "generating_repository": "maven", + "target_name": "com_github_jnr_jnr_ffi" + } + }, + "software_amazon_awssdk_sdk_core_2_20_78": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_sdk_core_2_20_78", + "sha256": "1d060bab19739fa3a2071b4693b6fc31608a8c968e9554a0a2d2481343132498", + "urls": [ + "https://repo1.maven.org/maven2/software/amazon/awssdk/sdk-core/2.20.78/sdk-core-2.20.78.jar", + "https://maven.google.com/software/amazon/awssdk/sdk-core/2.20.78/sdk-core-2.20.78.jar" + ], + "downloaded_file_path": "software/amazon/awssdk/sdk-core/2.20.78/sdk-core-2.20.78.jar" + } + }, + "software_amazon_awssdk_utils_2_20_78": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_utils_2_20_78", + "sha256": "bf346be5ab0af9267a1c8101378f37e76fc977e9d8f5b8e5cfc98221e4179374", + "urls": [ + "https://repo1.maven.org/maven2/software/amazon/awssdk/utils/2.20.78/utils-2.20.78.jar", + "https://maven.google.com/software/amazon/awssdk/utils/2.20.78/utils-2.20.78.jar" + ], + "downloaded_file_path": "software/amazon/awssdk/utils/2.20.78/utils-2.20.78.jar" + } + }, + "com_google_auth_google_auth_library_credentials_1_19_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_auth_google_auth_library_credentials_1_19_0", + "sha256": "095984b0594888a47f311b3c9dcf6da9ed86feeea8f78140c55e14c27b0593e5", + "urls": [ + "https://repo1.maven.org/maven2/com/google/auth/google-auth-library-credentials/1.19.0/google-auth-library-credentials-1.19.0.jar" + ], + "downloaded_file_path": "com/google/auth/google-auth-library-credentials/1.19.0/google-auth-library-credentials-1.19.0.jar" + } + }, + "org_glassfish_hk2_hk2_locator_2_6_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_glassfish_hk2_hk2_locator_2_6_1", + "sha256": "febc668deb9f2000c76bd4918d8086c0a4c74d07bd0c60486b72c6bd38b62874", + "urls": [ + "https://repo1.maven.org/maven2/org/glassfish/hk2/hk2-locator/2.6.1/hk2-locator-2.6.1.jar" + ], + "downloaded_file_path": "org/glassfish/hk2/hk2-locator/2.6.1/hk2-locator-2.6.1.jar" + } + }, + "io_projectreactor_reactor_core_3_5_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_projectreactor_reactor_core_3_5_3", + "sha256": "86017581188627ae6de5d3822882f3594f87f9289ec4479391790ccfd5631508", + "urls": [ + "https://repo1.maven.org/maven2/io/projectreactor/reactor-core/3.5.3/reactor-core-3.5.3.jar" + ], + "downloaded_file_path": "io/projectreactor/reactor-core/3.5.3/reactor-core-3.5.3.jar" + } + }, + "com_github_jnr_jnr_constants_0_10_4": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_jnr_jnr_constants_0_10_4", + "sha256": "9a5b8cf9798d9d0331b8d8966c5235a22c4307676e35803a24659e6d76096f78", + "urls": [ + "https://repo1.maven.org/maven2/com/github/jnr/jnr-constants/0.10.4/jnr-constants-0.10.4.jar" + ], + "downloaded_file_path": "com/github/jnr/jnr-constants/0.10.4/jnr-constants-0.10.4.jar" + } + }, + "com_kohlschutter_junixsocket_junixsocket_common_2_6_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_kohlschutter_junixsocket_junixsocket_common_2_6_1", + "sha256": "93d120e2d49ddf5bfdee8258762fc874b26c657f027f8d6ccc1a055156bfcde1", + "urls": [ + "https://repo1.maven.org/maven2/com/kohlschutter/junixsocket/junixsocket-common/2.6.1/junixsocket-common-2.6.1.jar" + ], + "downloaded_file_path": "com/kohlschutter/junixsocket/junixsocket-common/2.6.1/junixsocket-common-2.6.1.jar" + } + }, + "com_fasterxml_jackson_jaxrs_jackson_jaxrs_json_provider_2_10_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_jaxrs_jackson_jaxrs_json_provider_2_10_3", + "sha256": "93026591dbb332030dbe865b9c811a016e470d8ff6daaa7031556d2185e62054", + "urls": [ + "https://repo1.maven.org/maven2/com/fasterxml/jackson/jaxrs/jackson-jaxrs-json-provider/2.10.3/jackson-jaxrs-json-provider-2.10.3.jar" + ], + "downloaded_file_path": "com/fasterxml/jackson/jaxrs/jackson-jaxrs-json-provider/2.10.3/jackson-jaxrs-json-provider-2.10.3.jar" + } + }, + "io_prometheus_simpleclient_tracer_common_0_15_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_tracer_common_0_15_0", + "sha256": "1baef082e619c06262e23de1b46ad35eb4df36ceb19be06ac7ef32a9833e12a4", + "urls": [ + "https://repo1.maven.org/maven2/io/prometheus/simpleclient_tracer_common/0.15.0/simpleclient_tracer_common-0.15.0.jar" + ], + "downloaded_file_path": "io/prometheus/simpleclient_tracer_common/0.15.0/simpleclient_tracer_common-0.15.0.jar" + } + }, + "com_google_code_findbugs_jsr305_3_0_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_code_findbugs_jsr305_3_0_2", + "sha256": "766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7", + "urls": [ + "https://repo1.maven.org/maven2/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar" + ], + "downloaded_file_path": "com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar" + } + }, + "com_fasterxml_jackson_core_jackson_core_2_14_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_core_jackson_core_2_14_2", + "sha256": "b5d37a77c88277b97e3593c8740925216c06df8e4172bbde058528df04ad3e7a", + "urls": [ + "https://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-core/2.14.2/jackson-core-2.14.2.jar", + "https://maven.google.com/com/fasterxml/jackson/core/jackson-core/2.14.2/jackson-core-2.14.2.jar" + ], + "downloaded_file_path": "com/fasterxml/jackson/core/jackson-core/2.14.2/jackson-core-2.14.2.jar" + } + }, + "com_github_jnr_jnr_ffi_jar_sources_2_2_14": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_jnr_jnr_ffi_jar_sources_2_2_14", + "sha256": "07f3eca123769c9aaeadd2f8d05a3ac3ed009a41b52f77efd12487112d7482f5", + "urls": [ + "https://repo1.maven.org/maven2/com/github/jnr/jnr-ffi/2.2.14/jnr-ffi-2.2.14-sources.jar" + ], + "downloaded_file_path": "com/github/jnr/jnr-ffi/2.2.14/jnr-ffi-2.2.14-sources.jar" + } + }, + "com_github_ben_manes_caffeine_caffeine": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_ben_manes_caffeine_caffeine", + "generating_repository": "maven", + "target_name": "com_github_ben_manes_caffeine_caffeine" + } + }, + "com_google_http_client_google_http_client_gson_1_42_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_http_client_google_http_client_gson_1_42_3", + "sha256": "8196efaa89c5f73b00b2b48edad02fcd78524259407c37ab1860737988545cee", + "urls": [ + "https://repo1.maven.org/maven2/com/google/http-client/google-http-client-gson/1.42.3/google-http-client-gson-1.42.3.jar" + ], + "downloaded_file_path": "com/google/http-client/google-http-client-gson/1.42.3/google-http-client-gson-1.42.3.jar" + } + }, + "io_grpc_grpc_api": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_api", + "generating_repository": "maven", + "target_name": "io_grpc_grpc_api" + } + }, + "com_google_errorprone_error_prone_annotation_2_22_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_errorprone_error_prone_annotation_2_22_0", + "sha256": "554c42449c9920ea1f6baec1d1b8aaac404a88be653f7cb441ee059316f8a1d1", + "urls": [ + "https://repo1.maven.org/maven2/com/google/errorprone/error_prone_annotation/2.22.0/error_prone_annotation-2.22.0.jar" + ], + "downloaded_file_path": "com/google/errorprone/error_prone_annotation/2.22.0/error_prone_annotation-2.22.0.jar" + } + }, + "org_glassfish_hk2_osgi_resource_locator_1_0_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_glassfish_hk2_osgi_resource_locator_1_0_3", + "sha256": "aab5d7849f7cfcda2cc7c541ba1bd365151d42276f151c825387245dfde3dd74", + "urls": [ + "https://repo1.maven.org/maven2/org/glassfish/hk2/osgi-resource-locator/1.0.3/osgi-resource-locator-1.0.3.jar" + ], + "downloaded_file_path": "org/glassfish/hk2/osgi-resource-locator/1.0.3/osgi-resource-locator-1.0.3.jar" + } + }, + "javax_annotation_javax_annotation_api_jar_sources_1_3_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~javax_annotation_javax_annotation_api_jar_sources_1_3_2", + "sha256": "128971e52e0d84a66e3b6e049dab8ad7b2c58b7e1ad37fa2debd3d40c2947b95", + "urls": [ + "https://repo1.maven.org/maven2/javax/annotation/javax.annotation-api/1.3.2/javax.annotation-api-1.3.2-sources.jar" + ], + "downloaded_file_path": "javax/annotation/javax.annotation-api/1.3.2/javax.annotation-api-1.3.2-sources.jar" + } + }, + "org_openjdk_jmh_jmh_core_jar_sources_1_37": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_openjdk_jmh_jmh_core_jar_sources_1_37", + "sha256": "fd4beda07b3b94cd0e32199401bbb2d9ed3371a770c8c320761b9442ff3e8e05", + "urls": [ + "https://repo1.maven.org/maven2/org/openjdk/jmh/jmh-core/1.37/jmh-core-1.37-sources.jar" + ], + "downloaded_file_path": "org/openjdk/jmh/jmh-core/1.37/jmh-core-1.37-sources.jar" + } + }, + "com_github_serceman_jnr_fuse_0_5_7": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_serceman_jnr_fuse_0_5_7", + "sha256": "ebe81ccbcbe1464996e5213ee24947cfba9eda7e9ffe154333f9bd8321217989", + "urls": [ + "https://repo1.maven.org/maven2/com/github/serceman/jnr-fuse/0.5.7/jnr-fuse-0.5.7.jar" + ], + "downloaded_file_path": "com/github/serceman/jnr-fuse/0.5.7/jnr-fuse-0.5.7.jar" + } + }, + "org_openjdk_jmh_jmh_generator_annprocess_jar_sources_1_37": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_openjdk_jmh_jmh_generator_annprocess_jar_sources_1_37", + "sha256": "cc1b661fb209ae1a433e331e8e78bab680674153b0a6ac69d47d11c60fb5e47e", + "urls": [ + "https://repo1.maven.org/maven2/org/openjdk/jmh/jmh-generator-annprocess/1.37/jmh-generator-annprocess-1.37-sources.jar" + ], + "downloaded_file_path": "org/openjdk/jmh/jmh-generator-annprocess/1.37/jmh-generator-annprocess-1.37-sources.jar" + } + }, + "org_yaml_snakeyaml": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_yaml_snakeyaml", + "generating_repository": "maven", + "target_name": "org_yaml_snakeyaml" + } + }, + "com_google_auto_value_auto_value_annotations_jar_sources_1_10_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_auto_value_auto_value_annotations_jar_sources_1_10_1", + "sha256": "44e6ce2884c18869422765b238f7f173faccd24643fabb5e95597382e80d50a8", + "urls": [ + "https://repo1.maven.org/maven2/com/google/auto/value/auto-value-annotations/1.10.1/auto-value-annotations-1.10.1-sources.jar" + ], + "downloaded_file_path": "com/google/auto/value/auto-value-annotations/1.10.1/auto-value-annotations-1.10.1-sources.jar" + } + }, + "io_grpc_grpc_rls_1_55_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_rls_1_55_1", + "sha256": "f828087440c2f6b274e196b21a6fb38db60648724c1be450f4d0ed991d819a6f", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-rls/1.55.1/grpc-rls-1.55.1.jar", + "https://maven.google.com/io/grpc/grpc-rls/1.55.1/grpc-rls-1.55.1.jar" + ], + "downloaded_file_path": "io/grpc/grpc-rls/1.55.1/grpc-rls-1.55.1.jar" + } + }, + "jakarta_xml_bind_jakarta_xml_bind_api_jar_sources_2_3_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~jakarta_xml_bind_jakarta_xml_bind_api_jar_sources_2_3_2", + "sha256": "61ceb3ed35ecf99f1803eac9c4b8f12103c7531952beae38ba53cc727f405532", + "urls": [ + "https://repo1.maven.org/maven2/jakarta/xml/bind/jakarta.xml.bind-api/2.3.2/jakarta.xml.bind-api-2.3.2-sources.jar" + ], + "downloaded_file_path": "jakarta/xml/bind/jakarta.xml.bind-api/2.3.2/jakarta.xml.bind-api-2.3.2-sources.jar" + } + }, + "com_google_googlejavaformat_google_java_format_1_17_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_googlejavaformat_google_java_format_1_17_0", + "sha256": "631ba54c39f6c20df027dc1420736df2e5e43c581880efdd1e46ddb4ce050e3e", + "urls": [ + "https://repo1.maven.org/maven2/com/google/googlejavaformat/google-java-format/1.17.0/google-java-format-1.17.0.jar", + "https://maven.google.com/com/google/googlejavaformat/google-java-format/1.17.0/google-java-format-1.17.0.jar" + ], + "downloaded_file_path": "com/google/googlejavaformat/google-java-format/1.17.0/google-java-format-1.17.0.jar" + } + }, + "org_jboss_marshalling_jboss_marshalling_jar_sources_2_0_11_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_jboss_marshalling_jboss_marshalling_jar_sources_2_0_11_Final", + "sha256": "4e9b508e3423fb82a33e72c77fd4fe63f108f167fa648d50a933b1b71d9084f2", + "urls": [ + "https://repo1.maven.org/maven2/org/jboss/marshalling/jboss-marshalling/2.0.11.Final/jboss-marshalling-2.0.11.Final-sources.jar" + ], + "downloaded_file_path": "org/jboss/marshalling/jboss-marshalling/2.0.11.Final/jboss-marshalling-2.0.11.Final-sources.jar" + } + }, + "com_google_guava_failureaccess_1_0_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_guava_failureaccess_1_0_1", + "sha256": "a171ee4c734dd2da837e4b16be9df4661afab72a41adaf31eb84dfdaf936ca26", + "urls": [ + "https://repo1.maven.org/maven2/com/google/guava/failureaccess/1.0.1/failureaccess-1.0.1.jar" + ], + "downloaded_file_path": "com/google/guava/failureaccess/1.0.1/failureaccess-1.0.1.jar" + } + }, + "io_perfmark_perfmark_api_0_26_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_perfmark_perfmark_api_0_26_0", + "sha256": "b7d23e93a34537ce332708269a0d1404788a5b5e1949e82f5535fce51b3ea95b", + "urls": [ + "https://repo1.maven.org/maven2/io/perfmark/perfmark-api/0.26.0/perfmark-api-0.26.0.jar" + ], + "downloaded_file_path": "io/perfmark/perfmark-api/0.26.0/perfmark-api-0.26.0.jar" + } + }, + "commons_codec_commons_codec_jar_sources_1_15": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~commons_codec_commons_codec_jar_sources_1_15", + "sha256": "7019940b2298d333edb946e2db3d10f1caacbbd52bb64e85832cfd0017e049cc", + "urls": [ + "https://repo1.maven.org/maven2/commons-codec/commons-codec/1.15/commons-codec-1.15-sources.jar" + ], + "downloaded_file_path": "commons-codec/commons-codec/1.15/commons-codec-1.15-sources.jar" + } + }, + "io_netty_netty_codec_http_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_http_4_1_97_Final", + "sha256": "7d6cad9cbd015e41f69787ce6a34beeba032b381e32e88207908431dc812778a", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-codec-http/4.1.97.Final/netty-codec-http-4.1.97.Final.jar" + ], + "downloaded_file_path": "io/netty/netty-codec-http/4.1.97.Final/netty-codec-http-4.1.97.Final.jar" + } + }, + "io_netty_netty_codec_http2_jar_sources_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_http2_jar_sources_4_1_97_Final", + "sha256": "7d8c2ec86545a19ccca24009809027f1745bc8339c8a97bcdc5833abd58e2ab3", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-codec-http2/4.1.97.Final/netty-codec-http2-4.1.97.Final-sources.jar" + ], + "downloaded_file_path": "io/netty/netty-codec-http2/4.1.97.Final/netty-codec-http2-4.1.97.Final-sources.jar" + } + }, + "software_amazon_awssdk_protocol_core_2_20_78": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_protocol_core_2_20_78", + "sha256": "9ae1459ad8bd5b6167997985ec7afebf9fc1105a3d727d8b485b276b5c2fbddb", + "urls": [ + "https://repo1.maven.org/maven2/software/amazon/awssdk/protocol-core/2.20.78/protocol-core-2.20.78.jar", + "https://maven.google.com/software/amazon/awssdk/protocol-core/2.20.78/protocol-core-2.20.78.jar" + ], + "downloaded_file_path": "software/amazon/awssdk/protocol-core/2.20.78/protocol-core-2.20.78.jar" + } + }, + "io_netty_netty_resolver_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_resolver_4_1_97_Final", + "sha256": "38a018c6d9fb2cb11b72881354782b45080bbd20b9a0ad6cde28b80d431ed0b1", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-resolver/4.1.97.Final/netty-resolver-4.1.97.Final.jar" + ], + "downloaded_file_path": "io/netty/netty-resolver/4.1.97.Final/netty-resolver-4.1.97.Final.jar" + } + }, + "io_grpc_grpc_context_1_56_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_context_1_56_1", + "sha256": "3d442ce08bfb1b487edf76d12e2dfd991c3877af32cf772a83c73d06f89743bc", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-context/1.56.1/grpc-context-1.56.1.jar" + ], + "downloaded_file_path": "io/grpc/grpc-context/1.56.1/grpc-context-1.56.1.jar" + } + }, + "io_prometheus_simpleclient_httpserver_jar_sources_0_15_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_httpserver_jar_sources_0_15_0", + "sha256": "b06cfea384c1a0e7d233c9325eb62d9ea4d144a744ce7991a5a96ef8bb5a361e", + "urls": [ + "https://repo1.maven.org/maven2/io/prometheus/simpleclient_httpserver/0.15.0/simpleclient_httpserver-0.15.0-sources.jar" + ], + "downloaded_file_path": "io/prometheus/simpleclient_httpserver/0.15.0/simpleclient_httpserver-0.15.0-sources.jar" + } + }, + "com_google_api_gax_httpjson_0_113_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_api_gax_httpjson_0_113_1", + "sha256": "f7e4e84caa6577466fc828858193667135b291da044f007eafde99c0f929b781", + "urls": [ + "https://repo1.maven.org/maven2/com/google/api/gax-httpjson/0.113.1/gax-httpjson-0.113.1.jar", + "https://maven.google.com/com/google/api/gax-httpjson/0.113.1/gax-httpjson-0.113.1.jar" + ], + "downloaded_file_path": "com/google/api/gax-httpjson/0.113.1/gax-httpjson-0.113.1.jar" + } + }, + "jakarta_ws_rs_jakarta_ws_rs_api_jar_sources_2_1_6": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~jakarta_ws_rs_jakarta_ws_rs_api_jar_sources_2_1_6", + "sha256": "5fb0591472e00439db7d1511caa40a39cda42e24b0bade6378f880384b7cc073", + "urls": [ + "https://repo1.maven.org/maven2/jakarta/ws/rs/jakarta.ws.rs-api/2.1.6/jakarta.ws.rs-api-2.1.6-sources.jar" + ], + "downloaded_file_path": "jakarta/ws/rs/jakarta.ws.rs-api/2.1.6/jakarta.ws.rs-api-2.1.6-sources.jar" + } + }, + "org_objenesis_objenesis_3_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_objenesis_objenesis_3_3", + "sha256": "02dfd0b0439a5591e35b708ed2f5474eb0948f53abf74637e959b8e4ef69bfeb", + "urls": [ + "https://repo1.maven.org/maven2/org/objenesis/objenesis/3.3/objenesis-3.3.jar" + ], + "downloaded_file_path": "org/objenesis/objenesis/3.3/objenesis-3.3.jar" + } + }, + "org_openjdk_jmh_jmh_generator_annprocess": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_openjdk_jmh_jmh_generator_annprocess", + "generating_repository": "maven", + "target_name": "org_openjdk_jmh_jmh_generator_annprocess" + } + }, + "com_amazonaws_aws_java_sdk_s3_jar_sources_1_12_544": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_amazonaws_aws_java_sdk_s3_jar_sources_1_12_544", + "sha256": "b91ef0fec99308cb3216fac69f9bb1a84149f05ab9b59e705107f492c02b4f64", + "urls": [ + "https://repo1.maven.org/maven2/com/amazonaws/aws-java-sdk-s3/1.12.544/aws-java-sdk-s3-1.12.544-sources.jar" + ], + "downloaded_file_path": "com/amazonaws/aws-java-sdk-s3/1.12.544/aws-java-sdk-s3-1.12.544-sources.jar" + } + }, + "com_github_docker_java_docker_java_transport_jersey_jar_sources_3_3_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_docker_java_docker_java_transport_jersey_jar_sources_3_3_3", + "sha256": "05a26581bdde6519c4d87aaae7569eebd713f5fda9f8fa28b51216d2d364a18b", + "urls": [ + "https://repo1.maven.org/maven2/com/github/docker-java/docker-java-transport-jersey/3.3.3/docker-java-transport-jersey-3.3.3-sources.jar" + ], + "downloaded_file_path": "com/github/docker-java/docker-java-transport-jersey/3.3.3/docker-java-transport-jersey-3.3.3-sources.jar" + } + }, + "io_netty_netty_transport_native_unix_common_jar_sources_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_native_unix_common_jar_sources_4_1_97_Final", + "sha256": "de1ea25a58fadbfa64061769281797cc9b133a48d0a039015d5b3d8f16cbfddc", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-transport-native-unix-common/4.1.97.Final/netty-transport-native-unix-common-4.1.97.Final-sources.jar" + ], + "downloaded_file_path": "io/netty/netty-transport-native-unix-common/4.1.97.Final/netty-transport-native-unix-common-4.1.97.Final-sources.jar" + } + }, + "org_codehaus_mojo_animal_sniffer_annotations_1_23": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_codehaus_mojo_animal_sniffer_annotations_1_23", + "sha256": "9ffe526bf43a6348e9d8b33b9cd6f580a7f5eed0cf055913007eda263de974d0", + "urls": [ + "https://repo1.maven.org/maven2/org/codehaus/mojo/animal-sniffer-annotations/1.23/animal-sniffer-annotations-1.23.jar" + ], + "downloaded_file_path": "org/codehaus/mojo/animal-sniffer-annotations/1.23/animal-sniffer-annotations-1.23.jar" + } + }, + "net_sf_jopt_simple_jopt_simple_jar_sources_5_0_4": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~net_sf_jopt_simple_jopt_simple_jar_sources_5_0_4", + "sha256": "06b283801a5a94ef697b7f2c79a048c4e2f848b3daddda61cab74d882bdd97a5", + "urls": [ + "https://repo1.maven.org/maven2/net/sf/jopt-simple/jopt-simple/5.0.4/jopt-simple-5.0.4-sources.jar" + ], + "downloaded_file_path": "net/sf/jopt-simple/jopt-simple/5.0.4/jopt-simple-5.0.4-sources.jar" + } + }, + "com_fasterxml_jackson_dataformat_jackson_dataformat_cbor_2_12_6": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_dataformat_jackson_dataformat_cbor_2_12_6", + "sha256": "cfa008d15f052e69221e8c3193056ff95c3c594271321ccac8d72dc1a770619c", + "urls": [ + "https://repo1.maven.org/maven2/com/fasterxml/jackson/dataformat/jackson-dataformat-cbor/2.12.6/jackson-dataformat-cbor-2.12.6.jar" + ], + "downloaded_file_path": "com/fasterxml/jackson/dataformat/jackson-dataformat-cbor/2.12.6/jackson-dataformat-cbor-2.12.6.jar" + } + }, + "io_grpc_grpc_core_1_55_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_core_1_55_1", + "sha256": "c4782555fefb61c72898759a7d11f5f221811935bcf983efb478d796228b65dc", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-core/1.55.1/grpc-core-1.55.1.jar", + "https://maven.google.com/io/grpc/grpc-core/1.55.1/grpc-core-1.55.1.jar" + ], + "downloaded_file_path": "io/grpc/grpc-core/1.55.1/grpc-core-1.55.1.jar" + } + }, + "com_kohlschutter_junixsocket_junixsocket_native_common_jar_sources_2_6_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_kohlschutter_junixsocket_junixsocket_native_common_jar_sources_2_6_1", + "sha256": "4cef32dce262263e247d783f4ed7d90c5376190321e829ba5e985a8a27fbda06", + "urls": [ + "https://repo1.maven.org/maven2/com/kohlschutter/junixsocket/junixsocket-native-common/2.6.1/junixsocket-native-common-2.6.1-sources.jar" + ], + "downloaded_file_path": "com/kohlschutter/junixsocket/junixsocket-native-common/2.6.1/junixsocket-native-common-2.6.1-sources.jar" + } + }, + "io_netty_netty_transport_native_kqueue_jar_osx_x86_64_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_native_kqueue_jar_osx_x86_64_4_1_97_Final", + "sha256": "6870051aca7fa4dc5d0f2938036215a269504c50d2e36c4af38fd00d22ad7d95", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-transport-native-kqueue/4.1.97.Final/netty-transport-native-kqueue-4.1.97.Final-osx-x86_64.jar" + ], + "downloaded_file_path": "io/netty/netty-transport-native-kqueue/4.1.97.Final/netty-transport-native-kqueue-4.1.97.Final-osx-x86_64.jar" + } + }, + "io_reactivex_rxjava3_rxjava_jar_sources_3_1_6": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_reactivex_rxjava3_rxjava_jar_sources_3_1_6", + "sha256": "4479ead52c21dbfeb23646e378f77b7b396eda170619027d4213975e368b14ca", + "urls": [ + "https://repo1.maven.org/maven2/io/reactivex/rxjava3/rxjava/3.1.6/rxjava-3.1.6-sources.jar" + ], + "downloaded_file_path": "io/reactivex/rxjava3/rxjava/3.1.6/rxjava-3.1.6-sources.jar" + } + }, + "com_google_api_grpc_grpc_google_cloud_storage_v2_2_22_3_alpha": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_api_grpc_grpc_google_cloud_storage_v2_2_22_3_alpha", + "sha256": "c62c1c54e44d9e4622bd6f7f1285f8456efd50880c1e6d107f5e6680033138d0", + "urls": [ + "https://repo1.maven.org/maven2/com/google/api/grpc/grpc-google-cloud-storage-v2/2.22.3-alpha/grpc-google-cloud-storage-v2-2.22.3-alpha.jar", + "https://maven.google.com/com/google/api/grpc/grpc-google-cloud-storage-v2/2.22.3-alpha/grpc-google-cloud-storage-v2-2.22.3-alpha.jar" + ], + "downloaded_file_path": "com/google/api/grpc/grpc-google-cloud-storage-v2/2.22.3-alpha/grpc-google-cloud-storage-v2-2.22.3-alpha.jar" + } + }, + "com_github_jnr_jnr_posix_jar_sources_3_1_17": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_jnr_jnr_posix_jar_sources_3_1_17", + "sha256": "91c102c59c1d775adbd65353f5a795c4f48f6a8546a1845c679100fd5336db23", + "urls": [ + "https://repo1.maven.org/maven2/com/github/jnr/jnr-posix/3.1.17/jnr-posix-3.1.17-sources.jar" + ], + "downloaded_file_path": "com/github/jnr/jnr-posix/3.1.17/jnr-posix-3.1.17-sources.jar" + } + }, + "com_google_protobuf_protobuf_java_util_jar_sources_3_22_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_protobuf_protobuf_java_util_jar_sources_3_22_3", + "sha256": "5bb8af97af2131a2594c836baf3aadc0fd9640bdcf386c99bab901f6065e518f", + "urls": [ + "https://repo1.maven.org/maven2/com/google/protobuf/protobuf-java-util/3.22.3/protobuf-java-util-3.22.3-sources.jar" + ], + "downloaded_file_path": "com/google/protobuf/protobuf-java-util/3.22.3/protobuf-java-util-3.22.3-sources.jar" + } + }, + "org_glassfish_hk2_hk2_api_2_6_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_glassfish_hk2_hk2_api_2_6_1", + "sha256": "c2cb80a01e58440ae57d5ee59af4d4d94e5180e04aff112b0cb611c07d61e773", + "urls": [ + "https://repo1.maven.org/maven2/org/glassfish/hk2/hk2-api/2.6.1/hk2-api-2.6.1.jar" + ], + "downloaded_file_path": "org/glassfish/hk2/hk2-api/2.6.1/hk2-api-2.6.1.jar" + } + }, + "com_fasterxml_jackson_module_jackson_module_jaxb_annotations_2_10_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_module_jackson_module_jaxb_annotations_2_10_3", + "sha256": "8099caad4ae189525ef94d337d72d3e888abefabbbacbc9f3d2f096d534f2fb5", + "urls": [ + "https://repo1.maven.org/maven2/com/fasterxml/jackson/module/jackson-module-jaxb-annotations/2.10.3/jackson-module-jaxb-annotations-2.10.3.jar" + ], + "downloaded_file_path": "com/fasterxml/jackson/module/jackson-module-jaxb-annotations/2.10.3/jackson-module-jaxb-annotations-2.10.3.jar" + } + }, + "org_apache_httpcomponents_httpclient_jar_sources_4_5_13": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_apache_httpcomponents_httpclient_jar_sources_4_5_13", + "sha256": "b1e9194fd83ce135831e28346731d9644cb2a08dea37ada2aa56ceb8f1b0c566", + "urls": [ + "https://repo1.maven.org/maven2/org/apache/httpcomponents/httpclient/4.5.13/httpclient-4.5.13-sources.jar" + ], + "downloaded_file_path": "org/apache/httpcomponents/httpclient/4.5.13/httpclient-4.5.13-sources.jar" + } + }, + "com_google_api_grpc_proto_google_iam_v1_1_14_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_api_grpc_proto_google_iam_v1_1_14_1", + "sha256": "65929519b53c68a1fba00091e34e441e11ee532bbe3790873f2b9e26f81cf98a", + "urls": [ + "https://repo1.maven.org/maven2/com/google/api/grpc/proto-google-iam-v1/1.14.1/proto-google-iam-v1-1.14.1.jar", + "https://maven.google.com/com/google/api/grpc/proto-google-iam-v1/1.14.1/proto-google-iam-v1-1.14.1.jar" + ], + "downloaded_file_path": "com/google/api/grpc/proto-google-iam-v1/1.14.1/proto-google-iam-v1-1.14.1.jar" + } + }, + "software_amazon_awssdk_netty_nio_client_2_20_78": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_netty_nio_client_2_20_78", + "sha256": "56999d51ff6b3efdb5b09241a126a466c96f3d93f629e94b2db5634da2b6c659", + "urls": [ + "https://repo1.maven.org/maven2/software/amazon/awssdk/netty-nio-client/2.20.78/netty-nio-client-2.20.78.jar", + "https://maven.google.com/software/amazon/awssdk/netty-nio-client/2.20.78/netty-nio-client-2.20.78.jar" + ], + "downloaded_file_path": "software/amazon/awssdk/netty-nio-client/2.20.78/netty-nio-client-2.20.78.jar" + } + }, + "com_esotericsoftware_kryo_jar_sources_5_5_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_esotericsoftware_kryo_jar_sources_5_5_0", + "sha256": "a7fe17d9e5c3f18ba2070b1356aeafc3f1626e8ebb6161a70d84c2f17adcd072", + "urls": [ + "https://repo1.maven.org/maven2/com/esotericsoftware/kryo/5.5.0/kryo-5.5.0-sources.jar" + ], + "downloaded_file_path": "com/esotericsoftware/kryo/5.5.0/kryo-5.5.0-sources.jar" + } + }, + "org_mockito_mockito_core": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_mockito_mockito_core", + "generating_repository": "maven", + "target_name": "org_mockito_mockito_core" + } + }, + "io_grpc_grpc_context_1_55_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_context_1_55_1", + "sha256": "541ec1d7ad3389f0b302461432a44b16fc1329153cd0e16faf2d2028b446340d", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-context/1.55.1/grpc-context-1.55.1.jar", + "https://maven.google.com/io/grpc/grpc-context/1.55.1/grpc-context-1.55.1.jar" + ], + "downloaded_file_path": "io/grpc/grpc-context/1.55.1/grpc-context-1.55.1.jar" + } + }, + "com_google_jimfs_jimfs_1_3_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_jimfs_jimfs_1_3_0", + "sha256": "82494408bb513f5512652e7b7f63d6f31f01eff57ce35c878644ffc2d25aee4f", + "urls": [ + "https://repo1.maven.org/maven2/com/google/jimfs/jimfs/1.3.0/jimfs-1.3.0.jar" + ], + "downloaded_file_path": "com/google/jimfs/jimfs/1.3.0/jimfs-1.3.0.jar" + } + }, + "org_ow2_asm_asm_analysis_9_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_ow2_asm_asm_analysis_9_2", + "sha256": "878fbe521731c072d14d2d65b983b1beae6ad06fda0007b6a8bae81f73f433c4", + "urls": [ + "https://repo1.maven.org/maven2/org/ow2/asm/asm-analysis/9.2/asm-analysis-9.2.jar" + ], + "downloaded_file_path": "org/ow2/asm/asm-analysis/9.2/asm-analysis-9.2.jar" + } + }, + "com_esotericsoftware_reflectasm_jar_sources_1_11_9": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_esotericsoftware_reflectasm_jar_sources_1_11_9", + "sha256": "8fc29f5069a1a43c38eb28b54f6850995734f31962813b13ac8a9b7a0624b45b", + "urls": [ + "https://repo1.maven.org/maven2/com/esotericsoftware/reflectasm/1.11.9/reflectasm-1.11.9-sources.jar" + ], + "downloaded_file_path": "com/esotericsoftware/reflectasm/1.11.9/reflectasm-1.11.9-sources.jar" + } + }, + "net_bytebuddy_byte_buddy_agent_jar_sources_1_9_7": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~net_bytebuddy_byte_buddy_agent_jar_sources_1_9_7", + "sha256": "f1ffcb60fb0cb3de2ab4ba36b3588f9c0f12b24e8eeb59f76c57664f42eaae80", + "urls": [ + "https://repo1.maven.org/maven2/net/bytebuddy/byte-buddy-agent/1.9.7/byte-buddy-agent-1.9.7-sources.jar" + ], + "downloaded_file_path": "net/bytebuddy/byte-buddy-agent/1.9.7/byte-buddy-agent-1.9.7-sources.jar" + } + }, + "org_mockito_mockito_core_2_25_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_mockito_mockito_core_2_25_0", + "sha256": "28028d70cc27d61442948fcb3d249d9df5b37c47aa0b82490a3d049094ff411f", + "urls": [ + "https://repo1.maven.org/maven2/org/mockito/mockito-core/2.25.0/mockito-core-2.25.0.jar" + ], + "downloaded_file_path": "org/mockito/mockito-core/2.25.0/mockito-core-2.25.0.jar" + } + }, + "com_google_auth_google_auth_library_oauth2_http_1_17_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_auth_google_auth_library_oauth2_http_1_17_0", + "sha256": "b8148e1af0c4197aea707d0166b4ed70a75b8eee7246be7eb0228a4834095e70", + "urls": [ + "https://repo1.maven.org/maven2/com/google/auth/google-auth-library-oauth2-http/1.17.0/google-auth-library-oauth2-http-1.17.0.jar", + "https://maven.google.com/com/google/auth/google-auth-library-oauth2-http/1.17.0/google-auth-library-oauth2-http-1.17.0.jar" + ], + "downloaded_file_path": "com/google/auth/google-auth-library-oauth2-http/1.17.0/google-auth-library-oauth2-http-1.17.0.jar" + } + }, + "io_netty_netty_buffer": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_buffer", + "generating_repository": "maven", + "target_name": "io_netty_netty_buffer" + } + }, + "com_amazonaws_jmespath_java_1_12_544": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_amazonaws_jmespath_java_1_12_544", + "sha256": "b707d67e8fcc87ffdf426bbe61bbe60ae97e865d35d6cec429a934d47fa2976c", + "urls": [ + "https://repo1.maven.org/maven2/com/amazonaws/jmespath-java/1.12.544/jmespath-java-1.12.544.jar" + ], + "downloaded_file_path": "com/amazonaws/jmespath-java/1.12.544/jmespath-java-1.12.544.jar" + } + }, + "com_google_errorprone_error_prone_check_api_jar_sources_2_22_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_errorprone_error_prone_check_api_jar_sources_2_22_0", + "sha256": "962656ccdd75e0f9891f5fbc5c53ea1ea381234eaadee50d3d04bafc094f0190", + "urls": [ + "https://repo1.maven.org/maven2/com/google/errorprone/error_prone_check_api/2.22.0/error_prone_check_api-2.22.0-sources.jar" + ], + "downloaded_file_path": "com/google/errorprone/error_prone_check_api/2.22.0/error_prone_check_api-2.22.0-sources.jar" + } + }, + "org_glassfish_hk2_osgi_resource_locator_jar_sources_1_0_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_glassfish_hk2_osgi_resource_locator_jar_sources_1_0_3", + "sha256": "603d0e07134189505c76a8c8d5d4451a91bf1327a05f1f5bcea09bad61bd507e", + "urls": [ + "https://repo1.maven.org/maven2/org/glassfish/hk2/osgi-resource-locator/1.0.3/osgi-resource-locator-1.0.3-sources.jar" + ], + "downloaded_file_path": "org/glassfish/hk2/osgi-resource-locator/1.0.3/osgi-resource-locator-1.0.3-sources.jar" + } + }, + "io_opencensus_opencensus_contrib_http_util_jar_sources_0_31_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_opencensus_opencensus_contrib_http_util_jar_sources_0_31_1", + "sha256": "d55afd5f96dc724bd903a77a38b0a344d0e59f02a64b9ab2f32618bc582ea924", + "urls": [ + "https://repo1.maven.org/maven2/io/opencensus/opencensus-contrib-http-util/0.31.1/opencensus-contrib-http-util-0.31.1-sources.jar" + ], + "downloaded_file_path": "io/opencensus/opencensus-contrib-http-util/0.31.1/opencensus-contrib-http-util-0.31.1-sources.jar" + } + }, + "io_grpc_grpc_testing_jar_sources_1_56_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_testing_jar_sources_1_56_1", + "sha256": "0e1ee432e6ec26940bce1726d47344772ba2afd60af93750d0fad54596c936ee", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-testing/1.56.1/grpc-testing-1.56.1-sources.jar" + ], + "downloaded_file_path": "io/grpc/grpc-testing/1.56.1/grpc-testing-1.56.1-sources.jar" + } + }, + "io_prometheus_simpleclient_tracer_otel_0_15_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_tracer_otel_0_15_0", + "sha256": "0595251da49aa7997777b365ffdf97f5e2e88cd7f0dacf49add91b4fc8222b50", + "urls": [ + "https://repo1.maven.org/maven2/io/prometheus/simpleclient_tracer_otel/0.15.0/simpleclient_tracer_otel-0.15.0.jar" + ], + "downloaded_file_path": "io/prometheus/simpleclient_tracer_otel/0.15.0/simpleclient_tracer_otel-0.15.0.jar" + } + }, + "org_apache_httpcomponents_httpclient_4_5_13": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_apache_httpcomponents_httpclient_4_5_13", + "sha256": "6fe9026a566c6a5001608cf3fc32196641f6c1e5e1986d1037ccdbd5f31ef743", + "urls": [ + "https://repo1.maven.org/maven2/org/apache/httpcomponents/httpclient/4.5.13/httpclient-4.5.13.jar" + ], + "downloaded_file_path": "org/apache/httpcomponents/httpclient/4.5.13/httpclient-4.5.13.jar" + } + }, + "org_apache_httpcomponents_httpclient_4_5_14": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_apache_httpcomponents_httpclient_4_5_14", + "sha256": "c8bc7e1c51a6d4ce72f40d2ebbabf1c4b68bfe76e732104b04381b493478e9d6", + "urls": [ + "https://repo1.maven.org/maven2/org/apache/httpcomponents/httpclient/4.5.14/httpclient-4.5.14.jar", + "https://maven.google.com/org/apache/httpcomponents/httpclient/4.5.14/httpclient-4.5.14.jar" + ], + "downloaded_file_path": "org/apache/httpcomponents/httpclient/4.5.14/httpclient-4.5.14.jar" + } + }, + "com_google_guava_guava_jar_sources_32_1_1_jre": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_guava_guava_jar_sources_32_1_1_jre", + "sha256": "5e7b6cebd2e9087a536c1054bf52a2e6a49c284772421f146640cfadc54ba573", + "urls": [ + "https://repo1.maven.org/maven2/com/google/guava/guava/32.1.1-jre/guava-32.1.1-jre-sources.jar" + ], + "downloaded_file_path": "com/google/guava/guava/32.1.1-jre/guava-32.1.1-jre-sources.jar" + } + }, + "com_github_docker_java_docker_java_api_3_3_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_docker_java_docker_java_api_3_3_3", + "sha256": "8be2f41ddc33306b83f91e413fc1a07cee02db05e4c493456de3399e5bcb7b6c", + "urls": [ + "https://repo1.maven.org/maven2/com/github/docker-java/docker-java-api/3.3.3/docker-java-api-3.3.3.jar" + ], + "downloaded_file_path": "com/github/docker-java/docker-java-api/3.3.3/docker-java-api-3.3.3.jar" + } + }, + "io_grpc_grpc_core_1_56_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_core_1_56_1", + "sha256": "fddeafc25019b7e5600028d6398e9ed7383056d9aecaf95aec5c39c5085a4830", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-core/1.56.1/grpc-core-1.56.1.jar" + ], + "downloaded_file_path": "io/grpc/grpc-core/1.56.1/grpc-core-1.56.1.jar" + } + }, + "com_kohlschutter_junixsocket_junixsocket_native_common_2_6_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_kohlschutter_junixsocket_junixsocket_native_common_2_6_1", + "sha256": "61fbbd6cfd2b6df65c0e7b19b16ff4f755d6cb1d333b566f4286407f12f18670", + "urls": [ + "https://repo1.maven.org/maven2/com/kohlschutter/junixsocket/junixsocket-native-common/2.6.1/junixsocket-native-common-2.6.1.jar" + ], + "downloaded_file_path": "com/kohlschutter/junixsocket/junixsocket-native-common/2.6.1/junixsocket-native-common-2.6.1.jar" + } + }, + "com_google_cloud_google_cloud_storage_2_22_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_cloud_google_cloud_storage_2_22_3", + "sha256": "a9b6e2cf02c37dd3a09ca4b2a091fd07eb5487b95995691df898ec223bdad5ab", + "urls": [ + "https://repo1.maven.org/maven2/com/google/cloud/google-cloud-storage/2.22.3/google-cloud-storage-2.22.3.jar", + "https://maven.google.com/com/google/cloud/google-cloud-storage/2.22.3/google-cloud-storage-2.22.3.jar" + ], + "downloaded_file_path": "com/google/cloud/google-cloud-storage/2.22.3/google-cloud-storage-2.22.3.jar" + } + }, + "io_prometheus_simpleclient_hotspot_jar_sources_0_15_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_hotspot_jar_sources_0_15_0", + "sha256": "352f4a0940814a22691132e6b7abcea4add6a8ce322b22a88be5494064036437", + "urls": [ + "https://repo1.maven.org/maven2/io/prometheus/simpleclient_hotspot/0.15.0/simpleclient_hotspot-0.15.0-sources.jar" + ], + "downloaded_file_path": "io/prometheus/simpleclient_hotspot/0.15.0/simpleclient_hotspot-0.15.0-sources.jar" + } + }, + "jakarta_xml_bind_jakarta_xml_bind_api_2_3_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~jakarta_xml_bind_jakarta_xml_bind_api_2_3_2", + "sha256": "69156304079bdeed9fc0ae3b39389f19b3cc4ba4443bc80508995394ead742ea", + "urls": [ + "https://repo1.maven.org/maven2/jakarta/xml/bind/jakarta.xml.bind-api/2.3.2/jakarta.xml.bind-api-2.3.2.jar" + ], + "downloaded_file_path": "jakarta/xml/bind/jakarta.xml.bind-api/2.3.2/jakarta.xml.bind-api-2.3.2.jar" + } + }, + "com_google_errorprone_error_prone_annotation_jar_sources_2_22_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_errorprone_error_prone_annotation_jar_sources_2_22_0", + "sha256": "45507d9cb6e18174656fd09f5a34033700ba75562bfcb188ec1706da10c10157", + "urls": [ + "https://repo1.maven.org/maven2/com/google/errorprone/error_prone_annotation/2.22.0/error_prone_annotation-2.22.0-sources.jar" + ], + "downloaded_file_path": "com/google/errorprone/error_prone_annotation/2.22.0/error_prone_annotation-2.22.0-sources.jar" + } + }, + "org_pcollections_pcollections_3_1_4": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_pcollections_pcollections_3_1_4", + "sha256": "34f579ba075c8da2c8a0fedd0f04e21eac2fb6c660d90d0fabb573e8b4dc6918", + "urls": [ + "https://repo1.maven.org/maven2/org/pcollections/pcollections/3.1.4/pcollections-3.1.4.jar" + ], + "downloaded_file_path": "org/pcollections/pcollections/3.1.4/pcollections-3.1.4.jar" + } + }, + "io_grpc_grpc_context": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_context", + "generating_repository": "maven", + "target_name": "io_grpc_grpc_context" + } + }, + "javax_cache_cache_api_1_1_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~javax_cache_cache_api_1_1_1", + "sha256": "9f34e007edfa82a7b2a2e1b969477dcf5099ce7f4f926fb54ce7e27c4a0cd54b", + "urls": [ + "https://repo1.maven.org/maven2/javax/cache/cache-api/1.1.1/cache-api-1.1.1.jar" + ], + "downloaded_file_path": "javax/cache/cache-api/1.1.1/cache-api-1.1.1.jar" + } + }, + "org_ow2_asm_asm_util_jar_sources_9_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_ow2_asm_asm_util_jar_sources_9_2", + "sha256": "b631d4561a24e84eaeee2c0495added214e4961ed328b02300f7d9b1f407c853", + "urls": [ + "https://repo1.maven.org/maven2/org/ow2/asm/asm-util/9.2/asm-util-9.2-sources.jar" + ], + "downloaded_file_path": "org/ow2/asm/asm-util/9.2/asm-util-9.2-sources.jar" + } + }, + "com_google_auth_google_auth_library_credentials_jar_sources_1_19_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_auth_google_auth_library_credentials_jar_sources_1_19_0", + "sha256": "f83533db6683adaf971f98dad16d74e8ac34909e5085b720e3c45542a3f1552c", + "urls": [ + "https://repo1.maven.org/maven2/com/google/auth/google-auth-library-credentials/1.19.0/google-auth-library-credentials-1.19.0-sources.jar" + ], + "downloaded_file_path": "com/google/auth/google-auth-library-credentials/1.19.0/google-auth-library-credentials-1.19.0-sources.jar" + } + }, + "io_netty_netty_transport_classes_epoll_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_classes_epoll_4_1_97_Final", + "sha256": "ee65fa17fe65f18fd22269f92bddad85bfb3a263cf65eba01e116a2f30b86ff5", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-transport-classes-epoll/4.1.97.Final/netty-transport-classes-epoll-4.1.97.Final.jar" + ], + "downloaded_file_path": "io/netty/netty-transport-classes-epoll/4.1.97.Final/netty-transport-classes-epoll-4.1.97.Final.jar" + } + }, + "org_ow2_asm_asm_analysis_jar_sources_9_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_ow2_asm_asm_analysis_jar_sources_9_2", + "sha256": "c5a6764bbcee9e4bcd8ee1ea33808f96b8b587371f329aa75a2f541f2ee1b0d5", + "urls": [ + "https://repo1.maven.org/maven2/org/ow2/asm/asm-analysis/9.2/asm-analysis-9.2-sources.jar" + ], + "downloaded_file_path": "org/ow2/asm/asm-analysis/9.2/asm-analysis-9.2-sources.jar" + } + }, + "com_google_code_findbugs_jsr305": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_code_findbugs_jsr305", + "generating_repository": "maven", + "target_name": "com_google_code_findbugs_jsr305" + } + }, + "com_amazonaws_aws_java_sdk_secretsmanager_jar_sources_1_12_544": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_amazonaws_aws_java_sdk_secretsmanager_jar_sources_1_12_544", + "sha256": "d264b64ad371a864f8ba3a0af6876abb8f4ab3fe293812bab84a24e27d0b0982", + "urls": [ + "https://repo1.maven.org/maven2/com/amazonaws/aws-java-sdk-secretsmanager/1.12.544/aws-java-sdk-secretsmanager-1.12.544-sources.jar" + ], + "downloaded_file_path": "com/amazonaws/aws-java-sdk-secretsmanager/1.12.544/aws-java-sdk-secretsmanager-1.12.544-sources.jar" + } + }, + "com_google_auth_google_auth_library_oauth2_http_jar_sources_1_19_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_auth_google_auth_library_oauth2_http_jar_sources_1_19_0", + "sha256": "3aabf134e1c21fb8b3573897f0aa9136ca58ebe0c76fb086ef9169b28e9f707e", + "urls": [ + "https://repo1.maven.org/maven2/com/google/auth/google-auth-library-oauth2-http/1.19.0/google-auth-library-oauth2-http-1.19.0-sources.jar" + ], + "downloaded_file_path": "com/google/auth/google-auth-library-oauth2-http/1.19.0/google-auth-library-oauth2-http-1.19.0-sources.jar" + } + }, + "io_netty_netty_transport": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport", + "generating_repository": "maven", + "target_name": "io_netty_netty_transport" + } + }, + "commons_logging_commons_logging_1_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~commons_logging_commons_logging_1_2", + "sha256": "daddea1ea0be0f56978ab3006b8ac92834afeefbd9b7e4e6316fca57df0fa636", + "urls": [ + "https://repo1.maven.org/maven2/commons-logging/commons-logging/1.2/commons-logging-1.2.jar" + ], + "downloaded_file_path": "commons-logging/commons-logging/1.2/commons-logging-1.2.jar" + } + }, + "jakarta_ws_rs_jakarta_ws_rs_api_2_1_6": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~jakarta_ws_rs_jakarta_ws_rs_api_2_1_6", + "sha256": "4cea299c846c8a6e6470cbfc2f7c391bc29b9caa2f9264ac1064ba91691f4adf", + "urls": [ + "https://repo1.maven.org/maven2/jakarta/ws/rs/jakarta.ws.rs-api/2.1.6/jakarta.ws.rs-api-2.1.6.jar" + ], + "downloaded_file_path": "jakarta/ws/rs/jakarta.ws.rs-api/2.1.6/jakarta.ws.rs-api-2.1.6.jar" + } + }, + "com_github_jnr_jffi": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_jnr_jffi", + "generating_repository": "maven", + "target_name": "com_github_jnr_jffi" + } + }, + "com_googlecode_json_simple_json_simple_jar_sources_1_1_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_googlecode_json_simple_json_simple_jar_sources_1_1_1", + "sha256": "26960e02aeb64dc06ada259495ad2a553dd53ded9aaf6a84c3f5974a56ce24d6", + "urls": [ + "https://repo1.maven.org/maven2/com/googlecode/json-simple/json-simple/1.1.1/json-simple-1.1.1-sources.jar" + ], + "downloaded_file_path": "com/googlecode/json-simple/json-simple/1.1.1/json-simple-1.1.1-sources.jar" + } + }, + "com_google_api_gax_2_28_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_api_gax_2_28_1", + "sha256": "dddd191a2621bc5a747800c417005618f9c1f03d3d5056cb0208905400f17fac", + "urls": [ + "https://repo1.maven.org/maven2/com/google/api/gax/2.28.1/gax-2.28.1.jar", + "https://maven.google.com/com/google/api/gax/2.28.1/gax-2.28.1.jar" + ], + "downloaded_file_path": "com/google/api/gax/2.28.1/gax-2.28.1.jar" + } + }, + "com_github_docker_java_docker_java_transport_jar_sources_3_3_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_docker_java_docker_java_transport_jar_sources_3_3_3", + "sha256": "0ec44c8b9349365c3dd2740ad41f9e65af079fd9a68bfc68a2d3efe5776ff687", + "urls": [ + "https://repo1.maven.org/maven2/com/github/docker-java/docker-java-transport/3.3.3/docker-java-transport-3.3.3-sources.jar" + ], + "downloaded_file_path": "com/github/docker-java/docker-java-transport/3.3.3/docker-java-transport-3.3.3-sources.jar" + } + }, + "software_amazon_awssdk_metrics_spi_2_20_78": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_metrics_spi_2_20_78", + "sha256": "41680096cb566090be0504eaf207dab91d680c16d57f68239260860871d7ab8f", + "urls": [ + "https://repo1.maven.org/maven2/software/amazon/awssdk/metrics-spi/2.20.78/metrics-spi-2.20.78.jar", + "https://maven.google.com/software/amazon/awssdk/metrics-spi/2.20.78/metrics-spi-2.20.78.jar" + ], + "downloaded_file_path": "software/amazon/awssdk/metrics-spi/2.20.78/metrics-spi-2.20.78.jar" + } + }, + "org_conscrypt_conscrypt_openjdk_uber_2_5_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_conscrypt_conscrypt_openjdk_uber_2_5_2", + "sha256": "eaf537d98e033d0f0451cd1b8cc74e02d7b55ec882da63c88060d806ba89c348", + "urls": [ + "https://repo1.maven.org/maven2/org/conscrypt/conscrypt-openjdk-uber/2.5.2/conscrypt-openjdk-uber-2.5.2.jar", + "https://maven.google.com/org/conscrypt/conscrypt-openjdk-uber/2.5.2/conscrypt-openjdk-uber-2.5.2.jar" + ], + "downloaded_file_path": "org/conscrypt/conscrypt-openjdk-uber/2.5.2/conscrypt-openjdk-uber-2.5.2.jar" + } + }, + "com_github_ben_manes_caffeine_caffeine_jar_sources_3_0_5": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_ben_manes_caffeine_caffeine_jar_sources_3_0_5", + "sha256": "2cca8d1cdfdf33c1d0eec0214cdc6d93ff8a95136bf798465b10a5924a69bc65", + "urls": [ + "https://repo1.maven.org/maven2/com/github/ben-manes/caffeine/caffeine/3.0.5/caffeine-3.0.5-sources.jar" + ], + "downloaded_file_path": "com/github/ben-manes/caffeine/caffeine/3.0.5/caffeine-3.0.5-sources.jar" + } + }, + "com_github_docker_java_docker_java_api_jar_sources_3_3_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_docker_java_docker_java_api_jar_sources_3_3_3", + "sha256": "cb262504c43a1ed7f79235a9f93611c322016bd6ca91a0ab37cfe21a55460a8b", + "urls": [ + "https://repo1.maven.org/maven2/com/github/docker-java/docker-java-api/3.3.3/docker-java-api-3.3.3-sources.jar" + ], + "downloaded_file_path": "com/github/docker-java/docker-java-api/3.3.3/docker-java-api-3.3.3-sources.jar" + } + }, + "org_checkerframework_checker_qual": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_checkerframework_checker_qual", + "generating_repository": "maven", + "target_name": "org_checkerframework_checker_qual" + } + }, + "org_glassfish_hk2_hk2_api_jar_sources_2_6_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_glassfish_hk2_hk2_api_jar_sources_2_6_1", + "sha256": "636e56f6454a7c680271dd8e2e49d1fd50625bb9e206555a14ccf900188cc18c", + "urls": [ + "https://repo1.maven.org/maven2/org/glassfish/hk2/hk2-api/2.6.1/hk2-api-2.6.1-sources.jar" + ], + "downloaded_file_path": "org/glassfish/hk2/hk2-api/2.6.1/hk2-api-2.6.1-sources.jar" + } + }, + "io_grpc_grpc_netty_jar_sources_1_56_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_netty_jar_sources_1_56_1", + "sha256": "3ce30acc50ab39f160948bae09c1c832093d6b23a533a20d1473466ca30a3783", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-netty/1.56.1/grpc-netty-1.56.1-sources.jar" + ], + "downloaded_file_path": "io/grpc/grpc-netty/1.56.1/grpc-netty-1.56.1-sources.jar" + } + }, + "junit_junit_jar_sources_4_13_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~junit_junit_jar_sources_4_13_2", + "sha256": "34181df6482d40ea4c046b063cb53c7ffae94bdf1b1d62695bdf3adf9dea7e3a", + "urls": [ + "https://repo1.maven.org/maven2/junit/junit/4.13.2/junit-4.13.2-sources.jar" + ], + "downloaded_file_path": "junit/junit/4.13.2/junit-4.13.2-sources.jar" + } + }, + "org_ow2_asm_asm_commons_9_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_ow2_asm_asm_commons_9_2", + "sha256": "be4ce53138a238bb522cd781cf91f3ba5ce2f6ca93ec62d46a162a127225e0a6", + "urls": [ + "https://repo1.maven.org/maven2/org/ow2/asm/asm-commons/9.2/asm-commons-9.2.jar" + ], + "downloaded_file_path": "org/ow2/asm/asm-commons/9.2/asm-commons-9.2.jar" + } + }, + "com_google_protobuf_protobuf_java_3_23_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_protobuf_protobuf_java_3_23_1", + "sha256": "d9fd335a65165c760f53ae718878448627ce742ab6e9102dffe9bc2ea7b136ca", + "urls": [ + "https://repo1.maven.org/maven2/com/google/protobuf/protobuf-java/3.23.1/protobuf-java-3.23.1.jar", + "https://maven.google.com/com/google/protobuf/protobuf-java/3.23.1/protobuf-java-3.23.1.jar" + ], + "downloaded_file_path": "com/google/protobuf/protobuf-java/3.23.1/protobuf-java-3.23.1.jar" + } + }, + "org_luaj_luaj_jse_3_0_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_luaj_luaj_jse_3_0_1", + "sha256": "9b1f0a3e8f68427c6d74c2bf00ae0e6dbfce35994d3001fed4cef6ecda50be55", + "urls": [ + "https://repo1.maven.org/maven2/org/luaj/luaj-jse/3.0.1/luaj-jse-3.0.1.jar" + ], + "downloaded_file_path": "org/luaj/luaj-jse/3.0.1/luaj-jse-3.0.1.jar" + } + }, + "org_glassfish_hk2_hk2_locator_jar_sources_2_6_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_glassfish_hk2_hk2_locator_jar_sources_2_6_1", + "sha256": "d76811aeabe487e35001fb4a0ab3d986a091c331f4d61962c33f6c98f94e5053", + "urls": [ + "https://repo1.maven.org/maven2/org/glassfish/hk2/hk2-locator/2.6.1/hk2-locator-2.6.1-sources.jar" + ], + "downloaded_file_path": "org/glassfish/hk2/hk2-locator/2.6.1/hk2-locator-2.6.1-sources.jar" + } + }, + "org_reflections_reflections_jar_sources_0_10_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_reflections_reflections_jar_sources_0_10_2", + "sha256": "7c8f0b91e298556ac8eebcbbb33de537baa146d80a7e5a6500e44cd8f76a91f4", + "urls": [ + "https://repo1.maven.org/maven2/org/reflections/reflections/0.10.2/reflections-0.10.2-sources.jar" + ], + "downloaded_file_path": "org/reflections/reflections/0.10.2/reflections-0.10.2-sources.jar" + } + }, + "org_apache_commons_commons_pool2": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_apache_commons_commons_pool2", + "generating_repository": "maven", + "target_name": "org_apache_commons_commons_pool2" + } + }, + "io_github_java_diff_utils_java_diff_utils_4_12": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_github_java_diff_utils_java_diff_utils_4_12", + "sha256": "9990a2039778f6b4cc94790141c2868864eacee0620c6c459451121a901cd5b5", + "urls": [ + "https://repo1.maven.org/maven2/io/github/java-diff-utils/java-diff-utils/4.12/java-diff-utils-4.12.jar" + ], + "downloaded_file_path": "io/github/java-diff-utils/java-diff-utils/4.12/java-diff-utils-4.12.jar" + } + }, + "maven": { + "bzlFile": "@@rules_jvm_external~5.3//:coursier.bzl", + "ruleClassName": "pinned_coursier_fetch", + "attributes": { + "name": "rules_jvm_external~5.3~maven~maven", + "repositories": [ + "{ \"repo_url\": \"https://repo1.maven.org/maven2\" }" + ], + "artifacts": [ + "{ \"group\": \"com.amazonaws\", \"artifact\": \"aws-java-sdk-s3\", \"version\": \"1.12.544\" }", + "{ \"group\": \"com.amazonaws\", \"artifact\": \"aws-java-sdk-secretsmanager\", \"version\": \"1.12.544\" }", + "{ \"group\": \"com.fasterxml.jackson.core\", \"artifact\": \"jackson-databind\", \"version\": \"2.15.0\" }", + "{ \"group\": \"com.github.ben-manes.caffeine\", \"artifact\": \"caffeine\", \"version\": \"2.9.0\" }", + "{ \"group\": \"com.github.docker-java\", \"artifact\": \"docker-java\", \"version\": \"3.3.3\" }", + "{ \"group\": \"com.github.fppt\", \"artifact\": \"jedis-mock\", \"version\": \"1.0.10\" }", + "{ \"group\": \"com.github.jnr\", \"artifact\": \"jffi\", \"version\": \"1.3.11\" }", + "{ \"group\": \"com.github.jnr\", \"artifact\": \"jffi\", \"version\": \"1.3.11\", \"packaging\": \"jar\", \"classifier\": \"native\" }", + "{ \"group\": \"com.github.jnr\", \"artifact\": \"jnr-constants\", \"version\": \"0.10.4\" }", + "{ \"group\": \"com.github.jnr\", \"artifact\": \"jnr-ffi\", \"version\": \"2.2.14\" }", + "{ \"group\": \"com.github.jnr\", \"artifact\": \"jnr-posix\", \"version\": \"3.1.17\" }", + "{ \"group\": \"com.github.pcj\", \"artifact\": \"google-options\", \"version\": \"1.0.0\" }", + "{ \"group\": \"com.github.serceman\", \"artifact\": \"jnr-fuse\", \"version\": \"0.5.7\" }", + "{ \"group\": \"com.github.luben\", \"artifact\": \"zstd-jni\", \"version\": \"1.5.5-7\" }", + "{ \"group\": \"com.github.oshi\", \"artifact\": \"oshi-core\", \"version\": \"6.4.5\" }", + "{ \"group\": \"com.google.auth\", \"artifact\": \"google-auth-library-credentials\", \"version\": \"1.19.0\" }", + "{ \"group\": \"com.google.auth\", \"artifact\": \"google-auth-library-oauth2-http\", \"version\": \"1.19.0\" }", + "{ \"group\": \"com.google.code.findbugs\", \"artifact\": \"jsr305\", \"version\": \"3.0.2\" }", + "{ \"group\": \"com.google.code.gson\", \"artifact\": \"gson\", \"version\": \"2.10.1\" }", + "{ \"group\": \"com.google.errorprone\", \"artifact\": \"error_prone_annotations\", \"version\": \"2.22.0\" }", + "{ \"group\": \"com.google.errorprone\", \"artifact\": \"error_prone_core\", \"version\": \"2.22.0\" }", + "{ \"group\": \"com.google.guava\", \"artifact\": \"failureaccess\", \"version\": \"1.0.1\" }", + "{ \"group\": \"com.google.guava\", \"artifact\": \"guava\", \"version\": \"32.1.1-jre\" }", + "{ \"group\": \"com.google.j2objc\", \"artifact\": \"j2objc-annotations\", \"version\": \"2.8\" }", + "{ \"group\": \"com.google.jimfs\", \"artifact\": \"jimfs\", \"version\": \"1.3.0\" }", + "{ \"group\": \"com.google.protobuf\", \"artifact\": \"protobuf-java-util\", \"version\": \"3.19.1\" }", + "{ \"group\": \"com.google.protobuf\", \"artifact\": \"protobuf-java\", \"version\": \"3.19.1\" }", + "{ \"group\": \"com.google.truth\", \"artifact\": \"truth\", \"version\": \"1.1.5\" }", + "{ \"group\": \"org.slf4j\", \"artifact\": \"slf4j-simple\", \"version\": \"2.0.9\" }", + "{ \"group\": \"com.googlecode.json-simple\", \"artifact\": \"json-simple\", \"version\": \"1.1.1\" }", + "{ \"group\": \"com.jayway.jsonpath\", \"artifact\": \"json-path\", \"version\": \"2.8.0\" }", + "{ \"group\": \"org.bouncycastle\", \"artifact\": \"bcprov-jdk15on\", \"version\": \"1.70\" }", + "{ \"group\": \"net.jcip\", \"artifact\": \"jcip-annotations\", \"version\": \"1.0\" }", + "{ \"group\": \"io.netty\", \"artifact\": \"netty-buffer\", \"version\": \"4.1.97.Final\" }", + "{ \"group\": \"io.netty\", \"artifact\": \"netty-codec\", \"version\": \"4.1.97.Final\" }", + "{ \"group\": \"io.netty\", \"artifact\": \"netty-codec-http\", \"version\": \"4.1.97.Final\" }", + "{ \"group\": \"io.netty\", \"artifact\": \"netty-codec-http2\", \"version\": \"4.1.97.Final\" }", + "{ \"group\": \"io.netty\", \"artifact\": \"netty-codec-socks\", \"version\": \"4.1.97.Final\" }", + "{ \"group\": \"io.netty\", \"artifact\": \"netty-common\", \"version\": \"4.1.97.Final\" }", + "{ \"group\": \"io.netty\", \"artifact\": \"netty-handler\", \"version\": \"4.1.97.Final\" }", + "{ \"group\": \"io.netty\", \"artifact\": \"netty-handler-proxy\", \"version\": \"4.1.97.Final\" }", + "{ \"group\": \"io.netty\", \"artifact\": \"netty-resolver\", \"version\": \"4.1.97.Final\" }", + "{ \"group\": \"io.netty\", \"artifact\": \"netty-transport\", \"version\": \"4.1.97.Final\" }", + "{ \"group\": \"io.netty\", \"artifact\": \"netty-transport-native-epoll\", \"version\": \"4.1.97.Final\" }", + "{ \"group\": \"io.netty\", \"artifact\": \"netty-transport-native-kqueue\", \"version\": \"4.1.97.Final\" }", + "{ \"group\": \"io.netty\", \"artifact\": \"netty-transport-native-unix-common\", \"version\": \"4.1.97.Final\" }", + "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-api\", \"version\": \"1.56.1\" }", + "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-auth\", \"version\": \"1.56.1\" }", + "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-core\", \"version\": \"1.56.1\" }", + "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-context\", \"version\": \"1.56.1\" }", + "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-netty\", \"version\": \"1.56.1\" }", + "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-stub\", \"version\": \"1.56.1\" }", + "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-protobuf\", \"version\": \"1.56.1\" }", + "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-testing\", \"version\": \"1.56.1\" }", + "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-services\", \"version\": \"1.56.1\" }", + "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-netty-shaded\", \"version\": \"1.56.1\" }", + "{ \"group\": \"io.prometheus\", \"artifact\": \"simpleclient\", \"version\": \"0.15.0\" }", + "{ \"group\": \"io.prometheus\", \"artifact\": \"simpleclient_hotspot\", \"version\": \"0.15.0\" }", + "{ \"group\": \"io.prometheus\", \"artifact\": \"simpleclient_httpserver\", \"version\": \"0.15.0\" }", + "{ \"group\": \"junit\", \"artifact\": \"junit\", \"version\": \"4.13.2\" }", + "{ \"group\": \"javax.annotation\", \"artifact\": \"javax.annotation-api\", \"version\": \"1.3.2\" }", + "{ \"group\": \"net.javacrumbs.future-converter\", \"artifact\": \"future-converter-java8-guava\", \"version\": \"1.2.0\" }", + "{ \"group\": \"org.apache.commons\", \"artifact\": \"commons-compress\", \"version\": \"1.23.0\" }", + "{ \"group\": \"org.apache.commons\", \"artifact\": \"commons-pool2\", \"version\": \"2.11.1\" }", + "{ \"group\": \"org.apache.commons\", \"artifact\": \"commons-lang3\", \"version\": \"3.13.0\" }", + "{ \"group\": \"commons-io\", \"artifact\": \"commons-io\", \"version\": \"2.13.0\" }", + "{ \"group\": \"me.dinowernli\", \"artifact\": \"java-grpc-prometheus\", \"version\": \"0.6.0\" }", + "{ \"group\": \"org.apache.tomcat\", \"artifact\": \"annotations-api\", \"version\": \"6.0.53\" }", + "{ \"group\": \"org.checkerframework\", \"artifact\": \"checker-qual\", \"version\": \"3.38.0\" }", + "{ \"group\": \"org.mockito\", \"artifact\": \"mockito-core\", \"version\": \"2.25.0\" }", + "{ \"group\": \"org.openjdk.jmh\", \"artifact\": \"jmh-core\", \"version\": \"1.37\" }", + "{ \"group\": \"org.openjdk.jmh\", \"artifact\": \"jmh-generator-annprocess\", \"version\": \"1.37\" }", + "{ \"group\": \"org.redisson\", \"artifact\": \"redisson\", \"version\": \"3.23.4\" }", + "{ \"group\": \"org.threeten\", \"artifact\": \"threetenbp\", \"version\": \"1.6.8\" }", + "{ \"group\": \"org.xerial\", \"artifact\": \"sqlite-jdbc\", \"version\": \"3.34.0\" }", + "{ \"group\": \"org.jetbrains\", \"artifact\": \"annotations\", \"version\": \"16.0.2\" }", + "{ \"group\": \"org.yaml\", \"artifact\": \"snakeyaml\", \"version\": \"2.2\" }", + "{ \"group\": \"org.projectlombok\", \"artifact\": \"lombok\", \"version\": \"1.18.30\" }" + ], + "fetch_sources": true, + "fetch_javadoc": false, + "generate_compat_repositories": false, + "maven_install_json": "@@//:maven_install.json", + "override_targets": {}, + "strict_visibility": false, + "strict_visibility_value": [ + "@@//visibility:private" + ], + "jetify": false, + "jetify_include_list": [ + "*" + ], + "additional_netrc_lines": [], + "fail_if_repin_required": true, + "use_starlark_android_rules": false, + "aar_import_bzl_label": "@build_bazel_rules_android//android:rules.bzl", + "duplicate_version_warning": "warn" + } + }, + "com_github_jnr_jnr_a64asm_1_0_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_jnr_jnr_a64asm_1_0_0", + "sha256": "53ae5ea7fa5c284e8279aa348e7b9de4548b0cae10bfd058fa217c791875e4cf", + "urls": [ + "https://repo1.maven.org/maven2/com/github/jnr/jnr-a64asm/1.0.0/jnr-a64asm-1.0.0.jar" + ], + "downloaded_file_path": "com/github/jnr/jnr-a64asm/1.0.0/jnr-a64asm-1.0.0.jar" + } + }, + "io_grpc_grpc_protobuf_jar_sources_1_56_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_protobuf_jar_sources_1_56_1", + "sha256": "62b6675a187374f8f4ea8d645d602930b587383fbb0979fa19e708f885499934", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-protobuf/1.56.1/grpc-protobuf-1.56.1-sources.jar" + ], + "downloaded_file_path": "io/grpc/grpc-protobuf/1.56.1/grpc-protobuf-1.56.1-sources.jar" + } + }, + "com_esotericsoftware_kryo_5_5_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_esotericsoftware_kryo_5_5_0", + "sha256": "4b902a21d99f7b4c32e6f7400e91f9284fd184db881bb9e18328e14d8127f7f9", + "urls": [ + "https://repo1.maven.org/maven2/com/esotericsoftware/kryo/5.5.0/kryo-5.5.0.jar" + ], + "downloaded_file_path": "com/esotericsoftware/kryo/5.5.0/kryo-5.5.0.jar" + } + }, + "io_prometheus_simpleclient_httpserver": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_httpserver", + "generating_repository": "maven", + "target_name": "io_prometheus_simpleclient_httpserver" + } + }, + "io_prometheus_simpleclient_0_15_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_0_15_0", + "sha256": "a43d6c00e3964a7063c1360ddcddc598df4f8e659a8313b27f90e4c555badb1d", + "urls": [ + "https://repo1.maven.org/maven2/io/prometheus/simpleclient/0.15.0/simpleclient-0.15.0.jar" + ], + "downloaded_file_path": "io/prometheus/simpleclient/0.15.0/simpleclient-0.15.0.jar" + } + }, + "com_google_cloud_google_cloud_core_grpc_2_18_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_cloud_google_cloud_core_grpc_2_18_1", + "sha256": "3021f5ac856552155edfb459a1f4c0b0bf3c5363e6fa4923a82af3e531ff33ad", + "urls": [ + "https://repo1.maven.org/maven2/com/google/cloud/google-cloud-core-grpc/2.18.1/google-cloud-core-grpc-2.18.1.jar", + "https://maven.google.com/com/google/cloud/google-cloud-core-grpc/2.18.1/google-cloud-core-grpc-2.18.1.jar" + ], + "downloaded_file_path": "com/google/cloud/google-cloud-core-grpc/2.18.1/google-cloud-core-grpc-2.18.1.jar" + } + }, + "jakarta_annotation_jakarta_annotation_api_1_3_5": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~jakarta_annotation_jakarta_annotation_api_1_3_5", + "sha256": "85fb03fc054cdf4efca8efd9b6712bbb418e1ab98241c4539c8585bbc23e1b8a", + "urls": [ + "https://repo1.maven.org/maven2/jakarta/annotation/jakarta.annotation-api/1.3.5/jakarta.annotation-api-1.3.5.jar" + ], + "downloaded_file_path": "jakarta/annotation/jakarta.annotation-api/1.3.5/jakarta.annotation-api-1.3.5.jar" + } + }, + "org_bouncycastle_bcprov_jdk15on": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_bouncycastle_bcprov_jdk15on", + "generating_repository": "maven", + "target_name": "org_bouncycastle_bcprov_jdk15on" + } + }, + "io_grpc_grpc_auth": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_auth", + "generating_repository": "maven", + "target_name": "io_grpc_grpc_auth" + } + }, + "org_glassfish_hk2_external_aopalliance_repackaged_jar_sources_2_6_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_glassfish_hk2_external_aopalliance_repackaged_jar_sources_2_6_1", + "sha256": "13392e5ad2540a5718abb1dc7c380ebd754c1b95c7d6140dd38bfeade1e6dd21", + "urls": [ + "https://repo1.maven.org/maven2/org/glassfish/hk2/external/aopalliance-repackaged/2.6.1/aopalliance-repackaged-2.6.1-sources.jar" + ], + "downloaded_file_path": "org/glassfish/hk2/external/aopalliance-repackaged/2.6.1/aopalliance-repackaged-2.6.1-sources.jar" + } + }, + "net_jcip_jcip_annotations_jar_sources_1_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~net_jcip_jcip_annotations_jar_sources_1_0", + "sha256": "e3ad6ae439e3cf8a25372de838efaa1a95f8ef9b5053d5d94fafe89c8c09814e", + "urls": [ + "https://repo1.maven.org/maven2/net/jcip/jcip-annotations/1.0/jcip-annotations-1.0-sources.jar" + ], + "downloaded_file_path": "net/jcip/jcip-annotations/1.0/jcip-annotations-1.0-sources.jar" + } + }, + "org_glassfish_jersey_core_jersey_common_jar_sources_2_30_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_glassfish_jersey_core_jersey_common_jar_sources_2_30_1", + "sha256": "bbc91b531c2aa801e578fc6737498159071f3030688714e44ed80001e17813f7", + "urls": [ + "https://repo1.maven.org/maven2/org/glassfish/jersey/core/jersey-common/2.30.1/jersey-common-2.30.1-sources.jar" + ], + "downloaded_file_path": "org/glassfish/jersey/core/jersey-common/2.30.1/jersey-common-2.30.1-sources.jar" + } + }, + "org_yaml_snakeyaml_2_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_yaml_snakeyaml_2_2", + "sha256": "1467931448a0817696ae2805b7b8b20bfb082652bf9c4efaed528930dc49389b", + "urls": [ + "https://repo1.maven.org/maven2/org/yaml/snakeyaml/2.2/snakeyaml-2.2.jar" + ], + "downloaded_file_path": "org/yaml/snakeyaml/2.2/snakeyaml-2.2.jar" + } + }, + "org_glassfish_jersey_connectors_jersey_apache_connector_2_30_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_glassfish_jersey_connectors_jersey_apache_connector_2_30_1", + "sha256": "28e87f2edc5284e293072941cea5e8ff462bb60f41c67b4ad7b906de2a7a8bd8", + "urls": [ + "https://repo1.maven.org/maven2/org/glassfish/jersey/connectors/jersey-apache-connector/2.30.1/jersey-apache-connector-2.30.1.jar" + ], + "downloaded_file_path": "org/glassfish/jersey/connectors/jersey-apache-connector/2.30.1/jersey-apache-connector-2.30.1.jar" + } + }, + "com_fasterxml_jackson_dataformat_jackson_dataformat_yaml_2_15_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_dataformat_jackson_dataformat_yaml_2_15_2", + "sha256": "37795cc1e8cb94b18d860dc3abd2e593617ce402149ae45aa89ed8bfb881c851", + "urls": [ + "https://repo1.maven.org/maven2/com/fasterxml/jackson/dataformat/jackson-dataformat-yaml/2.15.2/jackson-dataformat-yaml-2.15.2.jar" + ], + "downloaded_file_path": "com/fasterxml/jackson/dataformat/jackson-dataformat-yaml/2.15.2/jackson-dataformat-yaml-2.15.2.jar" + } + }, + "org_redisson_redisson": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_redisson_redisson", + "generating_repository": "maven", + "target_name": "org_redisson_redisson" + } + }, + "org_glassfish_jersey_core_jersey_common_2_30_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_glassfish_jersey_core_jersey_common_2_30_1", + "sha256": "273c3ea4e3ff9b960eb8dbb7c74e0127436678e486ccd94a351729f22a249830", + "urls": [ + "https://repo1.maven.org/maven2/org/glassfish/jersey/core/jersey-common/2.30.1/jersey-common-2.30.1.jar" + ], + "downloaded_file_path": "org/glassfish/jersey/core/jersey-common/2.30.1/jersey-common-2.30.1.jar" + } + }, + "org_xerial_sqlite_jdbc": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_xerial_sqlite_jdbc", + "generating_repository": "maven", + "target_name": "org_xerial_sqlite_jdbc" + } + }, + "com_amazonaws_aws_java_sdk_kms_1_12_544": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_amazonaws_aws_java_sdk_kms_1_12_544", + "sha256": "a79a3768887ea675f2e7b617b361d5250b2128413dbd5d8fa43755a9ecc1b032", + "urls": [ + "https://repo1.maven.org/maven2/com/amazonaws/aws-java-sdk-kms/1.12.544/aws-java-sdk-kms-1.12.544.jar" + ], + "downloaded_file_path": "com/amazonaws/aws-java-sdk-kms/1.12.544/aws-java-sdk-kms-1.12.544.jar" + } + }, + "net_bytebuddy_byte_buddy_1_14_5": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~net_bytebuddy_byte_buddy_1_14_5", + "sha256": "e99761a526df0fefbbd3fe14436b0f953000cdfa5151dc63c0b18d37d9c46f1c", + "urls": [ + "https://repo1.maven.org/maven2/net/bytebuddy/byte-buddy/1.14.5/byte-buddy-1.14.5.jar" + ], + "downloaded_file_path": "net/bytebuddy/byte-buddy/1.14.5/byte-buddy-1.14.5.jar" + } + }, + "junit_junit": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~junit_junit", + "generating_repository": "maven", + "target_name": "junit_junit" + } + }, + "com_google_auto_service_auto_service_annotations_jar_sources_1_0_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_auto_service_auto_service_annotations_jar_sources_1_0_1", + "sha256": "b013ca159b0fea3a0041d3d5fbb3b7e49a819da80a172a01fb17dd28fd98e72b", + "urls": [ + "https://repo1.maven.org/maven2/com/google/auto/service/auto-service-annotations/1.0.1/auto-service-annotations-1.0.1-sources.jar" + ], + "downloaded_file_path": "com/google/auto/service/auto-service-annotations/1.0.1/auto-service-annotations-1.0.1-sources.jar" + } + }, + "com_fasterxml_jackson_jaxrs_jackson_jaxrs_base_jar_sources_2_10_3": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_jaxrs_jackson_jaxrs_base_jar_sources_2_10_3", + "sha256": "6b979c532efa4f68686d85779d7d1f6d4c3de1fa53fbe6996132812b813b1349", + "urls": [ + "https://repo1.maven.org/maven2/com/fasterxml/jackson/jaxrs/jackson-jaxrs-base/2.10.3/jackson-jaxrs-base-2.10.3-sources.jar" + ], + "downloaded_file_path": "com/fasterxml/jackson/jaxrs/jackson-jaxrs-base/2.10.3/jackson-jaxrs-base-2.10.3-sources.jar" + } + }, + "org_apache_commons_commons_pool2_2_11_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_apache_commons_commons_pool2_2_11_1", + "sha256": "ea0505ee7515e58b1ac0e686e4d1a5d9f7d808e251a61bc371aa0595b9963f83", + "urls": [ + "https://repo1.maven.org/maven2/org/apache/commons/commons-pool2/2.11.1/commons-pool2-2.11.1.jar" + ], + "downloaded_file_path": "org/apache/commons/commons-pool2/2.11.1/commons-pool2-2.11.1.jar" + } + }, + "com_google_errorprone_error_prone_annotations_2_22_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_errorprone_error_prone_annotations_2_22_0", + "sha256": "82a027b86541f58d1f9ee020cdf6bebe82acc7a267d3c53a2ea5cd6335932bbd", + "urls": [ + "https://repo1.maven.org/maven2/com/google/errorprone/error_prone_annotations/2.22.0/error_prone_annotations-2.22.0.jar" + ], + "downloaded_file_path": "com/google/errorprone/error_prone_annotations/2.22.0/error_prone_annotations-2.22.0.jar" + } + }, + "io_netty_netty_codec_http": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_http", + "generating_repository": "maven", + "target_name": "io_netty_netty_codec_http" + } + }, + "io_grpc_grpc_services": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_services", + "generating_repository": "maven", + "target_name": "io_grpc_grpc_services" + } + }, + "org_glassfish_jersey_core_jersey_client_2_30_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_glassfish_jersey_core_jersey_client_2_30_1", + "sha256": "fe0aa736ce216e9efb6e17392142b87e704cf09e75a0cb6b3fd2d146937225c1", + "urls": [ + "https://repo1.maven.org/maven2/org/glassfish/jersey/core/jersey-client/2.30.1/jersey-client-2.30.1.jar" + ], + "downloaded_file_path": "org/glassfish/jersey/core/jersey-client/2.30.1/jersey-client-2.30.1.jar" + } + }, + "org_ow2_asm_asm_commons_jar_sources_9_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_ow2_asm_asm_commons_jar_sources_9_2", + "sha256": "6d98839136be45d5b1ffdca0fd2647eb8eaf92cff576648cbbf96f08afd3ed6d", + "urls": [ + "https://repo1.maven.org/maven2/org/ow2/asm/asm-commons/9.2/asm-commons-9.2-sources.jar" + ], + "downloaded_file_path": "org/ow2/asm/asm-commons/9.2/asm-commons-9.2-sources.jar" + } + }, + "net_jcip_jcip_annotations": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~net_jcip_jcip_annotations", + "generating_repository": "maven", + "target_name": "net_jcip_jcip_annotations" + } + }, + "org_bouncycastle_bcprov_jdk18on_1_75": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_bouncycastle_bcprov_jdk18on_1_75", + "sha256": "7f24018e9212dbda61c69212f8d7b1524c28efb978f10df590df3b4ccac47bd5", + "urls": [ + "https://repo1.maven.org/maven2/org/bouncycastle/bcprov-jdk18on/1.75/bcprov-jdk18on-1.75.jar" + ], + "downloaded_file_path": "org/bouncycastle/bcprov-jdk18on/1.75/bcprov-jdk18on-1.75.jar" + } + }, + "org_apache_commons_commons_compress": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_apache_commons_commons_compress", + "generating_repository": "maven", + "target_name": "org_apache_commons_commons_compress" + } + }, + "net_javacrumbs_future_converter_future_converter_java8_common_jar_sources_1_2_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~net_javacrumbs_future_converter_future_converter_java8_common_jar_sources_1_2_0", + "sha256": "8a0f6e7ead50cf9687ae7093bdd8e7f20cd26e42b848105206e18b245ebbc107", + "urls": [ + "https://repo1.maven.org/maven2/net/javacrumbs/future-converter/future-converter-java8-common/1.2.0/future-converter-java8-common-1.2.0-sources.jar" + ], + "downloaded_file_path": "net/javacrumbs/future-converter/future-converter-java8-common/1.2.0/future-converter-java8-common-1.2.0-sources.jar" + } + }, + "com_fasterxml_jackson_core_jackson_databind_jar_sources_2_15_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_core_jackson_databind_jar_sources_2_15_2", + "sha256": "6dafb34ba03f003c998dac3f786bcfd468dfcec39eaf465180bc433ce8566d30", + "urls": [ + "https://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-databind/2.15.2/jackson-databind-2.15.2-sources.jar" + ], + "downloaded_file_path": "com/fasterxml/jackson/core/jackson-databind/2.15.2/jackson-databind-2.15.2-sources.jar" + } + }, + "com_google_api_gax_grpc_2_28_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_api_gax_grpc_2_28_1", + "sha256": "e9e40d1d7354e8f857b05be2208c11722c1b97dc7aaa4b4b125fcf0457b45a03", + "urls": [ + "https://repo1.maven.org/maven2/com/google/api/gax-grpc/2.28.1/gax-grpc-2.28.1.jar", + "https://maven.google.com/com/google/api/gax-grpc/2.28.1/gax-grpc-2.28.1.jar" + ], + "downloaded_file_path": "com/google/api/gax-grpc/2.28.1/gax-grpc-2.28.1.jar" + } + }, + "com_github_oshi_oshi_core": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_oshi_oshi_core", + "generating_repository": "maven", + "target_name": "com_github_oshi_oshi_core" + } + }, + "com_google_errorprone_error_prone_core": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_errorprone_error_prone_core", + "generating_repository": "maven", + "target_name": "com_google_errorprone_error_prone_core" + } + }, + "com_amazonaws_aws_java_sdk_secretsmanager_1_12_544": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_amazonaws_aws_java_sdk_secretsmanager_1_12_544", + "sha256": "b6a0953948949282b46769896c9d1eb1660ed77632c52137fdb72b8372fe685e", + "urls": [ + "https://repo1.maven.org/maven2/com/amazonaws/aws-java-sdk-secretsmanager/1.12.544/aws-java-sdk-secretsmanager-1.12.544.jar" + ], + "downloaded_file_path": "com/amazonaws/aws-java-sdk-secretsmanager/1.12.544/aws-java-sdk-secretsmanager-1.12.544.jar" + } + }, + "software_amazon_ion_ion_java_1_0_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~software_amazon_ion_ion_java_1_0_2", + "sha256": "0d127b205a1fce0abc2a3757a041748651bc66c15cf4c059bac5833b27d471a5", + "urls": [ + "https://repo1.maven.org/maven2/software/amazon/ion/ion-java/1.0.2/ion-java-1.0.2.jar" + ], + "downloaded_file_path": "software/amazon/ion/ion-java/1.0.2/ion-java-1.0.2.jar" + } + }, + "com_amazonaws_aws_java_sdk_kms_jar_sources_1_12_544": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_amazonaws_aws_java_sdk_kms_jar_sources_1_12_544", + "sha256": "cc195a2be0a245eaee362cacd7c2f119522cea9c8f8b89db49f0634f05b15831", + "urls": [ + "https://repo1.maven.org/maven2/com/amazonaws/aws-java-sdk-kms/1.12.544/aws-java-sdk-kms-1.12.544-sources.jar" + ], + "downloaded_file_path": "com/amazonaws/aws-java-sdk-kms/1.12.544/aws-java-sdk-kms-1.12.544-sources.jar" + } + }, + "org_yaml_snakeyaml_jar_sources_2_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_yaml_snakeyaml_jar_sources_2_2", + "sha256": "8f7cf911cf63db55fd980a926d155bd846317737351a2f48ef1c1088c414538a", + "urls": [ + "https://repo1.maven.org/maven2/org/yaml/snakeyaml/2.2/snakeyaml-2.2-sources.jar" + ], + "downloaded_file_path": "org/yaml/snakeyaml/2.2/snakeyaml-2.2-sources.jar" + } + }, + "com_github_docker_java_docker_java": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_github_docker_java_docker_java", + "generating_repository": "maven", + "target_name": "com_github_docker_java_docker_java" + } + }, + "commons_codec_commons_codec_1_15": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~commons_codec_commons_codec_1_15", + "sha256": "b3e9f6d63a790109bf0d056611fbed1cf69055826defeb9894a71369d246ed63", + "urls": [ + "https://repo1.maven.org/maven2/commons-codec/commons-codec/1.15/commons-codec-1.15.jar" + ], + "downloaded_file_path": "commons-codec/commons-codec/1.15/commons-codec-1.15.jar" + } + }, + "io_grpc_grpc_googleapis_1_55_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_googleapis_1_55_1", + "sha256": "d77f33f3c78b99c0c604def7efe27f912b9cee49219698180101a064d67bd268", + "urls": [ + "https://repo1.maven.org/maven2/io/grpc/grpc-googleapis/1.55.1/grpc-googleapis-1.55.1.jar", + "https://maven.google.com/io/grpc/grpc-googleapis/1.55.1/grpc-googleapis-1.55.1.jar" + ], + "downloaded_file_path": "io/grpc/grpc-googleapis/1.55.1/grpc-googleapis-1.55.1.jar" + } + }, + "org_apache_commons_commons_lang3": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_apache_commons_commons_lang3", + "generating_repository": "maven", + "target_name": "org_apache_commons_commons_lang3" + } + }, + "com_google_guava_guava": { + "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", + "ruleClassName": "compat_repository", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_guava_guava", + "generating_repository": "maven", + "target_name": "com_google_guava_guava" + } + }, + "com_google_code_findbugs_jsr305_jar_sources_3_0_2": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~com_google_code_findbugs_jsr305_jar_sources_3_0_2", + "sha256": "1c9e85e272d0708c6a591dc74828c71603053b48cc75ae83cce56912a2aa063b", + "urls": [ + "https://repo1.maven.org/maven2/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2-sources.jar" + ], + "downloaded_file_path": "com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2-sources.jar" + } + }, + "io_netty_netty_common_4_1_97_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_common_4_1_97_Final", + "sha256": "a8aca0c8e9347acc75c885ecc749195d9775369aa520b9276f2d1128210a6c17", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-common/4.1.97.Final/netty-common-4.1.97.Final.jar" + ], + "downloaded_file_path": "io/netty/netty-common/4.1.97.Final/netty-common-4.1.97.Final.jar" + } + }, + "io_netty_netty_handler_4_1_86_Final": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~io_netty_netty_handler_4_1_86_Final", + "sha256": "e69b42292929b278dc522e25177ddf7c54025484b55879f8227349adfbe1c04d", + "urls": [ + "https://repo1.maven.org/maven2/io/netty/netty-handler/4.1.86.Final/netty-handler-4.1.86.Final.jar", + "https://maven.google.com/io/netty/netty-handler/4.1.86.Final/netty-handler-4.1.86.Final.jar" + ], + "downloaded_file_path": "io/netty/netty-handler/4.1.86.Final/netty-handler-4.1.86.Final.jar" + } + }, + "org_slf4j_slf4j_api_jar_sources_2_0_9": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_slf4j_slf4j_api_jar_sources_2_0_9", + "sha256": "0d83bc49452416dd121ee41cebf41cdc64b69e7f7fdc97c2762ec406336c7ad3", + "urls": [ + "https://repo1.maven.org/maven2/org/slf4j/slf4j-api/2.0.9/slf4j-api-2.0.9-sources.jar" + ], + "downloaded_file_path": "org/slf4j/slf4j-api/2.0.9/slf4j-api-2.0.9-sources.jar" + } + }, + "redis_clients_jedis_4_3_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~redis_clients_jedis_4_3_1", + "sha256": "597894244e42e1b3171470e9294781824dbf617949e77aa0230eaa3ec4772db4", + "urls": [ + "https://repo1.maven.org/maven2/redis/clients/jedis/4.3.1/jedis-4.3.1.jar" + ], + "downloaded_file_path": "redis/clients/jedis/4.3.1/jedis-4.3.1.jar" + } + }, + "org_glassfish_jersey_connectors_jersey_apache_connector_jar_sources_2_30_1": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_glassfish_jersey_connectors_jersey_apache_connector_jar_sources_2_30_1", + "sha256": "189accdc78e1ac392d6ae16d62d98b3567ca4fb836524d4f79e485c5455a9b93", + "urls": [ + "https://repo1.maven.org/maven2/org/glassfish/jersey/connectors/jersey-apache-connector/2.30.1/jersey-apache-connector-2.30.1-sources.jar" + ], + "downloaded_file_path": "org/glassfish/jersey/connectors/jersey-apache-connector/2.30.1/jersey-apache-connector-2.30.1-sources.jar" + } + }, + "org_xerial_sqlite_jdbc_jar_sources_3_34_0": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "name": "rules_jvm_external~5.3~maven~org_xerial_sqlite_jdbc_jar_sources_3_34_0", + "sha256": "e0c494fe9e7b719a0fe270bf19e63b26c821fce0a29c9066f5d1c39b9d38a6c0", + "urls": [ + "https://repo1.maven.org/maven2/org/xerial/sqlite-jdbc/3.34.0/sqlite-jdbc-3.34.0-sources.jar" + ], + "downloaded_file_path": "org/xerial/sqlite-jdbc/3.34.0/sqlite-jdbc-3.34.0-sources.jar" + } + } + } + } + } + } +} diff --git a/deps.bzl b/deps.bzl index ff66198bc9..1e44e16094 100644 --- a/deps.bzl +++ b/deps.bzl @@ -5,26 +5,8 @@ buildfarm dependencies that can be imported into other WORKSPACE files load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive", "http_file", "http_jar") load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") -RULES_JVM_EXTERNAL_TAG = "5.3" -RULES_JVM_EXTERNAL_SHA = "d31e369b854322ca5098ea12c69d7175ded971435e55c18dd9dd5f29cc5249ac" - def archive_dependencies(third_party): return [ - { - "name": "platforms", - "urls": [ - "https://mirror.bazel.build/github.com/bazelbuild/platforms/releases/download/0.0.7/platforms-0.0.7.tar.gz", - "https://github.com/bazelbuild/platforms/releases/download/0.0.7/platforms-0.0.7.tar.gz", - ], - "sha256": "3a561c99e7bdbe9173aa653fd579fe849f1d8d67395780ab4770b1f381431d51", - }, - { - "name": "rules_jvm_external", - "strip_prefix": "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG, - "sha256": RULES_JVM_EXTERNAL_SHA, - "url": "https://github.com/bazelbuild/rules_jvm_external/releases/download/%s/rules_jvm_external-%s.tar.gz" % (RULES_JVM_EXTERNAL_TAG, RULES_JVM_EXTERNAL_TAG), - }, - # Needed for "well-known protos" and @com_google_protobuf//:protoc. { "name": "com_google_protobuf", @@ -32,19 +14,13 @@ def archive_dependencies(third_party): "strip_prefix": "protobuf-25.0", "urls": ["https://github.com/protocolbuffers/protobuf/archive/v25.0.zip"], }, - { - "name": "com_github_bazelbuild_buildtools", - "sha256": "a02ba93b96a8151b5d8d3466580f6c1f7e77212c4eb181cba53eb2cae7752a23", - "strip_prefix": "buildtools-3.5.0", - "urls": ["https://github.com/bazelbuild/buildtools/archive/3.5.0.tar.gz"], - }, - # Needed for @grpc_java//compiler:grpc_java_plugin. { "name": "io_grpc_grpc_java", "sha256": "b8fb7ae4824fb5a5ae6e6fa26ffe2ad7ab48406fdeee54e8965a3b5948dd957e", "strip_prefix": "grpc-java-1.56.1", "urls": ["https://github.com/grpc/grpc-java/archive/v1.56.1.zip"], + # Bzlmod: Waiting for https://github.com/bazelbuild/bazel-central-registry/issues/353 }, { "name": "rules_pkg", @@ -53,14 +29,7 @@ def archive_dependencies(third_party): "https://mirror.bazel.build/github.com/bazelbuild/rules_pkg/releases/download/0.9.0/rules_pkg-0.9.0.tar.gz", "https://github.com/bazelbuild/rules_pkg/releases/download/0.9.0/rules_pkg-0.9.0.tar.gz", ], - }, - { - "name": "rules_license", - "sha256": "4531deccb913639c30e5c7512a054d5d875698daeb75d8cf90f284375fe7c360", - "urls": [ - "https://mirror.bazel.build/github.com/bazelbuild/rules_license/releases/download/0.0.7/rules_license-0.0.7.tar.gz", - "https://github.com/bazelbuild/rules_license/releases/download/0.0.7/rules_license-0.0.7.tar.gz", - ], + # Bzlmod : Waiting for >0.9.1 for https://github.com/bazelbuild/rules_pkg/pull/766 to be released }, # The APIs that we implement. @@ -82,12 +51,6 @@ def archive_dependencies(third_party): "strip_prefix": "remote-apis-636121a32fa7b9114311374e4786597d8e7a69f3", "url": "https://github.com/bazelbuild/remote-apis/archive/636121a32fa7b9114311374e4786597d8e7a69f3.zip", }, - { - "name": "rules_cc", - "sha256": "2037875b9a4456dce4a79d112a8ae885bbc4aad968e6587dca6e64f3a0900cdf", - "strip_prefix": "rules_cc-0.0.9", - "url": "https://github.com/bazelbuild/rules_cc/releases/download/0.0.9/rules_cc-0.0.9.tar.gz", - }, # Used to format proto files { @@ -107,25 +70,6 @@ def archive_dependencies(third_party): "patch_args": ["-p0"], "patches": ["%s:docker_go_toolchain.patch" % third_party], }, - - # Updated versions of io_bazel_rules_docker dependencies for bazel compatibility - { - "name": "io_bazel_rules_go", - "sha256": "d6ab6b57e48c09523e93050f13698f708428cfd5e619252e369d377af6597707", - "urls": [ - "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.43.0/rules_go-v0.43.0.zip", - "https://github.com/bazelbuild/rules_go/releases/download/v0.43.0/rules_go-v0.43.0.zip", - ], - }, - { - "name": "bazel_gazelle", - "sha256": "b7387f72efb59f876e4daae42f1d3912d0d45563eac7cb23d1de0b094ab588cf", - "urls": [ - "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.34.0/bazel-gazelle-v0.34.0.tar.gz", - "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.34.0/bazel-gazelle-v0.34.0.tar.gz", - ], - }, - # Bazel is referenced as a dependency so that buildfarm can access the linux-sandbox as a potential execution wrapper. { "name": "bazel", diff --git a/src/test/java/build/buildfarm/examples/ExampleConfigsTest.java b/src/test/java/build/buildfarm/examples/ExampleConfigsTest.java index 6033429f0e..ac1c605e80 100644 --- a/src/test/java/build/buildfarm/examples/ExampleConfigsTest.java +++ b/src/test/java/build/buildfarm/examples/ExampleConfigsTest.java @@ -35,16 +35,14 @@ public void skipWindows() { @Test public void shardWorkerConfig() throws IOException { Path configPath = - Paths.get( - System.getenv("TEST_SRCDIR"), "build_buildfarm", "examples", "config.minimal.yml"); + Paths.get(System.getenv("TEST_SRCDIR"), "_main", "examples", "config.minimal.yml"); BuildfarmConfigs configs = BuildfarmConfigs.getInstance(); configs.loadConfigs(configPath); } @Test public void fullConfig() throws IOException { - Path configPath = - Paths.get(System.getenv("TEST_SRCDIR"), "build_buildfarm", "examples", "config.yml"); + Path configPath = Paths.get(System.getenv("TEST_SRCDIR"), "_main", "examples", "config.yml"); BuildfarmConfigs configs = BuildfarmConfigs.getInstance(); configs.loadConfigs(configPath); } From 373cb215a757ca18cf1ee7fefaa83c0dbb693c44 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Tue, 9 Jan 2024 22:16:30 -0800 Subject: [PATCH 201/311] fix(coverage): coverage numbers are not accurate (#1609) The awk was pulling out the denominator of the metric, not the percent. Adjust the field. Before: ``` current line coverage: 1625% current function coverage: 340% ``` after: ``` current line coverage: 42% current function coverage: 51% ``` --- generate_coverage.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/generate_coverage.sh b/generate_coverage.sh index 7560334dbc..703ad93883 100755 --- a/generate_coverage.sh +++ b/generate_coverage.sh @@ -72,8 +72,8 @@ gate_lcov_results() { lcov_results=`$LCOV_TOOL --summary $traces 2>&1` # extract our percentage numbers - local line_percentage=$(echo "$lcov_results" | tr '\n' ' ' | awk '{print $8}' | sed 's/.$//') - local function_percentage=$(echo "$lcov_results" | tr '\n' ' ' | awk '{print $14}' | sed 's/.$//') + local line_percentage=$(echo "$lcov_results" | tr '\n' ' ' | awk '{print $5}' | sed 's/.$//') + local function_percentage=$(echo "$lcov_results" | tr '\n' ' ' | awk '{print $11}' | sed 's/.$//') line_percentage=${line_percentage%.*} function_percentage=${function_percentage%.*} From b40c14b051449382271ba7e221690d5e4867911a Mon Sep 17 00:00:00 2001 From: Andrew Rothstein Date: Wed, 10 Jan 2024 14:58:50 -0500 Subject: [PATCH 202/311] Add `helm lint` CI job. Split tag/release for the Helm chart from the entire repo with tags: `helm/X.Y.Z-b1` (#1602) * add helm chart linting stage, bundle chart on helm/* tags * fix triggers * try try again * always lint before bundling * extract the helm chart version from the git tag ref * fix name * tickle the beast * too much stack overflow * better names * that's output * gussy up readme * simplify * stage 0.2.2 * put extraVolumeMounts under .Values.shardWorker * omit defaults * leave out emacs gitignore * wrong example --- .../workflows/buildfarm-helm-chart-lint.yml | 24 ++++++++++++++ .../buildfarm-helm-chart-publish.yml | 31 ++++++++++++++----- README.md | 4 ++- kubernetes/helm-charts/buildfarm/Chart.yaml | 2 +- .../templates/shard-worker/statefulsets.yaml | 18 +++++------ kubernetes/helm-charts/buildfarm/values.yaml | 27 +++++++++------- 6 files changed, 76 insertions(+), 30 deletions(-) create mode 100644 .github/workflows/buildfarm-helm-chart-lint.yml diff --git a/.github/workflows/buildfarm-helm-chart-lint.yml b/.github/workflows/buildfarm-helm-chart-lint.yml new file mode 100644 index 0000000000..c301732145 --- /dev/null +++ b/.github/workflows/buildfarm-helm-chart-lint.yml @@ -0,0 +1,24 @@ +--- +name: Lint Helm Chart + +on: + push: + paths: + - kubernetes/helm-charts/buildfarm/** + +env: + CHART_ROOT: kubernetes/helm-charts/buildfarm + +jobs: + lint: + name: Lint Helm Chart + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - id: helm-lint + name: Lint Helm Chart + run: |- + set -ex + helm dep up "${CHART_ROOT}" + helm lint "${CHART_ROOT}" diff --git a/.github/workflows/buildfarm-helm-chart-publish.yml b/.github/workflows/buildfarm-helm-chart-publish.yml index 0207d1593b..0c43525e8c 100644 --- a/.github/workflows/buildfarm-helm-chart-publish.yml +++ b/.github/workflows/buildfarm-helm-chart-publish.yml @@ -4,22 +4,39 @@ name: Package and Publish Helm Chart on: push: tags: - - '*' + - 'helm/*' env: GH_TOKEN: ${{ github.token }} + CHART_ROOT: kubernetes/helm-charts/buildfarm jobs: build: - if: github.repository == 'bazelbuild/bazel-buildfarm' - name: Package and Release BuildFarm Helm Chart + name: Lint, Package, and Release BuildFarm Helm Chart runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 - - name: helm package + uses: actions/checkout@v4 + - id: get-chart-ver + name: Extracting Helm Chart Version from Tag + run: | + set -ex + echo "chart_ver=$(echo $GITHUB_REF | cut -d / -f 4)" >> $GITHUB_OUTPUT + - id: set-chart-yaml-version + name: Etching Helm Chart Version into Chart.yaml for Packaging + run: | + set -ex + echo setting Chart version to \ + "${{ steps.get-chart-ver.outputs.chart_ver }}" \ + in ${CHART_ROOT}/Chart.yaml + yq -i \ + '.version |= "${{ steps.get-chart-ver.outputs.chart_ver }}"' \ + ${CHART_ROOT}/Chart.yaml + - id: helm-lint-package-release + name: Helm Chart Lint, Package, and Release run: |- set -ex - helm dep up kubernetes/helm-charts/buildfarm - helm package kubernetes/helm-charts/buildfarm + helm dep up "${CHART_ROOT}" + helm lint "${CHART_ROOT}" + helm package "${CHART_ROOT}" gh release create "${{ github.ref_name }}" *.tgz diff --git a/README.md b/README.md index fa66df79c8..4aaeec6a49 100644 --- a/README.md +++ b/README.md @@ -138,9 +138,11 @@ buildfarm_images() To install with helm: ```bash +# https://github.com/bazelbuild/bazel-buildfarm/releases/download/helm%2F0.2.2/buildfarm-0.2.2.tgz +CHART_VER="0.2.2" helm install \ -n bazel-buildfarm \ --create-namespace \ bazel-buildfarm \ - "https://github.com/bazelbuild/bazel-buildfarm/releases/download/${BUILDFARM_VERSION:-2.8.0}/buildfarm-${CHART_VERSION:-0.2.0}.tgz" + "https://github.com/bazelbuild/bazel-buildfarm/releases/download/helm%2F${CHART_VER}/buildfarm-${CHART_VER}.tgz" ``` diff --git a/kubernetes/helm-charts/buildfarm/Chart.yaml b/kubernetes/helm-charts/buildfarm/Chart.yaml index dc92b0f61b..593568d011 100644 --- a/kubernetes/helm-charts/buildfarm/Chart.yaml +++ b/kubernetes/helm-charts/buildfarm/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.2.0 +version: 0.2.2 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/kubernetes/helm-charts/buildfarm/templates/shard-worker/statefulsets.yaml b/kubernetes/helm-charts/buildfarm/templates/shard-worker/statefulsets.yaml index 62706a61ac..ce5dbc9139 100644 --- a/kubernetes/helm-charts/buildfarm/templates/shard-worker/statefulsets.yaml +++ b/kubernetes/helm-charts/buildfarm/templates/shard-worker/statefulsets.yaml @@ -74,20 +74,20 @@ spec: readOnly: true - mountPath: /tmp/worker name: {{ include "buildfarm.fullname" . }}-shard-worker-data - {{- with .Values.extraVolumeMounts }} - {{- tpl (toYaml .) $ | nindent 12 -}} - {{- end }} + {{- with .Values.shardWorker.extraVolumeMounts }} + {{- tpl (toYaml .) $ | nindent 12 -}} + {{- end }} + {{- with .Values.shardWorker.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} + {{- tpl (toYaml .) $ | nindent 6 -}} {{- end }} + {{- with .Values.shardWorker.affinity }} - affinity: - {{- toYaml . | nindent 8 }} + {{- tpl (toYaml .) $ | nindent 6 -}} {{- end }} + {{- with .Values.shardWorker.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} + {{- tpl (toYaml .) $ | nindent 6 -}} {{- end }} volumes: - configMap: diff --git a/kubernetes/helm-charts/buildfarm/values.yaml b/kubernetes/helm-charts/buildfarm/values.yaml index f1e21a97c9..c18593a7e8 100644 --- a/kubernetes/helm-charts/buildfarm/values.yaml +++ b/kubernetes/helm-charts/buildfarm/values.yaml @@ -131,22 +131,25 @@ shardWorker: type: ClusterIP port: 8982 - nodeSelector: {} - tolerations: [] - affinity: {} - extraVolumes: [] - # - name: additionalSecret - # secret: - # secretName: my-secret - # defaultMode: 0600 + #nodeSelector: {} + #tolerations: [] + #affinity: {} + + #extraVolumes: + # - name: additionalSecret + # secret: + # secretName: my-secret + # defaultMode: 0600 + + #extraVolumeMounts: + # - name: customConfig + # mountPath: /mnt/config + # readOnly: true - extraVolumeMounts: [] - # - name: customConfig - # mountPath: /mnt/config - # readOnly: true extraEnv: - name: JAVABIN value: "/usr/bin/java" + serviceMonitor: ## If true, a ServiceMonitor CRD is created for a prometheus operator ## https://github.com/coreos/prometheus-operator From d155c0be466a59733a0fb06a66b9259c7457d90d Mon Sep 17 00:00:00 2001 From: amishra-u <119983081+amishra-u@users.noreply.github.com> Date: Fri, 12 Jan 2024 11:26:32 -0800 Subject: [PATCH 203/311] Publish storage worker and execute worker pool size in prometheus (#1606) * Publish storage worker and execute worker pool size in prometheus * run formatter * add doc --------- Co-authored-by: Yuriy Belenitsky --- _site/docs/metrics/metrics.md | 8 ++++++++ .../buildfarm/instance/shard/ServerInstance.java | 12 ++++++++++++ 2 files changed, 20 insertions(+) diff --git a/_site/docs/metrics/metrics.md b/_site/docs/metrics/metrics.md index 6079b7e9b7..c0bfb4a75a 100644 --- a/_site/docs/metrics/metrics.md +++ b/_site/docs/metrics/metrics.md @@ -100,6 +100,14 @@ The number of dispatched operations that have been requeued Gauge of the number of workers available +**storage_worker_pool_size** + +Gauge of the number of storage workers available + +**execute_worker_pool_size** + +Gauge of the number of execute workers available. + **queue_size** Gauge of the size of the queue (using a queue_name label for each individual queue) diff --git a/src/main/java/build/buildfarm/instance/shard/ServerInstance.java b/src/main/java/build/buildfarm/instance/shard/ServerInstance.java index 50c1de2f6f..5f7173150c 100644 --- a/src/main/java/build/buildfarm/instance/shard/ServerInstance.java +++ b/src/main/java/build/buildfarm/instance/shard/ServerInstance.java @@ -209,6 +209,16 @@ public class ServerInstance extends NodeInstance { // Other metrics from the backplane private static final Gauge workerPoolSize = Gauge.build().name("worker_pool_size").help("Active worker pool size.").register(); + private static final Gauge storageWorkerPoolSize = + Gauge.build() + .name("storage_worker_pool_size") + .help("Active storage worker pool size.") + .register(); + private static final Gauge executeWorkerPoolSize = + Gauge.build() + .name("execute_worker_pool_size") + .help("Active execute worker pool size.") + .register(); private static final Gauge queueSize = Gauge.build().name("queue_size").labelNames("queue_name").help("Queue size.").register(); @@ -511,6 +521,8 @@ public void run() { TimeUnit.SECONDS.sleep(30); BackplaneStatus backplaneStatus = backplaneStatus(); workerPoolSize.set(backplaneStatus.getActiveWorkersCount()); + executeWorkerPoolSize.set(backplaneStatus.getActiveExecuteWorkersCount()); + storageWorkerPoolSize.set(backplaneStatus.getActiveStorageWorkersCount()); dispatchedOperationsSize.set(backplaneStatus.getDispatchedSize()); preQueueSize.set(backplaneStatus.getPrequeue().getSize()); updateQueueSizes(backplaneStatus.getOperationQueue().getProvisionsList()); From 646d9565fa2edee877163f3b3358274347eb2e96 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Mon, 22 Jan 2024 06:41:30 -0800 Subject: [PATCH 204/311] bf-cat Output salt/platform, deindent command (#1615) --- src/main/java/build/buildfarm/tools/Cat.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/build/buildfarm/tools/Cat.java b/src/main/java/build/buildfarm/tools/Cat.java index bca404b3c1..f80e579f64 100644 --- a/src/main/java/build/buildfarm/tools/Cat.java +++ b/src/main/java/build/buildfarm/tools/Cat.java @@ -101,8 +101,7 @@ private static void printAction(ByteString actionBlob) { } private static void printAction(int level, Action action) { - indentOut( - level + 1, "Command Digest: Command " + DigestUtil.toString(action.getCommandDigest())); + indentOut(level, "Command Digest: Command " + DigestUtil.toString(action.getCommandDigest())); indentOut( level, "Input Root Digest: Directory " + DigestUtil.toString(action.getInputRootDigest())); indentOut(level, "DoNotCache: " + (action.getDoNotCache() ? "true" : "false")); @@ -113,6 +112,8 @@ private static void printAction(int level, Action action) { + (action.getTimeout().getSeconds() + action.getTimeout().getNanos() / 1e9) + "s"); } + indentOut(level, "Salt: " + action.getSalt()); + indentOut(level, "Platform: " + action.getPlatform()); } private static void printCommand(ByteString commandBlob) { From ea35e56c72287ca89fbf216d6ed2e177aa85cb26 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Mon, 22 Jan 2024 07:00:59 -0800 Subject: [PATCH 205/311] Provide hashedName in BackplaneStatus Queue Name (#1616) Avoid stripping the existingHash, used to calculate the slot with suffix modifiers for queue balancing. Client presentation may also move to presenting each balanced queue name, removing the coordinated calculation on the client. The name could only have been used by a client prior for name presentation or determination of queue names in redis from slot arrangement. --- .../build/buildfarm/common/redis/BalancedRedisQueue.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/build/buildfarm/common/redis/BalancedRedisQueue.java b/src/main/java/build/buildfarm/common/redis/BalancedRedisQueue.java index 9123f5eaf9..044a3b25ce 100644 --- a/src/main/java/build/buildfarm/common/redis/BalancedRedisQueue.java +++ b/src/main/java/build/buildfarm/common/redis/BalancedRedisQueue.java @@ -330,7 +330,11 @@ public QueueStatus status(JedisCluster jedis) { } // build proto - return QueueStatus.newBuilder().setName(name).setSize(size).addAllInternalSizes(sizes).build(); + return QueueStatus.newBuilder() + .setName(RedisHashtags.hashedName(name, originalHashtag)) + .setSize(size) + .addAllInternalSizes(sizes) + .build(); } /** From fe2c51c3cb23898232677081948943b7f8026a10 Mon Sep 17 00:00:00 2001 From: coder1363691 <67998200+coder1363691@users.noreply.github.com> Date: Thu, 25 Jan 2024 12:16:10 +0800 Subject: [PATCH 206/311] set expire and drop invocationId (#1589) * set expire and drop invocationId * fix format * patch configuration doc * fix typo * re-run ci use luxe's patch * set expire when every active operation insert * fix return code * fix ci if statement --------- Co-authored-by: wangpengfei.pfwang Co-authored-by: George Gensure --- _site/docs/configuration/configuration.md | 1 + examples/config.yml | 1 + src/main/java/build/buildfarm/common/config/Backplane.java | 1 + .../java/build/buildfarm/instance/shard/Operations.java | 6 +++++- 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/_site/docs/configuration/configuration.md b/_site/docs/configuration/configuration.md index 9e9d0ab0f9..ba85d4a6c5 100644 --- a/_site/docs/configuration/configuration.md +++ b/_site/docs/configuration/configuration.md @@ -206,6 +206,7 @@ server: | maxPreQueueDepth | Integer, _1000000_ | | | Maximum lengh that the arrival queue is allowed to reach to control load on the Redis cluster | | priorityQueue | boolean, _false_ | | | Priority queue type allows prioritizing operations based on Bazel's --remote_execution_priority= flag | | timeout | Integer, _10000_ | | | Default timeout | +| maxInvocationIdTimeout | Integer, _604800_ | | | Maximum TTL (Time-to-Live in second) of invocationId keys in RedisBackplane | | maxAttempts | Integer, _20_ | | | Maximum number of execution attempts | | cacheCas | boolean, _false_ | | | | diff --git a/examples/config.yml b/examples/config.yml index c02ff4cfcb..4e66e00bd8 100644 --- a/examples/config.yml +++ b/examples/config.yml @@ -79,6 +79,7 @@ backplane: priorityQueue: false priorityPollIntervalMillis: 100 timeout: 10000 + maxInvocationIdTimeout: 604800 maxAttempts: 20 cacheCas: false queues: diff --git a/src/main/java/build/buildfarm/common/config/Backplane.java b/src/main/java/build/buildfarm/common/config/Backplane.java index 16a90e9111..1693e378e6 100644 --- a/src/main/java/build/buildfarm/common/config/Backplane.java +++ b/src/main/java/build/buildfarm/common/config/Backplane.java @@ -40,6 +40,7 @@ public enum BACKPLANE_TYPE { private String operationChannelPrefix = "OperationChannel"; private String casPrefix = "ContentAddressableStorage"; private int casExpire = 604800; // 1 Week + private int maxInvocationIdTimeout = 604800; @Getter(AccessLevel.NONE) private boolean subscribeToBackplane = true; // deprecated diff --git a/src/main/java/build/buildfarm/instance/shard/Operations.java b/src/main/java/build/buildfarm/instance/shard/Operations.java index 0088bdf038..c114fe32ef 100644 --- a/src/main/java/build/buildfarm/instance/shard/Operations.java +++ b/src/main/java/build/buildfarm/instance/shard/Operations.java @@ -14,6 +14,7 @@ package build.buildfarm.instance.shard; +import build.buildfarm.common.config.BuildfarmConfigs; import build.buildfarm.common.redis.RedisMap; import java.util.Map; import java.util.Set; @@ -28,6 +29,7 @@ * information about the operations that ran. */ public class Operations { + private static BuildfarmConfigs configs = BuildfarmConfigs.getInstance(); /** * @field operationIds * @brief A mapping from operationID -> operation @@ -98,7 +100,9 @@ public void insert( // We also store a mapping from invocationID -> operationIDs // This is a common lookup that needs to be performant. - jedis.sadd(invocationId, operationId); + if (invocationId != "" && jedis.sadd(invocationId, operationId) == 1) { + jedis.expire(invocationId, configs.getBackplane().getMaxInvocationIdTimeout()); + } } /** From b7980a03e864a81920f0d5af3f8c2ade19c27909 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Thu, 25 Jan 2024 09:16:30 -0800 Subject: [PATCH 207/311] Add OSSF scorecard (#1618) * feat: add OSSF Scorecards workflow Adding OSSF Scorecards workflow as github action. It runs periodially. Output goes into Code Scanning alerts of GitHub. * docs(README): add some badges - OSSF Scorecard - License (from GitHub) - latest Release (from GitHub) --- .github/workflows/scorecards.yml | 68 ++++++++++++++++++++++++++++++++ README.md | 4 ++ 2 files changed, 72 insertions(+) create mode 100644 .github/workflows/scorecards.yml diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml new file mode 100644 index 0000000000..04f97ff17e --- /dev/null +++ b/.github/workflows/scorecards.yml @@ -0,0 +1,68 @@ +name: Scorecards supply-chain security +on: + # For Branch-Protection check. Only the default branch is supported. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection + branch_protection_rule: + # To guarantee Maintained check is occasionally updated. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained + schedule: + - cron: "23 2 * * 5" + push: + branches: ["main"] + +# Declare default permissions as read only. +permissions: read-all + +jobs: + analysis: + name: Scorecards analysis + runs-on: ubuntu-latest + permissions: + # Needed to upload the results to code-scanning dashboard. + security-events: write + # Needed to publish results and get a badge (see publish_results below). + id-token: write + # Uncomment the permissions below if installing in a private repository. + # contents: read + # actions: read + + steps: + - name: "Checkout code" + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + with: + persist-credentials: false + + - name: "Run analysis" + uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1 + with: + results_file: results.sarif + results_format: sarif + # (Optional) "write" PAT token. Uncomment the `repo_token` line below if: + # - you want to enable the Branch-Protection check on a *public* repository, or + # - you are installing Scorecards on a *private* repository + # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat. + # repo_token: ${{ secrets.SCORECARD_TOKEN }} + + # Public repositories: + # - Publish results to OpenSSF REST API for easy access by consumers + # - Allows the repository to include the Scorecard badge. + # - See https://github.com/ossf/scorecard-action#publishing-results. + # For private repositories: + # - `publish_results` will always be set to `false`, regardless + # of the value entered here. + publish_results: true + + # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF + # format to the repository Actions tab. + - name: "Upload artifact" + uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + with: + name: SARIF file + path: results.sarif + retention-days: 5 + + # Upload the results to GitHub's code scanning dashboard. + - name: "Upload to code-scanning" + uses: github/codeql-action/upload-sarif@4759df8df70c5ebe7042c3029bbace20eee13edd # v2.23.1 + with: + sarif_file: results.sarif diff --git a/README.md b/README.md index 4aaeec6a49..385d6e5e9b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ # Bazel Buildfarm ![Build status](https://badge.buildkite.com/45f4fd4c0cfb95f7705156a4119641c6d5d6c310452d6e65a4.svg?branch=main) +[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/bazelbuild/bazel-buildfarm/badge)](https://securityscorecards.dev/viewer/?uri=github.com/bazelbuild/bazel-buildfarm) +![GitHub License](https://img.shields.io/github/license/bazelbuild/bazel-buildfarm) +![GitHub Release](https://img.shields.io/github/v/release/bazelbuild/bazel-buildfarm) + This repository hosts the [Bazel](https://bazel.build) remote caching and execution system. From 8a7873be179c1cb6809708a11d7ef04849695f8f Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Thu, 25 Jan 2024 09:16:53 -0800 Subject: [PATCH 208/311] chore: remove rules_oss_audit (#1617) Remove rules_oss_audit and accompanying documentation --- .bazelci/presubmit.yml | 5 ++--- BUILD | 13 ------------- WORKSPACE | 8 -------- _site/docs/security/security.md | 21 --------------------- deps.bzl | 8 -------- third_party/rules_oss_audit_pyyaml.patch | 7 ------- 6 files changed, 2 insertions(+), 60 deletions(-) delete mode 100644 _site/docs/security/security.md delete mode 100644 third_party/rules_oss_audit_pyyaml.patch diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index 43aeba5380..687ffc1781 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -63,8 +63,7 @@ tasks: USE_BAZEL_VERSION: 17be878292730359c9c90efdceabed26126df7ae build_flags: - "--cxxopt=-std=c++14" - # FIXME: remove audit subtraction when https://github.com/bazelbuild/bazel-buildfarm/issues/1595 fixed - - "--build_tag_filters=-container,-audit" + - "--build_tag_filters=-container" build_targets: - "..." test_flags: @@ -74,7 +73,7 @@ tasks: windows: name: "Unit Tests" build_flags: - - "--build_tag_filters=-container,-audit" + - "--build_tag_filters=-container" build_targets: - "..." test_flags: diff --git a/BUILD b/BUILD index d82be09f83..a749c0caa3 100644 --- a/BUILD +++ b/BUILD @@ -3,7 +3,6 @@ load("@io_bazel_rules_docker//java:image.bzl", "java_image") load("@io_bazel_rules_docker//docker/package_managers:download_pkgs.bzl", "download_pkgs") load("@io_bazel_rules_docker//docker/package_managers:install_pkgs.bzl", "install_pkgs") load("@io_bazel_rules_docker//container:container.bzl", "container_image", "container_push") -load("@rules_oss_audit//oss_audit:java/oss_audit.bzl", "oss_audit") load("//:jvm_flags.bzl", "server_jvm_flags", "worker_jvm_flags") package(default_visibility = ["//visibility:public"]) @@ -137,12 +136,6 @@ java_image( ], ) -oss_audit( - name = "buildfarm-server-audit", - src = "//src/main/java/build/buildfarm:buildfarm-server", - tags = ["audit"], -) - # A worker image may need additional packages installed that are not in the base image. # We use download/install rules to extend an upstream image. # Download cgroup-tools so that the worker is able to restrict actions via control groups. @@ -190,12 +183,6 @@ java_image( ], ) -oss_audit( - name = "buildfarm-shard-worker-audit", - src = "//src/main/java/build/buildfarm:buildfarm-shard-worker", - tags = ["audit"], -) - # Below targets push public docker images to bazelbuild dockerhub. container_push( diff --git a/WORKSPACE b/WORKSPACE index 0d4b9462d5..3ce5827108 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -8,14 +8,6 @@ load(":defs.bzl", "buildfarm_init") buildfarm_init() -load("@rules_oss_audit//oss_audit:repositories.bzl", "rules_oss_audit_dependencies") - -rules_oss_audit_dependencies() - -load("@rules_oss_audit//oss_audit:setup.bzl", "rules_oss_audit_setup") - -rules_oss_audit_setup() - load("@maven//:compat.bzl", "compat_repositories") compat_repositories() diff --git a/_site/docs/security/security.md b/_site/docs/security/security.md deleted file mode 100644 index a476000546..0000000000 --- a/_site/docs/security/security.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -layout: default -title: Security -has_children: false -nav_order: 6 ---- - -# Auditing Buildfarm Artifacts -The complexities of identifying and tracking open-source software (OSS) to comply with license requirements adds friction to the development and integration process. We solve this problem for buildfarm artifacts by creating an accurate "bill of materials" (BOM) containing OSS and third-party packages used to create our deployment. - -To audit buildfarm artifacts run the following: -``` -bazel build :buildfarm-server-audit :buildfarm-shard-worker-audit -``` - -To see the BOM file: -``` -cat bazel-bin/buildfarm-server.bom.yaml -``` - -The BOM file contains library names with corresponding license information. This currently only works for maven dependencies. diff --git a/deps.bzl b/deps.bzl index 1e44e16094..daa4a5ca17 100644 --- a/deps.bzl +++ b/deps.bzl @@ -88,14 +88,6 @@ def archive_dependencies(third_party): "strip_prefix": "TARDIS-f54fa4743e67763bb1ad77039b3d15be64e2e564", "url": "https://github.com/Unilang/TARDIS/archive/f54fa4743e67763bb1ad77039b3d15be64e2e564.zip", }, - { - "name": "rules_oss_audit", - "sha256": "8ee8376b05b5ddd2287b070e9a88ec85ef907d47f44e321ce5d4bc2b192eed4e", - "strip_prefix": "rules_oss_audit-167dab5b16abdb5996438f22364de544ff24693f", - "url": "https://github.com/vmware/rules_oss_audit/archive/167dab5b16abdb5996438f22364de544ff24693f.zip", - "patch_args": ["-p1"], - "patches": ["%s:rules_oss_audit_pyyaml.patch" % third_party], - }, ] def buildfarm_dependencies(repository_name = "build_buildfarm"): diff --git a/third_party/rules_oss_audit_pyyaml.patch b/third_party/rules_oss_audit_pyyaml.patch deleted file mode 100644 index d2297f018c..0000000000 --- a/third_party/rules_oss_audit_pyyaml.patch +++ /dev/null @@ -1,7 +0,0 @@ -diff --git a/oss_audit/tools/requirements.txt b/oss_audit/tools/requirements.txt -index 932bd69..be2b74d 100644 ---- a/oss_audit/tools/requirements.txt -+++ b/oss_audit/tools/requirements.txt -@@ -1 +1 @@ --PyYAML==5.4.1 -+PyYAML==6.0.1 From bb6019672cd6d91cf7a2bea936cdbfdf86d70e45 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Sun, 4 Feb 2024 13:02:29 -0800 Subject: [PATCH 209/311] Changes to upgrade to mockito 5.10.0 (#1623) --- defs.bzl | 2 +- .../java/build/buildfarm/cas/GrpcCASTest.java | 14 ++-- .../cas/MemoryWriteOutputStreamTest.java | 4 +- .../buildfarm/cas/cfc/CASFileCacheTest.java | 6 +- .../common/grpc/ByteStreamHelperTest.java | 6 +- .../grpc/StubWriteOutputStreamTest.java | 74 ++++++++----------- .../services/WriteStreamObserverTest.java | 6 +- .../instance/shard/DispatchedMonitorTest.java | 10 +-- .../instance/shard/ServerInstanceTest.java | 12 +-- .../buildfarm/instance/shard/UtilTest.java | 4 +- .../instance/stub/StubInstanceTest.java | 11 +-- 11 files changed, 71 insertions(+), 78 deletions(-) diff --git a/defs.bzl b/defs.bzl index 9ca4aec502..baa2f2de0d 100644 --- a/defs.bzl +++ b/defs.bzl @@ -103,7 +103,7 @@ def buildfarm_init(name = "buildfarm"): "me.dinowernli:java-grpc-prometheus:0.6.0", "org.apache.tomcat:annotations-api:6.0.53", "org.checkerframework:checker-qual:3.38.0", - "org.mockito:mockito-core:2.25.0", + "org.mockito:mockito-core:5.10.0", "org.openjdk.jmh:jmh-core:1.37", "org.openjdk.jmh:jmh-generator-annprocess:1.37", "org.redisson:redisson:3.23.4", diff --git a/src/test/java/build/buildfarm/cas/GrpcCASTest.java b/src/test/java/build/buildfarm/cas/GrpcCASTest.java index 6db6fd59aa..dfe0c60fd8 100644 --- a/src/test/java/build/buildfarm/cas/GrpcCASTest.java +++ b/src/test/java/build/buildfarm/cas/GrpcCASTest.java @@ -19,9 +19,11 @@ import static org.mockito.Mockito.any; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.verifyNoMoreInteractions; import build.bazel.remote.execution.v2.Compressor; import build.bazel.remote.execution.v2.ContentAddressableStorageGrpc.ContentAddressableStorageImplBase; @@ -162,7 +164,7 @@ public void putAddsExpiration() throws IOException, InterruptedException { verify(uploader, times(1)) .uploadBlob(eq(HashCode.fromString(digest.getHash())), any(Chunker.class)); assertThat(onExpirations.get(digest)).containsExactly(onExpiration); - verifyZeroInteractions(onExpiration); + verifyNoInteractions(onExpiration); } @Test @@ -220,11 +222,13 @@ public void findMissingBlobsSwallowsFilteredList() throws Exception { Channel channel = InProcessChannelBuilder.forName(fakeServerName).directExecutor().build(); Runnable onExpiration = mock(Runnable.class); GrpcCAS cas = new GrpcCAS("test", /* readonly=*/ false, channel, null, onExpirations); - ContentAddressableStorageImplBase casService = mock(ContentAddressableStorageImplBase.class); + ContentAddressableStorageImplBase casService = spy(ContentAddressableStorageImplBase.class); serviceRegistry.addService(casService); + // Mutable calls bindService, and clearInvocations is undesirable + verify(casService, times(1)).bindService(); Digest emptyDigest = Digest.getDefaultInstance(); assertThat(cas.findMissingBlobs(ImmutableList.of(emptyDigest))).isEmpty(); - verifyZeroInteractions(casService); - verifyZeroInteractions(onExpiration); + verifyNoMoreInteractions(casService); + verifyNoInteractions(onExpiration); } } diff --git a/src/test/java/build/buildfarm/cas/MemoryWriteOutputStreamTest.java b/src/test/java/build/buildfarm/cas/MemoryWriteOutputStreamTest.java index 2a979d346e..545b0d0d2f 100644 --- a/src/test/java/build/buildfarm/cas/MemoryWriteOutputStreamTest.java +++ b/src/test/java/build/buildfarm/cas/MemoryWriteOutputStreamTest.java @@ -16,7 +16,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.verifyNoInteractions; import build.bazel.remote.execution.v2.Digest; import build.buildfarm.common.DigestUtil; @@ -45,6 +45,6 @@ public void asyncWriteCompletionIsComplete() throws IOException { writtenFuture.set(content); assertThat(write.isComplete()).isTrue(); assertThat(write.getCommittedSize()).isEqualTo(digest.getSizeBytes()); - verifyZeroInteractions(cas); + verifyNoInteractions(cas); } } diff --git a/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java b/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java index caaab02b35..48a57ee8c7 100644 --- a/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java +++ b/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java @@ -32,7 +32,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; import build.bazel.remote.execution.v2.Compressor; @@ -212,7 +212,7 @@ public void putEmptyFileThrowsIllegalStateException() throws IOException, Interr try { fileCache.put(blobDigest, false); } finally { - verifyZeroInteractions(mockInputStreamFactory); + verifyNoInteractions(mockInputStreamFactory); } } @@ -886,7 +886,7 @@ public void duplicateExpiredEntrySuppressesDigestExpiration() fileCache.put(new Blob(ByteString.copyFromUtf8("Hello, World"), DIGEST_UTIL)); - verifyZeroInteractions(onExpire); + verifyNoInteractions(onExpire); // assert expiration of non-executable digest String expiringKey = fileCache.getKey(expiringBlob.getDigest(), /* isExecutable=*/ false); assertThat(storage.containsKey(expiringKey)).isFalse(); diff --git a/src/test/java/build/buildfarm/common/grpc/ByteStreamHelperTest.java b/src/test/java/build/buildfarm/common/grpc/ByteStreamHelperTest.java index 14b4789ef3..6f456a5f31 100644 --- a/src/test/java/build/buildfarm/common/grpc/ByteStreamHelperTest.java +++ b/src/test/java/build/buildfarm/common/grpc/ByteStreamHelperTest.java @@ -20,7 +20,6 @@ import static org.mockito.Mockito.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -43,17 +42,20 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; @RunWith(JUnit4.class) public class ByteStreamHelperTest { @Rule public final GrpcCleanupRule grpcCleanup = new GrpcCleanupRule(); - private final ByteStreamImplBase serviceImpl = mock(ByteStreamImplBase.class); + @Spy private ByteStreamImplBase serviceImpl; private Channel channel; @Before public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); String serverName = InProcessServerBuilder.generateName(); grpcCleanup diff --git a/src/test/java/build/buildfarm/common/grpc/StubWriteOutputStreamTest.java b/src/test/java/build/buildfarm/common/grpc/StubWriteOutputStreamTest.java index 5219e9d39d..1c4c93c88a 100644 --- a/src/test/java/build/buildfarm/common/grpc/StubWriteOutputStreamTest.java +++ b/src/test/java/build/buildfarm/common/grpc/StubWriteOutputStreamTest.java @@ -17,10 +17,6 @@ import static com.google.common.truth.Truth.assertThat; import static java.util.concurrent.TimeUnit.MICROSECONDS; import static java.util.concurrent.TimeUnit.SECONDS; -import static org.mockito.AdditionalAnswers.delegatesTo; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -40,6 +36,7 @@ import io.grpc.inprocess.InProcessServerBuilder; import io.grpc.stub.StreamObserver; import io.grpc.testing.GrpcCleanupRule; +import io.grpc.util.MutableHandlerRegistry; import java.io.IOException; import java.io.OutputStream; import java.util.List; @@ -49,37 +46,27 @@ import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.mockito.ArgumentCaptor; +import org.mockito.MockitoAnnotations; @RunWith(JUnit4.class) public class StubWriteOutputStreamTest { @Rule public final GrpcCleanupRule grpcCleanup = new GrpcCleanupRule(); - @SuppressWarnings("unchecked") - private final StreamObserver writeObserver = mock(StreamObserver.class); - - private final ByteStreamImplBase serviceImpl = - mock( - ByteStreamImplBase.class, - delegatesTo( - new ByteStreamImplBase() { - @Override - public StreamObserver write( - StreamObserver responseObserver) { - return writeObserver; - } - })); + private final MutableHandlerRegistry serviceRegistry = new MutableHandlerRegistry(); private Channel channel; @Before public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + String serverName = InProcessServerBuilder.generateName(); grpcCleanup .register( InProcessServerBuilder.forName(serverName) + .fallbackHandlerRegistry(serviceRegistry) .directExecutor() - .addService(serviceImpl) .build()) .start(); @@ -91,28 +78,22 @@ public void setUp() throws Exception { @Test public void resetExceptionsAreInterpreted() { String unimplementedResourceName = "unimplemented-resource"; - QueryWriteStatusRequest unimplementedRequest = - QueryWriteStatusRequest.newBuilder().setResourceName(unimplementedResourceName).build(); - doAnswer( - invocation -> { - StreamObserver observer = invocation.getArgument(1); - observer.onError(Status.UNIMPLEMENTED.asException()); - return null; - }) - .when(serviceImpl) - .queryWriteStatus(eq(unimplementedRequest), any(StreamObserver.class)); - String notFoundResourceName = "not-found-resource"; - QueryWriteStatusRequest notFoundRequest = - QueryWriteStatusRequest.newBuilder().setResourceName(notFoundResourceName).build(); - doAnswer( - invocation -> { - StreamObserver observer = invocation.getArgument(1); - observer.onError(Status.NOT_FOUND.asException()); - return null; - }) - .when(serviceImpl) - .queryWriteStatus(eq(notFoundRequest), any(StreamObserver.class)); + serviceRegistry.addService( + new ByteStreamImplBase() { + @Override + public void queryWriteStatus( + QueryWriteStatusRequest request, + StreamObserver responseObserver) { + if (request.getResourceName().equals(unimplementedResourceName)) { + responseObserver.onError(Status.UNIMPLEMENTED.asException()); + } else if (request.getResourceName().equals(notFoundResourceName)) { + responseObserver.onError(Status.NOT_FOUND.asException()); + } else { + responseObserver.onError(Status.INVALID_ARGUMENT.asException()); + } + } + }); StubWriteOutputStream write = new StubWriteOutputStream( @@ -123,8 +104,6 @@ public void resetExceptionsAreInterpreted() { /* expectedSize=*/ StubWriteOutputStream.UNLIMITED_EXPECTED_SIZE, /* autoflush=*/ true); assertThat(write.getCommittedSize()).isEqualTo(0); - verify(serviceImpl, times(1)) - .queryWriteStatus(eq(unimplementedRequest), any(StreamObserver.class)); write = new StubWriteOutputStream( @@ -135,12 +114,20 @@ public void resetExceptionsAreInterpreted() { /* expectedSize=*/ StubWriteOutputStream.UNLIMITED_EXPECTED_SIZE, /* autoflush=*/ true); assertThat(write.getCommittedSize()).isEqualTo(0); - verify(serviceImpl, times(1)).queryWriteStatus(eq(notFoundRequest), any(StreamObserver.class)); } @SuppressWarnings("unchecked") @Test public void resetIsRespectedOnSubsequentWrite() throws IOException { + StreamObserver writeObserver = mock(StreamObserver.class); + serviceRegistry.addService( + new ByteStreamImplBase() { + @Override + public StreamObserver write( + StreamObserver responseObserver) { + return writeObserver; + } + }); String resourceName = "reset-resource"; StubWriteOutputStream write = new StubWriteOutputStream( @@ -156,7 +143,6 @@ public void resetIsRespectedOnSubsequentWrite() throws IOException { write.reset(); content.writeTo(out); } - verify(serviceImpl, times(1)).write(any(StreamObserver.class)); ArgumentCaptor writeRequestCaptor = ArgumentCaptor.forClass(WriteRequest.class); verify(writeObserver, times(3)).onNext(writeRequestCaptor.capture()); List requests = writeRequestCaptor.getAllValues(); diff --git a/src/test/java/build/buildfarm/common/services/WriteStreamObserverTest.java b/src/test/java/build/buildfarm/common/services/WriteStreamObserverTest.java index b6d144a66b..165232ab05 100644 --- a/src/test/java/build/buildfarm/common/services/WriteStreamObserverTest.java +++ b/src/test/java/build/buildfarm/common/services/WriteStreamObserverTest.java @@ -8,7 +8,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; import build.bazel.remote.execution.v2.Compressor; @@ -89,7 +89,7 @@ public void cancelledBeforeGetOutputIsSilent() throws Exception { any(RequestMetadata.class)); verify(write, times(1)).getOutput(any(Long.class), any(TimeUnit.class), any(Runnable.class)); verify(out, times(1)).close(); - verifyZeroInteractions(responseObserver); + verifyNoInteractions(responseObserver); } @Test @@ -136,6 +136,6 @@ public void noErrorWhenContextCancelled() throws Exception { eq(cancelledDigest), eq(uuid), any(RequestMetadata.class)); - verifyZeroInteractions(responseObserver); + verifyNoInteractions(responseObserver); } } diff --git a/src/test/java/build/buildfarm/instance/shard/DispatchedMonitorTest.java b/src/test/java/build/buildfarm/instance/shard/DispatchedMonitorTest.java index c1410739b6..3066570526 100644 --- a/src/test/java/build/buildfarm/instance/shard/DispatchedMonitorTest.java +++ b/src/test/java/build/buildfarm/instance/shard/DispatchedMonitorTest.java @@ -22,7 +22,7 @@ import static org.mockito.Mockito.eq; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; import build.buildfarm.backplane.Backplane; @@ -67,7 +67,7 @@ public void shouldStopWhenBackplanIsStopped() { dispatchedMonitor.run(); verify(backplane, atLeastOnce()).isStopped(); - verifyZeroInteractions(requeuer); + verifyNoInteractions(requeuer); } @Test @@ -78,7 +78,7 @@ public void shouldIgnoreOperationWithFutureRequeueAt() throws Exception { ImmutableList.of( DispatchedOperation.newBuilder().setRequeueAt(Long.MAX_VALUE).build())); dispatchedMonitor.iterate(); - verifyZeroInteractions(requeuer); + verifyNoInteractions(requeuer); } @Test @@ -123,7 +123,7 @@ public void shouldIgnoreOperationWithEarlyRequeueAtWhenBackplaneDisallowsQueuein .build())); when(requeuer.apply(eq(queueEntry), any(Duration.class))).thenReturn(immediateFuture(null)); dispatchedMonitor.iterate(); - verifyZeroInteractions(requeuer); + verifyNoInteractions(requeuer); } @Test @@ -132,7 +132,7 @@ public void shouldIgnoreBackplaneException() throws Exception { when(backplane.getDispatchedOperations()) .thenThrow(new IOException("transient error condition")); dispatchedMonitor.iterate(); - verifyZeroInteractions(requeuer); + verifyNoInteractions(requeuer); } @Test diff --git a/src/test/java/build/buildfarm/instance/shard/ServerInstanceTest.java b/src/test/java/build/buildfarm/instance/shard/ServerInstanceTest.java index d66a600dab..3fc6f30707 100644 --- a/src/test/java/build/buildfarm/instance/shard/ServerInstanceTest.java +++ b/src/test/java/build/buildfarm/instance/shard/ServerInstanceTest.java @@ -32,6 +32,7 @@ import static java.util.concurrent.TimeUnit.SECONDS; import static org.mockito.AdditionalAnswers.answer; import static org.mockito.ArgumentMatchers.anyIterable; +import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.any; @@ -121,7 +122,6 @@ import org.junit.runners.JUnit4; import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatcher; -import org.mockito.Matchers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.stubbing.Answer; @@ -355,7 +355,7 @@ public void queueActionFailsQueueEligibility() throws Exception { .setSkipCacheLookup(true) .build(); - when(mockBackplane.propertiesEligibleForQueue(Matchers.anyList())).thenReturn(false); + when(mockBackplane.propertiesEligibleForQueue(anyList())).thenReturn(false); when(mockBackplane.canQueue()).thenReturn(true); @@ -482,7 +482,7 @@ public void queueDirectoryMissingErrorsOperation() throws Exception { .setSkipCacheLookup(true) .build(); - when(mockBackplane.propertiesEligibleForQueue(Matchers.anyList())).thenReturn(true); + when(mockBackplane.propertiesEligibleForQueue(anyList())).thenReturn(true); when(mockBackplane.canQueue()).thenReturn(true); @@ -555,7 +555,7 @@ public void queueOperationPutFailureCancelsOperation() throws Exception { .setSkipCacheLookup(true) .build(); - when(mockBackplane.propertiesEligibleForQueue(Matchers.anyList())).thenReturn(true); + when(mockBackplane.propertiesEligibleForQueue(anyList())).thenReturn(true); when(mockBackplane.canQueue()).thenReturn(true); @@ -621,7 +621,7 @@ public void queueWithFailedCacheCheckContinues() throws Exception { .setActionDigest(actionKey.getDigest()) .build(); - when(mockBackplane.propertiesEligibleForQueue(Matchers.anyList())).thenReturn(true); + when(mockBackplane.propertiesEligibleForQueue(anyList())).thenReturn(true); when(mockBackplane.canQueue()).thenReturn(true); @@ -733,7 +733,7 @@ public void requeueFailsOnMissingDirectory() throws Exception { Digest missingDirectoryDigest = Digest.newBuilder().setHash("missing-directory").setSizeBytes(1).build(); - when(mockBackplane.propertiesEligibleForQueue(Matchers.anyList())).thenReturn(true); + when(mockBackplane.propertiesEligibleForQueue(anyList())).thenReturn(true); when(mockBackplane.getOperation(eq(operationName))) .thenReturn( diff --git a/src/test/java/build/buildfarm/instance/shard/UtilTest.java b/src/test/java/build/buildfarm/instance/shard/UtilTest.java index 01e8a017fc..e02dcedda6 100644 --- a/src/test/java/build/buildfarm/instance/shard/UtilTest.java +++ b/src/test/java/build/buildfarm/instance/shard/UtilTest.java @@ -25,7 +25,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; import build.bazel.remote.execution.v2.Digest; @@ -135,7 +135,7 @@ public void correctMissingBlobFailsImmediatelyOnUnretriable() throws Interrupted } verify(instance, times(1)).findMissingBlobs(eq(digests), any(RequestMetadata.class)); assertThat(caughtException).isTrue(); - verifyZeroInteractions(backplane); + verifyNoInteractions(backplane); } @Test diff --git a/src/test/java/build/buildfarm/instance/stub/StubInstanceTest.java b/src/test/java/build/buildfarm/instance/stub/StubInstanceTest.java index 526946af1e..da355098ad 100644 --- a/src/test/java/build/buildfarm/instance/stub/StubInstanceTest.java +++ b/src/test/java/build/buildfarm/instance/stub/StubInstanceTest.java @@ -20,7 +20,8 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.verifyNoMoreInteractions; import build.bazel.remote.execution.v2.Action; import build.bazel.remote.execution.v2.ActionCacheGrpc.ActionCacheImplBase; @@ -419,7 +420,7 @@ public void read(ReadRequest request, StreamObserver responseObser assertThat(ioException).isNotNull(); Status status = Status.fromThrowable(ioException); assertThat(status.getCode()).isEqualTo(Code.UNAVAILABLE); - verifyZeroInteractions(out); + verifyNoInteractions(out); instance.stop(); } @@ -491,7 +492,7 @@ public void read(ReadRequest request, StreamObserver responseObser assertThat(ioException).isNotNull(); Status status = Status.fromThrowable(ioException); assertThat(status.getCode()).isEqualTo(Code.DEADLINE_EXCEEDED); - verifyZeroInteractions(out); + verifyNoInteractions(out); instance.stop(); } @@ -510,7 +511,7 @@ public void readBlobInterchangeDoesNotRequestUntilStarted() { verify(mockBlobObserver, times(1)).setOnReadyHandler(onReadyCaptor.capture()); // call it onReadyCaptor.getValue().run(); - // verify zero interactions with mockRequestStream - verifyZeroInteractions(mockRequestStream); + // verify no more interactions with mockRequestStream + verifyNoMoreInteractions(mockRequestStream); } } From 8a3abb642fa80f2f02ecc4df20e6ef56309d727f Mon Sep 17 00:00:00 2001 From: George Gensure Date: Tue, 13 Feb 2024 18:52:52 -0500 Subject: [PATCH 210/311] Fix com_grail_bazel_toolchain fetch (#1630) --- deps.bzl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deps.bzl b/deps.bzl index daa4a5ca17..358c20d938 100644 --- a/deps.bzl +++ b/deps.bzl @@ -55,8 +55,8 @@ def archive_dependencies(third_party): # Used to format proto files { "name": "com_grail_bazel_toolchain", - "sha256": "95f0bab6982c7e5a83447e08bf32fa7a47f210169da5e5ec62411fef0d8e7f59", - "strip_prefix": "bazel-toolchain-0.9", + "sha256": "b2d168315dd0785f170b2b306b86e577c36e812b8f8b05568f9403141f2c24dd", + "strip_prefix": "toolchains_llvm-0.9", "url": "https://github.com/grailbio/bazel-toolchain/archive/refs/tags/0.9.tar.gz", "patch_args": ["-p1"], "patches": ["%s:clang_toolchain.patch" % third_party], From 60b3890dbe4e330799ddab7738f498554cb12bf3 Mon Sep 17 00:00:00 2001 From: Andrew Rothstein Date: Thu, 15 Feb 2024 15:29:16 +0100 Subject: [PATCH 211/311] fix template bugs with with (#1631) * fix template bugs with with * stage chart v0.2.3 --- README.md | 4 ++-- kubernetes/helm-charts/buildfarm/Chart.yaml | 2 +- .../buildfarm/templates/shard-worker/statefulsets.yaml | 9 ++++++--- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 385d6e5e9b..84e2f75737 100644 --- a/README.md +++ b/README.md @@ -142,8 +142,8 @@ buildfarm_images() To install with helm: ```bash -# https://github.com/bazelbuild/bazel-buildfarm/releases/download/helm%2F0.2.2/buildfarm-0.2.2.tgz -CHART_VER="0.2.2" +# https://github.com/bazelbuild/bazel-buildfarm/releases/download/helm%2F0.2.3/buildfarm-0.2.3.tgz +CHART_VER="0.2.3" helm install \ -n bazel-buildfarm \ --create-namespace \ diff --git a/kubernetes/helm-charts/buildfarm/Chart.yaml b/kubernetes/helm-charts/buildfarm/Chart.yaml index 593568d011..909ed735d5 100644 --- a/kubernetes/helm-charts/buildfarm/Chart.yaml +++ b/kubernetes/helm-charts/buildfarm/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.2.2 +version: 0.2.3 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/kubernetes/helm-charts/buildfarm/templates/shard-worker/statefulsets.yaml b/kubernetes/helm-charts/buildfarm/templates/shard-worker/statefulsets.yaml index ce5dbc9139..8582807d8e 100644 --- a/kubernetes/helm-charts/buildfarm/templates/shard-worker/statefulsets.yaml +++ b/kubernetes/helm-charts/buildfarm/templates/shard-worker/statefulsets.yaml @@ -79,15 +79,18 @@ spec: {{- end }} {{- with .Values.shardWorker.nodeSelector }} - {{- tpl (toYaml .) $ | nindent 6 -}} + nodeSelector: + {{- tpl (toYaml .) $ | nindent 8 -}} {{- end }} {{- with .Values.shardWorker.affinity }} - {{- tpl (toYaml .) $ | nindent 6 -}} + affinity: + {{- tpl (toYaml .) $ | nindent 8 -}} {{- end }} {{- with .Values.shardWorker.tolerations }} - {{- tpl (toYaml .) $ | nindent 6 -}} + tolerations: + {{- tpl (toYaml .) $ | nindent 8 -}} {{- end }} volumes: - configMap: From 1eb0528ec71ae786daee82403cd0ee445466e9f3 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Thu, 15 Feb 2024 14:19:03 -0500 Subject: [PATCH 212/311] Update llvm-toolchains repo url (#1633) --- deps.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps.bzl b/deps.bzl index 358c20d938..717def2de3 100644 --- a/deps.bzl +++ b/deps.bzl @@ -57,7 +57,7 @@ def archive_dependencies(third_party): "name": "com_grail_bazel_toolchain", "sha256": "b2d168315dd0785f170b2b306b86e577c36e812b8f8b05568f9403141f2c24dd", "strip_prefix": "toolchains_llvm-0.9", - "url": "https://github.com/grailbio/bazel-toolchain/archive/refs/tags/0.9.tar.gz", + "url": "https://github.com/bazel-contrib/toolchains_llvm/archive/refs/tags/0.9.tar.gz", "patch_args": ["-p1"], "patches": ["%s:clang_toolchain.patch" % third_party], }, From cab70f2d31dba3dfdccec8e84207c02c4178c7a5 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Sun, 18 Feb 2024 15:37:31 -0500 Subject: [PATCH 213/311] Describe maxSizeBytes default and sentinel (#1636) --- _site/docs/configuration/configuration.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/_site/docs/configuration/configuration.md b/_site/docs/configuration/configuration.md index ba85d4a6c5..5ca58b303e 100644 --- a/_site/docs/configuration/configuration.md +++ b/_site/docs/configuration/configuration.md @@ -336,13 +336,13 @@ worker: Unless specified, options are only relevant for FILESYSTEM type | Configuration | Accepted and _Default_ Values | Description | -|------------------------------|-------------------------------|---------------------------------------------------------------------------------------------------------------| -| type | _FILESYSTEM_, GRPC | Type of CAS used | -| path | String, _cache_ | Local cache location relative to the 'root', or absolute | -| maxSizeBytes | Integer, _2147483648_ | Limit for contents of files retained from CAS in the cache | -| fileDirectoriesIndexInMemory | boolean, _false_ | Determines if the file directories bidirectional mapping should be stored in memory or in sqllite | -| skipLoad | boolean, _false_ | Determines if transient data on the worker should be loaded into CAS on worker startup (affects startup time) | -| target | String, _null_ | For GRPC CAS type, target for external CAS endpoint | +|------------------------------|-------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------| +| type | _FILESYSTEM_, GRPC | Type of CAS used | +| path | String, _cache_ | Local cache location relative to the 'root', or absolute | +| maxSizeBytes | Integer, _0_ | Limit for contents of files retained from CAS in the cache, value of 0 means to auto-configure to 90% of _root_/_path_ underlying filesystem space | +| fileDirectoriesIndexInMemory | boolean, _false_ | Determines if the file directories bidirectional mapping should be stored in memory or in sqlite | +| skipLoad | boolean, _false_ | Determines if transient data on the worker should be loaded into CAS on worker startup (affects startup time) | +| target | String, _null_ | For GRPC CAS type, target for external CAS endpoint | Example: From 14810a42ec8ea1fd65009d1183dd37a8ace0a0e3 Mon Sep 17 00:00:00 2001 From: Andrew Rothstein Date: Mon, 19 Feb 2024 15:09:41 +0100 Subject: [PATCH 214/311] migrate dependency to Bitnami Redis helm chart (#1637) * rework for bitnami redis helm chart * still doesn't work tho less specified * disable redis pwd -- not for production use * chart/bitnami-redis:18.14.2 * and later * stage chart v0.3.0 --- README.md | 4 ++-- kubernetes/helm-charts/buildfarm/Chart.yaml | 6 +++--- .../buildfarm/templates/configmap.yaml | 2 +- kubernetes/helm-charts/buildfarm/values.yaml | 15 +++------------ 4 files changed, 9 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 84e2f75737..67037a566c 100644 --- a/README.md +++ b/README.md @@ -142,8 +142,8 @@ buildfarm_images() To install with helm: ```bash -# https://github.com/bazelbuild/bazel-buildfarm/releases/download/helm%2F0.2.3/buildfarm-0.2.3.tgz -CHART_VER="0.2.3" +# https://github.com/bazelbuild/bazel-buildfarm/releases/download/helm%2F0.3.0/buildfarm-0.3.0.tgz +CHART_VER="0.3.0" helm install \ -n bazel-buildfarm \ --create-namespace \ diff --git a/kubernetes/helm-charts/buildfarm/Chart.yaml b/kubernetes/helm-charts/buildfarm/Chart.yaml index 909ed735d5..8e105c726e 100644 --- a/kubernetes/helm-charts/buildfarm/Chart.yaml +++ b/kubernetes/helm-charts/buildfarm/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.2.3 +version: 0.3.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to @@ -26,5 +26,5 @@ appVersion: 2.8.0 dependencies: - condition: redis.enabled name: redis - repository: https://charts.helm.sh/stable - version: 10.5.7 + repository: oci://registry-1.docker.io/bitnamicharts + version: ~18.14.2 diff --git a/kubernetes/helm-charts/buildfarm/templates/configmap.yaml b/kubernetes/helm-charts/buildfarm/templates/configmap.yaml index 809d83e049..6b30f841a6 100644 --- a/kubernetes/helm-charts/buildfarm/templates/configmap.yaml +++ b/kubernetes/helm-charts/buildfarm/templates/configmap.yaml @@ -11,7 +11,7 @@ data: {{- end }} backplane: {{- if .Values.redis.enabled }} - redisUri: "{{ .Values.redis.scheme }}://{{ printf "%s-redis-master.%s" (include "redis.fullname" .) (.Release.Namespace) }}:{{ "6379" }}" + redisUri: '{{ printf "redis://%s-redis-master.%s:6379" .Release.Name .Release.Namespace }}' {{- else }} redisUri: "{{ .Values.externalRedis.uri }}" {{- end }} diff --git a/kubernetes/helm-charts/buildfarm/values.yaml b/kubernetes/helm-charts/buildfarm/values.yaml index c18593a7e8..ff3f0c7ae2 100644 --- a/kubernetes/helm-charts/buildfarm/values.yaml +++ b/kubernetes/helm-charts/buildfarm/values.yaml @@ -172,19 +172,10 @@ redis: ## - set to `false` if using `externalRedis.*` ## enabled: true - scheme: "redis" - ## See more redis configs: https://github.com/bitnami/charts/blob/main/bitnami/redis/README.md - usePassword: false - ## configs for redis cluster mode - ## - cluster: - ## if redis runs in cluster mode - ## + auth: enabled: false - - ## the number of redis slaves - ## - slaveCount: 1 + replica: + replicaCount: 1 externalRedis: uri: "redis://localhost:6379" From 7ec7fdb1c6c9c567bfd09db95ae3c74b1e5111b0 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Thu, 22 Feb 2024 21:42:30 -0500 Subject: [PATCH 215/311] Dequeue flags expire after timeout effect (#1642) The flag key which contains a timeout for an operation that has been observed in a Queue's Dequeue (atomic safeguard list, either queue or dequeue) must not expire before the time it will be expired, and reasonably not before the time it takes a failsafe period to identify the timeout has elapsed. This was broken in #713, where the original expiry was 2x the configured timeout, and reduced to just the timeout in seconds. We now set the expiry to 1 hour or 10x the timeout, to make unlikely an expiry clearing the flag in a working system. Commented loudly to avoid removing the same padding again. --- .../instance/shard/RedisShardBackplane.java | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java index 84a9f2e525..5977cc1a5b 100644 --- a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java +++ b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java @@ -244,17 +244,20 @@ private void scanProcessing(JedisCluster jedis, Consumer onOperationName protected void visit(ExecuteEntry executeEntry, String executeEntryJson) { String operationName = executeEntry.getOperationName(); String value = state.processingOperations.get(jedis, operationName); - long defaultTimeout_ms = configs.getBackplane().getProcessingTimeoutMillis(); + long processingTimeout_ms = configs.getBackplane().getProcessingTimeoutMillis(); // get the operation's expiration Instant expiresAt = convertToMilliInstant(value, operationName); // if expiration is invalid, add a valid one. if (expiresAt == null) { - expiresAt = now.plusMillis(defaultTimeout_ms); + expiresAt = now.plusMillis(processingTimeout_ms); String keyValue = String.format("%d", expiresAt.toEpochMilli()); - long timeout_s = Time.millisecondsToSeconds(defaultTimeout_ms); - state.processingOperations.insert(jedis, operationName, keyValue, timeout_s); + // persist the flag for at least an hour, and at most 10 times longer than the timeout + // the key identifies so that we don't loop with the flag expired, resetting the + // unaccounted for operation + long expire_s = Math.max(3600, Time.millisecondsToSeconds(processingTimeout_ms) * 10); + state.processingOperations.insert(jedis, operationName, keyValue, expire_s); } // handle expiration @@ -277,17 +280,21 @@ private void scanDispatching(JedisCluster jedis, Consumer onOperationNam protected void visit(QueueEntry queueEntry, String queueEntryJson) { String operationName = queueEntry.getExecuteEntry().getOperationName(); String value = state.dispatchingOperations.get(jedis, operationName); - long defaultTimeout_ms = configs.getBackplane().getDispatchingTimeoutMillis(); + long dispatchingTimeout_ms = configs.getBackplane().getDispatchingTimeoutMillis(); // get the operation's expiration Instant expiresAt = convertToMilliInstant(value, operationName); // if expiration is invalid, add a valid one. if (expiresAt == null) { - expiresAt = now.plusMillis(defaultTimeout_ms); + expiresAt = now.plusMillis(dispatchingTimeout_ms); String keyValue = String.format("%d", expiresAt.toEpochMilli()); - long timeout_s = Time.millisecondsToSeconds(defaultTimeout_ms); - state.dispatchingOperations.insert(jedis, operationName, keyValue, timeout_s); + // persist the flag for at least an hour, and at most 10 times longer than the timeout + // the key identifies so that we don't loop with the flag expired, resetting the + // unaccounted for operation + long expire_s = + Math.max(3600, Time.millisecondsToSeconds(dispatchingTimeout_ms) * 10); + state.dispatchingOperations.insert(jedis, operationName, keyValue, expire_s); } // handle expiration From b38568b7a5e5c9421f9ed89257cf5f0bd29881a2 Mon Sep 17 00:00:00 2001 From: Yuriy Belenitsky Date: Mon, 26 Feb 2024 09:56:10 -0500 Subject: [PATCH 216/311] Update .bazelversion to use bazel 7.0.2 (#1641) * Update .bazelversion to use bazel 7.0.0 Bump bazel to v7.0.0 * Update .bazelversion --- .bazelversion | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bazelversion b/.bazelversion index 19b860c187..a8907c025d 100644 --- a/.bazelversion +++ b/.bazelversion @@ -1 +1 @@ -6.4.0 +7.0.2 From 4318801008df1b15115008a351deafbb9eadc9c6 Mon Sep 17 00:00:00 2001 From: Yuriy Belenitsky Date: Thu, 29 Feb 2024 14:16:46 -0500 Subject: [PATCH 217/311] Disable rules_docker transitions (#1648) This PR fixes the issues introduced by setting default bazel version to 7, which is now breaking CI. Example errors: in constraint_values attribute of platform rule @@io_bazel_rules_docker//platforms:image_transition: '@@io_bazel_rules_docker//platforms:image_transition_cpu' does not have mandatory providers: 'ConstraintValueInfo' Analysis of target '@@io_bazel_rules_docker//platforms:image_transition' failed ERROR: /home/yuriyb/bazel-buildfarm/BUILD:119:11: Target @@io_bazel_rules_docker//platforms:image_transition was referenced as a platform, but does not provide PlatformInfo --- .bazelrc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.bazelrc b/.bazelrc index 60199a4cbe..4946f027c9 100644 --- a/.bazelrc +++ b/.bazelrc @@ -4,6 +4,9 @@ build --java_runtime_version=remotejdk_17 build --tool_java_language_version=17 build --tool_java_runtime_version=remotejdk_17 +# Prevents rules_docker issues when building with bazel 7 +build --@io_bazel_rules_docker//transitions:enable=false + common --enable_platform_specific_config build:fuse --define=fuse=true From 535515bc3619eb3cd75b1258ca372181c5776cfa Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Fri, 1 Mar 2024 06:40:42 -0800 Subject: [PATCH 218/311] style: buildifier (#1653) >buildifier -mode fix -lint fix -r . --- BUILD | 4 ++-- defs.bzl | 8 ++++---- images.bzl | 2 +- persistentworkers/src/main/protobuf/BUILD | 2 +- src/main/java/build/buildfarm/common/resources/BUILD | 2 +- src/main/protobuf/BUILD.bazel | 4 ++-- src/test/many/BUILD | 2 +- src/test/many/many-cc.bzl | 2 +- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/BUILD b/BUILD index a749c0caa3..b93df8471e 100644 --- a/BUILD +++ b/BUILD @@ -1,8 +1,8 @@ load("@buildifier_prebuilt//:rules.bzl", "buildifier") -load("@io_bazel_rules_docker//java:image.bzl", "java_image") +load("@io_bazel_rules_docker//container:container.bzl", "container_image", "container_push") load("@io_bazel_rules_docker//docker/package_managers:download_pkgs.bzl", "download_pkgs") load("@io_bazel_rules_docker//docker/package_managers:install_pkgs.bzl", "install_pkgs") -load("@io_bazel_rules_docker//container:container.bzl", "container_image", "container_push") +load("@io_bazel_rules_docker//java:image.bzl", "java_image") load("//:jvm_flags.bzl", "server_jvm_flags", "worker_jvm_flags") package(default_visibility = ["//visibility:public"]) diff --git a/defs.bzl b/defs.bzl index baa2f2de0d..84b2733751 100644 --- a/defs.bzl +++ b/defs.bzl @@ -2,15 +2,15 @@ buildfarm definitions that can be imported into other WORKSPACE files """ -load("@rules_jvm_external//:defs.bzl", "maven_install") -load("@remote_apis//:repository_rules.bzl", "switched_rules_by_language") +load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") +load("@com_grail_bazel_toolchain//toolchain:rules.bzl", "llvm_toolchain") load( "@io_bazel_rules_docker//repositories:repositories.bzl", container_repositories = "repositories", ) load("@io_grpc_grpc_java//:repositories.bzl", "IO_GRPC_GRPC_JAVA_OVERRIDE_TARGETS", "grpc_java_repositories") -load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") -load("@com_grail_bazel_toolchain//toolchain:rules.bzl", "llvm_toolchain") +load("@remote_apis//:repository_rules.bzl", "switched_rules_by_language") +load("@rules_jvm_external//:defs.bzl", "maven_install") IO_NETTY_MODULES = [ "buffer", diff --git a/images.bzl b/images.bzl index faa70c3ff1..800615160d 100644 --- a/images.bzl +++ b/images.bzl @@ -2,8 +2,8 @@ buildfarm images that can be imported into other WORKSPACE files """ -load("@io_bazel_rules_docker//repositories:deps.bzl", container_deps = "deps") load("@io_bazel_rules_docker//container:container.bzl", "container_pull") +load("@io_bazel_rules_docker//repositories:deps.bzl", container_deps = "deps") def buildfarm_images(): """ diff --git a/persistentworkers/src/main/protobuf/BUILD b/persistentworkers/src/main/protobuf/BUILD index bec20e6ff7..24411a07a4 100755 --- a/persistentworkers/src/main/protobuf/BUILD +++ b/persistentworkers/src/main/protobuf/BUILD @@ -1,5 +1,5 @@ -load("@rules_proto//proto:defs.bzl", "proto_library") load("@bazel_tools//tools/build_rules:utilities.bzl", "java_library_srcs") +load("@rules_proto//proto:defs.bzl", "proto_library") package(default_visibility = ["//visibility:public"]) diff --git a/src/main/java/build/buildfarm/common/resources/BUILD b/src/main/java/build/buildfarm/common/resources/BUILD index 0e8924c447..7fce137e12 100644 --- a/src/main/java/build/buildfarm/common/resources/BUILD +++ b/src/main/java/build/buildfarm/common/resources/BUILD @@ -1,5 +1,5 @@ -load("@rules_proto//proto:defs.bzl", "proto_library") load("@rules_java//java:defs.bzl", "java_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") package(default_visibility = ["//visibility:public"]) diff --git a/src/main/protobuf/BUILD.bazel b/src/main/protobuf/BUILD.bazel index 9f2e044cce..4e37226bf1 100644 --- a/src/main/protobuf/BUILD.bazel +++ b/src/main/protobuf/BUILD.bazel @@ -1,6 +1,6 @@ -load("@rules_proto//proto:defs.bzl", "proto_library") -load("@rules_java//java:defs.bzl", "java_proto_library") load("@io_grpc_grpc_java//:java_grpc_library.bzl", "java_grpc_library") +load("@rules_java//java:defs.bzl", "java_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") package(default_visibility = ["//visibility:public"]) diff --git a/src/test/many/BUILD b/src/test/many/BUILD index 0526104520..775051cb23 100644 --- a/src/test/many/BUILD +++ b/src/test/many/BUILD @@ -8,10 +8,10 @@ MANY_CC_LIBRARIES, and MANY_CC_LIBRARY_SOURCES. For instance: MANY_CC_BINARIES=20 MANY_CC_LIBRARIES=10 MANY_CC_LIBRARY_SOURCES=5 bazel build //:cc """ -load(":many-cc.bzl", "many_cc") load("@many-params//:cc-binaries.bzl", "cc_binaries") load("@many-params//:cc-libraries.bzl", "cc_libraries") load("@many-params//:cc-library-sources.bzl", "cc_library_sources") +load(":many-cc.bzl", "many_cc") many_cc( name = "cc", diff --git a/src/test/many/many-cc.bzl b/src/test/many/many-cc.bzl index 90c88113b4..03fb37b0cc 100644 --- a/src/test/many/many-cc.bzl +++ b/src/test/many/many-cc.bzl @@ -2,8 +2,8 @@ Provide a simple C++ build graph as large as desired. """ -load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library") load("@bazel_skylib//rules:write_file.bzl", _write_file = "write_file") +load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library") def write_file(name, out, lines): """ From 6994b3c06a55bf7336d0e4ea564abf8a6ce5be5f Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Fri, 1 Mar 2024 06:41:06 -0800 Subject: [PATCH 219/311] chore: update CODEOWNERS (#1654) Removing a stale codeowner that's not part of the repo anymore, per GitHub warning. --- CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index 6ee2ef6c3e..f755f1edff 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1 +1 @@ -* @werkt @ulfjack +* @werkt From ea78d25be5443f3f4f5c6f8c003aa4771c9c7ff1 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Fri, 1 Mar 2024 09:59:07 -0800 Subject: [PATCH 220/311] build: pin python-dateutil (#1657) v2.9.0 seems to not be so compatible with python2 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 6b843cc0be..2e49d697f7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,5 +10,5 @@ RUN apt-get update RUN apt-get -y install wget git zip python gcc openjdk-8-jdk g++ redis redis-server RUN wget --tries=10 -O get-pip.py https://bootstrap.pypa.io/pip/2.7/get-pip.py RUN python2 get-pip.py -RUN pip install python-dateutil +RUN pip install python-dateutil==2.8.2 COPY . buildfarm From 9bc6b0241d736bfa7e61a4fdb4ed94e01bd9a400 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Sat, 2 Mar 2024 09:57:33 -0800 Subject: [PATCH 221/311] chore(deps): bump io_grpc_grpc_java to 1.62.2 (#1658) --- defs.bzl | 2 +- deps.bzl | 6 +++--- src/test/java/build/buildfarm/cas/BUILD | 1 + src/test/java/build/buildfarm/common/grpc/BUILD | 1 + src/test/java/build/buildfarm/common/services/BUILD | 1 + src/test/java/build/buildfarm/instance/stub/BUILD | 1 + src/test/java/build/buildfarm/proxy/http/BUILD | 1 + src/test/java/build/buildfarm/server/BUILD | 1 + 8 files changed, 10 insertions(+), 4 deletions(-) diff --git a/defs.bzl b/defs.bzl index 84b2733751..55d4a4db45 100644 --- a/defs.bzl +++ b/defs.bzl @@ -88,7 +88,7 @@ def buildfarm_init(name = "buildfarm"): "org.bouncycastle:bcprov-jdk15on:1.70", "net.jcip:jcip-annotations:1.0", ] + ["io.netty:netty-%s:4.1.97.Final" % module for module in IO_NETTY_MODULES] + - ["io.grpc:grpc-%s:1.56.1" % module for module in IO_GRPC_MODULES] + + ["io.grpc:grpc-%s:1.62.2" % module for module in IO_GRPC_MODULES] + [ "io.prometheus:simpleclient:0.15.0", "io.prometheus:simpleclient_hotspot:0.15.0", diff --git a/deps.bzl b/deps.bzl index 717def2de3..e1f8b944e9 100644 --- a/deps.bzl +++ b/deps.bzl @@ -17,9 +17,9 @@ def archive_dependencies(third_party): # Needed for @grpc_java//compiler:grpc_java_plugin. { "name": "io_grpc_grpc_java", - "sha256": "b8fb7ae4824fb5a5ae6e6fa26ffe2ad7ab48406fdeee54e8965a3b5948dd957e", - "strip_prefix": "grpc-java-1.56.1", - "urls": ["https://github.com/grpc/grpc-java/archive/v1.56.1.zip"], + "sha256": "5d617856c295d863307f4036a1b1e93f9eeaf6da41424d2de7c9b330a810fc3b", + "strip_prefix": "grpc-java-1.62.2", + "urls": ["https://github.com/grpc/grpc-java/archive/v1.62.2.zip"], # Bzlmod: Waiting for https://github.com/bazelbuild/bazel-central-registry/issues/353 }, { diff --git a/src/test/java/build/buildfarm/cas/BUILD b/src/test/java/build/buildfarm/cas/BUILD index fc127b1ea6..11d3dad231 100644 --- a/src/test/java/build/buildfarm/cas/BUILD +++ b/src/test/java/build/buildfarm/cas/BUILD @@ -21,6 +21,7 @@ java_test( "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_context", "@maven//:io_grpc_grpc_core", + "@maven//:io_grpc_grpc_inprocess", "@maven//:io_grpc_grpc_stub", "@maven//:org_mockito_mockito_core", "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_grpc", diff --git a/src/test/java/build/buildfarm/common/grpc/BUILD b/src/test/java/build/buildfarm/common/grpc/BUILD index 35be7f36da..ab703cf463 100644 --- a/src/test/java/build/buildfarm/common/grpc/BUILD +++ b/src/test/java/build/buildfarm/common/grpc/BUILD @@ -28,6 +28,7 @@ java_test( "@maven//:com_google_truth_truth", "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_core", + "@maven//:io_grpc_grpc_inprocess", "@maven//:io_grpc_grpc_stub", "@maven//:io_grpc_grpc_testing", "@maven//:org_mockito_mockito_core", diff --git a/src/test/java/build/buildfarm/common/services/BUILD b/src/test/java/build/buildfarm/common/services/BUILD index 6fe1f35c55..929489036b 100644 --- a/src/test/java/build/buildfarm/common/services/BUILD +++ b/src/test/java/build/buildfarm/common/services/BUILD @@ -22,6 +22,7 @@ java_test( "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_context", "@maven//:io_grpc_grpc_core", + "@maven//:io_grpc_grpc_inprocess", "@maven//:io_grpc_grpc_stub", "@maven//:org_mockito_mockito_core", "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", diff --git a/src/test/java/build/buildfarm/instance/stub/BUILD b/src/test/java/build/buildfarm/instance/stub/BUILD index 8f44f01795..861267775c 100644 --- a/src/test/java/build/buildfarm/instance/stub/BUILD +++ b/src/test/java/build/buildfarm/instance/stub/BUILD @@ -19,6 +19,7 @@ java_test( "@maven//:com_google_truth_truth", "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_core", + "@maven//:io_grpc_grpc_inprocess", "@maven//:io_grpc_grpc_stub", "@maven//:org_mockito_mockito_core", "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_grpc", diff --git a/src/test/java/build/buildfarm/proxy/http/BUILD b/src/test/java/build/buildfarm/proxy/http/BUILD index 90fcb5d6c1..73a1ee1196 100644 --- a/src/test/java/build/buildfarm/proxy/http/BUILD +++ b/src/test/java/build/buildfarm/proxy/http/BUILD @@ -14,6 +14,7 @@ java_test( "@maven//:com_google_truth_truth", "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_core", + "@maven//:io_grpc_grpc_inprocess", "@maven//:io_grpc_grpc_stub", "@maven//:org_mockito_mockito_core", "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", diff --git a/src/test/java/build/buildfarm/server/BUILD b/src/test/java/build/buildfarm/server/BUILD index ff60c29b94..e87890ba07 100644 --- a/src/test/java/build/buildfarm/server/BUILD +++ b/src/test/java/build/buildfarm/server/BUILD @@ -31,6 +31,7 @@ java_test( "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_context", "@maven//:io_grpc_grpc_core", + "@maven//:io_grpc_grpc_inprocess", "@maven//:io_grpc_grpc_netty", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", From 55ac48c4f6aedcd06b77e24e0add243660bfcf15 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Sat, 2 Mar 2024 09:58:52 -0800 Subject: [PATCH 222/311] build(protobuf): switch to protobuf from BCR (#1656) Swap to using the protobuf dependency directly from Bazel Central Registry (BCR) at http://registry.bazel.build This is a downgrade (25.0->23.1), but 23.1 is the latest in the BCR today. --- MODULE.bazel | 3 ++- deps.bzl | 7 ------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 83268eda13..1fe77da220 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -4,7 +4,8 @@ module( ) bazel_dep(name = "gazelle", version = "0.34.0", repo_name = "bazel_gazelle") -bazel_dep(name = "platforms", version = "0.0.7") +bazel_dep(name = "platforms", version = "0.0.8") +bazel_dep(name = "protobuf", version = "23.1", repo_name = "com_google_protobuf") bazel_dep(name = "rules_cc", version = "0.0.9") bazel_dep(name = "rules_go", version = "0.43.0", repo_name = "io_bazel_rules_go") bazel_dep(name = "rules_jvm_external", version = "5.3") diff --git a/deps.bzl b/deps.bzl index e1f8b944e9..1624655920 100644 --- a/deps.bzl +++ b/deps.bzl @@ -7,13 +7,6 @@ load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") def archive_dependencies(third_party): return [ - # Needed for "well-known protos" and @com_google_protobuf//:protoc. - { - "name": "com_google_protobuf", - "sha256": "79082dc68d8bab2283568ce0be3982b73e19ddd647c2411d1977ca5282d2d6b3", - "strip_prefix": "protobuf-25.0", - "urls": ["https://github.com/protocolbuffers/protobuf/archive/v25.0.zip"], - }, # Needed for @grpc_java//compiler:grpc_java_plugin. { "name": "io_grpc_grpc_java", From f2166af21ff3e22f21921b4c4925e4905a3d2eeb Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Sat, 2 Mar 2024 09:59:26 -0800 Subject: [PATCH 223/311] refactor(tests): replace ExpectedException with assertThrows (#1652) --- .../buildfarm/common/DigestUtilTest.java | 14 ++++++----- .../build/buildfarm/worker/FuseCASTest.java | 25 ++++++++++--------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/test/java/build/buildfarm/common/DigestUtilTest.java b/src/test/java/build/buildfarm/common/DigestUtilTest.java index 8d581fc84e..45df23990e 100644 --- a/src/test/java/build/buildfarm/common/DigestUtilTest.java +++ b/src/test/java/build/buildfarm/common/DigestUtilTest.java @@ -15,28 +15,30 @@ package build.buildfarm.common; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; import build.bazel.remote.execution.v2.Digest; import build.bazel.remote.execution.v2.DigestFunction; import build.buildfarm.common.DigestUtil.HashFunction; import com.google.protobuf.ByteString; import java.io.IOException; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @RunWith(JUnit4.class) public class DigestUtilTest { - @Rule public final ExpectedException exception = ExpectedException.none(); @Test public void buildThrowsOnInvalidHashCode() { DigestUtil digestUtil = new DigestUtil(HashFunction.MD5); - exception.expect(NumberFormatException.class); - exception.expectMessage("[foo] is not a valid MD5 hash."); - digestUtil.build("foo", 3); + NumberFormatException expected = + assertThrows( + NumberFormatException.class, + () -> { + digestUtil.build("foo", 3); + }); + assertThat(expected.getMessage()).isEqualTo("[foo] is not a valid MD5 hash."); } @Test diff --git a/src/test/java/build/buildfarm/worker/FuseCASTest.java b/src/test/java/build/buildfarm/worker/FuseCASTest.java index 98534fecf5..34e4a3cb9e 100644 --- a/src/test/java/build/buildfarm/worker/FuseCASTest.java +++ b/src/test/java/build/buildfarm/worker/FuseCASTest.java @@ -15,6 +15,7 @@ package build.buildfarm.worker; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; import build.bazel.remote.execution.v2.Digest; import build.bazel.remote.execution.v2.Directory; @@ -29,9 +30,7 @@ import jnr.ffi.provider.DelegatingMemoryIO; import jnr.ffi.provider.converters.StringResultConverter; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import ru.serce.jnrfuse.ErrorCodes; @@ -42,8 +41,6 @@ public class FuseCASTest { private FuseCAS fuseCAS; - @Rule public final ExpectedException exception = ExpectedException.none(); - private final ByteString content = ByteString.copyFromUtf8("Peanut Butter"); @Before @@ -97,30 +94,34 @@ public void createInputRootMakesDirectory() throws IOException, InterruptedExcep assertThat(fuseCAS.getattr("/test", createFileStat())).isEqualTo(0); } - @Test + @Test(expected = IllegalArgumentException.class) public void createInputRootEmptyTopdirThrows() throws IOException, InterruptedException { - exception.expect(IllegalArgumentException.class); fuseCAS.createInputRoot("", Digest.newBuilder().build()); } - @Test + @Test(expected = IllegalArgumentException.class) public void createInputRootEmptyAfterSlashes() throws IOException, InterruptedException { - exception.expect(IllegalArgumentException.class); fuseCAS.createInputRoot("///", Digest.newBuilder().build()); } @Test public void createInputRootFileAsDirectoryThrows() throws IOException, InterruptedException { fuseCAS.createInputRoot("test", Digest.newBuilder().setHash("/test").build()); - exception.expect(IllegalArgumentException.class); - fuseCAS.createInputRoot("test/file/subdir", Digest.newBuilder().build()); + assertThrows( + IllegalArgumentException.class, + () -> { + fuseCAS.createInputRoot("test/file/subdir", Digest.newBuilder().build()); + }); } @Test public void createInputRootEmptyComponentsIgnored() throws IOException, InterruptedException { fuseCAS.createInputRoot("/test/", Digest.newBuilder().setHash("/test").build()); - exception.expect(IllegalArgumentException.class); - fuseCAS.createInputRoot("test/file/subdir", Digest.newBuilder().build()); + assertThrows( + IllegalArgumentException.class, + () -> { + fuseCAS.createInputRoot("test/file/subdir", Digest.newBuilder().build()); + }); } @Test From c5335c03941279ce999945b9284b1e48af6aa2d4 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Sat, 2 Mar 2024 09:59:40 -0800 Subject: [PATCH 224/311] docs(metrics): Update prometheus metrics (#1650) Some of these don't exist in the code anymore. Also, labeled some metric types. --- _site/docs/metrics/metrics.md | 56 ++--------------------------------- 1 file changed, 2 insertions(+), 54 deletions(-) diff --git a/_site/docs/metrics/metrics.md b/_site/docs/metrics/metrics.md index c0bfb4a75a..84bbf7e3b5 100644 --- a/_site/docs/metrics/metrics.md +++ b/_site/docs/metrics/metrics.md @@ -48,53 +48,9 @@ Counter for number of operations that failed to requeue Gauge of the number of dispatched operations -**dispatched_operations_build_amount** -Gauge for the number of dispatched operations that are build actions -**dispatched_operations_test_amount** -Gauge for the number of dispatched operations that are test actions - -**dispatched_operations_unknown_amount** - -Gauge for the number of dispatched operations that could not be identified as build / test - -**dispatched_operations_from_queue_amount** - -Gauge for the number of dispatched operations that came from each queue (using "queue_name" as label) - -**dispatched_operations_tools_amount** - -Gauge for the number of dispatched operations by tool name (using "tool_name" as label) - -**dispatched_operations_mnemonics_amount** - -Gauge for the number of dispatched operations by mnemonic (using "mnemonic" as label) - -**dispatched_operations_command_tools** - -Gauge for the number of dispatched operations by cli tool (using "tool" as label) - -**dispatched_operations_targets_amount** - -Gauge for the number of dispatched operations by target (using "target" as label) - -**dispatched_operations_config_amount** - -Gauge for the number of dispatched operations by config (using "config" as label) - -**dispatched_operations_platform_properties** - -Gauge for the number of dispatched operations by platform properties (using "config" as label) - -**dispatched_operations_clients_being_served** - -The number of build clients currently being served - -**dispatched_operations_requeued_operations_amount** - -The number of dispatched operations that have been requeued **worker_pool_size** @@ -112,14 +68,6 @@ Gauge of the number of execute workers available. Gauge of the size of the queue (using a queue_name label for each individual queue) -**blocked_actions_size** - -Gauge of the number of blocked actions - -**blocked_invocations_size** - -Gauge of the number of blocked invocations - **actions** Counter for the number of actions processed @@ -198,7 +146,7 @@ Counter showing service restarts **cas_size** -Total size of the worker's CAS in bytes +Gauge of total size of the worker's CAS in bytes **cas_ttl_s** @@ -206,7 +154,7 @@ Histogram for amount of time CAS entries live on L1 storage before expiration (s **cas_entry_count** -The total number of entries in the worker's CAS +Gauge of the total number of entries in the worker's CAS Java interceptors can be used to monitor Grpc services using Prometheus. To enable [these metrics](https://github.com/grpc-ecosystem/java-grpc-prometheus), add the following configuration to your server: ``` From 80b5bde9a44904fae0b461a766053ed785823951 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Sat, 2 Mar 2024 10:50:17 -0800 Subject: [PATCH 225/311] chore: bump googleapis (#1655) Bumping to the tip of the https://github.com/googleapis/googleapis main branch. --- deps.bzl | 6 +++--- third_party/BUILD.googleapis | 26 +++++++++++++++----------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/deps.bzl b/deps.bzl index 1624655920..975bc7aad9 100644 --- a/deps.bzl +++ b/deps.bzl @@ -31,9 +31,9 @@ def archive_dependencies(third_party): "build_file": "%s:BUILD.googleapis" % third_party, "patch_cmds": ["find google -name 'BUILD.bazel' -type f -delete"], "patch_cmds_win": ["Remove-Item google -Recurse -Include *.bazel"], - "sha256": "745cb3c2e538e33a07e2e467a15228ccbecadc1337239f6740d57a74d9cdef81", - "strip_prefix": "googleapis-6598bb829c9e9a534be674649ffd1b4671a821f9", - "url": "https://github.com/googleapis/googleapis/archive/6598bb829c9e9a534be674649ffd1b4671a821f9.zip", + "sha256": "1980dc4a4d02420d4da588665e3ecbe55e02a1c2e32d8906a2268c67d1085e0b", + "strip_prefix": "googleapis-5f8a02d6b7e77bd26e0375a00ca20eb2f3ee1ba2", + "url": "https://github.com/googleapis/googleapis/archive/5f8a02d6b7e77bd26e0375a00ca20eb2f3ee1ba2.zip", }, { "name": "remote_apis", diff --git a/third_party/BUILD.googleapis b/third_party/BUILD.googleapis index e51fecb67b..53638b757d 100644 --- a/third_party/BUILD.googleapis +++ b/third_party/BUILD.googleapis @@ -109,13 +109,13 @@ proto_library( srcs = ["google/longrunning/operations.proto"], deps = [ ":google_api_annotations_proto", + ":google_api_client_proto", ":google_api_http_proto", ":google_rpc_status_proto", - ":google_api_client_proto", "@com_google_protobuf//:any_proto", - "@com_google_protobuf//:empty_proto", - "@com_google_protobuf//:duration_proto", "@com_google_protobuf//:descriptor_proto", + "@com_google_protobuf//:duration_proto", + "@com_google_protobuf//:empty_proto", ], ) @@ -148,9 +148,9 @@ proto_library( deps = [ ":google_api_annotations_proto", ":google_api_auth_proto", - ":google_devtools_build_v1_build_events_proto", - ":google_api_field_behavior_proto", ":google_api_client_proto", + ":google_api_field_behavior_proto", + ":google_devtools_build_v1_build_events_proto", "@com_google_protobuf//:any_proto", "@com_google_protobuf//:duration_proto", "@com_google_protobuf//:empty_proto", @@ -175,17 +175,17 @@ proto_library( name = "google_api_client_proto", srcs = ["google/api/client.proto"], deps = [ - "@com_google_protobuf//:descriptor_proto", ":google_api_field_behavior_proto", - ] + ":google_api_launch_stage_proto", + "@com_google_protobuf//:descriptor_proto", + "@com_google_protobuf//:duration_proto", + ], ) proto_library( name = "google_api_field_behavior_proto", srcs = ["google/api/field_behavior.proto"], - deps = [ - "@com_google_protobuf//:descriptor_proto", - ] + deps = ["@com_google_protobuf//:descriptor_proto"], ) proto_library( @@ -197,5 +197,9 @@ proto_library( proto_library( name = "google_api_auth_proto", srcs = ["google/api/auth.proto"], - deps = [":google_api_annotations_proto"], +) + +proto_library( + name = "google_api_launch_stage_proto", + srcs = ["google/api/launch_stage.proto"], ) From cf5f08f1c6a643f6d092beb4747449d9a6d6657f Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Sat, 2 Mar 2024 10:52:12 -0800 Subject: [PATCH 226/311] build(bzlmod): turn off lockfile completely (#1651) There are platform-specific parts that need to be kept up-to-date. A macOS developer might not be able to update the linux/amd64 parts of the manifest. --- .bazelrc | 5 + MODULE.bazel | 2 + MODULE.bazel.lock | 8484 --------------------------------------------- 3 files changed, 7 insertions(+), 8484 deletions(-) delete mode 100644 MODULE.bazel.lock diff --git a/.bazelrc b/.bazelrc index 4946f027c9..5a5d45b6ba 100644 --- a/.bazelrc +++ b/.bazelrc @@ -26,5 +26,10 @@ common --incompatible_disallow_empty_glob common --enable_bzlmod +# See also https://bazel.build/external/lockfile. +common --lockfile_mode=off +# It's off because we have mac/windows/linux developers who may not have access +# to all three to update the platform-specific bits of the lockfile. + # Support protobuf on macOS with Xcode 15.x common:macos --host_cxxopt=-std=c++14 --cxxopt=-std=c++14 diff --git a/MODULE.bazel b/MODULE.bazel index 1fe77da220..dd4df9eb00 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,3 +1,5 @@ +"""Buildfarm build and test""" + module( name = "build_buildfarm", repo_name = "build_buildfarm", diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock deleted file mode 100644 index a58ae1defb..0000000000 --- a/MODULE.bazel.lock +++ /dev/null @@ -1,8484 +0,0 @@ -{ - "lockFileVersion": 3, - "moduleFileHash": "3f11511a2b9a5f6fb04a3324b46b42a4fa6bcae5f2aed6e1f6f6cf980cfd218e", - "flags": { - "cmdRegistries": [ - "https://bcr.bazel.build/" - ], - "cmdModuleOverrides": {}, - "allowedYankedVersions": [], - "envVarAllowedYankedVersions": "", - "ignoreDevDependency": false, - "directDependenciesMode": "WARNING", - "compatibilityMode": "ERROR" - }, - "localOverrideHashes": { - "bazel_tools": "922ea6752dc9105de5af957f7a99a6933c0a6a712d23df6aad16a9c399f7e787" - }, - "moduleDepGraph": { - "": { - "name": "build_buildfarm", - "version": "", - "key": "", - "repoName": "build_buildfarm", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [ - { - "extensionBzlFile": "@rules_jvm_external//:extensions.bzl", - "extensionName": "maven", - "usingModule": "", - "location": { - "file": "@@//:MODULE.bazel", - "line": 47, - "column": 22 - }, - "imports": { - "maven": "maven", - "unpinned_maven": "unpinned_maven" - }, - "devImports": [], - "tags": [ - { - "tagName": "install", - "attributeValues": { - "artifacts": [ - "com.amazonaws:aws-java-sdk-s3:1.12.544", - "com.amazonaws:aws-java-sdk-secretsmanager:1.12.544", - "com.fasterxml.jackson.core:jackson-databind:2.15.0", - "com.github.ben-manes.caffeine:caffeine:2.9.0", - "com.github.docker-java:docker-java:3.3.3", - "com.github.fppt:jedis-mock:1.0.10", - "com.github.jnr:jffi:1.3.11", - "com.github.jnr:jffi:jar:native:1.3.11", - "com.github.jnr:jnr-constants:0.10.4", - "com.github.jnr:jnr-ffi:2.2.14", - "com.github.jnr:jnr-posix:3.1.17", - "com.github.pcj:google-options:1.0.0", - "com.github.serceman:jnr-fuse:0.5.7", - "com.github.luben:zstd-jni:1.5.5-7", - "com.github.oshi:oshi-core:6.4.5", - "com.google.auth:google-auth-library-credentials:1.19.0", - "com.google.auth:google-auth-library-oauth2-http:1.19.0", - "com.google.code.findbugs:jsr305:3.0.2", - "com.google.code.gson:gson:2.10.1", - "com.google.errorprone:error_prone_annotations:2.22.0", - "com.google.errorprone:error_prone_core:2.22.0", - "com.google.guava:failureaccess:1.0.1", - "com.google.guava:guava:32.1.1-jre", - "com.google.j2objc:j2objc-annotations:2.8", - "com.google.jimfs:jimfs:1.3.0", - "com.google.protobuf:protobuf-java-util:3.19.1", - "com.google.protobuf:protobuf-java:3.19.1", - "com.google.truth:truth:1.1.5", - "org.slf4j:slf4j-simple:2.0.9", - "com.googlecode.json-simple:json-simple:1.1.1", - "com.jayway.jsonpath:json-path:2.8.0", - "org.bouncycastle:bcprov-jdk15on:1.70", - "net.jcip:jcip-annotations:1.0", - "io.netty:netty-buffer:4.1.97.Final", - "io.netty:netty-codec:4.1.97.Final", - "io.netty:netty-codec-http:4.1.97.Final", - "io.netty:netty-codec-http2:4.1.97.Final", - "io.netty:netty-codec-socks:4.1.97.Final", - "io.netty:netty-common:4.1.97.Final", - "io.netty:netty-handler:4.1.97.Final", - "io.netty:netty-handler-proxy:4.1.97.Final", - "io.netty:netty-resolver:4.1.97.Final", - "io.netty:netty-transport:4.1.97.Final", - "io.netty:netty-transport-native-epoll:4.1.97.Final", - "io.netty:netty-transport-native-kqueue:4.1.97.Final", - "io.netty:netty-transport-native-unix-common:4.1.97.Final", - "io.grpc:grpc-api:1.56.1", - "io.grpc:grpc-auth:1.56.1", - "io.grpc:grpc-core:1.56.1", - "io.grpc:grpc-context:1.56.1", - "io.grpc:grpc-netty:1.56.1", - "io.grpc:grpc-stub:1.56.1", - "io.grpc:grpc-protobuf:1.56.1", - "io.grpc:grpc-testing:1.56.1", - "io.grpc:grpc-services:1.56.1", - "io.grpc:grpc-netty-shaded:1.56.1", - "io.prometheus:simpleclient:0.15.0", - "io.prometheus:simpleclient_hotspot:0.15.0", - "io.prometheus:simpleclient_httpserver:0.15.0", - "junit:junit:4.13.2", - "javax.annotation:javax.annotation-api:1.3.2", - "net.javacrumbs.future-converter:future-converter-java8-guava:1.2.0", - "org.apache.commons:commons-compress:1.23.0", - "org.apache.commons:commons-pool2:2.11.1", - "org.apache.commons:commons-lang3:3.13.0", - "commons-io:commons-io:2.13.0", - "me.dinowernli:java-grpc-prometheus:0.6.0", - "org.apache.tomcat:annotations-api:6.0.53", - "org.checkerframework:checker-qual:3.38.0", - "org.mockito:mockito-core:2.25.0", - "org.openjdk.jmh:jmh-core:1.37", - "org.openjdk.jmh:jmh-generator-annprocess:1.37", - "org.redisson:redisson:3.23.4", - "org.threeten:threetenbp:1.6.8", - "org.xerial:sqlite-jdbc:3.34.0", - "org.jetbrains:annotations:16.0.2", - "org.yaml:snakeyaml:2.2", - "org.projectlombok:lombok:1.18.30" - ], - "fail_if_repin_required": true, - "generate_compat_repositories": true, - "lock_file": "//:maven_install.json" - }, - "devDependency": false, - "location": { - "file": "@@//:MODULE.bazel", - "line": 48, - "column": 14 - } - } - ], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - } - ], - "deps": { - "bazel_gazelle": "gazelle@0.34.0", - "platforms": "platforms@0.0.7", - "rules_cc": "rules_cc@0.0.9", - "io_bazel_rules_go": "rules_go@0.43.0", - "rules_jvm_external": "rules_jvm_external@5.3", - "rules_license": "rules_license@0.0.7", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - } - }, - "gazelle@0.34.0": { - "name": "gazelle", - "version": "0.34.0", - "key": "gazelle@0.34.0", - "repoName": "bazel_gazelle", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [ - { - "extensionBzlFile": "@io_bazel_rules_go//go:extensions.bzl", - "extensionName": "go_sdk", - "usingModule": "gazelle@0.34.0", - "location": { - "file": "https://bcr.bazel.build/modules/gazelle/0.34.0/MODULE.bazel", - "line": 12, - "column": 23 - }, - "imports": { - "go_host_compatible_sdk_label": "go_host_compatible_sdk_label" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - }, - { - "extensionBzlFile": "@bazel_gazelle//internal/bzlmod:non_module_deps.bzl", - "extensionName": "non_module_deps", - "usingModule": "gazelle@0.34.0", - "location": { - "file": "https://bcr.bazel.build/modules/gazelle/0.34.0/MODULE.bazel", - "line": 20, - "column": 32 - }, - "imports": { - "bazel_gazelle_go_repository_cache": "bazel_gazelle_go_repository_cache", - "bazel_gazelle_go_repository_tools": "bazel_gazelle_go_repository_tools", - "bazel_gazelle_is_bazel_module": "bazel_gazelle_is_bazel_module" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - }, - { - "extensionBzlFile": "@bazel_gazelle//:extensions.bzl", - "extensionName": "go_deps", - "usingModule": "gazelle@0.34.0", - "location": { - "file": "https://bcr.bazel.build/modules/gazelle/0.34.0/MODULE.bazel", - "line": 28, - "column": 24 - }, - "imports": { - "com_github_bazelbuild_buildtools": "com_github_bazelbuild_buildtools", - "com_github_bmatcuk_doublestar_v4": "com_github_bmatcuk_doublestar_v4", - "com_github_fsnotify_fsnotify": "com_github_fsnotify_fsnotify", - "com_github_google_go_cmp": "com_github_google_go_cmp", - "com_github_pmezard_go_difflib": "com_github_pmezard_go_difflib", - "org_golang_x_mod": "org_golang_x_mod", - "org_golang_x_sync": "org_golang_x_sync", - "org_golang_x_tools": "org_golang_x_tools", - "org_golang_x_tools_go_vcs": "org_golang_x_tools_go_vcs", - "bazel_gazelle_go_repository_config": "bazel_gazelle_go_repository_config" - }, - "devImports": [], - "tags": [ - { - "tagName": "from_file", - "attributeValues": { - "go_mod": "//:go.mod" - }, - "devDependency": false, - "location": { - "file": "https://bcr.bazel.build/modules/gazelle/0.34.0/MODULE.bazel", - "line": 29, - "column": 18 - } - }, - { - "tagName": "module", - "attributeValues": { - "path": "golang.org/x/tools", - "sum": "h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=", - "version": "v0.13.0" - }, - "devDependency": false, - "location": { - "file": "https://bcr.bazel.build/modules/gazelle/0.34.0/MODULE.bazel", - "line": 33, - "column": 15 - } - } - ], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - } - ], - "deps": { - "bazel_skylib": "bazel_skylib@1.4.1", - "com_google_protobuf": "protobuf@3.19.6", - "io_bazel_rules_go": "rules_go@0.43.0", - "rules_proto": "rules_proto@4.0.0", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "gazelle~0.34.0", - "urls": [ - "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.34.0/bazel-gazelle-v0.34.0.tar.gz" - ], - "integrity": "sha256-tzh/cu+1n4duTarkLx05EtDUVWPqx8sj0d4LCUq1iM8=", - "strip_prefix": "", - "remote_patches": {}, - "remote_patch_strip": 0 - } - } - }, - "platforms@0.0.7": { - "name": "platforms", - "version": "0.0.7", - "key": "platforms@0.0.7", - "repoName": "platforms", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "rules_license": "rules_license@0.0.7", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "platforms", - "urls": [ - "https://github.com/bazelbuild/platforms/releases/download/0.0.7/platforms-0.0.7.tar.gz" - ], - "integrity": "sha256-OlYcmee9vpFzqmU/1Xn+hJ8djWc5V4CrR3Cx84FDHVE=", - "strip_prefix": "", - "remote_patches": {}, - "remote_patch_strip": 0 - } - } - }, - "rules_cc@0.0.9": { - "name": "rules_cc", - "version": "0.0.9", - "key": "rules_cc@0.0.9", - "repoName": "rules_cc", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [ - "@local_config_cc_toolchains//:all" - ], - "extensionUsages": [ - { - "extensionBzlFile": "@bazel_tools//tools/cpp:cc_configure.bzl", - "extensionName": "cc_configure_extension", - "usingModule": "rules_cc@0.0.9", - "location": { - "file": "https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel", - "line": 9, - "column": 29 - }, - "imports": { - "local_config_cc_toolchains": "local_config_cc_toolchains" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - } - ], - "deps": { - "platforms": "platforms@0.0.7", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_cc~0.0.9", - "urls": [ - "https://github.com/bazelbuild/rules_cc/releases/download/0.0.9/rules_cc-0.0.9.tar.gz" - ], - "integrity": "sha256-IDeHW5pEVtzkp50RKorohbvEqtlo5lh9ym5k86CQDN8=", - "strip_prefix": "rules_cc-0.0.9", - "remote_patches": { - "https://bcr.bazel.build/modules/rules_cc/0.0.9/patches/module_dot_bazel_version.patch": "sha256-mM+qzOI0SgAdaJBlWOSMwMPKpaA9b7R37Hj/tp5bb4g=" - }, - "remote_patch_strip": 0 - } - } - }, - "rules_go@0.43.0": { - "name": "rules_go", - "version": "0.43.0", - "key": "rules_go@0.43.0", - "repoName": "io_bazel_rules_go", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [ - "@go_toolchains//:all" - ], - "extensionUsages": [ - { - "extensionBzlFile": "@io_bazel_rules_go//go/private:extensions.bzl", - "extensionName": "non_module_dependencies", - "usingModule": "rules_go@0.43.0", - "location": { - "file": "https://bcr.bazel.build/modules/rules_go/0.43.0/MODULE.bazel", - "line": 14, - "column": 40 - }, - "imports": { - "io_bazel_rules_nogo": "io_bazel_rules_nogo" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - }, - { - "extensionBzlFile": "@io_bazel_rules_go//go:extensions.bzl", - "extensionName": "go_sdk", - "usingModule": "rules_go@0.43.0", - "location": { - "file": "https://bcr.bazel.build/modules/rules_go/0.43.0/MODULE.bazel", - "line": 20, - "column": 23 - }, - "imports": { - "go_toolchains": "go_toolchains" - }, - "devImports": [], - "tags": [ - { - "tagName": "download", - "attributeValues": { - "name": "go_default_sdk", - "version": "1.21.1" - }, - "devDependency": false, - "location": { - "file": "https://bcr.bazel.build/modules/rules_go/0.43.0/MODULE.bazel", - "line": 21, - "column": 16 - } - } - ], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - }, - { - "extensionBzlFile": "@gazelle//:extensions.bzl", - "extensionName": "go_deps", - "usingModule": "rules_go@0.43.0", - "location": { - "file": "https://bcr.bazel.build/modules/rules_go/0.43.0/MODULE.bazel", - "line": 31, - "column": 24 - }, - "imports": { - "com_github_gogo_protobuf": "com_github_gogo_protobuf", - "com_github_golang_mock": "com_github_golang_mock", - "com_github_golang_protobuf": "com_github_golang_protobuf", - "org_golang_google_genproto": "org_golang_google_genproto", - "org_golang_google_grpc": "org_golang_google_grpc", - "org_golang_google_protobuf": "org_golang_google_protobuf", - "org_golang_x_net": "org_golang_x_net" - }, - "devImports": [], - "tags": [ - { - "tagName": "from_file", - "attributeValues": { - "go_mod": "//:go.mod" - }, - "devDependency": false, - "location": { - "file": "https://bcr.bazel.build/modules/rules_go/0.43.0/MODULE.bazel", - "line": 32, - "column": 18 - } - }, - { - "tagName": "module", - "attributeValues": { - "path": "github.com/gogo/protobuf", - "sum": "h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=", - "version": "v1.3.2" - }, - "devDependency": false, - "location": { - "file": "https://bcr.bazel.build/modules/rules_go/0.43.0/MODULE.bazel", - "line": 33, - "column": 15 - } - } - ], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - } - ], - "deps": { - "bazel_features": "bazel_features@1.1.1", - "bazel_skylib": "bazel_skylib@1.4.1", - "platforms": "platforms@0.0.7", - "rules_proto": "rules_proto@4.0.0", - "com_google_protobuf": "protobuf@3.19.6", - "gazelle": "gazelle@0.34.0", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_go~0.43.0", - "urls": [ - "https://github.com/bazelbuild/rules_go/releases/download/v0.43.0/rules_go-v0.43.0.zip" - ], - "integrity": "sha256-1qtrV+SMCVI+kwUPE2mPcIQoz9XmGSUuNp03evZZdwc=", - "strip_prefix": "", - "remote_patches": {}, - "remote_patch_strip": 0 - } - } - }, - "rules_jvm_external@5.3": { - "name": "rules_jvm_external", - "version": "5.3", - "key": "rules_jvm_external@5.3", - "repoName": "rules_jvm_external", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [ - { - "extensionBzlFile": "@rules_jvm_external//:non-module-deps.bzl", - "extensionName": "non_module_deps", - "usingModule": "rules_jvm_external@5.3", - "location": { - "file": "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel", - "line": 9, - "column": 32 - }, - "imports": { - "io_bazel_rules_kotlin": "io_bazel_rules_kotlin" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - }, - { - "extensionBzlFile": ":extensions.bzl", - "extensionName": "maven", - "usingModule": "rules_jvm_external@5.3", - "location": { - "file": "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel", - "line": 16, - "column": 22 - }, - "imports": { - "rules_jvm_external_deps": "rules_jvm_external_deps" - }, - "devImports": [], - "tags": [ - { - "tagName": "install", - "attributeValues": { - "name": "rules_jvm_external_deps", - "artifacts": [ - "com.google.auth:google-auth-library-credentials:1.17.0", - "com.google.auth:google-auth-library-oauth2-http:1.17.0", - "com.google.cloud:google-cloud-core:2.18.1", - "com.google.cloud:google-cloud-storage:2.22.3", - "com.google.code.gson:gson:2.10.1", - "com.google.googlejavaformat:google-java-format:1.17.0", - "com.google.guava:guava:32.0.0-jre", - "org.apache.maven:maven-artifact:3.9.2", - "software.amazon.awssdk:s3:2.20.78" - ], - "lock_file": "@rules_jvm_external//:rules_jvm_external_deps_install.json" - }, - "devDependency": false, - "location": { - "file": "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel", - "line": 18, - "column": 14 - } - } - ], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - } - ], - "deps": { - "bazel_skylib": "bazel_skylib@1.4.1", - "io_bazel_stardoc": "stardoc@0.5.3", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_jvm_external~5.3", - "urls": [ - "https://github.com/bazelbuild/rules_jvm_external/releases/download/5.3/rules_jvm_external-5.3.tar.gz" - ], - "integrity": "sha256-0x42m4VDIspQmOoSxp1xdd7ZcUNeVcGN2d1fKcxSSaw=", - "strip_prefix": "rules_jvm_external-5.3", - "remote_patches": {}, - "remote_patch_strip": 0 - } - } - }, - "rules_license@0.0.7": { - "name": "rules_license", - "version": "0.0.7", - "key": "rules_license@0.0.7", - "repoName": "rules_license", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_license~0.0.7", - "urls": [ - "https://github.com/bazelbuild/rules_license/releases/download/0.0.7/rules_license-0.0.7.tar.gz" - ], - "integrity": "sha256-RTHezLkTY5ww5cdRKgVNXYdWmNrrddjPkPKEN1/nw2A=", - "strip_prefix": "", - "remote_patches": {}, - "remote_patch_strip": 0 - } - } - }, - "bazel_tools@_": { - "name": "bazel_tools", - "version": "", - "key": "bazel_tools@_", - "repoName": "bazel_tools", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [ - "@local_config_cc_toolchains//:all", - "@local_config_sh//:local_sh_toolchain" - ], - "extensionUsages": [ - { - "extensionBzlFile": "@bazel_tools//tools/cpp:cc_configure.bzl", - "extensionName": "cc_configure_extension", - "usingModule": "bazel_tools@_", - "location": { - "file": "@@bazel_tools//:MODULE.bazel", - "line": 17, - "column": 29 - }, - "imports": { - "local_config_cc": "local_config_cc", - "local_config_cc_toolchains": "local_config_cc_toolchains" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - }, - { - "extensionBzlFile": "@bazel_tools//tools/osx:xcode_configure.bzl", - "extensionName": "xcode_configure_extension", - "usingModule": "bazel_tools@_", - "location": { - "file": "@@bazel_tools//:MODULE.bazel", - "line": 21, - "column": 32 - }, - "imports": { - "local_config_xcode": "local_config_xcode" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - }, - { - "extensionBzlFile": "@rules_java//java:extensions.bzl", - "extensionName": "toolchains", - "usingModule": "bazel_tools@_", - "location": { - "file": "@@bazel_tools//:MODULE.bazel", - "line": 24, - "column": 32 - }, - "imports": { - "local_jdk": "local_jdk", - "remote_java_tools": "remote_java_tools", - "remote_java_tools_linux": "remote_java_tools_linux", - "remote_java_tools_windows": "remote_java_tools_windows", - "remote_java_tools_darwin_x86_64": "remote_java_tools_darwin_x86_64", - "remote_java_tools_darwin_arm64": "remote_java_tools_darwin_arm64" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - }, - { - "extensionBzlFile": "@bazel_tools//tools/sh:sh_configure.bzl", - "extensionName": "sh_configure_extension", - "usingModule": "bazel_tools@_", - "location": { - "file": "@@bazel_tools//:MODULE.bazel", - "line": 35, - "column": 39 - }, - "imports": { - "local_config_sh": "local_config_sh" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - }, - { - "extensionBzlFile": "@bazel_tools//tools/test:extensions.bzl", - "extensionName": "remote_coverage_tools_extension", - "usingModule": "bazel_tools@_", - "location": { - "file": "@@bazel_tools//:MODULE.bazel", - "line": 39, - "column": 48 - }, - "imports": { - "remote_coverage_tools": "remote_coverage_tools" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - }, - { - "extensionBzlFile": "@bazel_tools//tools/android:android_extensions.bzl", - "extensionName": "remote_android_tools_extensions", - "usingModule": "bazel_tools@_", - "location": { - "file": "@@bazel_tools//:MODULE.bazel", - "line": 42, - "column": 42 - }, - "imports": { - "android_gmaven_r8": "android_gmaven_r8", - "android_tools": "android_tools" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - } - ], - "deps": { - "rules_cc": "rules_cc@0.0.9", - "rules_java": "rules_java@7.1.0", - "rules_license": "rules_license@0.0.7", - "rules_proto": "rules_proto@4.0.0", - "rules_python": "rules_python@0.4.0", - "platforms": "platforms@0.0.7", - "com_google_protobuf": "protobuf@3.19.6", - "zlib": "zlib@1.3", - "build_bazel_apple_support": "apple_support@1.5.0", - "local_config_platform": "local_config_platform@_" - } - }, - "local_config_platform@_": { - "name": "local_config_platform", - "version": "", - "key": "local_config_platform@_", - "repoName": "local_config_platform", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "platforms": "platforms@0.0.7", - "bazel_tools": "bazel_tools@_" - } - }, - "bazel_skylib@1.4.1": { - "name": "bazel_skylib", - "version": "1.4.1", - "key": "bazel_skylib@1.4.1", - "repoName": "bazel_skylib", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [ - "//toolchains/unittest:cmd_toolchain", - "//toolchains/unittest:bash_toolchain" - ], - "extensionUsages": [], - "deps": { - "platforms": "platforms@0.0.7", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "bazel_skylib~1.4.1", - "urls": [ - "https://github.com/bazelbuild/bazel-skylib/releases/download/1.4.1/bazel-skylib-1.4.1.tar.gz" - ], - "integrity": "sha256-uKFSeQF3QYCvx5iusoxGNL3M8ZxNmOe90c550f6aqtc=", - "strip_prefix": "", - "remote_patches": {}, - "remote_patch_strip": 0 - } - } - }, - "protobuf@3.19.6": { - "name": "protobuf", - "version": "3.19.6", - "key": "protobuf@3.19.6", - "repoName": "protobuf", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "bazel_skylib": "bazel_skylib@1.4.1", - "zlib": "zlib@1.3", - "rules_python": "rules_python@0.4.0", - "rules_cc": "rules_cc@0.0.9", - "rules_proto": "rules_proto@4.0.0", - "rules_java": "rules_java@7.1.0", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "protobuf~3.19.6", - "urls": [ - "https://github.com/protocolbuffers/protobuf/archive/refs/tags/v3.19.6.zip" - ], - "integrity": "sha256-OH4sVZuyx8G8N5jE5s/wFTgaebJ1hpavy/johzC0c4k=", - "strip_prefix": "protobuf-3.19.6", - "remote_patches": { - "https://bcr.bazel.build/modules/protobuf/3.19.6/patches/relative_repo_names.patch": "sha256-w/5gw/zGv8NFId+669hcdw1Uus2lxgYpulATHIwIByI=", - "https://bcr.bazel.build/modules/protobuf/3.19.6/patches/remove_dependency_on_rules_jvm_external.patch": "sha256-THUTnVgEBmjA0W7fKzIyZOVG58DnW9HQTkr4D2zKUUc=", - "https://bcr.bazel.build/modules/protobuf/3.19.6/patches/add_module_dot_bazel_for_examples.patch": "sha256-s/b1gi3baK3LsXefI2rQilhmkb2R5jVJdnT6zEcdfHY=", - "https://bcr.bazel.build/modules/protobuf/3.19.6/patches/module_dot_bazel.patch": "sha256-S0DEni8zgx7rHscW3z/rCEubQnYec0XhNet640cw0h4=" - }, - "remote_patch_strip": 1 - } - } - }, - "rules_proto@4.0.0": { - "name": "rules_proto", - "version": "4.0.0", - "key": "rules_proto@4.0.0", - "repoName": "rules_proto", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "bazel_skylib": "bazel_skylib@1.4.1", - "rules_cc": "rules_cc@0.0.9", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_proto~4.0.0", - "urls": [ - "https://github.com/bazelbuild/rules_proto/archive/refs/tags/4.0.0.zip" - ], - "integrity": "sha256-Lr5z6xyuRA19pNtRYMGjKaynwQpck4H/lwYyVjyhoq4=", - "strip_prefix": "rules_proto-4.0.0", - "remote_patches": { - "https://bcr.bazel.build/modules/rules_proto/4.0.0/patches/module_dot_bazel.patch": "sha256-MclJO7tIAM2ElDAmscNId9pKTpOuDGHgVlW/9VBOIp0=" - }, - "remote_patch_strip": 0 - } - } - }, - "bazel_features@1.1.1": { - "name": "bazel_features", - "version": "1.1.1", - "key": "bazel_features@1.1.1", - "repoName": "bazel_features", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [ - { - "extensionBzlFile": "@bazel_features//private:extensions.bzl", - "extensionName": "version_extension", - "usingModule": "bazel_features@1.1.1", - "location": { - "file": "https://bcr.bazel.build/modules/bazel_features/1.1.1/MODULE.bazel", - "line": 6, - "column": 24 - }, - "imports": { - "bazel_features_globals": "bazel_features_globals", - "bazel_features_version": "bazel_features_version" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - } - ], - "deps": { - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "bazel_features~1.1.1", - "urls": [ - "https://github.com/bazel-contrib/bazel_features/releases/download/v1.1.1/bazel_features-v1.1.1.tar.gz" - ], - "integrity": "sha256-YsJuQn5cvHUQJERpJ2IuOYqdzfMsZDJSOIFXCdEcEag=", - "strip_prefix": "bazel_features-1.1.1", - "remote_patches": { - "https://bcr.bazel.build/modules/bazel_features/1.1.1/patches/module_dot_bazel_version.patch": "sha256-+56MAEsc7bYN/Pzhn252ZQUxiRzZg9bynXj1qpsmCYs=" - }, - "remote_patch_strip": 1 - } - } - }, - "stardoc@0.5.3": { - "name": "stardoc", - "version": "0.5.3", - "key": "stardoc@0.5.3", - "repoName": "stardoc", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "bazel_skylib": "bazel_skylib@1.4.1", - "rules_java": "rules_java@7.1.0", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "stardoc~0.5.3", - "urls": [ - "https://github.com/bazelbuild/stardoc/releases/download/0.5.3/stardoc-0.5.3.tar.gz" - ], - "integrity": "sha256-P9j+xN3sPGcL2BCQTi4zFwvt/hL5Ct+UNQgYS+RYyLs=", - "strip_prefix": "", - "remote_patches": { - "https://bcr.bazel.build/modules/stardoc/0.5.3/patches/module_dot_bazel.patch": "sha256-Lgpy9OCr0zBWYuHoyM1rJJrgxn23X/bwgICEF7XiEug=" - }, - "remote_patch_strip": 0 - } - } - }, - "rules_java@7.1.0": { - "name": "rules_java", - "version": "7.1.0", - "key": "rules_java@7.1.0", - "repoName": "rules_java", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [ - "//toolchains:all", - "@local_jdk//:runtime_toolchain_definition", - "@local_jdk//:bootstrap_runtime_toolchain_definition", - "@remotejdk11_linux_toolchain_config_repo//:all", - "@remotejdk11_linux_aarch64_toolchain_config_repo//:all", - "@remotejdk11_linux_ppc64le_toolchain_config_repo//:all", - "@remotejdk11_linux_s390x_toolchain_config_repo//:all", - "@remotejdk11_macos_toolchain_config_repo//:all", - "@remotejdk11_macos_aarch64_toolchain_config_repo//:all", - "@remotejdk11_win_toolchain_config_repo//:all", - "@remotejdk11_win_arm64_toolchain_config_repo//:all", - "@remotejdk17_linux_toolchain_config_repo//:all", - "@remotejdk17_linux_aarch64_toolchain_config_repo//:all", - "@remotejdk17_linux_ppc64le_toolchain_config_repo//:all", - "@remotejdk17_linux_s390x_toolchain_config_repo//:all", - "@remotejdk17_macos_toolchain_config_repo//:all", - "@remotejdk17_macos_aarch64_toolchain_config_repo//:all", - "@remotejdk17_win_toolchain_config_repo//:all", - "@remotejdk17_win_arm64_toolchain_config_repo//:all", - "@remotejdk21_linux_toolchain_config_repo//:all", - "@remotejdk21_linux_aarch64_toolchain_config_repo//:all", - "@remotejdk21_macos_toolchain_config_repo//:all", - "@remotejdk21_macos_aarch64_toolchain_config_repo//:all", - "@remotejdk21_win_toolchain_config_repo//:all" - ], - "extensionUsages": [ - { - "extensionBzlFile": "@rules_java//java:extensions.bzl", - "extensionName": "toolchains", - "usingModule": "rules_java@7.1.0", - "location": { - "file": "https://bcr.bazel.build/modules/rules_java/7.1.0/MODULE.bazel", - "line": 19, - "column": 27 - }, - "imports": { - "remote_java_tools": "remote_java_tools", - "remote_java_tools_linux": "remote_java_tools_linux", - "remote_java_tools_windows": "remote_java_tools_windows", - "remote_java_tools_darwin_x86_64": "remote_java_tools_darwin_x86_64", - "remote_java_tools_darwin_arm64": "remote_java_tools_darwin_arm64", - "local_jdk": "local_jdk", - "remotejdk11_linux_toolchain_config_repo": "remotejdk11_linux_toolchain_config_repo", - "remotejdk11_linux_aarch64_toolchain_config_repo": "remotejdk11_linux_aarch64_toolchain_config_repo", - "remotejdk11_linux_ppc64le_toolchain_config_repo": "remotejdk11_linux_ppc64le_toolchain_config_repo", - "remotejdk11_linux_s390x_toolchain_config_repo": "remotejdk11_linux_s390x_toolchain_config_repo", - "remotejdk11_macos_toolchain_config_repo": "remotejdk11_macos_toolchain_config_repo", - "remotejdk11_macos_aarch64_toolchain_config_repo": "remotejdk11_macos_aarch64_toolchain_config_repo", - "remotejdk11_win_toolchain_config_repo": "remotejdk11_win_toolchain_config_repo", - "remotejdk11_win_arm64_toolchain_config_repo": "remotejdk11_win_arm64_toolchain_config_repo", - "remotejdk17_linux_toolchain_config_repo": "remotejdk17_linux_toolchain_config_repo", - "remotejdk17_linux_aarch64_toolchain_config_repo": "remotejdk17_linux_aarch64_toolchain_config_repo", - "remotejdk17_linux_ppc64le_toolchain_config_repo": "remotejdk17_linux_ppc64le_toolchain_config_repo", - "remotejdk17_linux_s390x_toolchain_config_repo": "remotejdk17_linux_s390x_toolchain_config_repo", - "remotejdk17_macos_toolchain_config_repo": "remotejdk17_macos_toolchain_config_repo", - "remotejdk17_macos_aarch64_toolchain_config_repo": "remotejdk17_macos_aarch64_toolchain_config_repo", - "remotejdk17_win_toolchain_config_repo": "remotejdk17_win_toolchain_config_repo", - "remotejdk17_win_arm64_toolchain_config_repo": "remotejdk17_win_arm64_toolchain_config_repo", - "remotejdk21_linux_toolchain_config_repo": "remotejdk21_linux_toolchain_config_repo", - "remotejdk21_linux_aarch64_toolchain_config_repo": "remotejdk21_linux_aarch64_toolchain_config_repo", - "remotejdk21_macos_toolchain_config_repo": "remotejdk21_macos_toolchain_config_repo", - "remotejdk21_macos_aarch64_toolchain_config_repo": "remotejdk21_macos_aarch64_toolchain_config_repo", - "remotejdk21_win_toolchain_config_repo": "remotejdk21_win_toolchain_config_repo" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - } - ], - "deps": { - "platforms": "platforms@0.0.7", - "rules_cc": "rules_cc@0.0.9", - "bazel_skylib": "bazel_skylib@1.4.1", - "rules_proto": "rules_proto@4.0.0", - "rules_license": "rules_license@0.0.7", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0", - "urls": [ - "https://github.com/bazelbuild/rules_java/releases/download/7.1.0/rules_java-7.1.0.tar.gz" - ], - "integrity": "sha256-o3pOX2OrgnFuXdau75iO2EYcegC46TYnImKJn1h81OE=", - "strip_prefix": "", - "remote_patches": {}, - "remote_patch_strip": 0 - } - } - }, - "rules_python@0.4.0": { - "name": "rules_python", - "version": "0.4.0", - "key": "rules_python@0.4.0", - "repoName": "rules_python", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [ - "@bazel_tools//tools/python:autodetecting_toolchain" - ], - "extensionUsages": [ - { - "extensionBzlFile": "@rules_python//bzlmod:extensions.bzl", - "extensionName": "pip_install", - "usingModule": "rules_python@0.4.0", - "location": { - "file": "https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel", - "line": 7, - "column": 28 - }, - "imports": { - "pypi__click": "pypi__click", - "pypi__pip": "pypi__pip", - "pypi__pip_tools": "pypi__pip_tools", - "pypi__pkginfo": "pypi__pkginfo", - "pypi__setuptools": "pypi__setuptools", - "pypi__wheel": "pypi__wheel" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - } - ], - "deps": { - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_python~0.4.0", - "urls": [ - "https://github.com/bazelbuild/rules_python/releases/download/0.4.0/rules_python-0.4.0.tar.gz" - ], - "integrity": "sha256-lUqom0kb5KCDMEosuDgBnIuMNyCnq7nEy4GseiQjDOo=", - "strip_prefix": "", - "remote_patches": { - "https://bcr.bazel.build/modules/rules_python/0.4.0/patches/propagate_pip_install_dependencies.patch": "sha256-v7S/dem/mixg63MF4KoRGDA4KEol9ab/tIVp+6Xq0D0=", - "https://bcr.bazel.build/modules/rules_python/0.4.0/patches/module_dot_bazel.patch": "sha256-kG4VIfWxQazzTuh50mvsx6pmyoRVA4lfH5rkto/Oq+Y=" - }, - "remote_patch_strip": 1 - } - } - }, - "zlib@1.3": { - "name": "zlib", - "version": "1.3", - "key": "zlib@1.3", - "repoName": "zlib", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "platforms": "platforms@0.0.7", - "rules_cc": "rules_cc@0.0.9", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "zlib~1.3", - "urls": [ - "https://github.com/madler/zlib/releases/download/v1.3/zlib-1.3.tar.gz" - ], - "integrity": "sha256-/wukwpIBPbwnUws6geH5qBPNOd4Byl4Pi/NVcC76WT4=", - "strip_prefix": "zlib-1.3", - "remote_patches": { - "https://bcr.bazel.build/modules/zlib/1.3/patches/add_build_file.patch": "sha256-Ei+FYaaOo7A3jTKunMEodTI0Uw5NXQyZEcboMC8JskY=", - "https://bcr.bazel.build/modules/zlib/1.3/patches/module_dot_bazel.patch": "sha256-fPWLM+2xaF/kuy+kZc1YTfW6hNjrkG400Ho7gckuyJk=" - }, - "remote_patch_strip": 0 - } - } - }, - "apple_support@1.5.0": { - "name": "apple_support", - "version": "1.5.0", - "key": "apple_support@1.5.0", - "repoName": "build_bazel_apple_support", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [ - "@local_config_apple_cc_toolchains//:all" - ], - "extensionUsages": [ - { - "extensionBzlFile": "@build_bazel_apple_support//crosstool:setup.bzl", - "extensionName": "apple_cc_configure_extension", - "usingModule": "apple_support@1.5.0", - "location": { - "file": "https://bcr.bazel.build/modules/apple_support/1.5.0/MODULE.bazel", - "line": 17, - "column": 35 - }, - "imports": { - "local_config_apple_cc": "local_config_apple_cc", - "local_config_apple_cc_toolchains": "local_config_apple_cc_toolchains" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - } - ], - "deps": { - "bazel_skylib": "bazel_skylib@1.4.1", - "platforms": "platforms@0.0.7", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "apple_support~1.5.0", - "urls": [ - "https://github.com/bazelbuild/apple_support/releases/download/1.5.0/apple_support.1.5.0.tar.gz" - ], - "integrity": "sha256-miM41vja0yRPgj8txghKA+TQ+7J8qJLclw5okNW0gYQ=", - "strip_prefix": "", - "remote_patches": {}, - "remote_patch_strip": 0 - } - } - } - }, - "moduleExtensions": { - "@@apple_support~1.5.0//crosstool:setup.bzl%apple_cc_configure_extension": { - "general": { - "bzlTransitiveDigest": "pMLFCYaRPkgXPQ8vtuNkMfiHfPmRBy6QJfnid4sWfv0=", - "accumulatedFileDigests": {}, - "envVariables": {}, - "generatedRepoSpecs": { - "local_config_apple_cc": { - "bzlFile": "@@apple_support~1.5.0//crosstool:setup.bzl", - "ruleClassName": "_apple_cc_autoconf", - "attributes": { - "name": "apple_support~1.5.0~apple_cc_configure_extension~local_config_apple_cc" - } - }, - "local_config_apple_cc_toolchains": { - "bzlFile": "@@apple_support~1.5.0//crosstool:setup.bzl", - "ruleClassName": "_apple_cc_autoconf_toolchains", - "attributes": { - "name": "apple_support~1.5.0~apple_cc_configure_extension~local_config_apple_cc_toolchains" - } - } - } - } - }, - "@@bazel_features~1.1.1//private:extensions.bzl%version_extension": { - "general": { - "bzlTransitiveDigest": "xm7Skm1Las5saxzFWt2hbS+e68BWi+MXyt6+lKIhjPA=", - "accumulatedFileDigests": {}, - "envVariables": {}, - "generatedRepoSpecs": { - "bazel_features_version": { - "bzlFile": "@@bazel_features~1.1.1//private:version_repo.bzl", - "ruleClassName": "version_repo", - "attributes": { - "name": "bazel_features~1.1.1~version_extension~bazel_features_version" - } - }, - "bazel_features_globals": { - "bzlFile": "@@bazel_features~1.1.1//private:globals_repo.bzl", - "ruleClassName": "globals_repo", - "attributes": { - "name": "bazel_features~1.1.1~version_extension~bazel_features_globals", - "globals": { - "RunEnvironmentInfo": "5.3.0", - "DefaultInfo": "0.0.1", - "__TestingOnly_NeverAvailable": "1000000000.0.0" - } - } - } - } - } - }, - "@@bazel_tools//tools/cpp:cc_configure.bzl%cc_configure_extension": { - "general": { - "bzlTransitiveDigest": "O9sf6ilKWU9Veed02jG9o2HM/xgV/UAyciuFBuxrFRY=", - "accumulatedFileDigests": {}, - "envVariables": {}, - "generatedRepoSpecs": { - "local_config_cc": { - "bzlFile": "@@bazel_tools//tools/cpp:cc_configure.bzl", - "ruleClassName": "cc_autoconf", - "attributes": { - "name": "bazel_tools~cc_configure_extension~local_config_cc" - } - }, - "local_config_cc_toolchains": { - "bzlFile": "@@bazel_tools//tools/cpp:cc_configure.bzl", - "ruleClassName": "cc_autoconf_toolchains", - "attributes": { - "name": "bazel_tools~cc_configure_extension~local_config_cc_toolchains" - } - } - } - } - }, - "@@bazel_tools//tools/osx:xcode_configure.bzl%xcode_configure_extension": { - "general": { - "bzlTransitiveDigest": "Qh2bWTU6QW6wkrd87qrU4YeY+SG37Nvw3A0PR4Y0L2Y=", - "accumulatedFileDigests": {}, - "envVariables": {}, - "generatedRepoSpecs": { - "local_config_xcode": { - "bzlFile": "@@bazel_tools//tools/osx:xcode_configure.bzl", - "ruleClassName": "xcode_autoconf", - "attributes": { - "name": "bazel_tools~xcode_configure_extension~local_config_xcode", - "xcode_locator": "@bazel_tools//tools/osx:xcode_locator.m", - "remote_xcode": "" - } - } - } - } - }, - "@@bazel_tools//tools/sh:sh_configure.bzl%sh_configure_extension": { - "general": { - "bzlTransitiveDigest": "hp4NgmNjEg5+xgvzfh6L83bt9/aiiWETuNpwNuF1MSU=", - "accumulatedFileDigests": {}, - "envVariables": {}, - "generatedRepoSpecs": { - "local_config_sh": { - "bzlFile": "@@bazel_tools//tools/sh:sh_configure.bzl", - "ruleClassName": "sh_config", - "attributes": { - "name": "bazel_tools~sh_configure_extension~local_config_sh" - } - } - } - } - }, - "@@rules_go~0.43.0//go:extensions.bzl%go_sdk": { - "os:osx,arch:aarch64": { - "bzlTransitiveDigest": "X7FY+0kUDFpsa3ulS9IPEJAqEW8vwFdmD7u4epims+M=", - "accumulatedFileDigests": {}, - "envVariables": {}, - "generatedRepoSpecs": { - "go_default_sdk": { - "bzlFile": "@@rules_go~0.43.0//go/private:sdk.bzl", - "ruleClassName": "go_download_sdk_rule", - "attributes": { - "name": "rules_go~0.43.0~go_sdk~go_default_sdk", - "goos": "", - "goarch": "", - "sdks": {}, - "experiments": [], - "patches": [], - "patch_strip": 0, - "urls": [ - "https://dl.google.com/go/{}" - ], - "version": "1.21.1", - "strip_prefix": "go" - } - }, - "go_host_compatible_sdk_label": { - "bzlFile": "@@rules_go~0.43.0//go/private:extensions.bzl", - "ruleClassName": "host_compatible_toolchain", - "attributes": { - "name": "rules_go~0.43.0~go_sdk~go_host_compatible_sdk_label", - "toolchain": "@go_default_sdk//:ROOT" - } - }, - "go_toolchains": { - "bzlFile": "@@rules_go~0.43.0//go/private:sdk.bzl", - "ruleClassName": "go_multiple_toolchains", - "attributes": { - "name": "rules_go~0.43.0~go_sdk~go_toolchains", - "prefixes": [ - "_0000_go_default_sdk_" - ], - "geese": [ - "" - ], - "goarchs": [ - "" - ], - "sdk_repos": [ - "go_default_sdk" - ], - "sdk_types": [ - "remote" - ], - "sdk_versions": [ - "1.21.1" - ] - } - } - } - } - }, - "@@rules_java~7.1.0//java:extensions.bzl%toolchains": { - "general": { - "bzlTransitiveDigest": "iUIRqCK7tkhvcDJCAfPPqSd06IHG0a8HQD0xeQyVAqw=", - "accumulatedFileDigests": {}, - "envVariables": {}, - "generatedRepoSpecs": { - "remotejdk21_linux_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk21_linux_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_linux//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_linux//:jdk\",\n)\n" - } - }, - "remotejdk17_linux_s390x_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_s390x_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:s390x\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_s390x//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:s390x\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_s390x//:jdk\",\n)\n" - } - }, - "remotejdk17_macos_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_macos_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_macos//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_macos//:jdk\",\n)\n" - } - }, - "remotejdk21_macos_aarch64_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk21_macos_aarch64_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_macos_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_macos_aarch64//:jdk\",\n)\n" - } - }, - "remotejdk17_linux_aarch64_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_aarch64_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_aarch64//:jdk\",\n)\n" - } - }, - "remotejdk21_macos_aarch64": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk21_macos_aarch64", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n", - "sha256": "2a7a99a3ea263dbd8d32a67d1e6e363ba8b25c645c826f5e167a02bbafaff1fa", - "strip_prefix": "zulu21.28.85-ca-jdk21.0.0-macosx_aarch64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-macosx_aarch64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-macosx_aarch64.tar.gz" - ] - } - }, - "remotejdk17_linux_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux//:jdk\",\n)\n" - } - }, - "remotejdk17_macos_aarch64": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_macos_aarch64", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", - "sha256": "314b04568ec0ae9b36ba03c9cbd42adc9e1265f74678923b19297d66eb84dcca", - "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-macosx_aarch64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-macosx_aarch64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-macosx_aarch64.tar.gz" - ] - } - }, - "remote_java_tools_windows": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remote_java_tools_windows", - "sha256": "c5c70c214a350f12cbf52da8270fa43ba629b795f3dd328028a38f8f0d39c2a1", - "urls": [ - "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.1/java_tools_windows-v13.1.zip", - "https://github.com/bazelbuild/java_tools/releases/download/java_v13.1/java_tools_windows-v13.1.zip" - ] - } - }, - "remotejdk11_win": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_win", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", - "sha256": "43408193ce2fa0862819495b5ae8541085b95660153f2adcf91a52d3a1710e83", - "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-win_x64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-win_x64.zip", - "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-win_x64.zip" - ] - } - }, - "remotejdk11_win_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_win_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_win//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_win//:jdk\",\n)\n" - } - }, - "remotejdk11_linux_aarch64": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_aarch64", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", - "sha256": "54174439f2b3fddd11f1048c397fe7bb45d4c9d66d452d6889b013d04d21c4de", - "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-linux_aarch64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-linux_aarch64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-linux_aarch64.tar.gz" - ] - } - }, - "remotejdk17_linux": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_linux", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", - "sha256": "b9482f2304a1a68a614dfacddcf29569a72f0fac32e6c74f83dc1b9a157b8340", - "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-linux_x64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-linux_x64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-linux_x64.tar.gz" - ] - } - }, - "remotejdk11_linux_s390x_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_s390x_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:s390x\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_s390x//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:s390x\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_s390x//:jdk\",\n)\n" - } - }, - "remotejdk11_linux_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux//:jdk\",\n)\n" - } - }, - "remotejdk11_macos": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_macos", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", - "sha256": "bcaab11cfe586fae7583c6d9d311c64384354fb2638eb9a012eca4c3f1a1d9fd", - "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-macosx_x64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-macosx_x64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-macosx_x64.tar.gz" - ] - } - }, - "remotejdk11_win_arm64": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_win_arm64", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", - "sha256": "b8a28e6e767d90acf793ea6f5bed0bb595ba0ba5ebdf8b99f395266161e53ec2", - "strip_prefix": "jdk-11.0.13+8", - "urls": [ - "https://mirror.bazel.build/aka.ms/download-jdk/microsoft-jdk-11.0.13.8.1-windows-aarch64.zip" - ] - } - }, - "remotejdk17_macos": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_macos", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", - "sha256": "640453e8afe8ffe0fb4dceb4535fb50db9c283c64665eebb0ba68b19e65f4b1f", - "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-macosx_x64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-macosx_x64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-macosx_x64.tar.gz" - ] - } - }, - "remotejdk21_macos": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk21_macos", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n", - "sha256": "9639b87db586d0c89f7a9892ae47f421e442c64b97baebdff31788fbe23265bd", - "strip_prefix": "zulu21.28.85-ca-jdk21.0.0-macosx_x64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-macosx_x64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-macosx_x64.tar.gz" - ] - } - }, - "remotejdk21_macos_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk21_macos_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_macos//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_macos//:jdk\",\n)\n" - } - }, - "remotejdk17_macos_aarch64_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_macos_aarch64_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_macos_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_macos_aarch64//:jdk\",\n)\n" - } - }, - "remotejdk17_win": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_win", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", - "sha256": "192f2afca57701de6ec496234f7e45d971bf623ff66b8ee4a5c81582054e5637", - "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-win_x64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-win_x64.zip", - "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-win_x64.zip" - ] - } - }, - "remotejdk11_macos_aarch64_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_macos_aarch64_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_macos_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_macos_aarch64//:jdk\",\n)\n" - } - }, - "remotejdk11_linux_ppc64le_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_ppc64le_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:ppc\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_ppc64le//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:ppc\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_ppc64le//:jdk\",\n)\n" - } - }, - "remotejdk21_linux": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk21_linux", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n", - "sha256": "0c0eadfbdc47a7ca64aeab51b9c061f71b6e4d25d2d87674512e9b6387e9e3a6", - "strip_prefix": "zulu21.28.85-ca-jdk21.0.0-linux_x64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-linux_x64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-linux_x64.tar.gz" - ] - } - }, - "remote_java_tools_linux": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remote_java_tools_linux", - "sha256": "d134da9b04c9023fb6e56a5d4bffccee73f7bc9572ddc4e747778dacccd7a5a7", - "urls": [ - "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.1/java_tools_linux-v13.1.zip", - "https://github.com/bazelbuild/java_tools/releases/download/java_v13.1/java_tools_linux-v13.1.zip" - ] - } - }, - "remotejdk21_win": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk21_win", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n", - "sha256": "e9959d500a0d9a7694ac243baf657761479da132f0f94720cbffd092150bd802", - "strip_prefix": "zulu21.28.85-ca-jdk21.0.0-win_x64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-win_x64.zip", - "https://cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-win_x64.zip" - ] - } - }, - "remotejdk21_linux_aarch64": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk21_linux_aarch64", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n", - "sha256": "1fb64b8036c5d463d8ab59af06bf5b6b006811e6012e3b0eb6bccf57f1c55835", - "strip_prefix": "zulu21.28.85-ca-jdk21.0.0-linux_aarch64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-linux_aarch64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-linux_aarch64.tar.gz" - ] - } - }, - "remotejdk11_linux_aarch64_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_aarch64_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_aarch64//:jdk\",\n)\n" - } - }, - "remotejdk11_linux_s390x": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_s390x", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", - "sha256": "a58fc0361966af0a5d5a31a2d8a208e3c9bb0f54f345596fd80b99ea9a39788b", - "strip_prefix": "jdk-11.0.15+10", - "urls": [ - "https://mirror.bazel.build/github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.15+10/OpenJDK11U-jdk_s390x_linux_hotspot_11.0.15_10.tar.gz", - "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.15+10/OpenJDK11U-jdk_s390x_linux_hotspot_11.0.15_10.tar.gz" - ] - } - }, - "remotejdk17_linux_aarch64": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_aarch64", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", - "sha256": "6531cef61e416d5a7b691555c8cf2bdff689201b8a001ff45ab6740062b44313", - "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-linux_aarch64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-linux_aarch64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-linux_aarch64.tar.gz" - ] - } - }, - "remotejdk17_win_arm64_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_win_arm64_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:arm64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_win_arm64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:arm64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_win_arm64//:jdk\",\n)\n" - } - }, - "remotejdk11_linux": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_linux", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", - "sha256": "a34b404f87a08a61148b38e1416d837189e1df7a040d949e743633daf4695a3c", - "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-linux_x64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-linux_x64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-linux_x64.tar.gz" - ] - } - }, - "remotejdk11_macos_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_macos_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_macos//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_macos//:jdk\",\n)\n" - } - }, - "remotejdk17_linux_ppc64le_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_ppc64le_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:ppc\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_ppc64le//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:ppc\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_ppc64le//:jdk\",\n)\n" - } - }, - "remotejdk17_win_arm64": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_win_arm64", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", - "sha256": "6802c99eae0d788e21f52d03cab2e2b3bf42bc334ca03cbf19f71eb70ee19f85", - "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-win_aarch64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-win_aarch64.zip", - "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-win_aarch64.zip" - ] - } - }, - "remote_java_tools_darwin_arm64": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remote_java_tools_darwin_arm64", - "sha256": "dab5bb87ec43e980faea6e1cec14bafb217b8e2f5346f53aa784fd715929a930", - "urls": [ - "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.1/java_tools_darwin_arm64-v13.1.zip", - "https://github.com/bazelbuild/java_tools/releases/download/java_v13.1/java_tools_darwin_arm64-v13.1.zip" - ] - } - }, - "remotejdk17_linux_ppc64le": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_ppc64le", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", - "sha256": "00a4c07603d0218cd678461b5b3b7e25b3253102da4022d31fc35907f21a2efd", - "strip_prefix": "jdk-17.0.8.1+1", - "urls": [ - "https://mirror.bazel.build/github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.8.1%2B1/OpenJDK17U-jdk_ppc64le_linux_hotspot_17.0.8.1_1.tar.gz", - "https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.8.1%2B1/OpenJDK17U-jdk_ppc64le_linux_hotspot_17.0.8.1_1.tar.gz" - ] - } - }, - "remotejdk21_linux_aarch64_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk21_linux_aarch64_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_linux_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_linux_aarch64//:jdk\",\n)\n" - } - }, - "remotejdk11_win_arm64_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_win_arm64_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:arm64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_win_arm64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:arm64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_win_arm64//:jdk\",\n)\n" - } - }, - "local_jdk": { - "bzlFile": "@@rules_java~7.1.0//toolchains:local_java_repository.bzl", - "ruleClassName": "_local_java_repository_rule", - "attributes": { - "name": "rules_java~7.1.0~toolchains~local_jdk", - "java_home": "", - "version": "", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = {RUNTIME_VERSION},\n)\n" - } - }, - "remote_java_tools_darwin_x86_64": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remote_java_tools_darwin_x86_64", - "sha256": "0db40d8505a2b65ef0ed46e4256757807db8162f7acff16225be57c1d5726dbc", - "urls": [ - "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.1/java_tools_darwin_x86_64-v13.1.zip", - "https://github.com/bazelbuild/java_tools/releases/download/java_v13.1/java_tools_darwin_x86_64-v13.1.zip" - ] - } - }, - "remote_java_tools": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remote_java_tools", - "sha256": "286bdbbd66e616fc4ed3f90101418729a73baa7e8c23a98ffbef558f74c0ad14", - "urls": [ - "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.1/java_tools-v13.1.zip", - "https://github.com/bazelbuild/java_tools/releases/download/java_v13.1/java_tools-v13.1.zip" - ] - } - }, - "remotejdk17_linux_s390x": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_s390x", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", - "sha256": "ffacba69c6843d7ca70d572489d6cc7ab7ae52c60f0852cedf4cf0d248b6fc37", - "strip_prefix": "jdk-17.0.8.1+1", - "urls": [ - "https://mirror.bazel.build/github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.8.1%2B1/OpenJDK17U-jdk_s390x_linux_hotspot_17.0.8.1_1.tar.gz", - "https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.8.1%2B1/OpenJDK17U-jdk_s390x_linux_hotspot_17.0.8.1_1.tar.gz" - ] - } - }, - "remotejdk17_win_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_win_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_win//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_win//:jdk\",\n)\n" - } - }, - "remotejdk11_linux_ppc64le": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_ppc64le", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", - "sha256": "a8fba686f6eb8ae1d1a9566821dbd5a85a1108b96ad857fdbac5c1e4649fc56f", - "strip_prefix": "jdk-11.0.15+10", - "urls": [ - "https://mirror.bazel.build/github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.15+10/OpenJDK11U-jdk_ppc64le_linux_hotspot_11.0.15_10.tar.gz", - "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.15+10/OpenJDK11U-jdk_ppc64le_linux_hotspot_11.0.15_10.tar.gz" - ] - } - }, - "remotejdk11_macos_aarch64": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_macos_aarch64", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", - "sha256": "7632bc29f8a4b7d492b93f3bc75a7b61630894db85d136456035ab2a24d38885", - "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-macosx_aarch64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-macosx_aarch64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-macosx_aarch64.tar.gz" - ] - } - }, - "remotejdk21_win_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk21_win_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_win//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_win//:jdk\",\n)\n" - } - } - } - } - }, - "@@rules_jvm_external~5.3//:extensions.bzl%maven": { - "general": { - "bzlTransitiveDigest": "9VQBVBpk1BYX8MlZX/v6yoWpeoWbbeIDc8bZ2kiueLI=", - "accumulatedFileDigests": { - "@@//:maven_install.json": "a5ee74885480c4e38f70dd8ca3e8ef2b7d89c81a581bbc196965d22aabd9b2ab", - "@@rules_jvm_external~5.3//:rules_jvm_external_deps_install.json": "741ab2ef3843a43eaacb45d1448835c9deb99c95162279f513096eface8acd44" - }, - "envVariables": {}, - "generatedRepoSpecs": { - "io_grpc_grpc_netty_shaded_jar_sources_1_56_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_netty_shaded_jar_sources_1_56_1", - "sha256": "4a7dd3517fc4540e926cd958b3a48ffc561f42ad9dfe31e3f2ccc13ba1742939", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-netty-shaded/1.56.1/grpc-netty-shaded-1.56.1-sources.jar" - ], - "downloaded_file_path": "io/grpc/grpc-netty-shaded/1.56.1/grpc-netty-shaded-1.56.1-sources.jar" - } - }, - "me_dinowernli_java_grpc_prometheus": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~me_dinowernli_java_grpc_prometheus", - "generating_repository": "maven", - "target_name": "me_dinowernli_java_grpc_prometheus" - } - }, - "com_sun_activation_jakarta_activation_1_2_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_sun_activation_jakarta_activation_1_2_1", - "sha256": "d84d4ba8b55cdb7fdcbb885e6939386367433f56f5ab8cfdc302a7c3587fa92b", - "urls": [ - "https://repo1.maven.org/maven2/com/sun/activation/jakarta.activation/1.2.1/jakarta.activation-1.2.1.jar" - ], - "downloaded_file_path": "com/sun/activation/jakarta.activation/1.2.1/jakarta.activation-1.2.1.jar" - } - }, - "io_netty_netty_resolver_dns_jar_sources_4_1_96_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_resolver_dns_jar_sources_4_1_96_Final", - "sha256": "77eeef5ac81bf4b1ad919dc0e7b44bd4f2a4f71418c57beb341685f299fdc963", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-resolver-dns/4.1.96.Final/netty-resolver-dns-4.1.96.Final-sources.jar" - ], - "downloaded_file_path": "io/netty/netty-resolver-dns/4.1.96.Final/netty-resolver-dns-4.1.96.Final-sources.jar" - } - }, - "io_grpc_grpc_alts_1_55_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_alts_1_55_1", - "sha256": "9ab78b042d55cb501a2126c831896f3223e39c65085351b40a588b085ed6d431", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-alts/1.55.1/grpc-alts-1.55.1.jar", - "https://maven.google.com/io/grpc/grpc-alts/1.55.1/grpc-alts-1.55.1.jar" - ], - "downloaded_file_path": "io/grpc/grpc-alts/1.55.1/grpc-alts-1.55.1.jar" - } - }, - "com_github_jnr_jffi_1_3_11": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_jnr_jffi_1_3_11", - "sha256": "74d3bce7397b4872ccb6a6fd84b8f260503f76509adc9548029f665852ad38d7", - "urls": [ - "https://repo1.maven.org/maven2/com/github/jnr/jffi/1.3.11/jffi-1.3.11.jar" - ], - "downloaded_file_path": "com/github/jnr/jffi/1.3.11/jffi-1.3.11.jar" - } - }, - "io_prometheus_simpleclient_tracer_common_jar_sources_0_15_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_tracer_common_jar_sources_0_15_0", - "sha256": "ad5a691dc6b1b5096de0a209530c07a8f98d31d51895730136699a74caa1145a", - "urls": [ - "https://repo1.maven.org/maven2/io/prometheus/simpleclient_tracer_common/0.15.0/simpleclient_tracer_common-0.15.0-sources.jar" - ], - "downloaded_file_path": "io/prometheus/simpleclient_tracer_common/0.15.0/simpleclient_tracer_common-0.15.0-sources.jar" - } - }, - "com_google_truth_truth": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_truth_truth", - "generating_repository": "maven", - "target_name": "com_google_truth_truth" - } - }, - "io_opencensus_opencensus_api_jar_sources_0_31_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_opencensus_opencensus_api_jar_sources_0_31_1", - "sha256": "6748d57aaae81995514ad3e2fb11a95aa88e158b3f93450288018eaccf31e86b", - "urls": [ - "https://repo1.maven.org/maven2/io/opencensus/opencensus-api/0.31.1/opencensus-api-0.31.1-sources.jar" - ], - "downloaded_file_path": "io/opencensus/opencensus-api/0.31.1/opencensus-api-0.31.1-sources.jar" - } - }, - "com_github_kevinstern_software_and_algorithms_1_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_kevinstern_software_and_algorithms_1_0", - "sha256": "61ab82439cef37343b14f53154c461619375373a56b9338e895709fb54e0864c", - "urls": [ - "https://repo1.maven.org/maven2/com/github/kevinstern/software-and-algorithms/1.0/software-and-algorithms-1.0.jar" - ], - "downloaded_file_path": "com/github/kevinstern/software-and-algorithms/1.0/software-and-algorithms-1.0.jar" - } - }, - "com_google_protobuf_protobuf_java_util": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_protobuf_protobuf_java_util", - "generating_repository": "maven", - "target_name": "com_google_protobuf_protobuf_java_util" - } - }, - "io_grpc_grpc_api_1_56_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_api_1_56_1", - "sha256": "b090b1bb5a3b066f7f2ef14b9ba68e3304de80ba34f90414aed3b519c30999e8", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-api/1.56.1/grpc-api-1.56.1.jar" - ], - "downloaded_file_path": "io/grpc/grpc-api/1.56.1/grpc-api-1.56.1.jar" - } - }, - "org_apache_commons_commons_compress_1_23_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_apache_commons_commons_compress_1_23_0", - "sha256": "c267f17160e9ef662b4d78b7f29dca7c82b15c5cff2cb6a9865ef4ab3dd5b787", - "urls": [ - "https://repo1.maven.org/maven2/org/apache/commons/commons-compress/1.23.0/commons-compress-1.23.0.jar" - ], - "downloaded_file_path": "org/apache/commons/commons-compress/1.23.0/commons-compress-1.23.0.jar" - } - }, - "org_reactivestreams_reactive_streams_1_0_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_reactivestreams_reactive_streams_1_0_3", - "sha256": "1dee0481072d19c929b623e155e14d2f6085dc011529a0a0dbefc84cf571d865", - "urls": [ - "https://repo1.maven.org/maven2/org/reactivestreams/reactive-streams/1.0.3/reactive-streams-1.0.3.jar", - "https://maven.google.com/org/reactivestreams/reactive-streams/1.0.3/reactive-streams-1.0.3.jar" - ], - "downloaded_file_path": "org/reactivestreams/reactive-streams/1.0.3/reactive-streams-1.0.3.jar" - } - }, - "com_google_protobuf_protobuf_java_util_3_22_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_protobuf_protobuf_java_util_3_22_3", - "sha256": "c615f76879dc5c303e4df5b94a6afa39534058c7545db2d483fd95d9f63c8bfe", - "urls": [ - "https://repo1.maven.org/maven2/com/google/protobuf/protobuf-java-util/3.22.3/protobuf-java-util-3.22.3.jar" - ], - "downloaded_file_path": "com/google/protobuf/protobuf-java-util/3.22.3/protobuf-java-util-3.22.3.jar" - } - }, - "org_reactivestreams_reactive_streams_1_0_4": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_reactivestreams_reactive_streams_1_0_4", - "sha256": "f75ca597789b3dac58f61857b9ac2e1034a68fa672db35055a8fb4509e325f28", - "urls": [ - "https://repo1.maven.org/maven2/org/reactivestreams/reactive-streams/1.0.4/reactive-streams-1.0.4.jar" - ], - "downloaded_file_path": "org/reactivestreams/reactive-streams/1.0.4/reactive-streams-1.0.4.jar" - } - }, - "com_amazonaws_aws_java_sdk_s3_1_12_544": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_amazonaws_aws_java_sdk_s3_1_12_544", - "sha256": "817b2fac490d3e02ecaf3253c2e2ab0bf6d2291a841574cec70464312d669230", - "urls": [ - "https://repo1.maven.org/maven2/com/amazonaws/aws-java-sdk-s3/1.12.544/aws-java-sdk-s3-1.12.544.jar" - ], - "downloaded_file_path": "com/amazonaws/aws-java-sdk-s3/1.12.544/aws-java-sdk-s3-1.12.544.jar" - } - }, - "joda_time_joda_time_2_8_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~joda_time_joda_time_2_8_1", - "sha256": "b4670b95f75957c974284c5f3ada966040be2578f643c5c6083d262162061fa2", - "urls": [ - "https://repo1.maven.org/maven2/joda-time/joda-time/2.8.1/joda-time-2.8.1.jar" - ], - "downloaded_file_path": "joda-time/joda-time/2.8.1/joda-time-2.8.1.jar" - } - }, - "com_amazonaws_aws_java_sdk_s3": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_amazonaws_aws_java_sdk_s3", - "generating_repository": "maven", - "target_name": "com_amazonaws_aws_java_sdk_s3" - } - }, - "com_github_fppt_jedis_mock": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_fppt_jedis_mock", - "generating_repository": "maven", - "target_name": "com_github_fppt_jedis_mock" - } - }, - "com_jayway_jsonpath_json_path_2_8_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_jayway_jsonpath_json_path_2_8_0", - "sha256": "9601707e95cd79fb98570a01ea8cfb857b5cde948744d6e0edf733c11002c95b", - "urls": [ - "https://repo1.maven.org/maven2/com/jayway/jsonpath/json-path/2.8.0/json-path-2.8.0.jar" - ], - "downloaded_file_path": "com/jayway/jsonpath/json-path/2.8.0/json-path-2.8.0.jar" - } - }, - "com_google_errorprone_error_prone_annotations_jar_sources_2_22_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_errorprone_error_prone_annotations_jar_sources_2_22_0", - "sha256": "c989d7144e4b3313514972df85f8f9dfd53b300e1359e13ca5e6453965c8fcef", - "urls": [ - "https://repo1.maven.org/maven2/com/google/errorprone/error_prone_annotations/2.22.0/error_prone_annotations-2.22.0-sources.jar" - ], - "downloaded_file_path": "com/google/errorprone/error_prone_annotations/2.22.0/error_prone_annotations-2.22.0-sources.jar" - } - }, - "io_prometheus_simpleclient_tracer_otel_agent_jar_sources_0_15_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_tracer_otel_agent_jar_sources_0_15_0", - "sha256": "9071a9ecf1473fd9c71c27082c549dd4e5686039444efb662392b1f3391a5d36", - "urls": [ - "https://repo1.maven.org/maven2/io/prometheus/simpleclient_tracer_otel_agent/0.15.0/simpleclient_tracer_otel_agent-0.15.0-sources.jar" - ], - "downloaded_file_path": "io/prometheus/simpleclient_tracer_otel_agent/0.15.0/simpleclient_tracer_otel_agent-0.15.0-sources.jar" - } - }, - "com_github_serceman_jnr_fuse": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_serceman_jnr_fuse", - "generating_repository": "maven", - "target_name": "com_github_serceman_jnr_fuse" - } - }, - "org_checkerframework_checker_qual_jar_sources_3_38_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_checkerframework_checker_qual_jar_sources_3_38_0", - "sha256": "c1184779ca27c09efe55b54109bf8a2b654112c6e8b28105c0c2dcc5a84465b1", - "urls": [ - "https://repo1.maven.org/maven2/org/checkerframework/checker-qual/3.38.0/checker-qual-3.38.0-sources.jar" - ], - "downloaded_file_path": "org/checkerframework/checker-qual/3.38.0/checker-qual-3.38.0-sources.jar" - } - }, - "org_bouncycastle_bcprov_jdk15on_1_70": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_bouncycastle_bcprov_jdk15on_1_70", - "sha256": "8f3c20e3e2d565d26f33e8d4857a37d0d7f8ac39b62a7026496fcab1bdac30d4", - "urls": [ - "https://repo1.maven.org/maven2/org/bouncycastle/bcprov-jdk15on/1.70/bcprov-jdk15on-1.70.jar" - ], - "downloaded_file_path": "org/bouncycastle/bcprov-jdk15on/1.70/bcprov-jdk15on-1.70.jar" - } - }, - "com_google_code_gson_gson_2_10_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_code_gson_gson_2_10_1", - "sha256": "4241c14a7727c34feea6507ec801318a3d4a90f070e4525681079fb94ee4c593", - "urls": [ - "https://repo1.maven.org/maven2/com/google/code/gson/gson/2.10.1/gson-2.10.1.jar" - ], - "downloaded_file_path": "com/google/code/gson/gson/2.10.1/gson-2.10.1.jar" - } - }, - "io_netty_netty_handler_jar_sources_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_handler_jar_sources_4_1_97_Final", - "sha256": "905739df92b7fe6468504e1e91b964654381eb3d162766f39552d06a0cbf4cd3", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-handler/4.1.97.Final/netty-handler-4.1.97.Final-sources.jar" - ], - "downloaded_file_path": "io/netty/netty-handler/4.1.97.Final/netty-handler-4.1.97.Final-sources.jar" - } - }, - "io_netty_netty_codec_dns_4_1_96_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_dns_4_1_96_Final", - "sha256": "857d0213bd4e504ad897a7c0f967ef3f728f120feea3e824729dad525b44bbce", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-codec-dns/4.1.96.Final/netty-codec-dns-4.1.96.Final.jar" - ], - "downloaded_file_path": "io/netty/netty-codec-dns/4.1.96.Final/netty-codec-dns-4.1.96.Final.jar" - } - }, - "com_google_errorprone_error_prone_core_2_22_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_errorprone_error_prone_core_2_22_0", - "sha256": "32a3df226a9a47f48dd895a9a89678d50ac404282c33400781c38757e8143f2c", - "urls": [ - "https://repo1.maven.org/maven2/com/google/errorprone/error_prone_core/2.22.0/error_prone_core-2.22.0.jar" - ], - "downloaded_file_path": "com/google/errorprone/error_prone_core/2.22.0/error_prone_core-2.22.0.jar" - } - }, - "com_fasterxml_jackson_core_jackson_databind": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_core_jackson_databind", - "generating_repository": "maven", - "target_name": "com_fasterxml_jackson_core_jackson_databind" - } - }, - "io_prometheus_simpleclient_jar_sources_0_15_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_jar_sources_0_15_0", - "sha256": "996c0ae2c1f6fe658865f8b3b3d073d136bd60de1a37fa78db2d52db328d1adb", - "urls": [ - "https://repo1.maven.org/maven2/io/prometheus/simpleclient/0.15.0/simpleclient-0.15.0-sources.jar" - ], - "downloaded_file_path": "io/prometheus/simpleclient/0.15.0/simpleclient-0.15.0-sources.jar" - } - }, - "org_ow2_asm_asm_tree_jar_sources_9_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_ow2_asm_asm_tree_jar_sources_9_2", - "sha256": "c35bc5b4b6c54bf15abec34ab821cf9d0801a64451f4f6070d93dcb87122aa08", - "urls": [ - "https://repo1.maven.org/maven2/org/ow2/asm/asm-tree/9.2/asm-tree-9.2-sources.jar" - ], - "downloaded_file_path": "org/ow2/asm/asm-tree/9.2/asm-tree-9.2-sources.jar" - } - }, - "io_netty_netty_transport_jar_sources_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_jar_sources_4_1_97_Final", - "sha256": "2ee8b4402c42f9bbbb3b4a14cce1f80d0b48f2115c718ea464f3050f58c70b2e", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-transport/4.1.97.Final/netty-transport-4.1.97.Final-sources.jar" - ], - "downloaded_file_path": "io/netty/netty-transport/4.1.97.Final/netty-transport-4.1.97.Final-sources.jar" - } - }, - "org_apache_commons_commons_math3_3_6_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_apache_commons_commons_math3_3_6_1", - "sha256": "1e56d7b058d28b65abd256b8458e3885b674c1d588fa43cd7d1cbb9c7ef2b308", - "urls": [ - "https://repo1.maven.org/maven2/org/apache/commons/commons-math3/3.6.1/commons-math3-3.6.1.jar" - ], - "downloaded_file_path": "org/apache/commons/commons-math3/3.6.1/commons-math3-3.6.1.jar" - } - }, - "org_jboss_marshalling_jboss_marshalling_river_jar_sources_2_0_11_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_jboss_marshalling_jboss_marshalling_river_jar_sources_2_0_11_Final", - "sha256": "c3cb3209f18c0d1fec289669426b105d5247ad53ae98326369c9b4db4b80ceac", - "urls": [ - "https://repo1.maven.org/maven2/org/jboss/marshalling/jboss-marshalling-river/2.0.11.Final/jboss-marshalling-river-2.0.11.Final-sources.jar" - ], - "downloaded_file_path": "org/jboss/marshalling/jboss-marshalling-river/2.0.11.Final/jboss-marshalling-river-2.0.11.Final-sources.jar" - } - }, - "jakarta_annotation_jakarta_annotation_api_jar_sources_1_3_5": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~jakarta_annotation_jakarta_annotation_api_jar_sources_1_3_5", - "sha256": "aa27e9291dce4ddbb0aea52a1cbef41c6330b96b0ae387a995ed412b68a3af7c", - "urls": [ - "https://repo1.maven.org/maven2/jakarta/annotation/jakarta.annotation-api/1.3.5/jakarta.annotation-api-1.3.5-sources.jar" - ], - "downloaded_file_path": "jakarta/annotation/jakarta.annotation-api/1.3.5/jakarta.annotation-api-1.3.5-sources.jar" - } - }, - "org_apache_commons_commons_compress_jar_sources_1_23_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_apache_commons_commons_compress_jar_sources_1_23_0", - "sha256": "2ba017aee1a90ebd2b27ba245c2338f37bf23948f035a2bd75becf623906b709", - "urls": [ - "https://repo1.maven.org/maven2/org/apache/commons/commons-compress/1.23.0/commons-compress-1.23.0-sources.jar" - ], - "downloaded_file_path": "org/apache/commons/commons-compress/1.23.0/commons-compress-1.23.0-sources.jar" - } - }, - "com_github_docker_java_docker_java_transport_netty_3_3_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_docker_java_docker_java_transport_netty_3_3_3", - "sha256": "30152706a19f46f97bea55e85182762d8b5d2d23bea5e465af403537677f879b", - "urls": [ - "https://repo1.maven.org/maven2/com/github/docker-java/docker-java-transport-netty/3.3.3/docker-java-transport-netty-3.3.3.jar" - ], - "downloaded_file_path": "com/github/docker-java/docker-java-transport-netty/3.3.3/docker-java-transport-netty-3.3.3.jar" - } - }, - "io_netty_netty_transport_native_epoll_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_native_epoll_4_1_97_Final", - "sha256": "418a0d0d66d2d52a63a0e2cd5377f8c3186db47c09e3b8af39a43fec39c077fe", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-transport-native-epoll/4.1.97.Final/netty-transport-native-epoll-4.1.97.Final.jar" - ], - "downloaded_file_path": "io/netty/netty-transport-native-epoll/4.1.97.Final/netty-transport-native-epoll-4.1.97.Final.jar" - } - }, - "net_javacrumbs_future_converter_future_converter_common_jar_sources_1_2_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~net_javacrumbs_future_converter_future_converter_common_jar_sources_1_2_0", - "sha256": "24f849eb33ef57a4ea597052f8fa78cbe14076cb36160e7b37a6373d1f162a70", - "urls": [ - "https://repo1.maven.org/maven2/net/javacrumbs/future-converter/future-converter-common/1.2.0/future-converter-common-1.2.0-sources.jar" - ], - "downloaded_file_path": "net/javacrumbs/future-converter/future-converter-common/1.2.0/future-converter-common-1.2.0-sources.jar" - } - }, - "com_google_errorprone_error_prone_type_annotations_2_22_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_errorprone_error_prone_type_annotations_2_22_0", - "sha256": "6618b1d28df562622b77187b5c6dfc9c4c97851af73bd64dc0300efe9a439b20", - "urls": [ - "https://repo1.maven.org/maven2/com/google/errorprone/error_prone_type_annotations/2.22.0/error_prone_type_annotations-2.22.0.jar" - ], - "downloaded_file_path": "com/google/errorprone/error_prone_type_annotations/2.22.0/error_prone_type_annotations-2.22.0.jar" - } - }, - "com_fasterxml_jackson_jaxrs_jackson_jaxrs_json_provider_jar_sources_2_10_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_jaxrs_jackson_jaxrs_json_provider_jar_sources_2_10_3", - "sha256": "b15fd7237ceb93aa289e22bb21335249e3cd33cd6a0fd1be769e6fc63b1513b5", - "urls": [ - "https://repo1.maven.org/maven2/com/fasterxml/jackson/jaxrs/jackson-jaxrs-json-provider/2.10.3/jackson-jaxrs-json-provider-2.10.3-sources.jar" - ], - "downloaded_file_path": "com/fasterxml/jackson/jaxrs/jackson-jaxrs-json-provider/2.10.3/jackson-jaxrs-json-provider-2.10.3-sources.jar" - } - }, - "net_java_dev_jna_jna_platform_jar_sources_5_13_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~net_java_dev_jna_jna_platform_jar_sources_5_13_0", - "sha256": "2f39937649df7e74f36f2b56ee2f15c15d4f9218fde43369c48a6b51e3cc087e", - "urls": [ - "https://repo1.maven.org/maven2/net/java/dev/jna/jna-platform/5.13.0/jna-platform-5.13.0-sources.jar" - ], - "downloaded_file_path": "net/java/dev/jna/jna-platform/5.13.0/jna-platform-5.13.0-sources.jar" - } - }, - "net_javacrumbs_future_converter_future_converter_java8_common_1_2_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~net_javacrumbs_future_converter_future_converter_java8_common_1_2_0", - "sha256": "bed25293fabbf59e048f67f88e55140ebc1cfa4fa899e397545d0193e866a65c", - "urls": [ - "https://repo1.maven.org/maven2/net/javacrumbs/future-converter/future-converter-java8-common/1.2.0/future-converter-java8-common-1.2.0.jar" - ], - "downloaded_file_path": "net/javacrumbs/future-converter/future-converter-java8-common/1.2.0/future-converter-java8-common-1.2.0.jar" - } - }, - "io_prometheus_simpleclient_hotspot": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_hotspot", - "generating_repository": "maven", - "target_name": "io_prometheus_simpleclient_hotspot" - } - }, - "io_netty_netty_codec": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec", - "generating_repository": "maven", - "target_name": "io_netty_netty_codec" - } - }, - "net_javacrumbs_future_converter_future_converter_guava_common_jar_sources_1_2_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~net_javacrumbs_future_converter_future_converter_guava_common_jar_sources_1_2_0", - "sha256": "f5a6c226632ab0c4225962146c8b4dbbfd8db75f1b573c2da29268ac1beecc57", - "urls": [ - "https://repo1.maven.org/maven2/net/javacrumbs/future-converter/future-converter-guava-common/1.2.0/future-converter-guava-common-1.2.0-sources.jar" - ], - "downloaded_file_path": "net/javacrumbs/future-converter/future-converter-guava-common/1.2.0/future-converter-guava-common-1.2.0-sources.jar" - } - }, - "io_grpc_grpc_api_1_55_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_api_1_55_1", - "sha256": "9f21b1585b1c578cf905fb4c926ce895494207cb5bf456a64a24c458850f51d3", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-api/1.55.1/grpc-api-1.55.1.jar", - "https://maven.google.com/io/grpc/grpc-api/1.55.1/grpc-api-1.55.1.jar" - ], - "downloaded_file_path": "io/grpc/grpc-api/1.55.1/grpc-api-1.55.1.jar" - } - }, - "com_fasterxml_jackson_module_jackson_module_jaxb_annotations_jar_sources_2_10_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_module_jackson_module_jaxb_annotations_jar_sources_2_10_3", - "sha256": "81e7738e3a836c465e3170cab143e1c3182c3ca5dd3cfabfceb9a23fe0939a34", - "urls": [ - "https://repo1.maven.org/maven2/com/fasterxml/jackson/module/jackson-module-jaxb-annotations/2.10.3/jackson-module-jaxb-annotations-2.10.3-sources.jar" - ], - "downloaded_file_path": "com/fasterxml/jackson/module/jackson-module-jaxb-annotations/2.10.3/jackson-module-jaxb-annotations-2.10.3-sources.jar" - } - }, - "com_google_errorprone_error_prone_core_jar_sources_2_22_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_errorprone_error_prone_core_jar_sources_2_22_0", - "sha256": "98c52d46fe499a61eea86234f5463bba6968c595dacddb38d89c161e354c62b4", - "urls": [ - "https://repo1.maven.org/maven2/com/google/errorprone/error_prone_core/2.22.0/error_prone_core-2.22.0-sources.jar" - ], - "downloaded_file_path": "com/google/errorprone/error_prone_core/2.22.0/error_prone_core-2.22.0-sources.jar" - } - }, - "net_bytebuddy_byte_buddy_jar_sources_1_14_5": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~net_bytebuddy_byte_buddy_jar_sources_1_14_5", - "sha256": "143dd9fe73f0566cc703934b7fd15abbb97bfab045064c2f176067e70456a136", - "urls": [ - "https://repo1.maven.org/maven2/net/bytebuddy/byte-buddy/1.14.5/byte-buddy-1.14.5-sources.jar" - ], - "downloaded_file_path": "net/bytebuddy/byte-buddy/1.14.5/byte-buddy-1.14.5-sources.jar" - } - }, - "com_google_protobuf_protobuf_java_util_3_23_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_protobuf_protobuf_java_util_3_23_1", - "sha256": "35d78f70fcba8ecaad6b2025a4879099a27997079158500a08fafebad8918c8c", - "urls": [ - "https://repo1.maven.org/maven2/com/google/protobuf/protobuf-java-util/3.23.1/protobuf-java-util-3.23.1.jar", - "https://maven.google.com/com/google/protobuf/protobuf-java-util/3.23.1/protobuf-java-util-3.23.1.jar" - ], - "downloaded_file_path": "com/google/protobuf/protobuf-java-util/3.23.1/protobuf-java-util-3.23.1.jar" - } - }, - "org_ow2_asm_asm_9_5": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_ow2_asm_asm_9_5", - "sha256": "b62e84b5980729751b0458c534cf1366f727542bb8d158621335682a460f0353", - "urls": [ - "https://repo1.maven.org/maven2/org/ow2/asm/asm/9.5/asm-9.5.jar" - ], - "downloaded_file_path": "org/ow2/asm/asm/9.5/asm-9.5.jar" - } - }, - "software_amazon_ion_ion_java_jar_sources_1_0_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~software_amazon_ion_ion_java_jar_sources_1_0_2", - "sha256": "d827fc9775443697bbcdfeb8ea2d3d75bf5ad7f2ca540dabda1a5f83cd0a39de", - "urls": [ - "https://repo1.maven.org/maven2/software/amazon/ion/ion-java/1.0.2/ion-java-1.0.2-sources.jar" - ], - "downloaded_file_path": "software/amazon/ion/ion-java/1.0.2/ion-java-1.0.2-sources.jar" - } - }, - "io_netty_netty_resolver_jar_sources_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_resolver_jar_sources_4_1_97_Final", - "sha256": "dd687a7b2016d38d92d988172b787c713d786e5b8c37896796b156e6798cbd95", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-resolver/4.1.97.Final/netty-resolver-4.1.97.Final-sources.jar" - ], - "downloaded_file_path": "io/netty/netty-resolver/4.1.97.Final/netty-resolver-4.1.97.Final-sources.jar" - } - }, - "org_pcollections_pcollections_jar_sources_3_1_4": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_pcollections_pcollections_jar_sources_3_1_4", - "sha256": "38d91b91467dedcedfd36b6b5f577008fd51748ce74150ebe11ec1227acce218", - "urls": [ - "https://repo1.maven.org/maven2/org/pcollections/pcollections/3.1.4/pcollections-3.1.4-sources.jar" - ], - "downloaded_file_path": "org/pcollections/pcollections/3.1.4/pcollections-3.1.4-sources.jar" - } - }, - "com_google_guava_listenablefuture_9999_0_empty_to_avoid_conflict_with_guava": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_guava_listenablefuture_9999_0_empty_to_avoid_conflict_with_guava", - "sha256": "b372a037d4230aa57fbeffdef30fd6123f9c0c2db85d0aced00c91b974f33f99", - "urls": [ - "https://repo1.maven.org/maven2/com/google/guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar" - ], - "downloaded_file_path": "com/google/guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar" - } - }, - "com_jayway_jsonpath_json_path_jar_sources_2_8_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_jayway_jsonpath_json_path_jar_sources_2_8_0", - "sha256": "ce1d02241b445abf7f4c067b94d77c917fa06fbcbb048519b932a2197a2cc3fd", - "urls": [ - "https://repo1.maven.org/maven2/com/jayway/jsonpath/json-path/2.8.0/json-path-2.8.0-sources.jar" - ], - "downloaded_file_path": "com/jayway/jsonpath/json-path/2.8.0/json-path-2.8.0-sources.jar" - } - }, - "com_google_code_gson_gson": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_code_gson_gson", - "generating_repository": "maven", - "target_name": "com_google_code_gson_gson" - } - }, - "org_json_json_20220320": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_json_json_20220320", - "sha256": "1edf7fcea79a16b8dfdd3bc988ddec7f8908b1f7762fdf00d39acb037542747a", - "urls": [ - "https://repo1.maven.org/maven2/org/json/json/20220320/json-20220320.jar" - ], - "downloaded_file_path": "org/json/json/20220320/json-20220320.jar" - } - }, - "com_fasterxml_jackson_jaxrs_jackson_jaxrs_base_2_10_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_jaxrs_jackson_jaxrs_base_2_10_3", - "sha256": "3b6b74311d094990e6d8de356363988050fb2bf5389138b198b01a0ceb9a9668", - "urls": [ - "https://repo1.maven.org/maven2/com/fasterxml/jackson/jaxrs/jackson-jaxrs-base/2.10.3/jackson-jaxrs-base-2.10.3.jar" - ], - "downloaded_file_path": "com/fasterxml/jackson/jaxrs/jackson-jaxrs-base/2.10.3/jackson-jaxrs-base-2.10.3.jar" - } - }, - "com_google_api_grpc_gapic_google_cloud_storage_v2_2_22_3_alpha": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_api_grpc_gapic_google_cloud_storage_v2_2_22_3_alpha", - "sha256": "2843f647000e82fe1d3b89eff32a15aab7671d917c90b739f31c9aa895bf957a", - "urls": [ - "https://repo1.maven.org/maven2/com/google/api/grpc/gapic-google-cloud-storage-v2/2.22.3-alpha/gapic-google-cloud-storage-v2-2.22.3-alpha.jar", - "https://maven.google.com/com/google/api/grpc/gapic-google-cloud-storage-v2/2.22.3-alpha/gapic-google-cloud-storage-v2-2.22.3-alpha.jar" - ], - "downloaded_file_path": "com/google/api/grpc/gapic-google-cloud-storage-v2/2.22.3-alpha/gapic-google-cloud-storage-v2-2.22.3-alpha.jar" - } - }, - "com_github_ben_manes_caffeine_caffeine_3_0_5": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_ben_manes_caffeine_caffeine_3_0_5", - "sha256": "8a9b54d3506a3b92ee46b217bcee79196b21ca6d52dc2967c686a205fb2f9c15", - "urls": [ - "https://repo1.maven.org/maven2/com/github/ben-manes/caffeine/caffeine/3.0.5/caffeine-3.0.5.jar" - ], - "downloaded_file_path": "com/github/ben-manes/caffeine/caffeine/3.0.5/caffeine-3.0.5.jar" - } - }, - "org_jodd_jodd_core_jar_sources_5_1_6": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_jodd_jodd_core_jar_sources_5_1_6", - "sha256": "2eb5a3af95296bc941767870bf5cb242ba7ee59a5eb0524c73e734578f6c6c16", - "urls": [ - "https://repo1.maven.org/maven2/org/jodd/jodd-core/5.1.6/jodd-core-5.1.6-sources.jar" - ], - "downloaded_file_path": "org/jodd/jodd-core/5.1.6/jodd-core-5.1.6-sources.jar" - } - }, - "org_jetbrains_annotations": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_jetbrains_annotations", - "generating_repository": "maven", - "target_name": "org_jetbrains_annotations" - } - }, - "com_amazonaws_aws_java_sdk_core_1_12_544": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_amazonaws_aws_java_sdk_core_1_12_544", - "sha256": "79682855ea21bd65094ad97109f9b3e4361d3e02926f5ee14ade3411c7ca43da", - "urls": [ - "https://repo1.maven.org/maven2/com/amazonaws/aws-java-sdk-core/1.12.544/aws-java-sdk-core-1.12.544.jar" - ], - "downloaded_file_path": "com/amazonaws/aws-java-sdk-core/1.12.544/aws-java-sdk-core-1.12.544.jar" - } - }, - "org_checkerframework_checker_qual_3_38_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_checkerframework_checker_qual_3_38_0", - "sha256": "9bd02cbe679a58afa0fba44c9621fe70130653e8c4564eb8d65e14bbfe26b7f8", - "urls": [ - "https://repo1.maven.org/maven2/org/checkerframework/checker-qual/3.38.0/checker-qual-3.38.0.jar" - ], - "downloaded_file_path": "org/checkerframework/checker-qual/3.38.0/checker-qual-3.38.0.jar" - } - }, - "org_glassfish_hk2_external_jakarta_inject_2_6_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_glassfish_hk2_external_jakarta_inject_2_6_1", - "sha256": "5e88c123b3e41bca788b2683118867d9b6dec714247ea91c588aed46a36ee24f", - "urls": [ - "https://repo1.maven.org/maven2/org/glassfish/hk2/external/jakarta.inject/2.6.1/jakarta.inject-2.6.1.jar" - ], - "downloaded_file_path": "org/glassfish/hk2/external/jakarta.inject/2.6.1/jakarta.inject-2.6.1.jar" - } - }, - "io_netty_netty_codec_socks_jar_sources_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_socks_jar_sources_4_1_97_Final", - "sha256": "2b48738f837dfc66833b811f6a4eab7fc3a75abd47fee3e7572de7653e5172de", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-codec-socks/4.1.97.Final/netty-codec-socks-4.1.97.Final-sources.jar" - ], - "downloaded_file_path": "io/netty/netty-codec-socks/4.1.97.Final/netty-codec-socks-4.1.97.Final-sources.jar" - } - }, - "com_google_http_client_google_http_client_apache_v2_1_43_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_http_client_google_http_client_apache_v2_1_43_1", - "sha256": "18b25a8bed630a7b90204b7020f72219fdda643935fca6405e6e3937ae92b361", - "urls": [ - "https://repo1.maven.org/maven2/com/google/http-client/google-http-client-apache-v2/1.43.1/google-http-client-apache-v2-1.43.1.jar", - "https://maven.google.com/com/google/http-client/google-http-client-apache-v2/1.43.1/google-http-client-apache-v2-1.43.1.jar" - ], - "downloaded_file_path": "com/google/http-client/google-http-client-apache-v2/1.43.1/google-http-client-apache-v2-1.43.1.jar" - } - }, - "io_netty_netty_transport_classes_epoll_4_1_86_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_classes_epoll_4_1_86_Final", - "sha256": "3cc7eb87d85d6b4bf3d596a172a92df09f8d746c2b283c85543c95795b51edda", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-transport-classes-epoll/4.1.86.Final/netty-transport-classes-epoll-4.1.86.Final.jar", - "https://maven.google.com/io/netty/netty-transport-classes-epoll/4.1.86.Final/netty-transport-classes-epoll-4.1.86.Final.jar" - ], - "downloaded_file_path": "io/netty/netty-transport-classes-epoll/4.1.86.Final/netty-transport-classes-epoll-4.1.86.Final.jar" - } - }, - "com_github_jnr_jnr_x86asm_jar_sources_1_0_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_jnr_jnr_x86asm_jar_sources_1_0_2", - "sha256": "3c983efd496f95ea5382ca014f96613786826136e0ce13d5c1cbc3097ea92ca0", - "urls": [ - "https://repo1.maven.org/maven2/com/github/jnr/jnr-x86asm/1.0.2/jnr-x86asm-1.0.2-sources.jar" - ], - "downloaded_file_path": "com/github/jnr/jnr-x86asm/1.0.2/jnr-x86asm-1.0.2-sources.jar" - } - }, - "io_netty_netty_codec_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_4_1_97_Final", - "sha256": "bcc96737a0f912fcf031cf8c45ebda352a90a40437db0832caad3d5a63618b38", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-codec/4.1.97.Final/netty-codec-4.1.97.Final.jar" - ], - "downloaded_file_path": "io/netty/netty-codec/4.1.97.Final/netty-codec-4.1.97.Final.jar" - } - }, - "com_google_code_gson_gson_jar_sources_2_10_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_code_gson_gson_jar_sources_2_10_1", - "sha256": "eee1cc5c1f4267ee194cc245777e68084738ef390acd763354ce0ff6bfb7bcc1", - "urls": [ - "https://repo1.maven.org/maven2/com/google/code/gson/gson/2.10.1/gson-2.10.1-sources.jar" - ], - "downloaded_file_path": "com/google/code/gson/gson/2.10.1/gson-2.10.1-sources.jar" - } - }, - "org_threeten_threetenbp": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_threeten_threetenbp", - "generating_repository": "maven", - "target_name": "org_threeten_threetenbp" - } - }, - "com_github_jnr_jnr_ffi_2_2_14": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_jnr_jnr_ffi_2_2_14", - "sha256": "01fafe177b1e3136b3789aeb0ff0884ae1e24b5ada711192f67084103697f2d4", - "urls": [ - "https://repo1.maven.org/maven2/com/github/jnr/jnr-ffi/2.2.14/jnr-ffi-2.2.14.jar" - ], - "downloaded_file_path": "com/github/jnr/jnr-ffi/2.2.14/jnr-ffi-2.2.14.jar" - } - }, - "com_google_auto_value_auto_value_annotations_1_10_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_auto_value_auto_value_annotations_1_10_1", - "sha256": "a4fe0a211925e938a8510d741763ee1171a11bf931f5891ef4d4ee84fca72be2", - "urls": [ - "https://repo1.maven.org/maven2/com/google/auto/value/auto-value-annotations/1.10.1/auto-value-annotations-1.10.1.jar" - ], - "downloaded_file_path": "com/google/auto/value/auto-value-annotations/1.10.1/auto-value-annotations-1.10.1.jar" - } - }, - "org_ow2_asm_asm_tree_9_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_ow2_asm_asm_tree_9_2", - "sha256": "aabf9bd23091a4ebfc109c1f3ee7cf3e4b89f6ba2d3f51c5243f16b3cffae011", - "urls": [ - "https://repo1.maven.org/maven2/org/ow2/asm/asm-tree/9.2/asm-tree-9.2.jar" - ], - "downloaded_file_path": "org/ow2/asm/asm-tree/9.2/asm-tree-9.2.jar" - } - }, - "com_google_inject_guice_jar_sources_5_1_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_inject_guice_jar_sources_5_1_0", - "sha256": "79484227656350f8ea315198ed2ebdc8583e7ba42ecd90d367d66a7e491de52e", - "urls": [ - "https://repo1.maven.org/maven2/com/google/inject/guice/5.1.0/guice-5.1.0-sources.jar" - ], - "downloaded_file_path": "com/google/inject/guice/5.1.0/guice-5.1.0-sources.jar" - } - }, - "com_google_api_client_google_api_client_2_2_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_api_client_google_api_client_2_2_0", - "sha256": "58eca9fb0a869391689ffc828b3bd0b19ac76042ff9fab4881eddf7fde76903f", - "urls": [ - "https://repo1.maven.org/maven2/com/google/api-client/google-api-client/2.2.0/google-api-client-2.2.0.jar", - "https://maven.google.com/com/google/api-client/google-api-client/2.2.0/google-api-client-2.2.0.jar" - ], - "downloaded_file_path": "com/google/api-client/google-api-client/2.2.0/google-api-client-2.2.0.jar" - } - }, - "rules_jvm_external_deps": { - "bzlFile": "@@rules_jvm_external~5.3//:coursier.bzl", - "ruleClassName": "pinned_coursier_fetch", - "attributes": { - "name": "rules_jvm_external~5.3~maven~rules_jvm_external_deps", - "repositories": [ - "{ \"repo_url\": \"https://repo1.maven.org/maven2\" }" - ], - "artifacts": [ - "{ \"group\": \"com.google.auth\", \"artifact\": \"google-auth-library-credentials\", \"version\": \"1.17.0\" }", - "{ \"group\": \"com.google.auth\", \"artifact\": \"google-auth-library-oauth2-http\", \"version\": \"1.17.0\" }", - "{ \"group\": \"com.google.cloud\", \"artifact\": \"google-cloud-core\", \"version\": \"2.18.1\" }", - "{ \"group\": \"com.google.cloud\", \"artifact\": \"google-cloud-storage\", \"version\": \"2.22.3\" }", - "{ \"group\": \"com.google.code.gson\", \"artifact\": \"gson\", \"version\": \"2.10.1\" }", - "{ \"group\": \"com.google.googlejavaformat\", \"artifact\": \"google-java-format\", \"version\": \"1.17.0\" }", - "{ \"group\": \"com.google.guava\", \"artifact\": \"guava\", \"version\": \"32.0.0-jre\" }", - "{ \"group\": \"org.apache.maven\", \"artifact\": \"maven-artifact\", \"version\": \"3.9.2\" }", - "{ \"group\": \"software.amazon.awssdk\", \"artifact\": \"s3\", \"version\": \"2.20.78\" }" - ], - "fetch_sources": true, - "fetch_javadoc": false, - "generate_compat_repositories": false, - "maven_install_json": "@@rules_jvm_external~5.3//:rules_jvm_external_deps_install.json", - "override_targets": {}, - "strict_visibility": false, - "strict_visibility_value": [ - "@@//visibility:private" - ], - "jetify": false, - "jetify_include_list": [ - "*" - ], - "additional_netrc_lines": [], - "fail_if_repin_required": false, - "use_starlark_android_rules": false, - "aar_import_bzl_label": "@build_bazel_rules_android//android:rules.bzl", - "duplicate_version_warning": "warn" - } - }, - "net_javacrumbs_future_converter_future_converter_java8_guava": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~net_javacrumbs_future_converter_future_converter_java8_guava", - "generating_repository": "maven", - "target_name": "net_javacrumbs_future_converter_future_converter_java8_guava" - } - }, - "com_google_http_client_google_http_client_appengine_1_43_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_http_client_google_http_client_appengine_1_43_1", - "sha256": "93762484a9324f824455b24da0cb698a7e3467e2e4962ee541a14ff1922c3a88", - "urls": [ - "https://repo1.maven.org/maven2/com/google/http-client/google-http-client-appengine/1.43.1/google-http-client-appengine-1.43.1.jar", - "https://maven.google.com/com/google/http-client/google-http-client-appengine/1.43.1/google-http-client-appengine-1.43.1.jar" - ], - "downloaded_file_path": "com/google/http-client/google-http-client-appengine/1.43.1/google-http-client-appengine-1.43.1.jar" - } - }, - "io_grpc_grpc_auth_1_56_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_auth_1_56_1", - "sha256": "ac365e11532a4b779a2ac80ecc64dcbd3bafbdd666e08e22ffdb5c855069e3f9", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-auth/1.56.1/grpc-auth-1.56.1.jar" - ], - "downloaded_file_path": "io/grpc/grpc-auth/1.56.1/grpc-auth-1.56.1.jar" - } - }, - "com_google_auto_service_auto_service_annotations_1_0_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_auto_service_auto_service_annotations_1_0_1", - "sha256": "c7bec54b7b5588b5967e870341091c5691181d954cf2039f1bf0a6eeb837473b", - "urls": [ - "https://repo1.maven.org/maven2/com/google/auto/service/auto-service-annotations/1.0.1/auto-service-annotations-1.0.1.jar" - ], - "downloaded_file_path": "com/google/auto/service/auto-service-annotations/1.0.1/auto-service-annotations-1.0.1.jar" - } - }, - "io_grpc_grpc_xds_1_55_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_xds_1_55_1", - "sha256": "08e618b3e166981f86d8bd1623f161d6432923183c55338db77df49a2fb23893", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-xds/1.55.1/grpc-xds-1.55.1.jar", - "https://maven.google.com/io/grpc/grpc-xds/1.55.1/grpc-xds-1.55.1.jar" - ], - "downloaded_file_path": "io/grpc/grpc-xds/1.55.1/grpc-xds-1.55.1.jar" - } - }, - "com_fasterxml_jackson_core_jackson_annotations_jar_sources_2_15_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_core_jackson_annotations_jar_sources_2_15_2", - "sha256": "ce8e910f66e0c60d0beec66ccfe308a2426d606c85e67c76a5377dafb52eb4da", - "urls": [ - "https://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-annotations/2.15.2/jackson-annotations-2.15.2-sources.jar" - ], - "downloaded_file_path": "com/fasterxml/jackson/core/jackson-annotations/2.15.2/jackson-annotations-2.15.2-sources.jar" - } - }, - "junit_junit_4_13_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~junit_junit_4_13_2", - "sha256": "8e495b634469d64fb8acfa3495a065cbacc8a0fff55ce1e31007be4c16dc57d3", - "urls": [ - "https://repo1.maven.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar" - ], - "downloaded_file_path": "junit/junit/4.13.2/junit-4.13.2.jar" - } - }, - "com_google_guava_guava_32_1_1_jre": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_guava_guava_32_1_1_jre", - "sha256": "91fbba37f1c8b251cf9ea9e7d3a369eb79eb1e6a5df1d4bbf483dd0380740281", - "urls": [ - "https://repo1.maven.org/maven2/com/google/guava/guava/32.1.1-jre/guava-32.1.1-jre.jar" - ], - "downloaded_file_path": "com/google/guava/guava/32.1.1-jre/guava-32.1.1-jre.jar" - } - }, - "com_googlecode_json_simple_json_simple": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_googlecode_json_simple_json_simple", - "generating_repository": "maven", - "target_name": "com_googlecode_json_simple_json_simple" - } - }, - "io_netty_netty_codec_socks_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_socks_4_1_97_Final", - "sha256": "24081cae8a9685ff3fcde141f5050f28589c22e2ae6c447854e044df6d308028", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-codec-socks/4.1.97.Final/netty-codec-socks-4.1.97.Final.jar" - ], - "downloaded_file_path": "io/netty/netty-codec-socks/4.1.97.Final/netty-codec-socks-4.1.97.Final.jar" - } - }, - "com_esotericsoftware_minlog_1_3_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_esotericsoftware_minlog_1_3_1", - "sha256": "5d4d632cfbebfe0a7644501cc303570b691406181bee65e9916b921c767d7c72", - "urls": [ - "https://repo1.maven.org/maven2/com/esotericsoftware/minlog/1.3.1/minlog-1.3.1.jar" - ], - "downloaded_file_path": "com/esotericsoftware/minlog/1.3.1/minlog-1.3.1.jar" - } - }, - "org_hamcrest_hamcrest_core_1_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_hamcrest_hamcrest_core_1_3", - "sha256": "66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9", - "urls": [ - "https://repo1.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar" - ], - "downloaded_file_path": "org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar" - } - }, - "com_google_http_client_google_http_client_1_42_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_http_client_google_http_client_1_42_3", - "sha256": "e395dd1765e3e6bceb0c610706bcf4128de84bd6e65cf1d4adbf998b4114161c", - "urls": [ - "https://repo1.maven.org/maven2/com/google/http-client/google-http-client/1.42.3/google-http-client-1.42.3.jar" - ], - "downloaded_file_path": "com/google/http-client/google-http-client/1.42.3/google-http-client-1.42.3.jar" - } - }, - "org_jodd_jodd_bean_5_1_6": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_jodd_jodd_bean_5_1_6", - "sha256": "d07d805fe0d59b5d2dbc85d0ebfcf30f52d7fd5a3ff89ff4fbea1e46b1319705", - "urls": [ - "https://repo1.maven.org/maven2/org/jodd/jodd-bean/5.1.6/jodd-bean-5.1.6.jar" - ], - "downloaded_file_path": "org/jodd/jodd-bean/5.1.6/jodd-bean-5.1.6.jar" - } - }, - "me_dinowernli_java_grpc_prometheus_0_6_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~me_dinowernli_java_grpc_prometheus_0_6_0", - "sha256": "badf9c84d9ea4b598bfa3fc690c85a8f6d863265829b9cb79f33884d48729ed8", - "urls": [ - "https://repo1.maven.org/maven2/me/dinowernli/java-grpc-prometheus/0.6.0/java-grpc-prometheus-0.6.0.jar" - ], - "downloaded_file_path": "me/dinowernli/java-grpc-prometheus/0.6.0/java-grpc-prometheus-0.6.0.jar" - } - }, - "org_mockito_mockito_core_jar_sources_2_25_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_mockito_mockito_core_jar_sources_2_25_0", - "sha256": "2230169d4ffad6f6c1b07bba0e81e30fa734941faf073e847839c695907645ff", - "urls": [ - "https://repo1.maven.org/maven2/org/mockito/mockito-core/2.25.0/mockito-core-2.25.0-sources.jar" - ], - "downloaded_file_path": "org/mockito/mockito-core/2.25.0/mockito-core-2.25.0-sources.jar" - } - }, - "org_slf4j_jcl_over_slf4j_1_7_30": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_slf4j_jcl_over_slf4j_1_7_30", - "sha256": "71e9ee37b9e4eb7802a2acc5f41728a4cf3915e7483d798db3b4ff2ec8847c50", - "urls": [ - "https://repo1.maven.org/maven2/org/slf4j/jcl-over-slf4j/1.7.30/jcl-over-slf4j-1.7.30.jar" - ], - "downloaded_file_path": "org/slf4j/jcl-over-slf4j/1.7.30/jcl-over-slf4j-1.7.30.jar" - } - }, - "org_json_json_jar_sources_20220320": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_json_json_jar_sources_20220320", - "sha256": "741ba87153d52919259b085e9a066a603b7efe41ede242336f4e3232d230a899", - "urls": [ - "https://repo1.maven.org/maven2/org/json/json/20220320/json-20220320-sources.jar" - ], - "downloaded_file_path": "org/json/json/20220320/json-20220320-sources.jar" - } - }, - "io_grpc_grpc_stub": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_stub", - "generating_repository": "maven", - "target_name": "io_grpc_grpc_stub" - } - }, - "com_google_errorprone_error_prone_check_api_2_22_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_errorprone_error_prone_check_api_2_22_0", - "sha256": "1717bbf65757b8e1a83f3b0aa78c5ac25a6493008bc730091d404cf798fc0639", - "urls": [ - "https://repo1.maven.org/maven2/com/google/errorprone/error_prone_check_api/2.22.0/error_prone_check_api-2.22.0.jar" - ], - "downloaded_file_path": "com/google/errorprone/error_prone_check_api/2.22.0/error_prone_check_api-2.22.0.jar" - } - }, - "com_github_pcj_google_options_1_0_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_pcj_google_options_1_0_0", - "sha256": "f1f84449b46390a7fa73aac0b5acdec4312d6174146af0db1c92425c7005fdce", - "urls": [ - "https://repo1.maven.org/maven2/com/github/pcj/google-options/1.0.0/google-options-1.0.0.jar" - ], - "downloaded_file_path": "com/github/pcj/google-options/1.0.0/google-options-1.0.0.jar" - } - }, - "com_github_luben_zstd_jni": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_luben_zstd_jni", - "generating_repository": "maven", - "target_name": "com_github_luben_zstd_jni" - } - }, - "com_github_jnr_jnr_posix_3_1_17": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_jnr_jnr_posix_3_1_17", - "sha256": "9e24abedd700a1d8f0a2787566f2d0c4f3e4fbdb8be543d4b434ce445923c757", - "urls": [ - "https://repo1.maven.org/maven2/com/github/jnr/jnr-posix/3.1.17/jnr-posix-3.1.17.jar" - ], - "downloaded_file_path": "com/github/jnr/jnr-posix/3.1.17/jnr-posix-3.1.17.jar" - } - }, - "net_bytebuddy_byte_buddy_agent_1_9_7": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~net_bytebuddy_byte_buddy_agent_1_9_7", - "sha256": "145ce0fab5390374e69b2b4070d65fedaa2b07c3cfad06b330bea1b6dcfa826f", - "urls": [ - "https://repo1.maven.org/maven2/net/bytebuddy/byte-buddy-agent/1.9.7/byte-buddy-agent-1.9.7.jar" - ], - "downloaded_file_path": "net/bytebuddy/byte-buddy-agent/1.9.7/byte-buddy-agent-1.9.7.jar" - } - }, - "io_github_eisop_dataflow_errorprone_jar_sources_3_34_0_eisop1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_github_eisop_dataflow_errorprone_jar_sources_3_34_0_eisop1", - "sha256": "ec56c0f0a96c5e22a3608f2cf9f41c11b5698fee92dd665c21c2dc918e65ef9f", - "urls": [ - "https://repo1.maven.org/maven2/io/github/eisop/dataflow-errorprone/3.34.0-eisop1/dataflow-errorprone-3.34.0-eisop1-sources.jar" - ], - "downloaded_file_path": "io/github/eisop/dataflow-errorprone/3.34.0-eisop1/dataflow-errorprone-3.34.0-eisop1-sources.jar" - } - }, - "io_netty_netty_transport_native_kqueue": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_native_kqueue", - "generating_repository": "maven", - "target_name": "io_netty_netty_transport_native_kqueue" - } - }, - "org_jboss_marshalling_jboss_marshalling_2_0_11_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_jboss_marshalling_jboss_marshalling_2_0_11_Final", - "sha256": "93d6257e1ac0f93ba6ff85827c9ef65b5efabf7bd2241fb3b4caf6c426f4f149", - "urls": [ - "https://repo1.maven.org/maven2/org/jboss/marshalling/jboss-marshalling/2.0.11.Final/jboss-marshalling-2.0.11.Final.jar" - ], - "downloaded_file_path": "org/jboss/marshalling/jboss-marshalling/2.0.11.Final/jboss-marshalling-2.0.11.Final.jar" - } - }, - "com_google_truth_truth_1_1_5": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_truth_truth_1_1_5", - "sha256": "7f6d50d6f43a102942ef2c5a05f37a84f77788bb448cf33cceebf86d34e575c0", - "urls": [ - "https://repo1.maven.org/maven2/com/google/truth/truth/1.1.5/truth-1.1.5.jar" - ], - "downloaded_file_path": "com/google/truth/truth/1.1.5/truth-1.1.5.jar" - } - }, - "io_netty_netty_transport_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_4_1_97_Final", - "sha256": "197fd2d6c6b4afe677d9e95bf2e36b49a0bcabdfce0583683fb73f29a3f5a407", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-transport/4.1.97.Final/netty-transport-4.1.97.Final.jar" - ], - "downloaded_file_path": "io/netty/netty-transport/4.1.97.Final/netty-transport-4.1.97.Final.jar" - } - }, - "io_grpc_grpc_context_jar_sources_1_56_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_context_jar_sources_1_56_1", - "sha256": "315a2c4145c3362131d4af25c27ae9cd4924f8f84e661a31402c56b223bcb956", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-context/1.56.1/grpc-context-1.56.1-sources.jar" - ], - "downloaded_file_path": "io/grpc/grpc-context/1.56.1/grpc-context-1.56.1-sources.jar" - } - }, - "org_slf4j_slf4j_api_2_0_9": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_slf4j_slf4j_api_2_0_9", - "sha256": "0818930dc8d7debb403204611691da58e49d42c50b6ffcfdce02dadb7c3c2b6c", - "urls": [ - "https://repo1.maven.org/maven2/org/slf4j/slf4j-api/2.0.9/slf4j-api-2.0.9.jar" - ], - "downloaded_file_path": "org/slf4j/slf4j-api/2.0.9/slf4j-api-2.0.9.jar" - } - }, - "com_google_j2objc_j2objc_annotations_2_8": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_j2objc_j2objc_annotations_2_8", - "sha256": "f02a95fa1a5e95edb3ed859fd0fb7df709d121a35290eff8b74dce2ab7f4d6ed", - "urls": [ - "https://repo1.maven.org/maven2/com/google/j2objc/j2objc-annotations/2.8/j2objc-annotations-2.8.jar" - ], - "downloaded_file_path": "com/google/j2objc/j2objc-annotations/2.8/j2objc-annotations-2.8.jar" - } - }, - "io_netty_netty_codec_http2_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_http2_4_1_97_Final", - "sha256": "51fabf675563b59dc51dde22d29dbc5a20f836469cf48b8d53a07d3db0d775ad", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-codec-http2/4.1.97.Final/netty-codec-http2-4.1.97.Final.jar" - ], - "downloaded_file_path": "io/netty/netty-codec-http2/4.1.97.Final/netty-codec-http2-4.1.97.Final.jar" - } - }, - "io_prometheus_simpleclient_common_0_15_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_common_0_15_0", - "sha256": "8d2fa21b5c7959010818245788bd43131633dea989d3facb28cec45b2da37918", - "urls": [ - "https://repo1.maven.org/maven2/io/prometheus/simpleclient_common/0.15.0/simpleclient_common-0.15.0.jar" - ], - "downloaded_file_path": "io/prometheus/simpleclient_common/0.15.0/simpleclient_common-0.15.0.jar" - } - }, - "net_java_dev_jna_jna_jar_sources_5_13_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~net_java_dev_jna_jna_jar_sources_5_13_0", - "sha256": "a4c45843e8f60df141c4f37602365a421bb278ca1ef30ba0a043d6a871dd29f4", - "urls": [ - "https://repo1.maven.org/maven2/net/java/dev/jna/jna/5.13.0/jna-5.13.0-sources.jar" - ], - "downloaded_file_path": "net/java/dev/jna/jna/5.13.0/jna-5.13.0-sources.jar" - } - }, - "io_prometheus_simpleclient_hotspot_0_15_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_hotspot_0_15_0", - "sha256": "3c99768b090065bc0b25219061f94970aa569a2e363488d9120c79769d78c1a6", - "urls": [ - "https://repo1.maven.org/maven2/io/prometheus/simpleclient_hotspot/0.15.0/simpleclient_hotspot-0.15.0.jar" - ], - "downloaded_file_path": "io/prometheus/simpleclient_hotspot/0.15.0/simpleclient_hotspot-0.15.0.jar" - } - }, - "org_jboss_marshalling_jboss_marshalling_river_2_0_11_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_jboss_marshalling_jboss_marshalling_river_2_0_11_Final", - "sha256": "f3fa6545d15163468e1639fe3087de22234a9fd027a52be6e532bfe7bde6c554", - "urls": [ - "https://repo1.maven.org/maven2/org/jboss/marshalling/jboss-marshalling-river/2.0.11.Final/jboss-marshalling-river-2.0.11.Final.jar" - ], - "downloaded_file_path": "org/jboss/marshalling/jboss-marshalling-river/2.0.11.Final/jboss-marshalling-river-2.0.11.Final.jar" - } - }, - "org_luaj_luaj_jse_jar_sources_3_0_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_luaj_luaj_jse_jar_sources_3_0_1", - "sha256": "e9fc8eb5593ef489bafb79b5561b49114e8a233834f160c4657efe927a613f53", - "urls": [ - "https://repo1.maven.org/maven2/org/luaj/luaj-jse/3.0.1/luaj-jse-3.0.1-sources.jar" - ], - "downloaded_file_path": "org/luaj/luaj-jse/3.0.1/luaj-jse-3.0.1-sources.jar" - } - }, - "io_netty_netty_resolver_4_1_86_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_resolver_4_1_86_Final", - "sha256": "7628a1309d7f2443dc41d8923a7f269e2981b9616f80a999eb7264ae6bcbfdba", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-resolver/4.1.86.Final/netty-resolver-4.1.86.Final.jar", - "https://maven.google.com/io/netty/netty-resolver/4.1.86.Final/netty-resolver-4.1.86.Final.jar" - ], - "downloaded_file_path": "io/netty/netty-resolver/4.1.86.Final/netty-resolver-4.1.86.Final.jar" - } - }, - "net_javacrumbs_future_converter_future_converter_java8_guava_jar_sources_1_2_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~net_javacrumbs_future_converter_future_converter_java8_guava_jar_sources_1_2_0", - "sha256": "3e209e1d6e80d1cde253ac0e28d50588112d0128a9bf05dae7f4aea3a36bdc03", - "urls": [ - "https://repo1.maven.org/maven2/net/javacrumbs/future-converter/future-converter-java8-guava/1.2.0/future-converter-java8-guava-1.2.0-sources.jar" - ], - "downloaded_file_path": "net/javacrumbs/future-converter/future-converter-java8-guava/1.2.0/future-converter-java8-guava-1.2.0-sources.jar" - } - }, - "org_jetbrains_annotations_jar_sources_16_0_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_jetbrains_annotations_jar_sources_16_0_2", - "sha256": "699c2e6786e86fa5df5c82ffd0490d829107daa6225c0cffa290860abe4c1a80", - "urls": [ - "https://repo1.maven.org/maven2/org/jetbrains/annotations/16.0.2/annotations-16.0.2-sources.jar" - ], - "downloaded_file_path": "org/jetbrains/annotations/16.0.2/annotations-16.0.2-sources.jar" - } - }, - "software_amazon_awssdk_crt_core_2_20_78": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_crt_core_2_20_78", - "sha256": "f83ba65ea519cfcc2306994527d6432a969ac8efb418abfcf38128d08467f7cf", - "urls": [ - "https://repo1.maven.org/maven2/software/amazon/awssdk/crt-core/2.20.78/crt-core-2.20.78.jar", - "https://maven.google.com/software/amazon/awssdk/crt-core/2.20.78/crt-core-2.20.78.jar" - ], - "downloaded_file_path": "software/amazon/awssdk/crt-core/2.20.78/crt-core-2.20.78.jar" - } - }, - "com_google_guava_failureaccess": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_guava_failureaccess", - "generating_repository": "maven", - "target_name": "com_google_guava_failureaccess" - } - }, - "com_google_cloud_google_cloud_core_http_2_18_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_cloud_google_cloud_core_http_2_18_1", - "sha256": "52466ba755e309ae43977209897aac76f40103115cf37ca755a428dae5a190ae", - "urls": [ - "https://repo1.maven.org/maven2/com/google/cloud/google-cloud-core-http/2.18.1/google-cloud-core-http-2.18.1.jar", - "https://maven.google.com/com/google/cloud/google-cloud-core-http/2.18.1/google-cloud-core-http-2.18.1.jar" - ], - "downloaded_file_path": "com/google/cloud/google-cloud-core-http/2.18.1/google-cloud-core-http-2.18.1.jar" - } - }, - "javax_annotation_javax_annotation_api": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~javax_annotation_javax_annotation_api", - "generating_repository": "maven", - "target_name": "javax_annotation_javax_annotation_api" - } - }, - "io_opencensus_opencensus_api_0_31_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_opencensus_opencensus_api_0_31_1", - "sha256": "f1474d47f4b6b001558ad27b952e35eda5cc7146788877fc52938c6eba24b382", - "urls": [ - "https://repo1.maven.org/maven2/io/opencensus/opencensus-api/0.31.1/opencensus-api-0.31.1.jar" - ], - "downloaded_file_path": "io/opencensus/opencensus-api/0.31.1/opencensus-api-0.31.1.jar" - } - }, - "io_netty_netty_transport_classes_epoll_jar_sources_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_classes_epoll_jar_sources_4_1_97_Final", - "sha256": "96e2dbe0d3d8d4dae3ddc23443c174388373c1f6dd76401e23a26bd952bf4d08", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-transport-classes-epoll/4.1.97.Final/netty-transport-classes-epoll-4.1.97.Final-sources.jar" - ], - "downloaded_file_path": "io/netty/netty-transport-classes-epoll/4.1.97.Final/netty-transport-classes-epoll-4.1.97.Final-sources.jar" - } - }, - "io_netty_netty_codec_http2_4_1_86_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_http2_4_1_86_Final", - "sha256": "e8e8e28e6ab6bb989aed904778922045f388cfb420bc1eb37abf4df8801db167", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-codec-http2/4.1.86.Final/netty-codec-http2-4.1.86.Final.jar", - "https://maven.google.com/io/netty/netty-codec-http2/4.1.86.Final/netty-codec-http2-4.1.86.Final.jar" - ], - "downloaded_file_path": "io/netty/netty-codec-http2/4.1.86.Final/netty-codec-http2-4.1.86.Final.jar" - } - }, - "commons_io_commons_io": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~commons_io_commons_io", - "generating_repository": "maven", - "target_name": "commons_io_commons_io" - } - }, - "io_netty_netty_transport_native_unix_common": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_native_unix_common", - "generating_repository": "maven", - "target_name": "io_netty_netty_transport_native_unix_common" - } - }, - "org_javassist_javassist_jar_sources_3_28_0_GA": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_javassist_javassist_jar_sources_3_28_0_GA", - "sha256": "0b6cf0d138dc208263a2a0a39b1daae217707d58d79d7a4973a68ce62f8c2d1f", - "urls": [ - "https://repo1.maven.org/maven2/org/javassist/javassist/3.28.0-GA/javassist-3.28.0-GA-sources.jar" - ], - "downloaded_file_path": "org/javassist/javassist/3.28.0-GA/javassist-3.28.0-GA-sources.jar" - } - }, - "me_dinowernli_java_grpc_prometheus_jar_sources_0_6_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~me_dinowernli_java_grpc_prometheus_jar_sources_0_6_0", - "sha256": "a9029bdc0712ee294862aaa0c65e1308705472bb9fe429095b346a964be7b731", - "urls": [ - "https://repo1.maven.org/maven2/me/dinowernli/java-grpc-prometheus/0.6.0/java-grpc-prometheus-0.6.0-sources.jar" - ], - "downloaded_file_path": "me/dinowernli/java-grpc-prometheus/0.6.0/java-grpc-prometheus-0.6.0-sources.jar" - } - }, - "org_apache_maven_maven_artifact_3_9_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_apache_maven_maven_artifact_3_9_2", - "sha256": "f2174221d412a79572817b5aa77125348f43266670b6329a9881cdccf7bbc4b1", - "urls": [ - "https://repo1.maven.org/maven2/org/apache/maven/maven-artifact/3.9.2/maven-artifact-3.9.2.jar", - "https://maven.google.com/org/apache/maven/maven-artifact/3.9.2/maven-artifact-3.9.2.jar" - ], - "downloaded_file_path": "org/apache/maven/maven-artifact/3.9.2/maven-artifact-3.9.2.jar" - } - }, - "io_netty_netty_common": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_common", - "generating_repository": "maven", - "target_name": "io_netty_netty_common" - } - }, - "com_google_j2objc_j2objc_annotations_jar_sources_2_8": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_j2objc_j2objc_annotations_jar_sources_2_8", - "sha256": "7413eed41f111453a08837f5ac680edded7faed466cbd35745e402e13f4cc3f5", - "urls": [ - "https://repo1.maven.org/maven2/com/google/j2objc/j2objc-annotations/2.8/j2objc-annotations-2.8-sources.jar" - ], - "downloaded_file_path": "com/google/j2objc/j2objc-annotations/2.8/j2objc-annotations-2.8-sources.jar" - } - }, - "com_github_jnr_jffi_jar_sources_1_3_11": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_jnr_jffi_jar_sources_1_3_11", - "sha256": "df7dcc8843d61e60c5fe606e860646f1a82d11d2dc41a3d230da87fc0bcf4291", - "urls": [ - "https://repo1.maven.org/maven2/com/github/jnr/jffi/1.3.11/jffi-1.3.11-sources.jar" - ], - "downloaded_file_path": "com/github/jnr/jffi/1.3.11/jffi-1.3.11-sources.jar" - } - }, - "org_apache_commons_commons_lang3_jar_sources_3_13_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_apache_commons_commons_lang3_jar_sources_3_13_0", - "sha256": "6152e03a6c29e0d9dd1415aaa42cb13f6fab5fc5b2333077c29b498927535453", - "urls": [ - "https://repo1.maven.org/maven2/org/apache/commons/commons-lang3/3.13.0/commons-lang3-3.13.0-sources.jar" - ], - "downloaded_file_path": "org/apache/commons/commons-lang3/3.13.0/commons-lang3-3.13.0-sources.jar" - } - }, - "software_amazon_eventstream_eventstream_1_0_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~software_amazon_eventstream_eventstream_1_0_1", - "sha256": "0c37d8e696117f02c302191b8110b0d0eb20fa412fce34c3a269ec73c16ce822", - "urls": [ - "https://repo1.maven.org/maven2/software/amazon/eventstream/eventstream/1.0.1/eventstream-1.0.1.jar", - "https://maven.google.com/software/amazon/eventstream/eventstream/1.0.1/eventstream-1.0.1.jar" - ], - "downloaded_file_path": "software/amazon/eventstream/eventstream/1.0.1/eventstream-1.0.1.jar" - } - }, - "com_github_docker_java_docker_java_transport_jersey_3_3_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_docker_java_docker_java_transport_jersey_3_3_3", - "sha256": "7574d831272a56268f4468b901059cafdca6e10176c87fec83f65d26d28c6fb0", - "urls": [ - "https://repo1.maven.org/maven2/com/github/docker-java/docker-java-transport-jersey/3.3.3/docker-java-transport-jersey-3.3.3.jar" - ], - "downloaded_file_path": "com/github/docker-java/docker-java-transport-jersey/3.3.3/docker-java-transport-jersey-3.3.3.jar" - } - }, - "org_glassfish_hk2_hk2_utils_jar_sources_2_6_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_glassfish_hk2_hk2_utils_jar_sources_2_6_1", - "sha256": "36552a965412a1d5a9eb2ee0282fd224151e79ac5dc42ae794f0bac67e523dc5", - "urls": [ - "https://repo1.maven.org/maven2/org/glassfish/hk2/hk2-utils/2.6.1/hk2-utils-2.6.1-sources.jar" - ], - "downloaded_file_path": "org/glassfish/hk2/hk2-utils/2.6.1/hk2-utils-2.6.1-sources.jar" - } - }, - "io_netty_netty_handler": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_handler", - "generating_repository": "maven", - "target_name": "io_netty_netty_handler" - } - }, - "com_google_api_grpc_proto_google_common_protos_jar_sources_2_17_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_api_grpc_proto_google_common_protos_jar_sources_2_17_0", - "sha256": "cadaaa7232e1469abf515b99f2642b120fed9f68d6f36899ee493058b2159f18", - "urls": [ - "https://repo1.maven.org/maven2/com/google/api/grpc/proto-google-common-protos/2.17.0/proto-google-common-protos-2.17.0-sources.jar" - ], - "downloaded_file_path": "com/google/api/grpc/proto-google-common-protos/2.17.0/proto-google-common-protos-2.17.0-sources.jar" - } - }, - "net_minidev_accessors_smart_jar_sources_2_4_9": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~net_minidev_accessors_smart_jar_sources_2_4_9", - "sha256": "4b6022d773826980f124e7a2aed243cea6541238bc1bed785e2ce86076567f50", - "urls": [ - "https://repo1.maven.org/maven2/net/minidev/accessors-smart/2.4.9/accessors-smart-2.4.9-sources.jar" - ], - "downloaded_file_path": "net/minidev/accessors-smart/2.4.9/accessors-smart-2.4.9-sources.jar" - } - }, - "com_fasterxml_jackson_core_jackson_core_jar_sources_2_15_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_core_jackson_core_jar_sources_2_15_2", - "sha256": "4b29fe878549425194521d5c3270fae13f9c82cfcad639ebffea0963431bef45", - "urls": [ - "https://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-core/2.15.2/jackson-core-2.15.2-sources.jar" - ], - "downloaded_file_path": "com/fasterxml/jackson/core/jackson-core/2.15.2/jackson-core-2.15.2-sources.jar" - } - }, - "net_java_dev_jna_jna_platform_5_13_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~net_java_dev_jna_jna_platform_5_13_0", - "sha256": "474d7b88f6e97009b6ec1d98c3024dd95c23187c65dabfbc35331bcac3d173dd", - "urls": [ - "https://repo1.maven.org/maven2/net/java/dev/jna/jna-platform/5.13.0/jna-platform-5.13.0.jar" - ], - "downloaded_file_path": "net/java/dev/jna/jna-platform/5.13.0/jna-platform-5.13.0.jar" - } - }, - "io_grpc_grpc_protobuf_1_56_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_protobuf_1_56_1", - "sha256": "46185731a718d723d853723610a77e9062da9a6fc8b4ff14f370ba10cf097893", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-protobuf/1.56.1/grpc-protobuf-1.56.1.jar" - ], - "downloaded_file_path": "io/grpc/grpc-protobuf/1.56.1/grpc-protobuf-1.56.1.jar" - } - }, - "org_openjdk_jmh_jmh_core": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_openjdk_jmh_jmh_core", - "generating_repository": "maven", - "target_name": "org_openjdk_jmh_jmh_core" - } - }, - "com_github_serceman_jnr_fuse_jar_sources_0_5_7": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_serceman_jnr_fuse_jar_sources_0_5_7", - "sha256": "68a7003b43945ec3083fe2b8a5b882ff515449075122fcd6fb85f0c30bb750ab", - "urls": [ - "https://repo1.maven.org/maven2/com/github/serceman/jnr-fuse/0.5.7/jnr-fuse-0.5.7-sources.jar" - ], - "downloaded_file_path": "com/github/serceman/jnr-fuse/0.5.7/jnr-fuse-0.5.7-sources.jar" - } - }, - "com_google_truth_truth_jar_sources_1_1_5": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_truth_truth_jar_sources_1_1_5", - "sha256": "f1a94449ed48392525626f4e5edeff5c6e66af21c4c009ebb49b5109ac5db6b2", - "urls": [ - "https://repo1.maven.org/maven2/com/google/truth/truth/1.1.5/truth-1.1.5-sources.jar" - ], - "downloaded_file_path": "com/google/truth/truth/1.1.5/truth-1.1.5-sources.jar" - } - }, - "org_jodd_jodd_core_5_1_6": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_jodd_jodd_core_5_1_6", - "sha256": "4b504519263a98202480d3cf73562dff8245edc582350cc5f37d5965a0298122", - "urls": [ - "https://repo1.maven.org/maven2/org/jodd/jodd-core/5.1.6/jodd-core-5.1.6.jar" - ], - "downloaded_file_path": "org/jodd/jodd-core/5.1.6/jodd-core-5.1.6.jar" - } - }, - "org_objenesis_objenesis_jar_sources_3_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_objenesis_objenesis_jar_sources_3_3", - "sha256": "d06164f8ca002c8ef193cef2d682822014dd330505616af93a3fb64226fc131d", - "urls": [ - "https://repo1.maven.org/maven2/org/objenesis/objenesis/3.3/objenesis-3.3-sources.jar" - ], - "downloaded_file_path": "org/objenesis/objenesis/3.3/objenesis-3.3-sources.jar" - } - }, - "io_grpc_grpc_core": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_core", - "generating_repository": "maven", - "target_name": "io_grpc_grpc_core" - } - }, - "com_google_guava_guava_32_0_0_jre": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_guava_guava_32_0_0_jre", - "sha256": "39f3550b0343d8d19dd4e83bd165b58ea3389d2ddb9f2148e63903f79ecdb114", - "urls": [ - "https://repo1.maven.org/maven2/com/google/guava/guava/32.0.0-jre/guava-32.0.0-jre.jar", - "https://maven.google.com/com/google/guava/guava/32.0.0-jre/guava-32.0.0-jre.jar" - ], - "downloaded_file_path": "com/google/guava/guava/32.0.0-jre/guava-32.0.0-jre.jar" - } - }, - "io_netty_netty_codec_socks": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_socks", - "generating_repository": "maven", - "target_name": "io_netty_netty_codec_socks" - } - }, - "org_apache_httpcomponents_httpcore_jar_sources_4_4_15": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_apache_httpcomponents_httpcore_jar_sources_4_4_15", - "sha256": "1510fc72cf2858244bdeb0d7f5d266fe584ecbd2ffe0d91b10a6d80641cd1985", - "urls": [ - "https://repo1.maven.org/maven2/org/apache/httpcomponents/httpcore/4.4.15/httpcore-4.4.15-sources.jar" - ], - "downloaded_file_path": "org/apache/httpcomponents/httpcore/4.4.15/httpcore-4.4.15-sources.jar" - } - }, - "com_github_jnr_jnr_x86asm_1_0_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_jnr_jnr_x86asm_1_0_2", - "sha256": "39f3675b910e6e9b93825f8284bec9f4ad3044cd20a6f7c8ff9e2f8695ebf21e", - "urls": [ - "https://repo1.maven.org/maven2/com/github/jnr/jnr-x86asm/1.0.2/jnr-x86asm-1.0.2.jar" - ], - "downloaded_file_path": "com/github/jnr/jnr-x86asm/1.0.2/jnr-x86asm-1.0.2.jar" - } - }, - "software_amazon_awssdk_annotations_2_20_78": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_annotations_2_20_78", - "sha256": "90ce2bb257ffa63942831f7329e28cf22fa4caf0cc96ee4f2f4557b7554eae1e", - "urls": [ - "https://repo1.maven.org/maven2/software/amazon/awssdk/annotations/2.20.78/annotations-2.20.78.jar", - "https://maven.google.com/software/amazon/awssdk/annotations/2.20.78/annotations-2.20.78.jar" - ], - "downloaded_file_path": "software/amazon/awssdk/annotations/2.20.78/annotations-2.20.78.jar" - } - }, - "io_grpc_grpc_netty": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_netty", - "generating_repository": "maven", - "target_name": "io_grpc_grpc_netty" - } - }, - "io_grpc_grpc_testing": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_testing", - "generating_repository": "maven", - "target_name": "io_grpc_grpc_testing" - } - }, - "io_grpc_grpc_api_jar_sources_1_56_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_api_jar_sources_1_56_1", - "sha256": "e5e58482c95a332706d6c12a758d55ec195b01a3e54e2a38a6239ed7a3de26c0", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-api/1.56.1/grpc-api-1.56.1-sources.jar" - ], - "downloaded_file_path": "io/grpc/grpc-api/1.56.1/grpc-api-1.56.1-sources.jar" - } - }, - "org_ow2_asm_asm_jar_sources_9_5": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_ow2_asm_asm_jar_sources_9_5", - "sha256": "11214bbba797e0615402b8d57fd4be83c93a65244c5a88778015520d61078376", - "urls": [ - "https://repo1.maven.org/maven2/org/ow2/asm/asm/9.5/asm-9.5-sources.jar" - ], - "downloaded_file_path": "org/ow2/asm/asm/9.5/asm-9.5-sources.jar" - } - }, - "io_prometheus_simpleclient": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient", - "generating_repository": "maven", - "target_name": "io_prometheus_simpleclient" - } - }, - "com_google_jimfs_jimfs_jar_sources_1_3_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_jimfs_jimfs_jar_sources_1_3_0", - "sha256": "aa30e127e68ddba8e76395d14806f838f22c9ef904b07ff0266dfc5de7163059", - "urls": [ - "https://repo1.maven.org/maven2/com/google/jimfs/jimfs/1.3.0/jimfs-1.3.0-sources.jar" - ], - "downloaded_file_path": "com/google/jimfs/jimfs/1.3.0/jimfs-1.3.0-sources.jar" - } - }, - "com_google_apis_google_api_services_storage_v1_rev20230301_2_0_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_apis_google_api_services_storage_v1_rev20230301_2_0_0", - "sha256": "857ac102129477c55487ed94fd7e021b6093bd88370f9ccac799456a0ff86af9", - "urls": [ - "https://repo1.maven.org/maven2/com/google/apis/google-api-services-storage/v1-rev20230301-2.0.0/google-api-services-storage-v1-rev20230301-2.0.0.jar", - "https://maven.google.com/com/google/apis/google-api-services-storage/v1-rev20230301-2.0.0/google-api-services-storage-v1-rev20230301-2.0.0.jar" - ], - "downloaded_file_path": "com/google/apis/google-api-services-storage/v1-rev20230301-2.0.0/google-api-services-storage-v1-rev20230301-2.0.0.jar" - } - }, - "io_netty_netty_codec_http2": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_http2", - "generating_repository": "maven", - "target_name": "io_netty_netty_codec_http2" - } - }, - "io_grpc_grpc_auth_1_55_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_auth_1_55_1", - "sha256": "45d9bfaf837c41abf01e087773f535ea5afa6faad1faecbc6f32cb9ae423adef", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-auth/1.55.1/grpc-auth-1.55.1.jar", - "https://maven.google.com/io/grpc/grpc-auth/1.55.1/grpc-auth-1.55.1.jar" - ], - "downloaded_file_path": "io/grpc/grpc-auth/1.55.1/grpc-auth-1.55.1.jar" - } - }, - "com_google_auth_google_auth_library_credentials_1_17_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_auth_google_auth_library_credentials_1_17_0", - "sha256": "5de364ee7a9ce95d8715bf124bdb0d949d37649914db846cc7005584fba7ce4d", - "urls": [ - "https://repo1.maven.org/maven2/com/google/auth/google-auth-library-credentials/1.17.0/google-auth-library-credentials-1.17.0.jar", - "https://maven.google.com/com/google/auth/google-auth-library-credentials/1.17.0/google-auth-library-credentials-1.17.0.jar" - ], - "downloaded_file_path": "com/google/auth/google-auth-library-credentials/1.17.0/google-auth-library-credentials-1.17.0.jar" - } - }, - "com_github_jnr_jnr_constants_jar_sources_0_10_4": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_jnr_jnr_constants_jar_sources_0_10_4", - "sha256": "696f737f76a29d900401e52277274c3c12a47cb70d00eb9e3619f3ff0b261a5f", - "urls": [ - "https://repo1.maven.org/maven2/com/github/jnr/jnr-constants/0.10.4/jnr-constants-0.10.4-sources.jar" - ], - "downloaded_file_path": "com/github/jnr/jnr-constants/0.10.4/jnr-constants-0.10.4-sources.jar" - } - }, - "io_grpc_grpc_services_1_56_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_services_1_56_1", - "sha256": "0d14ece28e97b30aa9ef1b63782d48261dd63738ef1c5615afefb8b963c121c8", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-services/1.56.1/grpc-services-1.56.1.jar" - ], - "downloaded_file_path": "io/grpc/grpc-services/1.56.1/grpc-services-1.56.1.jar" - } - }, - "net_javacrumbs_future_converter_future_converter_common_1_2_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~net_javacrumbs_future_converter_future_converter_common_1_2_0", - "sha256": "567aeb2907088298fe5e67fd0fb1843571c24b46ef5b369f495c3d52c654b67b", - "urls": [ - "https://repo1.maven.org/maven2/net/javacrumbs/future-converter/future-converter-common/1.2.0/future-converter-common-1.2.0.jar" - ], - "downloaded_file_path": "net/javacrumbs/future-converter/future-converter-common/1.2.0/future-converter-common-1.2.0.jar" - } - }, - "org_codehaus_plexus_plexus_utils_3_5_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_codehaus_plexus_plexus_utils_3_5_1", - "sha256": "86e0255d4c879c61b4833ed7f13124e8bb679df47debb127326e7db7dd49a07b", - "urls": [ - "https://repo1.maven.org/maven2/org/codehaus/plexus/plexus-utils/3.5.1/plexus-utils-3.5.1.jar", - "https://maven.google.com/org/codehaus/plexus/plexus-utils/3.5.1/plexus-utils-3.5.1.jar" - ], - "downloaded_file_path": "org/codehaus/plexus/plexus-utils/3.5.1/plexus-utils-3.5.1.jar" - } - }, - "com_github_fppt_jedis_mock_jar_sources_1_0_10": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_fppt_jedis_mock_jar_sources_1_0_10", - "sha256": "315cd23d9c010ceee598fc594d4674b63f4bcd0375fe8c2b90d79ce50a12bb7e", - "urls": [ - "https://repo1.maven.org/maven2/com/github/fppt/jedis-mock/1.0.10/jedis-mock-1.0.10-sources.jar" - ], - "downloaded_file_path": "com/github/fppt/jedis-mock/1.0.10/jedis-mock-1.0.10-sources.jar" - } - }, - "io_grpc_grpc_protobuf_1_55_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_protobuf_1_55_1", - "sha256": "a170ef578cd94bf81c57f46cca9328e2db5136f45e18da80af26bbebcca9618c", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-protobuf/1.55.1/grpc-protobuf-1.55.1.jar", - "https://maven.google.com/io/grpc/grpc-protobuf/1.55.1/grpc-protobuf-1.55.1.jar" - ], - "downloaded_file_path": "io/grpc/grpc-protobuf/1.55.1/grpc-protobuf-1.55.1.jar" - } - }, - "org_glassfish_jersey_inject_jersey_hk2_2_30_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_glassfish_jersey_inject_jersey_hk2_2_30_1", - "sha256": "cd5f4c10cf4915d1c217c295fc8b4eadceda7a28f9488b1d01de6b8792b33496", - "urls": [ - "https://repo1.maven.org/maven2/org/glassfish/jersey/inject/jersey-hk2/2.30.1/jersey-hk2-2.30.1.jar" - ], - "downloaded_file_path": "org/glassfish/jersey/inject/jersey-hk2/2.30.1/jersey-hk2-2.30.1.jar" - } - }, - "net_java_dev_jna_jna_5_13_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~net_java_dev_jna_jna_5_13_0", - "sha256": "66d4f819a062a51a1d5627bffc23fac55d1677f0e0a1feba144aabdd670a64bb", - "urls": [ - "https://repo1.maven.org/maven2/net/java/dev/jna/jna/5.13.0/jna-5.13.0.jar" - ], - "downloaded_file_path": "net/java/dev/jna/jna/5.13.0/jna-5.13.0.jar" - } - }, - "com_google_http_client_google_http_client_1_43_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_http_client_google_http_client_1_43_1", - "sha256": "834e37b0af2cfe80b297be4d6a5c8fd0ccab1d0b13e9b8d7ac921e8dd2f251ec", - "urls": [ - "https://repo1.maven.org/maven2/com/google/http-client/google-http-client/1.43.1/google-http-client-1.43.1.jar", - "https://maven.google.com/com/google/http-client/google-http-client/1.43.1/google-http-client-1.43.1.jar" - ], - "downloaded_file_path": "com/google/http-client/google-http-client/1.43.1/google-http-client-1.43.1.jar" - } - }, - "io_opencensus_opencensus_proto_0_2_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_opencensus_opencensus_proto_0_2_0", - "sha256": "0c192d451e9dd74e98721b27d02f0e2b6bca44b51563b5dabf2e211f7a3ebf13", - "urls": [ - "https://repo1.maven.org/maven2/io/opencensus/opencensus-proto/0.2.0/opencensus-proto-0.2.0.jar", - "https://maven.google.com/io/opencensus/opencensus-proto/0.2.0/opencensus-proto-0.2.0.jar" - ], - "downloaded_file_path": "io/opencensus/opencensus-proto/0.2.0/opencensus-proto-0.2.0.jar" - } - }, - "com_fasterxml_jackson_core_jackson_databind_2_15_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_core_jackson_databind_2_15_2", - "sha256": "0eb2fdad6e40ab8832a78c9b22f58196dd970594e8d3d5a26ead87847c4f3a96", - "urls": [ - "https://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-databind/2.15.2/jackson-databind-2.15.2.jar" - ], - "downloaded_file_path": "com/fasterxml/jackson/core/jackson-databind/2.15.2/jackson-databind-2.15.2.jar" - } - }, - "org_slf4j_slf4j_api_1_7_30": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_slf4j_slf4j_api_1_7_30", - "sha256": "cdba07964d1bb40a0761485c6b1e8c2f8fd9eb1d19c53928ac0d7f9510105c57", - "urls": [ - "https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.30/slf4j-api-1.7.30.jar", - "https://maven.google.com/org/slf4j/slf4j-api/1.7.30/slf4j-api-1.7.30.jar" - ], - "downloaded_file_path": "org/slf4j/slf4j-api/1.7.30/slf4j-api-1.7.30.jar" - } - }, - "io_grpc_grpc_grpclb_1_55_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_grpclb_1_55_1", - "sha256": "9d0dcf87d99a1042a3a2343e96d394220c6be07cf1a5082d5df066e2077b3428", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-grpclb/1.55.1/grpc-grpclb-1.55.1.jar", - "https://maven.google.com/io/grpc/grpc-grpclb/1.55.1/grpc-grpclb-1.55.1.jar" - ], - "downloaded_file_path": "io/grpc/grpc-grpclb/1.55.1/grpc-grpclb-1.55.1.jar" - } - }, - "com_esotericsoftware_minlog_jar_sources_1_3_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_esotericsoftware_minlog_jar_sources_1_3_1", - "sha256": "fdaf83a8c51295eff3a8109473ce7b213582738f71593e16b1efa012ff1f99b5", - "urls": [ - "https://repo1.maven.org/maven2/com/esotericsoftware/minlog/1.3.1/minlog-1.3.1-sources.jar" - ], - "downloaded_file_path": "com/esotericsoftware/minlog/1.3.1/minlog-1.3.1-sources.jar" - } - }, - "net_javacrumbs_future_converter_future_converter_java8_guava_1_2_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~net_javacrumbs_future_converter_future_converter_java8_guava_1_2_0", - "sha256": "3b47ae8e2b2bfad810586c37537f002273c05237bd3adecafe9f9f57a2b18fde", - "urls": [ - "https://repo1.maven.org/maven2/net/javacrumbs/future-converter/future-converter-java8-guava/1.2.0/future-converter-java8-guava-1.2.0.jar" - ], - "downloaded_file_path": "net/javacrumbs/future-converter/future-converter-java8-guava/1.2.0/future-converter-java8-guava-1.2.0.jar" - } - }, - "com_google_errorprone_error_prone_annotations_2_18_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_errorprone_error_prone_annotations_2_18_0", - "sha256": "9e6814cb71816988a4fd1b07a993a8f21bb7058d522c162b1de849e19bea54ae", - "urls": [ - "https://repo1.maven.org/maven2/com/google/errorprone/error_prone_annotations/2.18.0/error_prone_annotations-2.18.0.jar", - "https://maven.google.com/com/google/errorprone/error_prone_annotations/2.18.0/error_prone_annotations-2.18.0.jar" - ], - "downloaded_file_path": "com/google/errorprone/error_prone_annotations/2.18.0/error_prone_annotations-2.18.0.jar" - } - }, - "com_google_cloud_google_cloud_core_2_18_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_cloud_google_cloud_core_2_18_1", - "sha256": "8a8da77a17193fae86012722237736db7d08cb6fac8df50a311427c95b26d4a6", - "urls": [ - "https://repo1.maven.org/maven2/com/google/cloud/google-cloud-core/2.18.1/google-cloud-core-2.18.1.jar", - "https://maven.google.com/com/google/cloud/google-cloud-core/2.18.1/google-cloud-core-2.18.1.jar" - ], - "downloaded_file_path": "com/google/cloud/google-cloud-core/2.18.1/google-cloud-core-2.18.1.jar" - } - }, - "com_github_jnr_jffi_jar_native_1_3_11": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_jnr_jffi_jar_native_1_3_11", - "sha256": "f4c26c0a4a3eddfdbaaf4dda77d4d9f7d148ba4208798f32ce475ce4d6778744", - "urls": [ - "https://repo1.maven.org/maven2/com/github/jnr/jffi/1.3.11/jffi-1.3.11-native.jar" - ], - "downloaded_file_path": "com/github/jnr/jffi/1.3.11/jffi-1.3.11-native.jar" - } - }, - "com_google_errorprone_error_prone_annotations": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_errorprone_error_prone_annotations", - "generating_repository": "maven", - "target_name": "com_google_errorprone_error_prone_annotations" - } - }, - "io_netty_netty_codec_dns_jar_sources_4_1_96_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_dns_jar_sources_4_1_96_Final", - "sha256": "080f78aa2451386f7c0ac993ed4b3eae28ea3b337c606aee29b0c723e01f9588", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-codec-dns/4.1.96.Final/netty-codec-dns-4.1.96.Final-sources.jar" - ], - "downloaded_file_path": "io/netty/netty-codec-dns/4.1.96.Final/netty-codec-dns-4.1.96.Final-sources.jar" - } - }, - "io_netty_netty_handler_proxy_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_handler_proxy_4_1_97_Final", - "sha256": "c789f30d0905a09b2a17c4cf397e1b57b0d63db714624eb0dec2282b9619e206", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-handler-proxy/4.1.97.Final/netty-handler-proxy-4.1.97.Final.jar" - ], - "downloaded_file_path": "io/netty/netty-handler-proxy/4.1.97.Final/netty-handler-proxy-4.1.97.Final.jar" - } - }, - "io_projectreactor_reactor_core_jar_sources_3_5_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_projectreactor_reactor_core_jar_sources_3_5_3", - "sha256": "c4193dbe135cc2a1db71c55771249158f611d3663e0f42b3ede5ab9e4302bce4", - "urls": [ - "https://repo1.maven.org/maven2/io/projectreactor/reactor-core/3.5.3/reactor-core-3.5.3-sources.jar" - ], - "downloaded_file_path": "io/projectreactor/reactor-core/3.5.3/reactor-core-3.5.3-sources.jar" - } - }, - "com_google_errorprone_error_prone_type_annotations_jar_sources_2_22_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_errorprone_error_prone_type_annotations_jar_sources_2_22_0", - "sha256": "84bbb947f3de91d97eee9abb6c5648c5b61d0fb4d132f86c4d7c80e4357e5da6", - "urls": [ - "https://repo1.maven.org/maven2/com/google/errorprone/error_prone_type_annotations/2.22.0/error_prone_type_annotations-2.22.0-sources.jar" - ], - "downloaded_file_path": "com/google/errorprone/error_prone_type_annotations/2.22.0/error_prone_type_annotations-2.22.0-sources.jar" - } - }, - "com_google_api_grpc_proto_google_common_protos_2_17_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_api_grpc_proto_google_common_protos_2_17_0", - "sha256": "4ef1fe0c327fc1521d1d753b0b1c4a875a54bd14ebded3afff0ca395320b6ea9", - "urls": [ - "https://repo1.maven.org/maven2/com/google/api/grpc/proto-google-common-protos/2.17.0/proto-google-common-protos-2.17.0.jar" - ], - "downloaded_file_path": "com/google/api/grpc/proto-google-common-protos/2.17.0/proto-google-common-protos-2.17.0.jar" - } - }, - "io_netty_netty_codec_http_jar_sources_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_http_jar_sources_4_1_97_Final", - "sha256": "fd45d71121285bed020b3cc2515288d252b9c07cbc4934a63615d7d8c8855289", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-codec-http/4.1.97.Final/netty-codec-http-4.1.97.Final-sources.jar" - ], - "downloaded_file_path": "io/netty/netty-codec-http/4.1.97.Final/netty-codec-http-4.1.97.Final-sources.jar" - } - }, - "io_netty_netty_transport_native_epoll": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_native_epoll", - "generating_repository": "maven", - "target_name": "io_netty_netty_transport_native_epoll" - } - }, - "software_amazon_awssdk_aws_xml_protocol_2_20_78": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_aws_xml_protocol_2_20_78", - "sha256": "c7977c61aeb3f74e471bedde0ab6ca44447af4cbff309c63f5e7d2a26dbcba7a", - "urls": [ - "https://repo1.maven.org/maven2/software/amazon/awssdk/aws-xml-protocol/2.20.78/aws-xml-protocol-2.20.78.jar", - "https://maven.google.com/software/amazon/awssdk/aws-xml-protocol/2.20.78/aws-xml-protocol-2.20.78.jar" - ], - "downloaded_file_path": "software/amazon/awssdk/aws-xml-protocol/2.20.78/aws-xml-protocol-2.20.78.jar" - } - }, - "com_sun_activation_jakarta_activation_jar_sources_1_2_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_sun_activation_jakarta_activation_jar_sources_1_2_1", - "sha256": "d254da455b0e1e36c7a9db2f0910fea9e8a012cbc85160207328e16bd3aea753", - "urls": [ - "https://repo1.maven.org/maven2/com/sun/activation/jakarta.activation/1.2.1/jakarta.activation-1.2.1-sources.jar" - ], - "downloaded_file_path": "com/sun/activation/jakarta.activation/1.2.1/jakarta.activation-1.2.1-sources.jar" - } - }, - "io_grpc_grpc_testing_1_56_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_testing_1_56_1", - "sha256": "b4cd4f2c410040fb097108eb6b7fa84826365b4d91844bd30b21f4e97eee906d", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-testing/1.56.1/grpc-testing-1.56.1.jar" - ], - "downloaded_file_path": "io/grpc/grpc-testing/1.56.1/grpc-testing-1.56.1.jar" - } - }, - "org_glassfish_hk2_external_aopalliance_repackaged_2_6_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_glassfish_hk2_external_aopalliance_repackaged_2_6_1", - "sha256": "bad77f9278d753406360af9e4747bd9b3161554ea9cd3d62411a0ae1f2c141fd", - "urls": [ - "https://repo1.maven.org/maven2/org/glassfish/hk2/external/aopalliance-repackaged/2.6.1/aopalliance-repackaged-2.6.1.jar" - ], - "downloaded_file_path": "org/glassfish/hk2/external/aopalliance-repackaged/2.6.1/aopalliance-repackaged-2.6.1.jar" - } - }, - "org_openjdk_jmh_jmh_core_1_37": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_openjdk_jmh_jmh_core_1_37", - "sha256": "dc0eaf2bbf0036a70b60798c785d6e03a9daf06b68b8edb0f1ba9eb3421baeb3", - "urls": [ - "https://repo1.maven.org/maven2/org/openjdk/jmh/jmh-core/1.37/jmh-core-1.37.jar" - ], - "downloaded_file_path": "org/openjdk/jmh/jmh-core/1.37/jmh-core-1.37.jar" - } - }, - "io_netty_netty_codec_http_4_1_86_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_http_4_1_86_Final", - "sha256": "3f6ceb3112cfcf7b70545eb5111220ce57db54d593f23f64c38333bb22c40b84", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-codec-http/4.1.86.Final/netty-codec-http-4.1.86.Final.jar", - "https://maven.google.com/io/netty/netty-codec-http/4.1.86.Final/netty-codec-http-4.1.86.Final.jar" - ], - "downloaded_file_path": "io/netty/netty-codec-http/4.1.86.Final/netty-codec-http-4.1.86.Final.jar" - } - }, - "aopalliance_aopalliance_1_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~aopalliance_aopalliance_1_0", - "sha256": "0addec670fedcd3f113c5c8091d783280d23f75e3acb841b61a9cdb079376a08", - "urls": [ - "https://repo1.maven.org/maven2/aopalliance/aopalliance/1.0/aopalliance-1.0.jar" - ], - "downloaded_file_path": "aopalliance/aopalliance/1.0/aopalliance-1.0.jar" - } - }, - "org_reactivestreams_reactive_streams_jar_sources_1_0_4": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_reactivestreams_reactive_streams_jar_sources_1_0_4", - "sha256": "5a7a36ae9536698c434ebe119feb374d721210fee68eb821a37ef3859b64b708", - "urls": [ - "https://repo1.maven.org/maven2/org/reactivestreams/reactive-streams/1.0.4/reactive-streams-1.0.4-sources.jar" - ], - "downloaded_file_path": "org/reactivestreams/reactive-streams/1.0.4/reactive-streams-1.0.4-sources.jar" - } - }, - "com_google_http_client_google_http_client_jackson2_1_43_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_http_client_google_http_client_jackson2_1_43_1", - "sha256": "1d41fa103da432dc49b41a321effc3e2fda722a3dc896a89dcdc3a4d5fe82255", - "urls": [ - "https://repo1.maven.org/maven2/com/google/http-client/google-http-client-jackson2/1.43.1/google-http-client-jackson2-1.43.1.jar", - "https://maven.google.com/com/google/http-client/google-http-client-jackson2/1.43.1/google-http-client-jackson2-1.43.1.jar" - ], - "downloaded_file_path": "com/google/http-client/google-http-client-jackson2/1.43.1/google-http-client-jackson2-1.43.1.jar" - } - }, - "io_netty_netty_transport_4_1_86_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_4_1_86_Final", - "sha256": "f6726dcd54e4922b46b3b4f4467b443a70a30eb08a62620c8fe502d8cb802c9f", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-transport/4.1.86.Final/netty-transport-4.1.86.Final.jar", - "https://maven.google.com/io/netty/netty-transport/4.1.86.Final/netty-transport-4.1.86.Final.jar" - ], - "downloaded_file_path": "io/netty/netty-transport/4.1.86.Final/netty-transport-4.1.86.Final.jar" - } - }, - "com_amazonaws_jmespath_java_jar_sources_1_12_544": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_amazonaws_jmespath_java_jar_sources_1_12_544", - "sha256": "496d7f1c237d107b3c4c766ff603ba6b3e773e59c590e3ed0156f56fdb3d0b4a", - "urls": [ - "https://repo1.maven.org/maven2/com/amazonaws/jmespath-java/1.12.544/jmespath-java-1.12.544-sources.jar" - ], - "downloaded_file_path": "com/amazonaws/jmespath-java/1.12.544/jmespath-java-1.12.544-sources.jar" - } - }, - "com_github_kevinstern_software_and_algorithms_jar_sources_1_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_kevinstern_software_and_algorithms_jar_sources_1_0", - "sha256": "37a46c7f8f6c5064ceb398be472c17507b1e7e7bfc72399c57efb5fa5310a8ae", - "urls": [ - "https://repo1.maven.org/maven2/com/github/kevinstern/software-and-algorithms/1.0/software-and-algorithms-1.0-sources.jar" - ], - "downloaded_file_path": "com/github/kevinstern/software-and-algorithms/1.0/software-and-algorithms-1.0-sources.jar" - } - }, - "com_github_pcj_google_options": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_pcj_google_options", - "generating_repository": "maven", - "target_name": "com_github_pcj_google_options" - } - }, - "io_github_eisop_dataflow_errorprone_3_34_0_eisop1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_github_eisop_dataflow_errorprone_3_34_0_eisop1", - "sha256": "89b4f5d2bd5059f067c5982a0e5988b87dfc8a8234795d68c6f3178846de3319", - "urls": [ - "https://repo1.maven.org/maven2/io/github/eisop/dataflow-errorprone/3.34.0-eisop1/dataflow-errorprone-3.34.0-eisop1.jar" - ], - "downloaded_file_path": "io/github/eisop/dataflow-errorprone/3.34.0-eisop1/dataflow-errorprone-3.34.0-eisop1.jar" - } - }, - "com_github_docker_java_docker_java_jar_sources_3_3_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_docker_java_docker_java_jar_sources_3_3_3", - "sha256": "ddc2c925a8b58cc47e5d683c770c9f261f6a6b7db028b38dd289be0e51a7c3df", - "urls": [ - "https://repo1.maven.org/maven2/com/github/docker-java/docker-java/3.3.3/docker-java-3.3.3-sources.jar" - ], - "downloaded_file_path": "com/github/docker-java/docker-java/3.3.3/docker-java-3.3.3-sources.jar" - } - }, - "io_prometheus_simpleclient_tracer_otel_jar_sources_0_15_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_tracer_otel_jar_sources_0_15_0", - "sha256": "f83fcb43addcd77adeb34ff00ee27141060ac103597272eb44f2d73aea4addea", - "urls": [ - "https://repo1.maven.org/maven2/io/prometheus/simpleclient_tracer_otel/0.15.0/simpleclient_tracer_otel-0.15.0-sources.jar" - ], - "downloaded_file_path": "io/prometheus/simpleclient_tracer_otel/0.15.0/simpleclient_tracer_otel-0.15.0-sources.jar" - } - }, - "io_reactivex_rxjava3_rxjava_3_1_6": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_reactivex_rxjava3_rxjava_3_1_6", - "sha256": "34682bd3ec6f043c5defb589a2d18113ba3e2d2372dd401744f8e4815c1db638", - "urls": [ - "https://repo1.maven.org/maven2/io/reactivex/rxjava3/rxjava/3.1.6/rxjava-3.1.6.jar" - ], - "downloaded_file_path": "io/reactivex/rxjava3/rxjava/3.1.6/rxjava-3.1.6.jar" - } - }, - "com_github_jnr_jnr_a64asm_jar_sources_1_0_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_jnr_jnr_a64asm_jar_sources_1_0_0", - "sha256": "2106b98c7d794fb01237e7243d975b9bc8450aa87bf34f93d7b5fcc651af7ff1", - "urls": [ - "https://repo1.maven.org/maven2/com/github/jnr/jnr-a64asm/1.0.0/jnr-a64asm-1.0.0-sources.jar" - ], - "downloaded_file_path": "com/github/jnr/jnr-a64asm/1.0.0/jnr-a64asm-1.0.0-sources.jar" - } - }, - "io_netty_netty_transport_classes_kqueue_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_classes_kqueue_4_1_97_Final", - "sha256": "964ef63eb24a5c979f0af473da13f9574497e11bd41543a66d10609d34013b9f", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-transport-classes-kqueue/4.1.97.Final/netty-transport-classes-kqueue-4.1.97.Final.jar" - ], - "downloaded_file_path": "io/netty/netty-transport-classes-kqueue/4.1.97.Final/netty-transport-classes-kqueue-4.1.97.Final.jar" - } - }, - "commons_io_commons_io_jar_sources_2_13_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~commons_io_commons_io_jar_sources_2_13_0", - "sha256": "1c7bece2e87ac49b24f09ec3c5ceb51560edd7a259889fceef96dda9c046a1b3", - "urls": [ - "https://repo1.maven.org/maven2/commons-io/commons-io/2.13.0/commons-io-2.13.0-sources.jar" - ], - "downloaded_file_path": "commons-io/commons-io/2.13.0/commons-io-2.13.0-sources.jar" - } - }, - "org_codehaus_mojo_animal_sniffer_annotations_jar_sources_1_23": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_codehaus_mojo_animal_sniffer_annotations_jar_sources_1_23", - "sha256": "4878fcc6808dbc88085a4622db670e703867754bc4bc40312c52bf3a3510d019", - "urls": [ - "https://repo1.maven.org/maven2/org/codehaus/mojo/animal-sniffer-annotations/1.23/animal-sniffer-annotations-1.23-sources.jar" - ], - "downloaded_file_path": "org/codehaus/mojo/animal-sniffer-annotations/1.23/animal-sniffer-annotations-1.23-sources.jar" - } - }, - "com_google_inject_guice_5_1_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_inject_guice_5_1_0", - "sha256": "4130e50bfac48099c860f0d903b91860c81a249c90f38245f8fed58fc817bc26", - "urls": [ - "https://repo1.maven.org/maven2/com/google/inject/guice/5.1.0/guice-5.1.0.jar" - ], - "downloaded_file_path": "com/google/inject/guice/5.1.0/guice-5.1.0.jar" - } - }, - "org_slf4j_slf4j_simple_jar_sources_2_0_9": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_slf4j_slf4j_simple_jar_sources_2_0_9", - "sha256": "45423388e9fc51af94ac936842211353dbde78c29350d1ed97445ed3e37416cd", - "urls": [ - "https://repo1.maven.org/maven2/org/slf4j/slf4j-simple/2.0.9/slf4j-simple-2.0.9-sources.jar" - ], - "downloaded_file_path": "org/slf4j/slf4j-simple/2.0.9/slf4j-simple-2.0.9-sources.jar" - } - }, - "org_apache_commons_commons_pool2_jar_sources_2_11_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_apache_commons_commons_pool2_jar_sources_2_11_1", - "sha256": "00f8a2910e6c36784384f382fb6edc61a0e856c550ee866e8d285cdd3c167111", - "urls": [ - "https://repo1.maven.org/maven2/org/apache/commons/commons-pool2/2.11.1/commons-pool2-2.11.1-sources.jar" - ], - "downloaded_file_path": "org/apache/commons/commons-pool2/2.11.1/commons-pool2-2.11.1-sources.jar" - } - }, - "com_amazonaws_aws_java_sdk_core_jar_sources_1_12_544": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_amazonaws_aws_java_sdk_core_jar_sources_1_12_544", - "sha256": "e1cc8b011d35e4d71ba452fbf0c2777a6dc2a2a4668ea8c9e72a610f77f1a71d", - "urls": [ - "https://repo1.maven.org/maven2/com/amazonaws/aws-java-sdk-core/1.12.544/aws-java-sdk-core-1.12.544-sources.jar" - ], - "downloaded_file_path": "com/amazonaws/aws-java-sdk-core/1.12.544/aws-java-sdk-core-1.12.544-sources.jar" - } - }, - "com_github_jnr_jnr_constants": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_jnr_jnr_constants", - "generating_repository": "maven", - "target_name": "com_github_jnr_jnr_constants" - } - }, - "com_google_auto_auto_common_1_2_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_auto_auto_common_1_2_1", - "sha256": "f43f29fe2a6ebaf04b2598cdeec32a4e346d49a9404e990f5fc19c19f3a28d0e", - "urls": [ - "https://repo1.maven.org/maven2/com/google/auto/auto-common/1.2.1/auto-common-1.2.1.jar" - ], - "downloaded_file_path": "com/google/auto/auto-common/1.2.1/auto-common-1.2.1.jar" - } - }, - "io_grpc_grpc_protobuf": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_protobuf", - "generating_repository": "maven", - "target_name": "io_grpc_grpc_protobuf" - } - }, - "io_prometheus_simpleclient_tracer_otel_agent_0_15_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_tracer_otel_agent_0_15_0", - "sha256": "0cbb4c29d17e9fe71bb2cec013c2999ae8a9050f237ad33211761b40d2586e0b", - "urls": [ - "https://repo1.maven.org/maven2/io/prometheus/simpleclient_tracer_otel_agent/0.15.0/simpleclient_tracer_otel_agent-0.15.0.jar" - ], - "downloaded_file_path": "io/prometheus/simpleclient_tracer_otel_agent/0.15.0/simpleclient_tracer_otel_agent-0.15.0.jar" - } - }, - "io_netty_netty_buffer_4_1_86_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_buffer_4_1_86_Final", - "sha256": "e42e15f47c865266b1faa6e038ebfd7ddadcf9f4ae9e6617edd4881dbd4abe88", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-buffer/4.1.86.Final/netty-buffer-4.1.86.Final.jar", - "https://maven.google.com/io/netty/netty-buffer/4.1.86.Final/netty-buffer-4.1.86.Final.jar" - ], - "downloaded_file_path": "io/netty/netty-buffer/4.1.86.Final/netty-buffer-4.1.86.Final.jar" - } - }, - "io_netty_netty_codec_4_1_86_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_4_1_86_Final", - "sha256": "0456840b5c851dad6cab881cd1a9ad5d916db65d81048145df1d9a6d03325bea", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-codec/4.1.86.Final/netty-codec-4.1.86.Final.jar", - "https://maven.google.com/io/netty/netty-codec/4.1.86.Final/netty-codec-4.1.86.Final.jar" - ], - "downloaded_file_path": "io/netty/netty-codec/4.1.86.Final/netty-codec-4.1.86.Final.jar" - } - }, - "org_openjdk_jmh_jmh_generator_annprocess_1_37": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_openjdk_jmh_jmh_generator_annprocess_1_37", - "sha256": "6a5604b5b804e0daca1145df1077609321687734a8b49387e49f10557c186c77", - "urls": [ - "https://repo1.maven.org/maven2/org/openjdk/jmh/jmh-generator-annprocess/1.37/jmh-generator-annprocess-1.37.jar" - ], - "downloaded_file_path": "org/openjdk/jmh/jmh-generator-annprocess/1.37/jmh-generator-annprocess-1.37.jar" - } - }, - "org_projectlombok_lombok_jar_sources_1_18_30": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_projectlombok_lombok_jar_sources_1_18_30", - "sha256": "d41c3ab349c0ec484449b545d2ac5c26ccc9c8b23f2dbbd6176382469f9eac71", - "urls": [ - "https://repo1.maven.org/maven2/org/projectlombok/lombok/1.18.30/lombok-1.18.30-sources.jar" - ], - "downloaded_file_path": "org/projectlombok/lombok/1.18.30/lombok-1.18.30-sources.jar" - } - }, - "org_apache_tomcat_annotations_api_6_0_53": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_apache_tomcat_annotations_api_6_0_53", - "sha256": "253829d3c12b7381d1044fc22c6436cff025fe0d459e4a329413e560a7d0dd13", - "urls": [ - "https://repo1.maven.org/maven2/org/apache/tomcat/annotations-api/6.0.53/annotations-api-6.0.53.jar" - ], - "downloaded_file_path": "org/apache/tomcat/annotations-api/6.0.53/annotations-api-6.0.53.jar" - } - }, - "io_perfmark_perfmark_api_jar_sources_0_26_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_perfmark_perfmark_api_jar_sources_0_26_0", - "sha256": "7379e0fef0c32d69f3ebae8f271f426fc808613f1cfbc29e680757f348ba8aa4", - "urls": [ - "https://repo1.maven.org/maven2/io/perfmark/perfmark-api/0.26.0/perfmark-api-0.26.0-sources.jar" - ], - "downloaded_file_path": "io/perfmark/perfmark-api/0.26.0/perfmark-api-0.26.0-sources.jar" - } - }, - "software_amazon_awssdk_aws_query_protocol_2_20_78": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_aws_query_protocol_2_20_78", - "sha256": "74c9b42046e3829836d2351a3a0bb06ae54f7e4f0c3d319c9b68166f245db549", - "urls": [ - "https://repo1.maven.org/maven2/software/amazon/awssdk/aws-query-protocol/2.20.78/aws-query-protocol-2.20.78.jar", - "https://maven.google.com/software/amazon/awssdk/aws-query-protocol/2.20.78/aws-query-protocol-2.20.78.jar" - ], - "downloaded_file_path": "software/amazon/awssdk/aws-query-protocol/2.20.78/aws-query-protocol-2.20.78.jar" - } - }, - "org_projectlombok_lombok_1_18_30": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_projectlombok_lombok_1_18_30", - "sha256": "14151b47582d570b4de16a147ece3bdbd19ace4aee5bde3a5578c87db9ecb998", - "urls": [ - "https://repo1.maven.org/maven2/org/projectlombok/lombok/1.18.30/lombok-1.18.30.jar" - ], - "downloaded_file_path": "org/projectlombok/lombok/1.18.30/lombok-1.18.30.jar" - } - }, - "org_apache_tomcat_annotations_api": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_apache_tomcat_annotations_api", - "generating_repository": "maven", - "target_name": "org_apache_tomcat_annotations_api" - } - }, - "io_netty_netty_resolver_dns_4_1_96_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_resolver_dns_4_1_96_Final", - "sha256": "09a4f0cc4fc7af083515cfb84d6e70af4223dfe129858274cf506cc626f5175e", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-resolver-dns/4.1.96.Final/netty-resolver-dns-4.1.96.Final.jar" - ], - "downloaded_file_path": "io/netty/netty-resolver-dns/4.1.96.Final/netty-resolver-dns-4.1.96.Final.jar" - } - }, - "com_google_api_grpc_proto_google_common_protos_2_19_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_api_grpc_proto_google_common_protos_2_19_1", - "sha256": "5557ee1b7f44a80fa595cdcedcc52ed3be143ce25408181c3ad136006cdd749f", - "urls": [ - "https://repo1.maven.org/maven2/com/google/api/grpc/proto-google-common-protos/2.19.1/proto-google-common-protos-2.19.1.jar", - "https://maven.google.com/com/google/api/grpc/proto-google-common-protos/2.19.1/proto-google-common-protos-2.19.1.jar" - ], - "downloaded_file_path": "com/google/api/grpc/proto-google-common-protos/2.19.1/proto-google-common-protos-2.19.1.jar" - } - }, - "com_github_oshi_oshi_core_jar_sources_6_4_5": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_oshi_oshi_core_jar_sources_6_4_5", - "sha256": "1ff5c3475458db16fce29e1aabce48242fe80221144de4b2a1dc62bd18f15062", - "urls": [ - "https://repo1.maven.org/maven2/com/github/oshi/oshi-core/6.4.5/oshi-core-6.4.5-sources.jar" - ], - "downloaded_file_path": "com/github/oshi/oshi-core/6.4.5/oshi-core-6.4.5-sources.jar" - } - }, - "javax_inject_javax_inject_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~javax_inject_javax_inject_1", - "sha256": "91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff", - "urls": [ - "https://repo1.maven.org/maven2/javax/inject/javax.inject/1/javax.inject-1.jar" - ], - "downloaded_file_path": "javax/inject/javax.inject/1/javax.inject-1.jar" - } - }, - "org_jodd_jodd_bean_jar_sources_5_1_6": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_jodd_jodd_bean_jar_sources_5_1_6", - "sha256": "961cff0114d349d3491293eea0c74a910b8676326c1af682f07e500782180160", - "urls": [ - "https://repo1.maven.org/maven2/org/jodd/jodd-bean/5.1.6/jodd-bean-5.1.6-sources.jar" - ], - "downloaded_file_path": "org/jodd/jodd-bean/5.1.6/jodd-bean-5.1.6-sources.jar" - } - }, - "software_amazon_awssdk_s3_2_20_78": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_s3_2_20_78", - "sha256": "0a21d9d740f20e8d65985b8e31154a6603f4f15a7c5acea5a70957745519327b", - "urls": [ - "https://repo1.maven.org/maven2/software/amazon/awssdk/s3/2.20.78/s3-2.20.78.jar", - "https://maven.google.com/software/amazon/awssdk/s3/2.20.78/s3-2.20.78.jar" - ], - "downloaded_file_path": "software/amazon/awssdk/s3/2.20.78/s3-2.20.78.jar" - } - }, - "com_google_android_annotations_jar_sources_4_1_1_4": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_android_annotations_jar_sources_4_1_1_4", - "sha256": "e9b667aa958df78ea1ad115f7bbac18a5869c3128b1d5043feb360b0cfce9d40", - "urls": [ - "https://repo1.maven.org/maven2/com/google/android/annotations/4.1.1.4/annotations-4.1.1.4-sources.jar" - ], - "downloaded_file_path": "com/google/android/annotations/4.1.1.4/annotations-4.1.1.4-sources.jar" - } - }, - "org_glassfish_hk2_hk2_utils_2_6_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_glassfish_hk2_hk2_utils_2_6_1", - "sha256": "30727f79086452fdefdab08451d982c2082aa239d9f75cdeb1ba271e3c887036", - "urls": [ - "https://repo1.maven.org/maven2/org/glassfish/hk2/hk2-utils/2.6.1/hk2-utils-2.6.1.jar" - ], - "downloaded_file_path": "org/glassfish/hk2/hk2-utils/2.6.1/hk2-utils-2.6.1.jar" - } - }, - "com_google_android_annotations_4_1_1_4": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_android_annotations_4_1_1_4", - "sha256": "ba734e1e84c09d615af6a09d33034b4f0442f8772dec120efb376d86a565ae15", - "urls": [ - "https://repo1.maven.org/maven2/com/google/android/annotations/4.1.1.4/annotations-4.1.1.4.jar" - ], - "downloaded_file_path": "com/google/android/annotations/4.1.1.4/annotations-4.1.1.4.jar" - } - }, - "com_github_pcj_google_options_jar_sources_1_0_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_pcj_google_options_jar_sources_1_0_0", - "sha256": "3871275e5323aaa132ed043c3c3bf6620f5fe73c8aeb456ce992db9ce5d59768", - "urls": [ - "https://repo1.maven.org/maven2/com/github/pcj/google-options/1.0.0/google-options-1.0.0-sources.jar" - ], - "downloaded_file_path": "com/github/pcj/google-options/1.0.0/google-options-1.0.0-sources.jar" - } - }, - "com_google_guava_failureaccess_jar_sources_1_0_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_guava_failureaccess_jar_sources_1_0_1", - "sha256": "092346eebbb1657b51aa7485a246bf602bb464cc0b0e2e1c7e7201fadce1e98f", - "urls": [ - "https://repo1.maven.org/maven2/com/google/guava/failureaccess/1.0.1/failureaccess-1.0.1-sources.jar" - ], - "downloaded_file_path": "com/google/guava/failureaccess/1.0.1/failureaccess-1.0.1-sources.jar" - } - }, - "redis_clients_jedis_jar_sources_4_3_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~redis_clients_jedis_jar_sources_4_3_1", - "sha256": "8590d6ad29f6760424e5d832ee2f738b9790393c9986e6754a03427bfb8d5d04", - "urls": [ - "https://repo1.maven.org/maven2/redis/clients/jedis/4.3.1/jedis-4.3.1-sources.jar" - ], - "downloaded_file_path": "redis/clients/jedis/4.3.1/jedis-4.3.1-sources.jar" - } - }, - "com_google_api_grpc_proto_google_cloud_storage_v2_2_22_3_alpha": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_api_grpc_proto_google_cloud_storage_v2_2_22_3_alpha", - "sha256": "346cc208553f4b286868bd05ccf4558e3798609559ec2b8fc8b2ea5e15819d8b", - "urls": [ - "https://repo1.maven.org/maven2/com/google/api/grpc/proto-google-cloud-storage-v2/2.22.3-alpha/proto-google-cloud-storage-v2-2.22.3-alpha.jar", - "https://maven.google.com/com/google/api/grpc/proto-google-cloud-storage-v2/2.22.3-alpha/proto-google-cloud-storage-v2-2.22.3-alpha.jar" - ], - "downloaded_file_path": "com/google/api/grpc/proto-google-cloud-storage-v2/2.22.3-alpha/proto-google-cloud-storage-v2-2.22.3-alpha.jar" - } - }, - "com_google_auth_google_auth_library_oauth2_http": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_auth_google_auth_library_oauth2_http", - "generating_repository": "maven", - "target_name": "com_google_auth_google_auth_library_oauth2_http" - } - }, - "io_github_java_diff_utils_java_diff_utils_jar_sources_4_12": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_github_java_diff_utils_java_diff_utils_jar_sources_4_12", - "sha256": "fa24217b6eaa115a05d4a8f0003fe913c62716ca2184d2e4f17de4a7d42a8822", - "urls": [ - "https://repo1.maven.org/maven2/io/github/java-diff-utils/java-diff-utils/4.12/java-diff-utils-4.12-sources.jar" - ], - "downloaded_file_path": "io/github/java-diff-utils/java-diff-utils/4.12/java-diff-utils-4.12-sources.jar" - } - }, - "commons_io_commons_io_2_13_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~commons_io_commons_io_2_13_0", - "sha256": "671eaa39688dac2ffaa4645b3c9980ae2d0ea2471e4ae6a5da199cd15ae23666", - "urls": [ - "https://repo1.maven.org/maven2/commons-io/commons-io/2.13.0/commons-io-2.13.0.jar" - ], - "downloaded_file_path": "commons-io/commons-io/2.13.0/commons-io-2.13.0.jar" - } - }, - "commons_logging_commons_logging_jar_sources_1_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~commons_logging_commons_logging_jar_sources_1_2", - "sha256": "44347acfe5860461728e9cb33251e97345be36f8a0dfd5c5130c172559455f41", - "urls": [ - "https://repo1.maven.org/maven2/commons-logging/commons-logging/1.2/commons-logging-1.2-sources.jar" - ], - "downloaded_file_path": "commons-logging/commons-logging/1.2/commons-logging-1.2-sources.jar" - } - }, - "jakarta_activation_jakarta_activation_api_jar_sources_1_2_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~jakarta_activation_jakarta_activation_api_jar_sources_1_2_1", - "sha256": "e9638b764202c0def1b4d54bd37a984c681b2ed46a548ae94ef3f7e4a4b58a31", - "urls": [ - "https://repo1.maven.org/maven2/jakarta/activation/jakarta.activation-api/1.2.1/jakarta.activation-api-1.2.1-sources.jar" - ], - "downloaded_file_path": "jakarta/activation/jakarta.activation-api/1.2.1/jakarta.activation-api-1.2.1-sources.jar" - } - }, - "io_grpc_grpc_netty_shaded_1_55_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_netty_shaded_1_55_1", - "sha256": "3dc035ea13bf854d4218bc6370ba8d786077a9e0d76337e61df7597a78a03c61", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-netty-shaded/1.55.1/grpc-netty-shaded-1.55.1.jar", - "https://maven.google.com/io/grpc/grpc-netty-shaded/1.55.1/grpc-netty-shaded-1.55.1.jar" - ], - "downloaded_file_path": "io/grpc/grpc-netty-shaded/1.55.1/grpc-netty-shaded-1.55.1.jar" - } - }, - "com_github_luben_zstd_jni_jar_sources_1_5_5_7": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_luben_zstd_jni_jar_sources_1_5_5_7", - "sha256": "6560c8d5e307feebb75630032c3e16c07e079907cf0238cc45647495af704599", - "urls": [ - "https://repo1.maven.org/maven2/com/github/luben/zstd-jni/1.5.5-7/zstd-jni-1.5.5-7-sources.jar" - ], - "downloaded_file_path": "com/github/luben/zstd-jni/1.5.5-7/zstd-jni-1.5.5-7-sources.jar" - } - }, - "com_github_luben_zstd_jni_1_5_5_7": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_luben_zstd_jni_1_5_5_7", - "sha256": "edd7fc60c2aaa6b77d3436f667bf30b06202633761ec20d683638b40e8f11426", - "urls": [ - "https://repo1.maven.org/maven2/com/github/luben/zstd-jni/1.5.5-7/zstd-jni-1.5.5-7.jar" - ], - "downloaded_file_path": "com/github/luben/zstd-jni/1.5.5-7/zstd-jni-1.5.5-7.jar" - } - }, - "io_netty_netty_resolver": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_resolver", - "generating_repository": "maven", - "target_name": "io_netty_netty_resolver" - } - }, - "org_redisson_redisson_3_23_4": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_redisson_redisson_3_23_4", - "sha256": "fe59768d63419b0073c0cbd6029d0be864ad5c9d233dd1337945f9edfe3df3ca", - "urls": [ - "https://repo1.maven.org/maven2/org/redisson/redisson/3.23.4/redisson-3.23.4.jar" - ], - "downloaded_file_path": "org/redisson/redisson/3.23.4/redisson-3.23.4.jar" - } - }, - "net_javacrumbs_future_converter_future_converter_guava_common_1_2_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~net_javacrumbs_future_converter_future_converter_guava_common_1_2_0", - "sha256": "82bfab706005ea51c3e76958a62564367cf9cae207c0b1d55b9734876b9780c1", - "urls": [ - "https://repo1.maven.org/maven2/net/javacrumbs/future-converter/future-converter-guava-common/1.2.0/future-converter-guava-common-1.2.0.jar" - ], - "downloaded_file_path": "net/javacrumbs/future-converter/future-converter-guava-common/1.2.0/future-converter-guava-common-1.2.0.jar" - } - }, - "org_ow2_asm_asm_util_9_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_ow2_asm_asm_util_9_2", - "sha256": "ff5b3cd331ae8a9a804768280da98f50f424fef23dd3c788bb320e08c94ee598", - "urls": [ - "https://repo1.maven.org/maven2/org/ow2/asm/asm-util/9.2/asm-util-9.2.jar" - ], - "downloaded_file_path": "org/ow2/asm/asm-util/9.2/asm-util-9.2.jar" - } - }, - "io_grpc_grpc_stub_1_55_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_stub_1_55_1", - "sha256": "58c114817d42237ce50a5f7677cf142564df64200e59c956e49302b6c8af616a", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-stub/1.55.1/grpc-stub-1.55.1.jar", - "https://maven.google.com/io/grpc/grpc-stub/1.55.1/grpc-stub-1.55.1.jar" - ], - "downloaded_file_path": "io/grpc/grpc-stub/1.55.1/grpc-stub-1.55.1.jar" - } - }, - "org_apache_commons_commons_lang3_3_12_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_apache_commons_commons_lang3_3_12_0", - "sha256": "d919d904486c037f8d193412da0c92e22a9fa24230b9d67a57855c5c31c7e94e", - "urls": [ - "https://repo1.maven.org/maven2/org/apache/commons/commons-lang3/3.12.0/commons-lang3-3.12.0.jar", - "https://maven.google.com/org/apache/commons/commons-lang3/3.12.0/commons-lang3-3.12.0.jar" - ], - "downloaded_file_path": "org/apache/commons/commons-lang3/3.12.0/commons-lang3-3.12.0.jar" - } - }, - "com_github_docker_java_docker_java_transport_3_3_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_docker_java_docker_java_transport_3_3_3", - "sha256": "103b94685f398b036cf9243cb8899680bcdb4e54c32340a32b2b5737a87a33ba", - "urls": [ - "https://repo1.maven.org/maven2/com/github/docker-java/docker-java-transport/3.3.3/docker-java-transport-3.3.3.jar" - ], - "downloaded_file_path": "com/github/docker-java/docker-java-transport/3.3.3/docker-java-transport-3.3.3.jar" - } - }, - "software_amazon_awssdk_auth_2_20_78": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_auth_2_20_78", - "sha256": "9eb0c3d97668b318ae5dcd127f434186a73d8e2552ad0fdd1fb71e3ffa5f0bec", - "urls": [ - "https://repo1.maven.org/maven2/software/amazon/awssdk/auth/2.20.78/auth-2.20.78.jar", - "https://maven.google.com/software/amazon/awssdk/auth/2.20.78/auth-2.20.78.jar" - ], - "downloaded_file_path": "software/amazon/awssdk/auth/2.20.78/auth-2.20.78.jar" - } - }, - "io_grpc_grpc_core_jar_sources_1_56_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_core_jar_sources_1_56_1", - "sha256": "9fd5eb82e115bcfc3babadb486d37d1096e86ce869ae0d1ccc4270aec60351ef", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-core/1.56.1/grpc-core-1.56.1-sources.jar" - ], - "downloaded_file_path": "io/grpc/grpc-core/1.56.1/grpc-core-1.56.1-sources.jar" - } - }, - "com_github_docker_java_docker_java_3_3_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_docker_java_docker_java_3_3_3", - "sha256": "3afb208216a17d8ce26a8f689303292701c87b974d43780cfba47bb2199a4467", - "urls": [ - "https://repo1.maven.org/maven2/com/github/docker-java/docker-java/3.3.3/docker-java-3.3.3.jar" - ], - "downloaded_file_path": "com/github/docker-java/docker-java/3.3.3/docker-java-3.3.3.jar" - } - }, - "org_apache_commons_commons_math3_jar_sources_3_6_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_apache_commons_commons_math3_jar_sources_3_6_1", - "sha256": "e2ff85a3c360d56c51a7021614a194f3fbaf224054642ac535016f118322934d", - "urls": [ - "https://repo1.maven.org/maven2/org/apache/commons/commons-math3/3.6.1/commons-math3-3.6.1-sources.jar" - ], - "downloaded_file_path": "org/apache/commons/commons-math3/3.6.1/commons-math3-3.6.1-sources.jar" - } - }, - "com_fasterxml_jackson_core_jackson_core_2_15_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_core_jackson_core_2_15_2", - "sha256": "303c99e82b1faa91a0bae5d8fbeb56f7e2adf9b526a900dd723bf140d62bd4b4", - "urls": [ - "https://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-core/2.15.2/jackson-core-2.15.2.jar" - ], - "downloaded_file_path": "com/fasterxml/jackson/core/jackson-core/2.15.2/jackson-core-2.15.2.jar" - } - }, - "io_netty_netty_transport_native_epoll_jar_linux_x86_64_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_native_epoll_jar_linux_x86_64_4_1_97_Final", - "sha256": "1e83fc9f82e5415cdbb688c6a5c6bbbd7d198e9fdd6fdf64b3dc5d54dd1acfd0", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-transport-native-epoll/4.1.97.Final/netty-transport-native-epoll-4.1.97.Final-linux-x86_64.jar" - ], - "downloaded_file_path": "io/netty/netty-transport-native-epoll/4.1.97.Final/netty-transport-native-epoll-4.1.97.Final-linux-x86_64.jar" - } - }, - "org_bouncycastle_bcpkix_jdk18on_1_75": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_bouncycastle_bcpkix_jdk18on_1_75", - "sha256": "9e2c1db5a6ed29fbc36b438d39ca9feb901bb69bad0ce8d7bc735264bea79bd3", - "urls": [ - "https://repo1.maven.org/maven2/org/bouncycastle/bcpkix-jdk18on/1.75/bcpkix-jdk18on-1.75.jar" - ], - "downloaded_file_path": "org/bouncycastle/bcpkix-jdk18on/1.75/bcpkix-jdk18on-1.75.jar" - } - }, - "org_reflections_reflections_0_10_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_reflections_reflections_0_10_2", - "sha256": "938a2d08fe54050d7610b944d8ddc3a09355710d9e6be0aac838dbc04e9a2825", - "urls": [ - "https://repo1.maven.org/maven2/org/reflections/reflections/0.10.2/reflections-0.10.2.jar" - ], - "downloaded_file_path": "org/reflections/reflections/0.10.2/reflections-0.10.2.jar" - } - }, - "com_github_fppt_jedis_mock_1_0_10": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_fppt_jedis_mock_1_0_10", - "sha256": "118684813167330681c6f1bebea2c1b67e3ed96bb862867437c0e4270d1fc88d", - "urls": [ - "https://repo1.maven.org/maven2/com/github/fppt/jedis-mock/1.0.10/jedis-mock-1.0.10.jar" - ], - "downloaded_file_path": "com/github/fppt/jedis-mock/1.0.10/jedis-mock-1.0.10.jar" - } - }, - "org_javassist_javassist_3_28_0_GA": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_javassist_javassist_3_28_0_GA", - "sha256": "57d0a9e9286f82f4eaa851125186997f811befce0e2060ff0a15a77f5a9dd9a7", - "urls": [ - "https://repo1.maven.org/maven2/org/javassist/javassist/3.28.0-GA/javassist-3.28.0-GA.jar" - ], - "downloaded_file_path": "org/javassist/javassist/3.28.0-GA/javassist-3.28.0-GA.jar" - } - }, - "com_google_http_client_google_http_client_gson_1_43_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_http_client_google_http_client_gson_1_43_1", - "sha256": "017406e5105a33147ab13baf7b491ff53d99e54a5e2b61b7ccd651e164229698", - "urls": [ - "https://repo1.maven.org/maven2/com/google/http-client/google-http-client-gson/1.43.1/google-http-client-gson-1.43.1.jar", - "https://maven.google.com/com/google/http-client/google-http-client-gson/1.43.1/google-http-client-gson-1.43.1.jar" - ], - "downloaded_file_path": "com/google/http-client/google-http-client-gson/1.43.1/google-http-client-gson-1.43.1.jar" - } - }, - "net_minidev_json_smart_2_4_10": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~net_minidev_json_smart_2_4_10", - "sha256": "70cab5e9488630dc631b1fc6e7fa550d95cddd19ba14db39ceca7cabfbd4e5ae", - "urls": [ - "https://repo1.maven.org/maven2/net/minidev/json-smart/2.4.10/json-smart-2.4.10.jar" - ], - "downloaded_file_path": "net/minidev/json-smart/2.4.10/json-smart-2.4.10.jar" - } - }, - "org_apache_httpcomponents_httpcore_4_4_15": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_apache_httpcomponents_httpcore_4_4_15", - "sha256": "3cbaed088c499a10f96dde58f39dc0e7985171abd88138ca1655a872011bb142", - "urls": [ - "https://repo1.maven.org/maven2/org/apache/httpcomponents/httpcore/4.4.15/httpcore-4.4.15.jar" - ], - "downloaded_file_path": "org/apache/httpcomponents/httpcore/4.4.15/httpcore-4.4.15.jar" - } - }, - "io_grpc_grpc_protobuf_lite_1_56_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_protobuf_lite_1_56_1", - "sha256": "5605030f1668edf93ade7f24b0bfe5ecf943774e02cf0ac5cac02387ac910185", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-protobuf-lite/1.56.1/grpc-protobuf-lite-1.56.1.jar" - ], - "downloaded_file_path": "io/grpc/grpc-protobuf-lite/1.56.1/grpc-protobuf-lite-1.56.1.jar" - } - }, - "org_apache_httpcomponents_httpcore_4_4_16": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_apache_httpcomponents_httpcore_4_4_16", - "sha256": "6c9b3dd142a09dc468e23ad39aad6f75a0f2b85125104469f026e52a474e464f", - "urls": [ - "https://repo1.maven.org/maven2/org/apache/httpcomponents/httpcore/4.4.16/httpcore-4.4.16.jar", - "https://maven.google.com/org/apache/httpcomponents/httpcore/4.4.16/httpcore-4.4.16.jar" - ], - "downloaded_file_path": "org/apache/httpcomponents/httpcore/4.4.16/httpcore-4.4.16.jar" - } - }, - "org_slf4j_slf4j_simple": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_slf4j_slf4j_simple", - "generating_repository": "maven", - "target_name": "org_slf4j_slf4j_simple" - } - }, - "io_netty_netty_codec_jar_sources_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_jar_sources_4_1_97_Final", - "sha256": "3f512c1a7ffa112ce3f8a8fec9545017063ae06583e80e841bdee76477f891f4", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-codec/4.1.97.Final/netty-codec-4.1.97.Final-sources.jar" - ], - "downloaded_file_path": "io/netty/netty-codec/4.1.97.Final/netty-codec-4.1.97.Final-sources.jar" - } - }, - "org_xerial_sqlite_jdbc_3_34_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_xerial_sqlite_jdbc_3_34_0", - "sha256": "605979c94e7fe00437f1e10dcfa657a23f125c8eb4d2f0ec17e3f84613894cc3", - "urls": [ - "https://repo1.maven.org/maven2/org/xerial/sqlite-jdbc/3.34.0/sqlite-jdbc-3.34.0.jar" - ], - "downloaded_file_path": "org/xerial/sqlite-jdbc/3.34.0/sqlite-jdbc-3.34.0.jar" - } - }, - "org_slf4j_jcl_over_slf4j_jar_sources_1_7_30": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_slf4j_jcl_over_slf4j_jar_sources_1_7_30", - "sha256": "e746bd5e537c8ceeb0c815a4edbaa4169444f74e658038e1966d8a3596eb8d05", - "urls": [ - "https://repo1.maven.org/maven2/org/slf4j/jcl-over-slf4j/1.7.30/jcl-over-slf4j-1.7.30-sources.jar" - ], - "downloaded_file_path": "org/slf4j/jcl-over-slf4j/1.7.30/jcl-over-slf4j-1.7.30-sources.jar" - } - }, - "io_grpc_grpc_netty_shaded_1_56_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_netty_shaded_1_56_1", - "sha256": "b15257e1137d609a7e8eb9bf4f0cec06b78ee69c030282db0a66d17cc9c3eaf1", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-netty-shaded/1.56.1/grpc-netty-shaded-1.56.1.jar" - ], - "downloaded_file_path": "io/grpc/grpc-netty-shaded/1.56.1/grpc-netty-shaded-1.56.1.jar" - } - }, - "com_google_protobuf_protobuf_java": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_protobuf_protobuf_java", - "generating_repository": "maven", - "target_name": "com_google_protobuf_protobuf_java" - } - }, - "unpinned_maven": { - "bzlFile": "@@rules_jvm_external~5.3//:coursier.bzl", - "ruleClassName": "coursier_fetch", - "attributes": { - "name": "rules_jvm_external~5.3~maven~unpinned_maven", - "repositories": [ - "{ \"repo_url\": \"https://repo1.maven.org/maven2\" }" - ], - "artifacts": [ - "{ \"group\": \"com.amazonaws\", \"artifact\": \"aws-java-sdk-s3\", \"version\": \"1.12.544\" }", - "{ \"group\": \"com.amazonaws\", \"artifact\": \"aws-java-sdk-secretsmanager\", \"version\": \"1.12.544\" }", - "{ \"group\": \"com.fasterxml.jackson.core\", \"artifact\": \"jackson-databind\", \"version\": \"2.15.0\" }", - "{ \"group\": \"com.github.ben-manes.caffeine\", \"artifact\": \"caffeine\", \"version\": \"2.9.0\" }", - "{ \"group\": \"com.github.docker-java\", \"artifact\": \"docker-java\", \"version\": \"3.3.3\" }", - "{ \"group\": \"com.github.fppt\", \"artifact\": \"jedis-mock\", \"version\": \"1.0.10\" }", - "{ \"group\": \"com.github.jnr\", \"artifact\": \"jffi\", \"version\": \"1.3.11\" }", - "{ \"group\": \"com.github.jnr\", \"artifact\": \"jffi\", \"version\": \"1.3.11\", \"packaging\": \"jar\", \"classifier\": \"native\" }", - "{ \"group\": \"com.github.jnr\", \"artifact\": \"jnr-constants\", \"version\": \"0.10.4\" }", - "{ \"group\": \"com.github.jnr\", \"artifact\": \"jnr-ffi\", \"version\": \"2.2.14\" }", - "{ \"group\": \"com.github.jnr\", \"artifact\": \"jnr-posix\", \"version\": \"3.1.17\" }", - "{ \"group\": \"com.github.pcj\", \"artifact\": \"google-options\", \"version\": \"1.0.0\" }", - "{ \"group\": \"com.github.serceman\", \"artifact\": \"jnr-fuse\", \"version\": \"0.5.7\" }", - "{ \"group\": \"com.github.luben\", \"artifact\": \"zstd-jni\", \"version\": \"1.5.5-7\" }", - "{ \"group\": \"com.github.oshi\", \"artifact\": \"oshi-core\", \"version\": \"6.4.5\" }", - "{ \"group\": \"com.google.auth\", \"artifact\": \"google-auth-library-credentials\", \"version\": \"1.19.0\" }", - "{ \"group\": \"com.google.auth\", \"artifact\": \"google-auth-library-oauth2-http\", \"version\": \"1.19.0\" }", - "{ \"group\": \"com.google.code.findbugs\", \"artifact\": \"jsr305\", \"version\": \"3.0.2\" }", - "{ \"group\": \"com.google.code.gson\", \"artifact\": \"gson\", \"version\": \"2.10.1\" }", - "{ \"group\": \"com.google.errorprone\", \"artifact\": \"error_prone_annotations\", \"version\": \"2.22.0\" }", - "{ \"group\": \"com.google.errorprone\", \"artifact\": \"error_prone_core\", \"version\": \"2.22.0\" }", - "{ \"group\": \"com.google.guava\", \"artifact\": \"failureaccess\", \"version\": \"1.0.1\" }", - "{ \"group\": \"com.google.guava\", \"artifact\": \"guava\", \"version\": \"32.1.1-jre\" }", - "{ \"group\": \"com.google.j2objc\", \"artifact\": \"j2objc-annotations\", \"version\": \"2.8\" }", - "{ \"group\": \"com.google.jimfs\", \"artifact\": \"jimfs\", \"version\": \"1.3.0\" }", - "{ \"group\": \"com.google.protobuf\", \"artifact\": \"protobuf-java-util\", \"version\": \"3.19.1\" }", - "{ \"group\": \"com.google.protobuf\", \"artifact\": \"protobuf-java\", \"version\": \"3.19.1\" }", - "{ \"group\": \"com.google.truth\", \"artifact\": \"truth\", \"version\": \"1.1.5\" }", - "{ \"group\": \"org.slf4j\", \"artifact\": \"slf4j-simple\", \"version\": \"2.0.9\" }", - "{ \"group\": \"com.googlecode.json-simple\", \"artifact\": \"json-simple\", \"version\": \"1.1.1\" }", - "{ \"group\": \"com.jayway.jsonpath\", \"artifact\": \"json-path\", \"version\": \"2.8.0\" }", - "{ \"group\": \"org.bouncycastle\", \"artifact\": \"bcprov-jdk15on\", \"version\": \"1.70\" }", - "{ \"group\": \"net.jcip\", \"artifact\": \"jcip-annotations\", \"version\": \"1.0\" }", - "{ \"group\": \"io.netty\", \"artifact\": \"netty-buffer\", \"version\": \"4.1.97.Final\" }", - "{ \"group\": \"io.netty\", \"artifact\": \"netty-codec\", \"version\": \"4.1.97.Final\" }", - "{ \"group\": \"io.netty\", \"artifact\": \"netty-codec-http\", \"version\": \"4.1.97.Final\" }", - "{ \"group\": \"io.netty\", \"artifact\": \"netty-codec-http2\", \"version\": \"4.1.97.Final\" }", - "{ \"group\": \"io.netty\", \"artifact\": \"netty-codec-socks\", \"version\": \"4.1.97.Final\" }", - "{ \"group\": \"io.netty\", \"artifact\": \"netty-common\", \"version\": \"4.1.97.Final\" }", - "{ \"group\": \"io.netty\", \"artifact\": \"netty-handler\", \"version\": \"4.1.97.Final\" }", - "{ \"group\": \"io.netty\", \"artifact\": \"netty-handler-proxy\", \"version\": \"4.1.97.Final\" }", - "{ \"group\": \"io.netty\", \"artifact\": \"netty-resolver\", \"version\": \"4.1.97.Final\" }", - "{ \"group\": \"io.netty\", \"artifact\": \"netty-transport\", \"version\": \"4.1.97.Final\" }", - "{ \"group\": \"io.netty\", \"artifact\": \"netty-transport-native-epoll\", \"version\": \"4.1.97.Final\" }", - "{ \"group\": \"io.netty\", \"artifact\": \"netty-transport-native-kqueue\", \"version\": \"4.1.97.Final\" }", - "{ \"group\": \"io.netty\", \"artifact\": \"netty-transport-native-unix-common\", \"version\": \"4.1.97.Final\" }", - "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-api\", \"version\": \"1.56.1\" }", - "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-auth\", \"version\": \"1.56.1\" }", - "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-core\", \"version\": \"1.56.1\" }", - "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-context\", \"version\": \"1.56.1\" }", - "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-netty\", \"version\": \"1.56.1\" }", - "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-stub\", \"version\": \"1.56.1\" }", - "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-protobuf\", \"version\": \"1.56.1\" }", - "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-testing\", \"version\": \"1.56.1\" }", - "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-services\", \"version\": \"1.56.1\" }", - "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-netty-shaded\", \"version\": \"1.56.1\" }", - "{ \"group\": \"io.prometheus\", \"artifact\": \"simpleclient\", \"version\": \"0.15.0\" }", - "{ \"group\": \"io.prometheus\", \"artifact\": \"simpleclient_hotspot\", \"version\": \"0.15.0\" }", - "{ \"group\": \"io.prometheus\", \"artifact\": \"simpleclient_httpserver\", \"version\": \"0.15.0\" }", - "{ \"group\": \"junit\", \"artifact\": \"junit\", \"version\": \"4.13.2\" }", - "{ \"group\": \"javax.annotation\", \"artifact\": \"javax.annotation-api\", \"version\": \"1.3.2\" }", - "{ \"group\": \"net.javacrumbs.future-converter\", \"artifact\": \"future-converter-java8-guava\", \"version\": \"1.2.0\" }", - "{ \"group\": \"org.apache.commons\", \"artifact\": \"commons-compress\", \"version\": \"1.23.0\" }", - "{ \"group\": \"org.apache.commons\", \"artifact\": \"commons-pool2\", \"version\": \"2.11.1\" }", - "{ \"group\": \"org.apache.commons\", \"artifact\": \"commons-lang3\", \"version\": \"3.13.0\" }", - "{ \"group\": \"commons-io\", \"artifact\": \"commons-io\", \"version\": \"2.13.0\" }", - "{ \"group\": \"me.dinowernli\", \"artifact\": \"java-grpc-prometheus\", \"version\": \"0.6.0\" }", - "{ \"group\": \"org.apache.tomcat\", \"artifact\": \"annotations-api\", \"version\": \"6.0.53\" }", - "{ \"group\": \"org.checkerframework\", \"artifact\": \"checker-qual\", \"version\": \"3.38.0\" }", - "{ \"group\": \"org.mockito\", \"artifact\": \"mockito-core\", \"version\": \"2.25.0\" }", - "{ \"group\": \"org.openjdk.jmh\", \"artifact\": \"jmh-core\", \"version\": \"1.37\" }", - "{ \"group\": \"org.openjdk.jmh\", \"artifact\": \"jmh-generator-annprocess\", \"version\": \"1.37\" }", - "{ \"group\": \"org.redisson\", \"artifact\": \"redisson\", \"version\": \"3.23.4\" }", - "{ \"group\": \"org.threeten\", \"artifact\": \"threetenbp\", \"version\": \"1.6.8\" }", - "{ \"group\": \"org.xerial\", \"artifact\": \"sqlite-jdbc\", \"version\": \"3.34.0\" }", - "{ \"group\": \"org.jetbrains\", \"artifact\": \"annotations\", \"version\": \"16.0.2\" }", - "{ \"group\": \"org.yaml\", \"artifact\": \"snakeyaml\", \"version\": \"2.2\" }", - "{ \"group\": \"org.projectlombok\", \"artifact\": \"lombok\", \"version\": \"1.18.30\" }" - ], - "fail_on_missing_checksum": true, - "fetch_sources": true, - "fetch_javadoc": false, - "excluded_artifacts": [], - "generate_compat_repositories": false, - "version_conflict_policy": "default", - "override_targets": {}, - "strict_visibility": false, - "strict_visibility_value": [ - "@@//visibility:private" - ], - "maven_install_json": "@@//:maven_install.json", - "resolve_timeout": 600, - "jetify": false, - "jetify_include_list": [ - "*" - ], - "use_starlark_android_rules": false, - "aar_import_bzl_label": "@build_bazel_rules_android//android:rules.bzl", - "duplicate_version_warning": "warn" - } - }, - "io_netty_netty_transport_native_unix_common_4_1_86_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_native_unix_common_4_1_86_Final", - "sha256": "ec26d03a06565791d57e997f793677ee4d3fc47b290b7951898c2ecd0232f115", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-transport-native-unix-common/4.1.86.Final/netty-transport-native-unix-common-4.1.86.Final.jar", - "https://maven.google.com/io/netty/netty-transport-native-unix-common/4.1.86.Final/netty-transport-native-unix-common-4.1.86.Final.jar" - ], - "downloaded_file_path": "io/netty/netty-transport-native-unix-common/4.1.86.Final/netty-transport-native-unix-common-4.1.86.Final.jar" - } - }, - "com_github_oshi_oshi_core_6_4_5": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_oshi_oshi_core_6_4_5", - "sha256": "7e634fb57b8763b7803d5f9caaed46d19c3bdbe81ddd8a93e61528c700cdc09e", - "urls": [ - "https://repo1.maven.org/maven2/com/github/oshi/oshi-core/6.4.5/oshi-core-6.4.5.jar" - ], - "downloaded_file_path": "com/github/oshi/oshi-core/6.4.5/oshi-core-6.4.5.jar" - } - }, - "joda_time_joda_time_jar_sources_2_8_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~joda_time_joda_time_jar_sources_2_8_1", - "sha256": "59086b3e0608df2eac1b21063d6bae37851173e24efc4cacd6705326408723d9", - "urls": [ - "https://repo1.maven.org/maven2/joda-time/joda-time/2.8.1/joda-time-2.8.1-sources.jar" - ], - "downloaded_file_path": "joda-time/joda-time/2.8.1/joda-time-2.8.1-sources.jar" - } - }, - "com_google_protobuf_protobuf_java_3_22_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_protobuf_protobuf_java_3_22_3", - "sha256": "59d388ea6a2d2d76ae8efff7fd4d0c60c6f0f464c3d3ab9be8e5add092975708", - "urls": [ - "https://repo1.maven.org/maven2/com/google/protobuf/protobuf-java/3.22.3/protobuf-java-3.22.3.jar" - ], - "downloaded_file_path": "com/google/protobuf/protobuf-java/3.22.3/protobuf-java-3.22.3.jar" - } - }, - "org_apache_commons_commons_lang3_3_13_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_apache_commons_commons_lang3_3_13_0", - "sha256": "82f528cf718c7a3c2f30fc5bc784e3c6a0a10b17605dadb9e16c82ede11e6064", - "urls": [ - "https://repo1.maven.org/maven2/org/apache/commons/commons-lang3/3.13.0/commons-lang3-3.13.0.jar" - ], - "downloaded_file_path": "org/apache/commons/commons-lang3/3.13.0/commons-lang3-3.13.0.jar" - } - }, - "software_amazon_awssdk_profiles_2_20_78": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_profiles_2_20_78", - "sha256": "c54925f8710a63b545f272ad651b40fc4310c4d3f49df50257645604d6021f32", - "urls": [ - "https://repo1.maven.org/maven2/software/amazon/awssdk/profiles/2.20.78/profiles-2.20.78.jar", - "https://maven.google.com/software/amazon/awssdk/profiles/2.20.78/profiles-2.20.78.jar" - ], - "downloaded_file_path": "software/amazon/awssdk/profiles/2.20.78/profiles-2.20.78.jar" - } - }, - "io_grpc_grpc_stub_1_56_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_stub_1_56_1", - "sha256": "64ffca5dde4565c4c0f876deea3d105341d45ce605b29053e79dc86a22f7953b", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-stub/1.56.1/grpc-stub-1.56.1.jar" - ], - "downloaded_file_path": "io/grpc/grpc-stub/1.56.1/grpc-stub-1.56.1.jar" - } - }, - "io_grpc_grpc_protobuf_lite_jar_sources_1_56_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_protobuf_lite_jar_sources_1_56_1", - "sha256": "515018e2d65b852e0fa99c6dcb6c1e711070e02bdb926ca5b3e04ed35ae0a874", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-protobuf-lite/1.56.1/grpc-protobuf-lite-1.56.1-sources.jar" - ], - "downloaded_file_path": "io/grpc/grpc-protobuf-lite/1.56.1/grpc-protobuf-lite-1.56.1-sources.jar" - } - }, - "com_googlecode_json_simple_json_simple_1_1_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_googlecode_json_simple_json_simple_1_1_1", - "sha256": "4e69696892b88b41c55d49ab2fdcc21eead92bf54acc588c0050596c3b75199c", - "urls": [ - "https://repo1.maven.org/maven2/com/googlecode/json-simple/json-simple/1.1.1/json-simple-1.1.1.jar" - ], - "downloaded_file_path": "com/googlecode/json-simple/json-simple/1.1.1/json-simple-1.1.1.jar" - } - }, - "io_netty_netty_transport_native_kqueue_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_native_kqueue_4_1_97_Final", - "sha256": "85916dd7569148bb3d4bc831d45846807b39d2b6f593dc8794a42ca71a4086c9", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-transport-native-kqueue/4.1.97.Final/netty-transport-native-kqueue-4.1.97.Final.jar" - ], - "downloaded_file_path": "io/netty/netty-transport-native-kqueue/4.1.97.Final/netty-transport-native-kqueue-4.1.97.Final.jar" - } - }, - "io_grpc_grpc_auth_jar_sources_1_56_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_auth_jar_sources_1_56_1", - "sha256": "301967032288267e509448bdcd8ba42c726b5e58732b2d7d357f864e036f0e23", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-auth/1.56.1/grpc-auth-1.56.1-sources.jar" - ], - "downloaded_file_path": "io/grpc/grpc-auth/1.56.1/grpc-auth-1.56.1-sources.jar" - } - }, - "com_google_api_api_common_2_11_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_api_api_common_2_11_1", - "sha256": "21f67354fa308826395d2ed171d25416a8001d50ea70f82b68f2bdd17bb8947f", - "urls": [ - "https://repo1.maven.org/maven2/com/google/api/api-common/2.11.1/api-common-2.11.1.jar", - "https://maven.google.com/com/google/api/api-common/2.11.1/api-common-2.11.1.jar" - ], - "downloaded_file_path": "com/google/api/api-common/2.11.1/api-common-2.11.1.jar" - } - }, - "io_netty_netty_transport_native_unix_common_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_native_unix_common_4_1_97_Final", - "sha256": "412fe140257c2dda5a5e15bee911298bd61928d03ee6be4db588e82c196c5dc6", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-transport-native-unix-common/4.1.97.Final/netty-transport-native-unix-common-4.1.97.Final.jar" - ], - "downloaded_file_path": "io/netty/netty-transport-native-unix-common/4.1.97.Final/netty-transport-native-unix-common-4.1.97.Final.jar" - } - }, - "com_google_oauth_client_google_oauth_client_1_34_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_oauth_client_google_oauth_client_1_34_1", - "sha256": "193edf97aefa28b93c5892bdc598bac34fa4c396588030084f290b1440e8b98a", - "urls": [ - "https://repo1.maven.org/maven2/com/google/oauth-client/google-oauth-client/1.34.1/google-oauth-client-1.34.1.jar", - "https://maven.google.com/com/google/oauth-client/google-oauth-client/1.34.1/google-oauth-client-1.34.1.jar" - ], - "downloaded_file_path": "com/google/oauth-client/google-oauth-client/1.34.1/google-oauth-client-1.34.1.jar" - } - }, - "com_amazonaws_aws_java_sdk_secretsmanager": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_amazonaws_aws_java_sdk_secretsmanager", - "generating_repository": "maven", - "target_name": "com_amazonaws_aws_java_sdk_secretsmanager" - } - }, - "javax_cache_cache_api_jar_sources_1_1_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~javax_cache_cache_api_jar_sources_1_1_1", - "sha256": "2387f48682d3475fd214a6b9c2d1ef732ae8ce9313a3b8f69e72449ce33c6068", - "urls": [ - "https://repo1.maven.org/maven2/javax/cache/cache-api/1.1.1/cache-api-1.1.1-sources.jar" - ], - "downloaded_file_path": "javax/cache/cache-api/1.1.1/cache-api-1.1.1-sources.jar" - } - }, - "org_bouncycastle_bcutil_jdk18on_jar_sources_1_75": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_bouncycastle_bcutil_jdk18on_jar_sources_1_75", - "sha256": "bf827dd7283566804ba0583d02c80f43f0713896814e9dc56b1242ff5cc656a7", - "urls": [ - "https://repo1.maven.org/maven2/org/bouncycastle/bcutil-jdk18on/1.75/bcutil-jdk18on-1.75-sources.jar" - ], - "downloaded_file_path": "org/bouncycastle/bcutil-jdk18on/1.75/bcutil-jdk18on-1.75-sources.jar" - } - }, - "io_grpc_grpc_stub_jar_sources_1_56_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_stub_jar_sources_1_56_1", - "sha256": "da927063466a063aaee49ca7c43b8cd487d3f24d3b8bb694216304060f386b8c", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-stub/1.56.1/grpc-stub-1.56.1-sources.jar" - ], - "downloaded_file_path": "io/grpc/grpc-stub/1.56.1/grpc-stub-1.56.1-sources.jar" - } - }, - "net_sf_jopt_simple_jopt_simple_5_0_4": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~net_sf_jopt_simple_jopt_simple_5_0_4", - "sha256": "df26cc58f235f477db07f753ba5a3ab243ebe5789d9f89ecf68dd62ea9a66c28", - "urls": [ - "https://repo1.maven.org/maven2/net/sf/jopt-simple/jopt-simple/5.0.4/jopt-simple-5.0.4.jar" - ], - "downloaded_file_path": "net/sf/jopt-simple/jopt-simple/5.0.4/jopt-simple-5.0.4.jar" - } - }, - "jakarta_activation_jakarta_activation_api_1_2_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~jakarta_activation_jakarta_activation_api_1_2_1", - "sha256": "8b0a0f52fa8b05c5431921a063ed866efaa41dadf2e3a7ee3e1961f2b0d9645b", - "urls": [ - "https://repo1.maven.org/maven2/jakarta/activation/jakarta.activation-api/1.2.1/jakarta.activation-api-1.2.1.jar" - ], - "downloaded_file_path": "jakarta/activation/jakarta.activation-api/1.2.1/jakarta.activation-api-1.2.1.jar" - } - }, - "io_netty_netty_handler_proxy_jar_sources_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_handler_proxy_jar_sources_4_1_97_Final", - "sha256": "19e0dac14e5028af4c7068a0a2872f50ad06588a5140a065648f1ab3c31cf5bc", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-handler-proxy/4.1.97.Final/netty-handler-proxy-4.1.97.Final-sources.jar" - ], - "downloaded_file_path": "io/netty/netty-handler-proxy/4.1.97.Final/netty-handler-proxy-4.1.97.Final-sources.jar" - } - }, - "io_netty_netty_transport_classes_kqueue_jar_sources_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_classes_kqueue_jar_sources_4_1_97_Final", - "sha256": "1db14659fab815b08ed06a60553bebabd402687d35b204f1af5add7396a549f4", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-transport-classes-kqueue/4.1.97.Final/netty-transport-classes-kqueue-4.1.97.Final-sources.jar" - ], - "downloaded_file_path": "io/netty/netty-transport-classes-kqueue/4.1.97.Final/netty-transport-classes-kqueue-4.1.97.Final-sources.jar" - } - }, - "software_amazon_awssdk_regions_2_20_78": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_regions_2_20_78", - "sha256": "af2dd9874404ef3bda177000134b7d9e04279a24a726388175b4dff2590740d7", - "urls": [ - "https://repo1.maven.org/maven2/software/amazon/awssdk/regions/2.20.78/regions-2.20.78.jar", - "https://maven.google.com/software/amazon/awssdk/regions/2.20.78/regions-2.20.78.jar" - ], - "downloaded_file_path": "software/amazon/awssdk/regions/2.20.78/regions-2.20.78.jar" - } - }, - "com_github_docker_java_docker_java_transport_netty_jar_sources_3_3_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_docker_java_docker_java_transport_netty_jar_sources_3_3_3", - "sha256": "9c8e9b8e0bf0495470d19c22e27b832dc5f0025786106212b0de6a478b5abde3", - "urls": [ - "https://repo1.maven.org/maven2/com/github/docker-java/docker-java-transport-netty/3.3.3/docker-java-transport-netty-3.3.3-sources.jar" - ], - "downloaded_file_path": "com/github/docker-java/docker-java-transport-netty/3.3.3/docker-java-transport-netty-3.3.3-sources.jar" - } - }, - "io_grpc_grpc_protobuf_lite_1_55_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_protobuf_lite_1_55_1", - "sha256": "d0253390609c72ec09c31ae46e79b01cd72a2ce2ccae11176de550ffd475c853", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-protobuf-lite/1.55.1/grpc-protobuf-lite-1.55.1.jar", - "https://maven.google.com/io/grpc/grpc-protobuf-lite/1.55.1/grpc-protobuf-lite-1.55.1.jar" - ], - "downloaded_file_path": "io/grpc/grpc-protobuf-lite/1.55.1/grpc-protobuf-lite-1.55.1.jar" - } - }, - "io_grpc_grpc_services_jar_sources_1_56_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_services_jar_sources_1_56_1", - "sha256": "e9676fe1c41585babbe70c26a28b418b87a80e81ed49481a5dfaaace1a71162e", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-services/1.56.1/grpc-services-1.56.1-sources.jar" - ], - "downloaded_file_path": "io/grpc/grpc-services/1.56.1/grpc-services-1.56.1-sources.jar" - } - }, - "net_minidev_accessors_smart_2_4_9": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~net_minidev_accessors_smart_2_4_9", - "sha256": "accdd5c7ac4c49b155890aaea1ffca2a9ccd5826b562dd95a99fc1887003e031", - "urls": [ - "https://repo1.maven.org/maven2/net/minidev/accessors-smart/2.4.9/accessors-smart-2.4.9.jar" - ], - "downloaded_file_path": "net/minidev/accessors-smart/2.4.9/accessors-smart-2.4.9.jar" - } - }, - "com_fasterxml_jackson_core_jackson_annotations_2_15_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_core_jackson_annotations_2_15_2", - "sha256": "04e21f94dcfee4b078fa5a5f53047b785aaba69d19de392f616e7a7fe5d3882f", - "urls": [ - "https://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-annotations/2.15.2/jackson-annotations-2.15.2.jar" - ], - "downloaded_file_path": "com/fasterxml/jackson/core/jackson-annotations/2.15.2/jackson-annotations-2.15.2.jar" - } - }, - "aopalliance_aopalliance_jar_sources_1_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~aopalliance_aopalliance_jar_sources_1_0", - "sha256": "e6ef91d439ada9045f419c77543ebe0416c3cdfc5b063448343417a3e4a72123", - "urls": [ - "https://repo1.maven.org/maven2/aopalliance/aopalliance/1.0/aopalliance-1.0-sources.jar" - ], - "downloaded_file_path": "aopalliance/aopalliance/1.0/aopalliance-1.0-sources.jar" - } - }, - "org_threeten_threetenbp_1_6_8": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_threeten_threetenbp_1_6_8", - "sha256": "e4b1eb3d90c38a54c7f3384fda957e0b5bf0b41b40672a44ae8b03cb6c87ce06", - "urls": [ - "https://repo1.maven.org/maven2/org/threeten/threetenbp/1.6.8/threetenbp-1.6.8.jar" - ], - "downloaded_file_path": "org/threeten/threetenbp/1.6.8/threetenbp-1.6.8.jar" - } - }, - "io_netty_netty_handler_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_handler_4_1_97_Final", - "sha256": "bd4771d19149cbc9c7464ed2d58035d79cdfed7adb59d38718b0d8e7a3dcc2de", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-handler/4.1.97.Final/netty-handler-4.1.97.Final.jar" - ], - "downloaded_file_path": "io/netty/netty-handler/4.1.97.Final/netty-handler-4.1.97.Final.jar" - } - }, - "com_google_http_client_google_http_client_jar_sources_1_42_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_http_client_google_http_client_jar_sources_1_42_3", - "sha256": "60d3d16ff67d6a395a81560227f51d282d3c65235154a696cafafe9032f43d5f", - "urls": [ - "https://repo1.maven.org/maven2/com/google/http-client/google-http-client/1.42.3/google-http-client-1.42.3-sources.jar" - ], - "downloaded_file_path": "com/google/http-client/google-http-client/1.42.3/google-http-client-1.42.3-sources.jar" - } - }, - "javax_inject_javax_inject_jar_sources_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~javax_inject_javax_inject_jar_sources_1", - "sha256": "c4b87ee2911c139c3daf498a781967f1eb2e75bc1a8529a2e7b328a15d0e433e", - "urls": [ - "https://repo1.maven.org/maven2/javax/inject/javax.inject/1/javax.inject-1-sources.jar" - ], - "downloaded_file_path": "javax/inject/javax.inject/1/javax.inject-1-sources.jar" - } - }, - "io_netty_netty_handler_proxy": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_handler_proxy", - "generating_repository": "maven", - "target_name": "io_netty_netty_handler_proxy" - } - }, - "com_esotericsoftware_reflectasm_1_11_9": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_esotericsoftware_reflectasm_1_11_9", - "sha256": "712b44da79a5b7f47a28cbfcb3d8ecfc872fae349c48aa4d3e38a5d69956afce", - "urls": [ - "https://repo1.maven.org/maven2/com/esotericsoftware/reflectasm/1.11.9/reflectasm-1.11.9.jar" - ], - "downloaded_file_path": "com/esotericsoftware/reflectasm/1.11.9/reflectasm-1.11.9.jar" - } - }, - "com_google_re2j_re2j_1_6": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_re2j_re2j_1_6", - "sha256": "c8b5c3472d4db594a865b2e47f835d07fb8b1415eeba559dccfb0a6945f033cd", - "urls": [ - "https://repo1.maven.org/maven2/com/google/re2j/re2j/1.6/re2j-1.6.jar", - "https://maven.google.com/com/google/re2j/re2j/1.6/re2j-1.6.jar" - ], - "downloaded_file_path": "com/google/re2j/re2j/1.6/re2j-1.6.jar" - } - }, - "software_amazon_awssdk_apache_client_2_20_78": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_apache_client_2_20_78", - "sha256": "771923580e38678b7f66c3a63f4b5f79eef9ffb81027e2a422aed2713ce4138b", - "urls": [ - "https://repo1.maven.org/maven2/software/amazon/awssdk/apache-client/2.20.78/apache-client-2.20.78.jar", - "https://maven.google.com/software/amazon/awssdk/apache-client/2.20.78/apache-client-2.20.78.jar" - ], - "downloaded_file_path": "software/amazon/awssdk/apache-client/2.20.78/apache-client-2.20.78.jar" - } - }, - "com_jayway_jsonpath_json_path": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_jayway_jsonpath_json_path", - "generating_repository": "maven", - "target_name": "com_jayway_jsonpath_json_path" - } - }, - "com_fasterxml_jackson_dataformat_jackson_dataformat_cbor_jar_sources_2_12_6": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_dataformat_jackson_dataformat_cbor_jar_sources_2_12_6", - "sha256": "1e70fe124ab0a0c3e9a909e75735799e987fb71b4f7649eb10199f4f3b873287", - "urls": [ - "https://repo1.maven.org/maven2/com/fasterxml/jackson/dataformat/jackson-dataformat-cbor/2.12.6/jackson-dataformat-cbor-2.12.6-sources.jar" - ], - "downloaded_file_path": "com/fasterxml/jackson/dataformat/jackson-dataformat-cbor/2.12.6/jackson-dataformat-cbor-2.12.6-sources.jar" - } - }, - "org_bouncycastle_bcpkix_jdk18on_jar_sources_1_75": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_bouncycastle_bcpkix_jdk18on_jar_sources_1_75", - "sha256": "bd621657020f859beff0c8279aef31380c18438596964da2c77a0542126bf780", - "urls": [ - "https://repo1.maven.org/maven2/org/bouncycastle/bcpkix-jdk18on/1.75/bcpkix-jdk18on-1.75-sources.jar" - ], - "downloaded_file_path": "org/bouncycastle/bcpkix-jdk18on/1.75/bcpkix-jdk18on-1.75-sources.jar" - } - }, - "org_redisson_redisson_jar_sources_3_23_4": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_redisson_redisson_jar_sources_3_23_4", - "sha256": "7701f55b848adeb366af2461e1323f50f2d8701e983b133b34f5085803cbbab6", - "urls": [ - "https://repo1.maven.org/maven2/org/redisson/redisson/3.23.4/redisson-3.23.4-sources.jar" - ], - "downloaded_file_path": "org/redisson/redisson/3.23.4/redisson-3.23.4-sources.jar" - } - }, - "org_threeten_threetenbp_jar_sources_1_6_8": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_threeten_threetenbp_jar_sources_1_6_8", - "sha256": "6b68e90399fd0d97ee7abbe3918c87a236d52a3fb3c434359a11942f9a1abc59", - "urls": [ - "https://repo1.maven.org/maven2/org/threeten/threetenbp/1.6.8/threetenbp-1.6.8-sources.jar" - ], - "downloaded_file_path": "org/threeten/threetenbp/1.6.8/threetenbp-1.6.8-sources.jar" - } - }, - "io_netty_netty_common_jar_sources_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_common_jar_sources_4_1_97_Final", - "sha256": "54e96a125cb58b3ac067fa59b4a97fb6f1aadbac3f3092e6cc7fa88684de9964", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-common/4.1.97.Final/netty-common-4.1.97.Final-sources.jar" - ], - "downloaded_file_path": "io/netty/netty-common/4.1.97.Final/netty-common-4.1.97.Final-sources.jar" - } - }, - "org_glassfish_hk2_external_jakarta_inject_jar_sources_2_6_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_glassfish_hk2_external_jakarta_inject_jar_sources_2_6_1", - "sha256": "fbbadf59b395bf326910de95682eaaa83dcc0f1d65cd4a077c6988deff6a527a", - "urls": [ - "https://repo1.maven.org/maven2/org/glassfish/hk2/external/jakarta.inject/2.6.1/jakarta.inject-2.6.1-sources.jar" - ], - "downloaded_file_path": "org/glassfish/hk2/external/jakarta.inject/2.6.1/jakarta.inject-2.6.1-sources.jar" - } - }, - "org_bouncycastle_bcprov_jdk18on_jar_sources_1_75": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_bouncycastle_bcprov_jdk18on_jar_sources_1_75", - "sha256": "72abfe335986c5f8d9f61489d5699dca7688303a7da60697cef77018187ac8bc", - "urls": [ - "https://repo1.maven.org/maven2/org/bouncycastle/bcprov-jdk18on/1.75/bcprov-jdk18on-1.75-sources.jar" - ], - "downloaded_file_path": "org/bouncycastle/bcprov-jdk18on/1.75/bcprov-jdk18on-1.75-sources.jar" - } - }, - "javax_annotation_javax_annotation_api_1_3_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~javax_annotation_javax_annotation_api_1_3_2", - "sha256": "e04ba5195bcd555dc95650f7cc614d151e4bcd52d29a10b8aa2197f3ab89ab9b", - "urls": [ - "https://repo1.maven.org/maven2/javax/annotation/javax.annotation-api/1.3.2/javax.annotation-api-1.3.2.jar" - ], - "downloaded_file_path": "javax/annotation/javax.annotation-api/1.3.2/javax.annotation-api-1.3.2.jar" - } - }, - "io_prometheus_simpleclient_httpserver_0_15_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_httpserver_0_15_0", - "sha256": "a1a16e1f804e3382ed8b400220ecb2913c96412d937e618f54a7088e6eb432b6", - "urls": [ - "https://repo1.maven.org/maven2/io/prometheus/simpleclient_httpserver/0.15.0/simpleclient_httpserver-0.15.0.jar" - ], - "downloaded_file_path": "io/prometheus/simpleclient_httpserver/0.15.0/simpleclient_httpserver-0.15.0.jar" - } - }, - "com_google_auth_google_auth_library_credentials": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_auth_google_auth_library_credentials", - "generating_repository": "maven", - "target_name": "com_google_auth_google_auth_library_credentials" - } - }, - "com_google_jimfs_jimfs": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_jimfs_jimfs", - "generating_repository": "maven", - "target_name": "com_google_jimfs_jimfs" - } - }, - "org_slf4j_slf4j_simple_2_0_9": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_slf4j_slf4j_simple_2_0_9", - "sha256": "71f9c6de6dbaec2d10caa303faf08c5e749be53b242896c64c96b7c6bb6d62dc", - "urls": [ - "https://repo1.maven.org/maven2/org/slf4j/slf4j-simple/2.0.9/slf4j-simple-2.0.9.jar" - ], - "downloaded_file_path": "org/slf4j/slf4j-simple/2.0.9/slf4j-simple-2.0.9.jar" - } - }, - "org_glassfish_jersey_core_jersey_client_jar_sources_2_30_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_glassfish_jersey_core_jersey_client_jar_sources_2_30_1", - "sha256": "44618799a585b0529c7b1fc63bdf4e0c5faa11c9cc8fb27621f3b24106be9ab7", - "urls": [ - "https://repo1.maven.org/maven2/org/glassfish/jersey/core/jersey-client/2.30.1/jersey-client-2.30.1-sources.jar" - ], - "downloaded_file_path": "org/glassfish/jersey/core/jersey-client/2.30.1/jersey-client-2.30.1-sources.jar" - } - }, - "com_github_docker_java_docker_java_core_jar_sources_3_3_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_docker_java_docker_java_core_jar_sources_3_3_3", - "sha256": "4858f9c8671cd792067fdaa4e99f04f6a660f546d08e03041664b754b79235f8", - "urls": [ - "https://repo1.maven.org/maven2/com/github/docker-java/docker-java-core/3.3.3/docker-java-core-3.3.3-sources.jar" - ], - "downloaded_file_path": "com/github/docker-java/docker-java-core/3.3.3/docker-java-core-3.3.3-sources.jar" - } - }, - "io_grpc_grpc_netty_shaded": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_netty_shaded", - "generating_repository": "maven", - "target_name": "io_grpc_grpc_netty_shaded" - } - }, - "io_netty_netty_common_4_1_86_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_common_4_1_86_Final", - "sha256": "a35a3f16e7cd45c5d8529aa3e7702d4ef3b36213ea332db59744ea348fc2ae99", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-common/4.1.86.Final/netty-common-4.1.86.Final.jar", - "https://maven.google.com/io/netty/netty-common/4.1.86.Final/netty-common-4.1.86.Final.jar" - ], - "downloaded_file_path": "io/netty/netty-common/4.1.86.Final/netty-common-4.1.86.Final.jar" - } - }, - "io_netty_netty_transport_native_kqueue_jar_sources_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_native_kqueue_jar_sources_4_1_97_Final", - "sha256": "2ea352ecbfc3cf601f98b0ffb06d30169ba40ed912fd68d66c0cd6f0bcf4d4b6", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-transport-native-kqueue/4.1.97.Final/netty-transport-native-kqueue-4.1.97.Final-sources.jar" - ], - "downloaded_file_path": "io/netty/netty-transport-native-kqueue/4.1.97.Final/netty-transport-native-kqueue-4.1.97.Final-sources.jar" - } - }, - "com_google_protobuf_protobuf_java_jar_sources_3_22_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_protobuf_protobuf_java_jar_sources_3_22_3", - "sha256": "49a699e1a696b4c6f681f4f0f9af5247fc97e0e665c5fbbbf797be7e7cd9c091", - "urls": [ - "https://repo1.maven.org/maven2/com/google/protobuf/protobuf-java/3.22.3/protobuf-java-3.22.3-sources.jar" - ], - "downloaded_file_path": "com/google/protobuf/protobuf-java/3.22.3/protobuf-java-3.22.3-sources.jar" - } - }, - "io_netty_netty_buffer_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_buffer_4_1_97_Final", - "sha256": "a4393f5b395486cc74d0325c9b41311abb9513ba0fd7ef8cf46e9345c3bffbea", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-buffer/4.1.97.Final/netty-buffer-4.1.97.Final.jar" - ], - "downloaded_file_path": "io/netty/netty-buffer/4.1.97.Final/netty-buffer-4.1.97.Final.jar" - } - }, - "software_amazon_awssdk_arns_2_20_78": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_arns_2_20_78", - "sha256": "83c9c5743f83375e1d4b5bedce3593107b4989beec96f809554f545feeae4f34", - "urls": [ - "https://repo1.maven.org/maven2/software/amazon/awssdk/arns/2.20.78/arns-2.20.78.jar", - "https://maven.google.com/software/amazon/awssdk/arns/2.20.78/arns-2.20.78.jar" - ], - "downloaded_file_path": "software/amazon/awssdk/arns/2.20.78/arns-2.20.78.jar" - } - }, - "io_netty_netty_buffer_jar_sources_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_buffer_jar_sources_4_1_97_Final", - "sha256": "0b691a25682115d65da9e565589e39ee272227a972ecf0de936b475d42a4be48", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-buffer/4.1.97.Final/netty-buffer-4.1.97.Final-sources.jar" - ], - "downloaded_file_path": "io/netty/netty-buffer/4.1.97.Final/netty-buffer-4.1.97.Final-sources.jar" - } - }, - "io_grpc_grpc_services_1_55_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_services_1_55_1", - "sha256": "324d773ca903ce13b67686c98f28f56a201ee75cbb859de071d05683d06d337b", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-services/1.55.1/grpc-services-1.55.1.jar", - "https://maven.google.com/io/grpc/grpc-services/1.55.1/grpc-services-1.55.1.jar" - ], - "downloaded_file_path": "io/grpc/grpc-services/1.55.1/grpc-services-1.55.1.jar" - } - }, - "com_kohlschutter_junixsocket_junixsocket_common_jar_sources_2_6_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_kohlschutter_junixsocket_junixsocket_common_jar_sources_2_6_1", - "sha256": "066422249c845d9a0439a91fd1035e2bdf13b7552f03e94d1caef795afe53612", - "urls": [ - "https://repo1.maven.org/maven2/com/kohlschutter/junixsocket/junixsocket-common/2.6.1/junixsocket-common-2.6.1-sources.jar" - ], - "downloaded_file_path": "com/kohlschutter/junixsocket/junixsocket-common/2.6.1/junixsocket-common-2.6.1-sources.jar" - } - }, - "com_github_jnr_jnr_posix": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_jnr_jnr_posix", - "generating_repository": "maven", - "target_name": "com_github_jnr_jnr_posix" - } - }, - "org_hamcrest_hamcrest_core_jar_sources_1_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_hamcrest_hamcrest_core_jar_sources_1_3", - "sha256": "e223d2d8fbafd66057a8848cc94222d63c3cedd652cc48eddc0ab5c39c0f84df", - "urls": [ - "https://repo1.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-sources.jar" - ], - "downloaded_file_path": "org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-sources.jar" - } - }, - "io_netty_netty_transport_native_epoll_jar_sources_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_native_epoll_jar_sources_4_1_97_Final", - "sha256": "a6e3591efc09729a68574bec1493bfc0d08019b6ed4a566b6cb4e8e45ab1e937", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-transport-native-epoll/4.1.97.Final/netty-transport-native-epoll-4.1.97.Final-sources.jar" - ], - "downloaded_file_path": "io/netty/netty-transport-native-epoll/4.1.97.Final/netty-transport-native-epoll-4.1.97.Final-sources.jar" - } - }, - "com_google_auto_auto_common_jar_sources_1_2_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_auto_auto_common_jar_sources_1_2_1", - "sha256": "6802fc6e48f84cacadab9418bc8eba732f4c6a4189fc8569b1f619cb88112b25", - "urls": [ - "https://repo1.maven.org/maven2/com/google/auto/auto-common/1.2.1/auto-common-1.2.1-sources.jar" - ], - "downloaded_file_path": "com/google/auto/auto-common/1.2.1/auto-common-1.2.1-sources.jar" - } - }, - "software_amazon_awssdk_aws_core_2_20_78": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_aws_core_2_20_78", - "sha256": "83d02aa3fc781288b73b5392ef870282788cdd552fdf6ad31b9038e20a452395", - "urls": [ - "https://repo1.maven.org/maven2/software/amazon/awssdk/aws-core/2.20.78/aws-core-2.20.78.jar", - "https://maven.google.com/software/amazon/awssdk/aws-core/2.20.78/aws-core-2.20.78.jar" - ], - "downloaded_file_path": "software/amazon/awssdk/aws-core/2.20.78/aws-core-2.20.78.jar" - } - }, - "net_jcip_jcip_annotations_1_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~net_jcip_jcip_annotations_1_0", - "sha256": "be5805392060c71474bf6c9a67a099471274d30b83eef84bfc4e0889a4f1dcc0", - "urls": [ - "https://repo1.maven.org/maven2/net/jcip/jcip-annotations/1.0/jcip-annotations-1.0.jar" - ], - "downloaded_file_path": "net/jcip/jcip-annotations/1.0/jcip-annotations-1.0.jar" - } - }, - "org_checkerframework_checker_qual_3_33_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_checkerframework_checker_qual_3_33_0", - "sha256": "e316255bbfcd9fe50d165314b85abb2b33cb2a66a93c491db648e498a82c2de1", - "urls": [ - "https://repo1.maven.org/maven2/org/checkerframework/checker-qual/3.33.0/checker-qual-3.33.0.jar", - "https://maven.google.com/org/checkerframework/checker-qual/3.33.0/checker-qual-3.33.0.jar" - ], - "downloaded_file_path": "org/checkerframework/checker-qual/3.33.0/checker-qual-3.33.0.jar" - } - }, - "software_amazon_awssdk_third_party_jackson_core_2_20_78": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_third_party_jackson_core_2_20_78", - "sha256": "3bc11fd8888ab3b8026dec0894e51dd76a7460f4baac4c1adead7a03a87f8a44", - "urls": [ - "https://repo1.maven.org/maven2/software/amazon/awssdk/third-party-jackson-core/2.20.78/third-party-jackson-core-2.20.78.jar", - "https://maven.google.com/software/amazon/awssdk/third-party-jackson-core/2.20.78/third-party-jackson-core-2.20.78.jar" - ], - "downloaded_file_path": "software/amazon/awssdk/third-party-jackson-core/2.20.78/third-party-jackson-core-2.20.78.jar" - } - }, - "com_github_docker_java_docker_java_core_3_3_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_docker_java_docker_java_core_3_3_3", - "sha256": "d1f60040b4666a6073d4a2e0b72fc86cfb1b77f36b093e46a4115ea255995267", - "urls": [ - "https://repo1.maven.org/maven2/com/github/docker-java/docker-java-core/3.3.3/docker-java-core-3.3.3.jar" - ], - "downloaded_file_path": "com/github/docker-java/docker-java-core/3.3.3/docker-java-core-3.3.3.jar" - } - }, - "net_minidev_json_smart_jar_sources_2_4_10": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~net_minidev_json_smart_jar_sources_2_4_10", - "sha256": "e2ece85df4e5489cf5644fd826d2875527a405233b02496b7520d871755f395d", - "urls": [ - "https://repo1.maven.org/maven2/net/minidev/json-smart/2.4.10/json-smart-2.4.10-sources.jar" - ], - "downloaded_file_path": "net/minidev/json-smart/2.4.10/json-smart-2.4.10-sources.jar" - } - }, - "com_google_j2objc_j2objc_annotations": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_j2objc_j2objc_annotations", - "generating_repository": "maven", - "target_name": "com_google_j2objc_j2objc_annotations" - } - }, - "org_projectlombok_lombok": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_projectlombok_lombok", - "generating_repository": "maven", - "target_name": "org_projectlombok_lombok" - } - }, - "software_amazon_awssdk_http_client_spi_2_20_78": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_http_client_spi_2_20_78", - "sha256": "a52f5fa04a3c7e5c15ae632e64c64c44d2d019a3ee609ddca38312039c7a5b24", - "urls": [ - "https://repo1.maven.org/maven2/software/amazon/awssdk/http-client-spi/2.20.78/http-client-spi-2.20.78.jar", - "https://maven.google.com/software/amazon/awssdk/http-client-spi/2.20.78/http-client-spi-2.20.78.jar" - ], - "downloaded_file_path": "software/amazon/awssdk/http-client-spi/2.20.78/http-client-spi-2.20.78.jar" - } - }, - "unpinned_rules_jvm_external_deps": { - "bzlFile": "@@rules_jvm_external~5.3//:coursier.bzl", - "ruleClassName": "coursier_fetch", - "attributes": { - "name": "rules_jvm_external~5.3~maven~unpinned_rules_jvm_external_deps", - "repositories": [ - "{ \"repo_url\": \"https://repo1.maven.org/maven2\" }" - ], - "artifacts": [ - "{ \"group\": \"com.google.auth\", \"artifact\": \"google-auth-library-credentials\", \"version\": \"1.17.0\" }", - "{ \"group\": \"com.google.auth\", \"artifact\": \"google-auth-library-oauth2-http\", \"version\": \"1.17.0\" }", - "{ \"group\": \"com.google.cloud\", \"artifact\": \"google-cloud-core\", \"version\": \"2.18.1\" }", - "{ \"group\": \"com.google.cloud\", \"artifact\": \"google-cloud-storage\", \"version\": \"2.22.3\" }", - "{ \"group\": \"com.google.code.gson\", \"artifact\": \"gson\", \"version\": \"2.10.1\" }", - "{ \"group\": \"com.google.googlejavaformat\", \"artifact\": \"google-java-format\", \"version\": \"1.17.0\" }", - "{ \"group\": \"com.google.guava\", \"artifact\": \"guava\", \"version\": \"32.0.0-jre\" }", - "{ \"group\": \"org.apache.maven\", \"artifact\": \"maven-artifact\", \"version\": \"3.9.2\" }", - "{ \"group\": \"software.amazon.awssdk\", \"artifact\": \"s3\", \"version\": \"2.20.78\" }" - ], - "fail_on_missing_checksum": true, - "fetch_sources": true, - "fetch_javadoc": false, - "excluded_artifacts": [], - "generate_compat_repositories": false, - "version_conflict_policy": "default", - "override_targets": {}, - "strict_visibility": false, - "strict_visibility_value": [ - "@@//visibility:private" - ], - "maven_install_json": "@@rules_jvm_external~5.3//:rules_jvm_external_deps_install.json", - "resolve_timeout": 600, - "jetify": false, - "jetify_include_list": [ - "*" - ], - "use_starlark_android_rules": false, - "aar_import_bzl_label": "@build_bazel_rules_android//android:rules.bzl", - "duplicate_version_warning": "warn" - } - }, - "org_bouncycastle_bcutil_jdk18on_1_75": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_bouncycastle_bcutil_jdk18on_1_75", - "sha256": "027f36578c1ffdf08878c1cc2aa1e191f4b9da119c1e8f113299c53f298fa664", - "urls": [ - "https://repo1.maven.org/maven2/org/bouncycastle/bcutil-jdk18on/1.75/bcutil-jdk18on-1.75.jar" - ], - "downloaded_file_path": "org/bouncycastle/bcutil-jdk18on/1.75/bcutil-jdk18on-1.75.jar" - } - }, - "org_jetbrains_annotations_16_0_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_jetbrains_annotations_16_0_2", - "sha256": "245abad9a39eab1266ac9a8796980f462577e708ef3f6d43be2e008e4b72b9b4", - "urls": [ - "https://repo1.maven.org/maven2/org/jetbrains/annotations/16.0.2/annotations-16.0.2.jar" - ], - "downloaded_file_path": "org/jetbrains/annotations/16.0.2/annotations-16.0.2.jar" - } - }, - "com_google_http_client_google_http_client_gson_jar_sources_1_42_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_http_client_google_http_client_gson_jar_sources_1_42_3", - "sha256": "9e476cdfe8cd02f6691a3549ccc2016a3d2de4ad1d3ef5234145e73b2e61f732", - "urls": [ - "https://repo1.maven.org/maven2/com/google/http-client/google-http-client-gson/1.42.3/google-http-client-gson-1.42.3-sources.jar" - ], - "downloaded_file_path": "com/google/http-client/google-http-client-gson/1.42.3/google-http-client-gson-1.42.3-sources.jar" - } - }, - "software_amazon_awssdk_endpoints_spi_2_20_78": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_endpoints_spi_2_20_78", - "sha256": "9e20aaeb3dda2305bc04fea71d284a5ab53c562a896cc9206bcff52281585bb2", - "urls": [ - "https://repo1.maven.org/maven2/software/amazon/awssdk/endpoints-spi/2.20.78/endpoints-spi-2.20.78.jar", - "https://maven.google.com/software/amazon/awssdk/endpoints-spi/2.20.78/endpoints-spi-2.20.78.jar" - ], - "downloaded_file_path": "software/amazon/awssdk/endpoints-spi/2.20.78/endpoints-spi-2.20.78.jar" - } - }, - "software_amazon_awssdk_json_utils_2_20_78": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_json_utils_2_20_78", - "sha256": "a8f0752527d123de28ddea281ad5829bbe10bbb657fe96da32b454f976042f50", - "urls": [ - "https://repo1.maven.org/maven2/software/amazon/awssdk/json-utils/2.20.78/json-utils-2.20.78.jar", - "https://maven.google.com/software/amazon/awssdk/json-utils/2.20.78/json-utils-2.20.78.jar" - ], - "downloaded_file_path": "software/amazon/awssdk/json-utils/2.20.78/json-utils-2.20.78.jar" - } - }, - "io_grpc_grpc_netty_1_56_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_netty_1_56_1", - "sha256": "0f457ae74e16c8928c004c1f2086dfdd2905f05c75a8a02ca6750e7d7dc6c8cc", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-netty/1.56.1/grpc-netty-1.56.1.jar" - ], - "downloaded_file_path": "io/grpc/grpc-netty/1.56.1/grpc-netty-1.56.1.jar" - } - }, - "io_prometheus_simpleclient_common_jar_sources_0_15_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_common_jar_sources_0_15_0", - "sha256": "4b43be524ff3b9e00dc3859170700d0a74194625586a49eef03ea616365d1bf8", - "urls": [ - "https://repo1.maven.org/maven2/io/prometheus/simpleclient_common/0.15.0/simpleclient_common-0.15.0-sources.jar" - ], - "downloaded_file_path": "io/prometheus/simpleclient_common/0.15.0/simpleclient_common-0.15.0-sources.jar" - } - }, - "org_bouncycastle_bcprov_jdk15on_jar_sources_1_70": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_bouncycastle_bcprov_jdk15on_jar_sources_1_70", - "sha256": "0252e39814e4403b5d91a7386c3a5ac3e1fe65d43c2d25fed8d45e8eebab2696", - "urls": [ - "https://repo1.maven.org/maven2/org/bouncycastle/bcprov-jdk15on/1.70/bcprov-jdk15on-1.70-sources.jar" - ], - "downloaded_file_path": "org/bouncycastle/bcprov-jdk15on/1.70/bcprov-jdk15on-1.70-sources.jar" - } - }, - "io_opencensus_opencensus_contrib_http_util_0_31_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_opencensus_opencensus_contrib_http_util_0_31_1", - "sha256": "3ea995b55a4068be22989b70cc29a4d788c2d328d1d50613a7a9afd13fdd2d0a", - "urls": [ - "https://repo1.maven.org/maven2/io/opencensus/opencensus-contrib-http-util/0.31.1/opencensus-contrib-http-util-0.31.1.jar" - ], - "downloaded_file_path": "io/opencensus/opencensus-contrib-http-util/0.31.1/opencensus-contrib-http-util-0.31.1.jar" - } - }, - "com_fasterxml_jackson_dataformat_jackson_dataformat_yaml_jar_sources_2_15_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_dataformat_jackson_dataformat_yaml_jar_sources_2_15_2", - "sha256": "fcc3d81d341c72284a59639185558fb1035414b6f42724ae0dac013673cf62e9", - "urls": [ - "https://repo1.maven.org/maven2/com/fasterxml/jackson/dataformat/jackson-dataformat-yaml/2.15.2/jackson-dataformat-yaml-2.15.2-sources.jar" - ], - "downloaded_file_path": "com/fasterxml/jackson/dataformat/jackson-dataformat-yaml/2.15.2/jackson-dataformat-yaml-2.15.2-sources.jar" - } - }, - "org_glassfish_jersey_inject_jersey_hk2_jar_sources_2_30_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_glassfish_jersey_inject_jersey_hk2_jar_sources_2_30_1", - "sha256": "e4a24b58b0a7fa5089ee3008356a2ee252766bb12516fc2eda27cc54e935bcd9", - "urls": [ - "https://repo1.maven.org/maven2/org/glassfish/jersey/inject/jersey-hk2/2.30.1/jersey-hk2-2.30.1-sources.jar" - ], - "downloaded_file_path": "org/glassfish/jersey/inject/jersey-hk2/2.30.1/jersey-hk2-2.30.1-sources.jar" - } - }, - "com_google_auth_google_auth_library_oauth2_http_1_19_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_auth_google_auth_library_oauth2_http_1_19_0", - "sha256": "01bdf5c5cd85e10b794e401775d9909b56a38ffce313fbd39510a5d87ed56f58", - "urls": [ - "https://repo1.maven.org/maven2/com/google/auth/google-auth-library-oauth2-http/1.19.0/google-auth-library-oauth2-http-1.19.0.jar" - ], - "downloaded_file_path": "com/google/auth/google-auth-library-oauth2-http/1.19.0/google-auth-library-oauth2-http-1.19.0.jar" - } - }, - "com_github_jnr_jnr_ffi": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_jnr_jnr_ffi", - "generating_repository": "maven", - "target_name": "com_github_jnr_jnr_ffi" - } - }, - "software_amazon_awssdk_sdk_core_2_20_78": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_sdk_core_2_20_78", - "sha256": "1d060bab19739fa3a2071b4693b6fc31608a8c968e9554a0a2d2481343132498", - "urls": [ - "https://repo1.maven.org/maven2/software/amazon/awssdk/sdk-core/2.20.78/sdk-core-2.20.78.jar", - "https://maven.google.com/software/amazon/awssdk/sdk-core/2.20.78/sdk-core-2.20.78.jar" - ], - "downloaded_file_path": "software/amazon/awssdk/sdk-core/2.20.78/sdk-core-2.20.78.jar" - } - }, - "software_amazon_awssdk_utils_2_20_78": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_utils_2_20_78", - "sha256": "bf346be5ab0af9267a1c8101378f37e76fc977e9d8f5b8e5cfc98221e4179374", - "urls": [ - "https://repo1.maven.org/maven2/software/amazon/awssdk/utils/2.20.78/utils-2.20.78.jar", - "https://maven.google.com/software/amazon/awssdk/utils/2.20.78/utils-2.20.78.jar" - ], - "downloaded_file_path": "software/amazon/awssdk/utils/2.20.78/utils-2.20.78.jar" - } - }, - "com_google_auth_google_auth_library_credentials_1_19_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_auth_google_auth_library_credentials_1_19_0", - "sha256": "095984b0594888a47f311b3c9dcf6da9ed86feeea8f78140c55e14c27b0593e5", - "urls": [ - "https://repo1.maven.org/maven2/com/google/auth/google-auth-library-credentials/1.19.0/google-auth-library-credentials-1.19.0.jar" - ], - "downloaded_file_path": "com/google/auth/google-auth-library-credentials/1.19.0/google-auth-library-credentials-1.19.0.jar" - } - }, - "org_glassfish_hk2_hk2_locator_2_6_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_glassfish_hk2_hk2_locator_2_6_1", - "sha256": "febc668deb9f2000c76bd4918d8086c0a4c74d07bd0c60486b72c6bd38b62874", - "urls": [ - "https://repo1.maven.org/maven2/org/glassfish/hk2/hk2-locator/2.6.1/hk2-locator-2.6.1.jar" - ], - "downloaded_file_path": "org/glassfish/hk2/hk2-locator/2.6.1/hk2-locator-2.6.1.jar" - } - }, - "io_projectreactor_reactor_core_3_5_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_projectreactor_reactor_core_3_5_3", - "sha256": "86017581188627ae6de5d3822882f3594f87f9289ec4479391790ccfd5631508", - "urls": [ - "https://repo1.maven.org/maven2/io/projectreactor/reactor-core/3.5.3/reactor-core-3.5.3.jar" - ], - "downloaded_file_path": "io/projectreactor/reactor-core/3.5.3/reactor-core-3.5.3.jar" - } - }, - "com_github_jnr_jnr_constants_0_10_4": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_jnr_jnr_constants_0_10_4", - "sha256": "9a5b8cf9798d9d0331b8d8966c5235a22c4307676e35803a24659e6d76096f78", - "urls": [ - "https://repo1.maven.org/maven2/com/github/jnr/jnr-constants/0.10.4/jnr-constants-0.10.4.jar" - ], - "downloaded_file_path": "com/github/jnr/jnr-constants/0.10.4/jnr-constants-0.10.4.jar" - } - }, - "com_kohlschutter_junixsocket_junixsocket_common_2_6_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_kohlschutter_junixsocket_junixsocket_common_2_6_1", - "sha256": "93d120e2d49ddf5bfdee8258762fc874b26c657f027f8d6ccc1a055156bfcde1", - "urls": [ - "https://repo1.maven.org/maven2/com/kohlschutter/junixsocket/junixsocket-common/2.6.1/junixsocket-common-2.6.1.jar" - ], - "downloaded_file_path": "com/kohlschutter/junixsocket/junixsocket-common/2.6.1/junixsocket-common-2.6.1.jar" - } - }, - "com_fasterxml_jackson_jaxrs_jackson_jaxrs_json_provider_2_10_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_jaxrs_jackson_jaxrs_json_provider_2_10_3", - "sha256": "93026591dbb332030dbe865b9c811a016e470d8ff6daaa7031556d2185e62054", - "urls": [ - "https://repo1.maven.org/maven2/com/fasterxml/jackson/jaxrs/jackson-jaxrs-json-provider/2.10.3/jackson-jaxrs-json-provider-2.10.3.jar" - ], - "downloaded_file_path": "com/fasterxml/jackson/jaxrs/jackson-jaxrs-json-provider/2.10.3/jackson-jaxrs-json-provider-2.10.3.jar" - } - }, - "io_prometheus_simpleclient_tracer_common_0_15_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_tracer_common_0_15_0", - "sha256": "1baef082e619c06262e23de1b46ad35eb4df36ceb19be06ac7ef32a9833e12a4", - "urls": [ - "https://repo1.maven.org/maven2/io/prometheus/simpleclient_tracer_common/0.15.0/simpleclient_tracer_common-0.15.0.jar" - ], - "downloaded_file_path": "io/prometheus/simpleclient_tracer_common/0.15.0/simpleclient_tracer_common-0.15.0.jar" - } - }, - "com_google_code_findbugs_jsr305_3_0_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_code_findbugs_jsr305_3_0_2", - "sha256": "766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7", - "urls": [ - "https://repo1.maven.org/maven2/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar" - ], - "downloaded_file_path": "com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar" - } - }, - "com_fasterxml_jackson_core_jackson_core_2_14_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_core_jackson_core_2_14_2", - "sha256": "b5d37a77c88277b97e3593c8740925216c06df8e4172bbde058528df04ad3e7a", - "urls": [ - "https://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-core/2.14.2/jackson-core-2.14.2.jar", - "https://maven.google.com/com/fasterxml/jackson/core/jackson-core/2.14.2/jackson-core-2.14.2.jar" - ], - "downloaded_file_path": "com/fasterxml/jackson/core/jackson-core/2.14.2/jackson-core-2.14.2.jar" - } - }, - "com_github_jnr_jnr_ffi_jar_sources_2_2_14": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_jnr_jnr_ffi_jar_sources_2_2_14", - "sha256": "07f3eca123769c9aaeadd2f8d05a3ac3ed009a41b52f77efd12487112d7482f5", - "urls": [ - "https://repo1.maven.org/maven2/com/github/jnr/jnr-ffi/2.2.14/jnr-ffi-2.2.14-sources.jar" - ], - "downloaded_file_path": "com/github/jnr/jnr-ffi/2.2.14/jnr-ffi-2.2.14-sources.jar" - } - }, - "com_github_ben_manes_caffeine_caffeine": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_ben_manes_caffeine_caffeine", - "generating_repository": "maven", - "target_name": "com_github_ben_manes_caffeine_caffeine" - } - }, - "com_google_http_client_google_http_client_gson_1_42_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_http_client_google_http_client_gson_1_42_3", - "sha256": "8196efaa89c5f73b00b2b48edad02fcd78524259407c37ab1860737988545cee", - "urls": [ - "https://repo1.maven.org/maven2/com/google/http-client/google-http-client-gson/1.42.3/google-http-client-gson-1.42.3.jar" - ], - "downloaded_file_path": "com/google/http-client/google-http-client-gson/1.42.3/google-http-client-gson-1.42.3.jar" - } - }, - "io_grpc_grpc_api": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_api", - "generating_repository": "maven", - "target_name": "io_grpc_grpc_api" - } - }, - "com_google_errorprone_error_prone_annotation_2_22_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_errorprone_error_prone_annotation_2_22_0", - "sha256": "554c42449c9920ea1f6baec1d1b8aaac404a88be653f7cb441ee059316f8a1d1", - "urls": [ - "https://repo1.maven.org/maven2/com/google/errorprone/error_prone_annotation/2.22.0/error_prone_annotation-2.22.0.jar" - ], - "downloaded_file_path": "com/google/errorprone/error_prone_annotation/2.22.0/error_prone_annotation-2.22.0.jar" - } - }, - "org_glassfish_hk2_osgi_resource_locator_1_0_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_glassfish_hk2_osgi_resource_locator_1_0_3", - "sha256": "aab5d7849f7cfcda2cc7c541ba1bd365151d42276f151c825387245dfde3dd74", - "urls": [ - "https://repo1.maven.org/maven2/org/glassfish/hk2/osgi-resource-locator/1.0.3/osgi-resource-locator-1.0.3.jar" - ], - "downloaded_file_path": "org/glassfish/hk2/osgi-resource-locator/1.0.3/osgi-resource-locator-1.0.3.jar" - } - }, - "javax_annotation_javax_annotation_api_jar_sources_1_3_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~javax_annotation_javax_annotation_api_jar_sources_1_3_2", - "sha256": "128971e52e0d84a66e3b6e049dab8ad7b2c58b7e1ad37fa2debd3d40c2947b95", - "urls": [ - "https://repo1.maven.org/maven2/javax/annotation/javax.annotation-api/1.3.2/javax.annotation-api-1.3.2-sources.jar" - ], - "downloaded_file_path": "javax/annotation/javax.annotation-api/1.3.2/javax.annotation-api-1.3.2-sources.jar" - } - }, - "org_openjdk_jmh_jmh_core_jar_sources_1_37": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_openjdk_jmh_jmh_core_jar_sources_1_37", - "sha256": "fd4beda07b3b94cd0e32199401bbb2d9ed3371a770c8c320761b9442ff3e8e05", - "urls": [ - "https://repo1.maven.org/maven2/org/openjdk/jmh/jmh-core/1.37/jmh-core-1.37-sources.jar" - ], - "downloaded_file_path": "org/openjdk/jmh/jmh-core/1.37/jmh-core-1.37-sources.jar" - } - }, - "com_github_serceman_jnr_fuse_0_5_7": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_serceman_jnr_fuse_0_5_7", - "sha256": "ebe81ccbcbe1464996e5213ee24947cfba9eda7e9ffe154333f9bd8321217989", - "urls": [ - "https://repo1.maven.org/maven2/com/github/serceman/jnr-fuse/0.5.7/jnr-fuse-0.5.7.jar" - ], - "downloaded_file_path": "com/github/serceman/jnr-fuse/0.5.7/jnr-fuse-0.5.7.jar" - } - }, - "org_openjdk_jmh_jmh_generator_annprocess_jar_sources_1_37": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_openjdk_jmh_jmh_generator_annprocess_jar_sources_1_37", - "sha256": "cc1b661fb209ae1a433e331e8e78bab680674153b0a6ac69d47d11c60fb5e47e", - "urls": [ - "https://repo1.maven.org/maven2/org/openjdk/jmh/jmh-generator-annprocess/1.37/jmh-generator-annprocess-1.37-sources.jar" - ], - "downloaded_file_path": "org/openjdk/jmh/jmh-generator-annprocess/1.37/jmh-generator-annprocess-1.37-sources.jar" - } - }, - "org_yaml_snakeyaml": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_yaml_snakeyaml", - "generating_repository": "maven", - "target_name": "org_yaml_snakeyaml" - } - }, - "com_google_auto_value_auto_value_annotations_jar_sources_1_10_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_auto_value_auto_value_annotations_jar_sources_1_10_1", - "sha256": "44e6ce2884c18869422765b238f7f173faccd24643fabb5e95597382e80d50a8", - "urls": [ - "https://repo1.maven.org/maven2/com/google/auto/value/auto-value-annotations/1.10.1/auto-value-annotations-1.10.1-sources.jar" - ], - "downloaded_file_path": "com/google/auto/value/auto-value-annotations/1.10.1/auto-value-annotations-1.10.1-sources.jar" - } - }, - "io_grpc_grpc_rls_1_55_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_rls_1_55_1", - "sha256": "f828087440c2f6b274e196b21a6fb38db60648724c1be450f4d0ed991d819a6f", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-rls/1.55.1/grpc-rls-1.55.1.jar", - "https://maven.google.com/io/grpc/grpc-rls/1.55.1/grpc-rls-1.55.1.jar" - ], - "downloaded_file_path": "io/grpc/grpc-rls/1.55.1/grpc-rls-1.55.1.jar" - } - }, - "jakarta_xml_bind_jakarta_xml_bind_api_jar_sources_2_3_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~jakarta_xml_bind_jakarta_xml_bind_api_jar_sources_2_3_2", - "sha256": "61ceb3ed35ecf99f1803eac9c4b8f12103c7531952beae38ba53cc727f405532", - "urls": [ - "https://repo1.maven.org/maven2/jakarta/xml/bind/jakarta.xml.bind-api/2.3.2/jakarta.xml.bind-api-2.3.2-sources.jar" - ], - "downloaded_file_path": "jakarta/xml/bind/jakarta.xml.bind-api/2.3.2/jakarta.xml.bind-api-2.3.2-sources.jar" - } - }, - "com_google_googlejavaformat_google_java_format_1_17_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_googlejavaformat_google_java_format_1_17_0", - "sha256": "631ba54c39f6c20df027dc1420736df2e5e43c581880efdd1e46ddb4ce050e3e", - "urls": [ - "https://repo1.maven.org/maven2/com/google/googlejavaformat/google-java-format/1.17.0/google-java-format-1.17.0.jar", - "https://maven.google.com/com/google/googlejavaformat/google-java-format/1.17.0/google-java-format-1.17.0.jar" - ], - "downloaded_file_path": "com/google/googlejavaformat/google-java-format/1.17.0/google-java-format-1.17.0.jar" - } - }, - "org_jboss_marshalling_jboss_marshalling_jar_sources_2_0_11_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_jboss_marshalling_jboss_marshalling_jar_sources_2_0_11_Final", - "sha256": "4e9b508e3423fb82a33e72c77fd4fe63f108f167fa648d50a933b1b71d9084f2", - "urls": [ - "https://repo1.maven.org/maven2/org/jboss/marshalling/jboss-marshalling/2.0.11.Final/jboss-marshalling-2.0.11.Final-sources.jar" - ], - "downloaded_file_path": "org/jboss/marshalling/jboss-marshalling/2.0.11.Final/jboss-marshalling-2.0.11.Final-sources.jar" - } - }, - "com_google_guava_failureaccess_1_0_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_guava_failureaccess_1_0_1", - "sha256": "a171ee4c734dd2da837e4b16be9df4661afab72a41adaf31eb84dfdaf936ca26", - "urls": [ - "https://repo1.maven.org/maven2/com/google/guava/failureaccess/1.0.1/failureaccess-1.0.1.jar" - ], - "downloaded_file_path": "com/google/guava/failureaccess/1.0.1/failureaccess-1.0.1.jar" - } - }, - "io_perfmark_perfmark_api_0_26_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_perfmark_perfmark_api_0_26_0", - "sha256": "b7d23e93a34537ce332708269a0d1404788a5b5e1949e82f5535fce51b3ea95b", - "urls": [ - "https://repo1.maven.org/maven2/io/perfmark/perfmark-api/0.26.0/perfmark-api-0.26.0.jar" - ], - "downloaded_file_path": "io/perfmark/perfmark-api/0.26.0/perfmark-api-0.26.0.jar" - } - }, - "commons_codec_commons_codec_jar_sources_1_15": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~commons_codec_commons_codec_jar_sources_1_15", - "sha256": "7019940b2298d333edb946e2db3d10f1caacbbd52bb64e85832cfd0017e049cc", - "urls": [ - "https://repo1.maven.org/maven2/commons-codec/commons-codec/1.15/commons-codec-1.15-sources.jar" - ], - "downloaded_file_path": "commons-codec/commons-codec/1.15/commons-codec-1.15-sources.jar" - } - }, - "io_netty_netty_codec_http_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_http_4_1_97_Final", - "sha256": "7d6cad9cbd015e41f69787ce6a34beeba032b381e32e88207908431dc812778a", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-codec-http/4.1.97.Final/netty-codec-http-4.1.97.Final.jar" - ], - "downloaded_file_path": "io/netty/netty-codec-http/4.1.97.Final/netty-codec-http-4.1.97.Final.jar" - } - }, - "io_netty_netty_codec_http2_jar_sources_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_http2_jar_sources_4_1_97_Final", - "sha256": "7d8c2ec86545a19ccca24009809027f1745bc8339c8a97bcdc5833abd58e2ab3", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-codec-http2/4.1.97.Final/netty-codec-http2-4.1.97.Final-sources.jar" - ], - "downloaded_file_path": "io/netty/netty-codec-http2/4.1.97.Final/netty-codec-http2-4.1.97.Final-sources.jar" - } - }, - "software_amazon_awssdk_protocol_core_2_20_78": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_protocol_core_2_20_78", - "sha256": "9ae1459ad8bd5b6167997985ec7afebf9fc1105a3d727d8b485b276b5c2fbddb", - "urls": [ - "https://repo1.maven.org/maven2/software/amazon/awssdk/protocol-core/2.20.78/protocol-core-2.20.78.jar", - "https://maven.google.com/software/amazon/awssdk/protocol-core/2.20.78/protocol-core-2.20.78.jar" - ], - "downloaded_file_path": "software/amazon/awssdk/protocol-core/2.20.78/protocol-core-2.20.78.jar" - } - }, - "io_netty_netty_resolver_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_resolver_4_1_97_Final", - "sha256": "38a018c6d9fb2cb11b72881354782b45080bbd20b9a0ad6cde28b80d431ed0b1", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-resolver/4.1.97.Final/netty-resolver-4.1.97.Final.jar" - ], - "downloaded_file_path": "io/netty/netty-resolver/4.1.97.Final/netty-resolver-4.1.97.Final.jar" - } - }, - "io_grpc_grpc_context_1_56_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_context_1_56_1", - "sha256": "3d442ce08bfb1b487edf76d12e2dfd991c3877af32cf772a83c73d06f89743bc", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-context/1.56.1/grpc-context-1.56.1.jar" - ], - "downloaded_file_path": "io/grpc/grpc-context/1.56.1/grpc-context-1.56.1.jar" - } - }, - "io_prometheus_simpleclient_httpserver_jar_sources_0_15_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_httpserver_jar_sources_0_15_0", - "sha256": "b06cfea384c1a0e7d233c9325eb62d9ea4d144a744ce7991a5a96ef8bb5a361e", - "urls": [ - "https://repo1.maven.org/maven2/io/prometheus/simpleclient_httpserver/0.15.0/simpleclient_httpserver-0.15.0-sources.jar" - ], - "downloaded_file_path": "io/prometheus/simpleclient_httpserver/0.15.0/simpleclient_httpserver-0.15.0-sources.jar" - } - }, - "com_google_api_gax_httpjson_0_113_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_api_gax_httpjson_0_113_1", - "sha256": "f7e4e84caa6577466fc828858193667135b291da044f007eafde99c0f929b781", - "urls": [ - "https://repo1.maven.org/maven2/com/google/api/gax-httpjson/0.113.1/gax-httpjson-0.113.1.jar", - "https://maven.google.com/com/google/api/gax-httpjson/0.113.1/gax-httpjson-0.113.1.jar" - ], - "downloaded_file_path": "com/google/api/gax-httpjson/0.113.1/gax-httpjson-0.113.1.jar" - } - }, - "jakarta_ws_rs_jakarta_ws_rs_api_jar_sources_2_1_6": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~jakarta_ws_rs_jakarta_ws_rs_api_jar_sources_2_1_6", - "sha256": "5fb0591472e00439db7d1511caa40a39cda42e24b0bade6378f880384b7cc073", - "urls": [ - "https://repo1.maven.org/maven2/jakarta/ws/rs/jakarta.ws.rs-api/2.1.6/jakarta.ws.rs-api-2.1.6-sources.jar" - ], - "downloaded_file_path": "jakarta/ws/rs/jakarta.ws.rs-api/2.1.6/jakarta.ws.rs-api-2.1.6-sources.jar" - } - }, - "org_objenesis_objenesis_3_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_objenesis_objenesis_3_3", - "sha256": "02dfd0b0439a5591e35b708ed2f5474eb0948f53abf74637e959b8e4ef69bfeb", - "urls": [ - "https://repo1.maven.org/maven2/org/objenesis/objenesis/3.3/objenesis-3.3.jar" - ], - "downloaded_file_path": "org/objenesis/objenesis/3.3/objenesis-3.3.jar" - } - }, - "org_openjdk_jmh_jmh_generator_annprocess": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_openjdk_jmh_jmh_generator_annprocess", - "generating_repository": "maven", - "target_name": "org_openjdk_jmh_jmh_generator_annprocess" - } - }, - "com_amazonaws_aws_java_sdk_s3_jar_sources_1_12_544": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_amazonaws_aws_java_sdk_s3_jar_sources_1_12_544", - "sha256": "b91ef0fec99308cb3216fac69f9bb1a84149f05ab9b59e705107f492c02b4f64", - "urls": [ - "https://repo1.maven.org/maven2/com/amazonaws/aws-java-sdk-s3/1.12.544/aws-java-sdk-s3-1.12.544-sources.jar" - ], - "downloaded_file_path": "com/amazonaws/aws-java-sdk-s3/1.12.544/aws-java-sdk-s3-1.12.544-sources.jar" - } - }, - "com_github_docker_java_docker_java_transport_jersey_jar_sources_3_3_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_docker_java_docker_java_transport_jersey_jar_sources_3_3_3", - "sha256": "05a26581bdde6519c4d87aaae7569eebd713f5fda9f8fa28b51216d2d364a18b", - "urls": [ - "https://repo1.maven.org/maven2/com/github/docker-java/docker-java-transport-jersey/3.3.3/docker-java-transport-jersey-3.3.3-sources.jar" - ], - "downloaded_file_path": "com/github/docker-java/docker-java-transport-jersey/3.3.3/docker-java-transport-jersey-3.3.3-sources.jar" - } - }, - "io_netty_netty_transport_native_unix_common_jar_sources_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_native_unix_common_jar_sources_4_1_97_Final", - "sha256": "de1ea25a58fadbfa64061769281797cc9b133a48d0a039015d5b3d8f16cbfddc", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-transport-native-unix-common/4.1.97.Final/netty-transport-native-unix-common-4.1.97.Final-sources.jar" - ], - "downloaded_file_path": "io/netty/netty-transport-native-unix-common/4.1.97.Final/netty-transport-native-unix-common-4.1.97.Final-sources.jar" - } - }, - "org_codehaus_mojo_animal_sniffer_annotations_1_23": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_codehaus_mojo_animal_sniffer_annotations_1_23", - "sha256": "9ffe526bf43a6348e9d8b33b9cd6f580a7f5eed0cf055913007eda263de974d0", - "urls": [ - "https://repo1.maven.org/maven2/org/codehaus/mojo/animal-sniffer-annotations/1.23/animal-sniffer-annotations-1.23.jar" - ], - "downloaded_file_path": "org/codehaus/mojo/animal-sniffer-annotations/1.23/animal-sniffer-annotations-1.23.jar" - } - }, - "net_sf_jopt_simple_jopt_simple_jar_sources_5_0_4": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~net_sf_jopt_simple_jopt_simple_jar_sources_5_0_4", - "sha256": "06b283801a5a94ef697b7f2c79a048c4e2f848b3daddda61cab74d882bdd97a5", - "urls": [ - "https://repo1.maven.org/maven2/net/sf/jopt-simple/jopt-simple/5.0.4/jopt-simple-5.0.4-sources.jar" - ], - "downloaded_file_path": "net/sf/jopt-simple/jopt-simple/5.0.4/jopt-simple-5.0.4-sources.jar" - } - }, - "com_fasterxml_jackson_dataformat_jackson_dataformat_cbor_2_12_6": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_dataformat_jackson_dataformat_cbor_2_12_6", - "sha256": "cfa008d15f052e69221e8c3193056ff95c3c594271321ccac8d72dc1a770619c", - "urls": [ - "https://repo1.maven.org/maven2/com/fasterxml/jackson/dataformat/jackson-dataformat-cbor/2.12.6/jackson-dataformat-cbor-2.12.6.jar" - ], - "downloaded_file_path": "com/fasterxml/jackson/dataformat/jackson-dataformat-cbor/2.12.6/jackson-dataformat-cbor-2.12.6.jar" - } - }, - "io_grpc_grpc_core_1_55_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_core_1_55_1", - "sha256": "c4782555fefb61c72898759a7d11f5f221811935bcf983efb478d796228b65dc", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-core/1.55.1/grpc-core-1.55.1.jar", - "https://maven.google.com/io/grpc/grpc-core/1.55.1/grpc-core-1.55.1.jar" - ], - "downloaded_file_path": "io/grpc/grpc-core/1.55.1/grpc-core-1.55.1.jar" - } - }, - "com_kohlschutter_junixsocket_junixsocket_native_common_jar_sources_2_6_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_kohlschutter_junixsocket_junixsocket_native_common_jar_sources_2_6_1", - "sha256": "4cef32dce262263e247d783f4ed7d90c5376190321e829ba5e985a8a27fbda06", - "urls": [ - "https://repo1.maven.org/maven2/com/kohlschutter/junixsocket/junixsocket-native-common/2.6.1/junixsocket-native-common-2.6.1-sources.jar" - ], - "downloaded_file_path": "com/kohlschutter/junixsocket/junixsocket-native-common/2.6.1/junixsocket-native-common-2.6.1-sources.jar" - } - }, - "io_netty_netty_transport_native_kqueue_jar_osx_x86_64_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_native_kqueue_jar_osx_x86_64_4_1_97_Final", - "sha256": "6870051aca7fa4dc5d0f2938036215a269504c50d2e36c4af38fd00d22ad7d95", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-transport-native-kqueue/4.1.97.Final/netty-transport-native-kqueue-4.1.97.Final-osx-x86_64.jar" - ], - "downloaded_file_path": "io/netty/netty-transport-native-kqueue/4.1.97.Final/netty-transport-native-kqueue-4.1.97.Final-osx-x86_64.jar" - } - }, - "io_reactivex_rxjava3_rxjava_jar_sources_3_1_6": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_reactivex_rxjava3_rxjava_jar_sources_3_1_6", - "sha256": "4479ead52c21dbfeb23646e378f77b7b396eda170619027d4213975e368b14ca", - "urls": [ - "https://repo1.maven.org/maven2/io/reactivex/rxjava3/rxjava/3.1.6/rxjava-3.1.6-sources.jar" - ], - "downloaded_file_path": "io/reactivex/rxjava3/rxjava/3.1.6/rxjava-3.1.6-sources.jar" - } - }, - "com_google_api_grpc_grpc_google_cloud_storage_v2_2_22_3_alpha": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_api_grpc_grpc_google_cloud_storage_v2_2_22_3_alpha", - "sha256": "c62c1c54e44d9e4622bd6f7f1285f8456efd50880c1e6d107f5e6680033138d0", - "urls": [ - "https://repo1.maven.org/maven2/com/google/api/grpc/grpc-google-cloud-storage-v2/2.22.3-alpha/grpc-google-cloud-storage-v2-2.22.3-alpha.jar", - "https://maven.google.com/com/google/api/grpc/grpc-google-cloud-storage-v2/2.22.3-alpha/grpc-google-cloud-storage-v2-2.22.3-alpha.jar" - ], - "downloaded_file_path": "com/google/api/grpc/grpc-google-cloud-storage-v2/2.22.3-alpha/grpc-google-cloud-storage-v2-2.22.3-alpha.jar" - } - }, - "com_github_jnr_jnr_posix_jar_sources_3_1_17": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_jnr_jnr_posix_jar_sources_3_1_17", - "sha256": "91c102c59c1d775adbd65353f5a795c4f48f6a8546a1845c679100fd5336db23", - "urls": [ - "https://repo1.maven.org/maven2/com/github/jnr/jnr-posix/3.1.17/jnr-posix-3.1.17-sources.jar" - ], - "downloaded_file_path": "com/github/jnr/jnr-posix/3.1.17/jnr-posix-3.1.17-sources.jar" - } - }, - "com_google_protobuf_protobuf_java_util_jar_sources_3_22_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_protobuf_protobuf_java_util_jar_sources_3_22_3", - "sha256": "5bb8af97af2131a2594c836baf3aadc0fd9640bdcf386c99bab901f6065e518f", - "urls": [ - "https://repo1.maven.org/maven2/com/google/protobuf/protobuf-java-util/3.22.3/protobuf-java-util-3.22.3-sources.jar" - ], - "downloaded_file_path": "com/google/protobuf/protobuf-java-util/3.22.3/protobuf-java-util-3.22.3-sources.jar" - } - }, - "org_glassfish_hk2_hk2_api_2_6_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_glassfish_hk2_hk2_api_2_6_1", - "sha256": "c2cb80a01e58440ae57d5ee59af4d4d94e5180e04aff112b0cb611c07d61e773", - "urls": [ - "https://repo1.maven.org/maven2/org/glassfish/hk2/hk2-api/2.6.1/hk2-api-2.6.1.jar" - ], - "downloaded_file_path": "org/glassfish/hk2/hk2-api/2.6.1/hk2-api-2.6.1.jar" - } - }, - "com_fasterxml_jackson_module_jackson_module_jaxb_annotations_2_10_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_module_jackson_module_jaxb_annotations_2_10_3", - "sha256": "8099caad4ae189525ef94d337d72d3e888abefabbbacbc9f3d2f096d534f2fb5", - "urls": [ - "https://repo1.maven.org/maven2/com/fasterxml/jackson/module/jackson-module-jaxb-annotations/2.10.3/jackson-module-jaxb-annotations-2.10.3.jar" - ], - "downloaded_file_path": "com/fasterxml/jackson/module/jackson-module-jaxb-annotations/2.10.3/jackson-module-jaxb-annotations-2.10.3.jar" - } - }, - "org_apache_httpcomponents_httpclient_jar_sources_4_5_13": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_apache_httpcomponents_httpclient_jar_sources_4_5_13", - "sha256": "b1e9194fd83ce135831e28346731d9644cb2a08dea37ada2aa56ceb8f1b0c566", - "urls": [ - "https://repo1.maven.org/maven2/org/apache/httpcomponents/httpclient/4.5.13/httpclient-4.5.13-sources.jar" - ], - "downloaded_file_path": "org/apache/httpcomponents/httpclient/4.5.13/httpclient-4.5.13-sources.jar" - } - }, - "com_google_api_grpc_proto_google_iam_v1_1_14_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_api_grpc_proto_google_iam_v1_1_14_1", - "sha256": "65929519b53c68a1fba00091e34e441e11ee532bbe3790873f2b9e26f81cf98a", - "urls": [ - "https://repo1.maven.org/maven2/com/google/api/grpc/proto-google-iam-v1/1.14.1/proto-google-iam-v1-1.14.1.jar", - "https://maven.google.com/com/google/api/grpc/proto-google-iam-v1/1.14.1/proto-google-iam-v1-1.14.1.jar" - ], - "downloaded_file_path": "com/google/api/grpc/proto-google-iam-v1/1.14.1/proto-google-iam-v1-1.14.1.jar" - } - }, - "software_amazon_awssdk_netty_nio_client_2_20_78": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_netty_nio_client_2_20_78", - "sha256": "56999d51ff6b3efdb5b09241a126a466c96f3d93f629e94b2db5634da2b6c659", - "urls": [ - "https://repo1.maven.org/maven2/software/amazon/awssdk/netty-nio-client/2.20.78/netty-nio-client-2.20.78.jar", - "https://maven.google.com/software/amazon/awssdk/netty-nio-client/2.20.78/netty-nio-client-2.20.78.jar" - ], - "downloaded_file_path": "software/amazon/awssdk/netty-nio-client/2.20.78/netty-nio-client-2.20.78.jar" - } - }, - "com_esotericsoftware_kryo_jar_sources_5_5_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_esotericsoftware_kryo_jar_sources_5_5_0", - "sha256": "a7fe17d9e5c3f18ba2070b1356aeafc3f1626e8ebb6161a70d84c2f17adcd072", - "urls": [ - "https://repo1.maven.org/maven2/com/esotericsoftware/kryo/5.5.0/kryo-5.5.0-sources.jar" - ], - "downloaded_file_path": "com/esotericsoftware/kryo/5.5.0/kryo-5.5.0-sources.jar" - } - }, - "org_mockito_mockito_core": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_mockito_mockito_core", - "generating_repository": "maven", - "target_name": "org_mockito_mockito_core" - } - }, - "io_grpc_grpc_context_1_55_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_context_1_55_1", - "sha256": "541ec1d7ad3389f0b302461432a44b16fc1329153cd0e16faf2d2028b446340d", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-context/1.55.1/grpc-context-1.55.1.jar", - "https://maven.google.com/io/grpc/grpc-context/1.55.1/grpc-context-1.55.1.jar" - ], - "downloaded_file_path": "io/grpc/grpc-context/1.55.1/grpc-context-1.55.1.jar" - } - }, - "com_google_jimfs_jimfs_1_3_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_jimfs_jimfs_1_3_0", - "sha256": "82494408bb513f5512652e7b7f63d6f31f01eff57ce35c878644ffc2d25aee4f", - "urls": [ - "https://repo1.maven.org/maven2/com/google/jimfs/jimfs/1.3.0/jimfs-1.3.0.jar" - ], - "downloaded_file_path": "com/google/jimfs/jimfs/1.3.0/jimfs-1.3.0.jar" - } - }, - "org_ow2_asm_asm_analysis_9_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_ow2_asm_asm_analysis_9_2", - "sha256": "878fbe521731c072d14d2d65b983b1beae6ad06fda0007b6a8bae81f73f433c4", - "urls": [ - "https://repo1.maven.org/maven2/org/ow2/asm/asm-analysis/9.2/asm-analysis-9.2.jar" - ], - "downloaded_file_path": "org/ow2/asm/asm-analysis/9.2/asm-analysis-9.2.jar" - } - }, - "com_esotericsoftware_reflectasm_jar_sources_1_11_9": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_esotericsoftware_reflectasm_jar_sources_1_11_9", - "sha256": "8fc29f5069a1a43c38eb28b54f6850995734f31962813b13ac8a9b7a0624b45b", - "urls": [ - "https://repo1.maven.org/maven2/com/esotericsoftware/reflectasm/1.11.9/reflectasm-1.11.9-sources.jar" - ], - "downloaded_file_path": "com/esotericsoftware/reflectasm/1.11.9/reflectasm-1.11.9-sources.jar" - } - }, - "net_bytebuddy_byte_buddy_agent_jar_sources_1_9_7": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~net_bytebuddy_byte_buddy_agent_jar_sources_1_9_7", - "sha256": "f1ffcb60fb0cb3de2ab4ba36b3588f9c0f12b24e8eeb59f76c57664f42eaae80", - "urls": [ - "https://repo1.maven.org/maven2/net/bytebuddy/byte-buddy-agent/1.9.7/byte-buddy-agent-1.9.7-sources.jar" - ], - "downloaded_file_path": "net/bytebuddy/byte-buddy-agent/1.9.7/byte-buddy-agent-1.9.7-sources.jar" - } - }, - "org_mockito_mockito_core_2_25_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_mockito_mockito_core_2_25_0", - "sha256": "28028d70cc27d61442948fcb3d249d9df5b37c47aa0b82490a3d049094ff411f", - "urls": [ - "https://repo1.maven.org/maven2/org/mockito/mockito-core/2.25.0/mockito-core-2.25.0.jar" - ], - "downloaded_file_path": "org/mockito/mockito-core/2.25.0/mockito-core-2.25.0.jar" - } - }, - "com_google_auth_google_auth_library_oauth2_http_1_17_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_auth_google_auth_library_oauth2_http_1_17_0", - "sha256": "b8148e1af0c4197aea707d0166b4ed70a75b8eee7246be7eb0228a4834095e70", - "urls": [ - "https://repo1.maven.org/maven2/com/google/auth/google-auth-library-oauth2-http/1.17.0/google-auth-library-oauth2-http-1.17.0.jar", - "https://maven.google.com/com/google/auth/google-auth-library-oauth2-http/1.17.0/google-auth-library-oauth2-http-1.17.0.jar" - ], - "downloaded_file_path": "com/google/auth/google-auth-library-oauth2-http/1.17.0/google-auth-library-oauth2-http-1.17.0.jar" - } - }, - "io_netty_netty_buffer": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_buffer", - "generating_repository": "maven", - "target_name": "io_netty_netty_buffer" - } - }, - "com_amazonaws_jmespath_java_1_12_544": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_amazonaws_jmespath_java_1_12_544", - "sha256": "b707d67e8fcc87ffdf426bbe61bbe60ae97e865d35d6cec429a934d47fa2976c", - "urls": [ - "https://repo1.maven.org/maven2/com/amazonaws/jmespath-java/1.12.544/jmespath-java-1.12.544.jar" - ], - "downloaded_file_path": "com/amazonaws/jmespath-java/1.12.544/jmespath-java-1.12.544.jar" - } - }, - "com_google_errorprone_error_prone_check_api_jar_sources_2_22_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_errorprone_error_prone_check_api_jar_sources_2_22_0", - "sha256": "962656ccdd75e0f9891f5fbc5c53ea1ea381234eaadee50d3d04bafc094f0190", - "urls": [ - "https://repo1.maven.org/maven2/com/google/errorprone/error_prone_check_api/2.22.0/error_prone_check_api-2.22.0-sources.jar" - ], - "downloaded_file_path": "com/google/errorprone/error_prone_check_api/2.22.0/error_prone_check_api-2.22.0-sources.jar" - } - }, - "org_glassfish_hk2_osgi_resource_locator_jar_sources_1_0_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_glassfish_hk2_osgi_resource_locator_jar_sources_1_0_3", - "sha256": "603d0e07134189505c76a8c8d5d4451a91bf1327a05f1f5bcea09bad61bd507e", - "urls": [ - "https://repo1.maven.org/maven2/org/glassfish/hk2/osgi-resource-locator/1.0.3/osgi-resource-locator-1.0.3-sources.jar" - ], - "downloaded_file_path": "org/glassfish/hk2/osgi-resource-locator/1.0.3/osgi-resource-locator-1.0.3-sources.jar" - } - }, - "io_opencensus_opencensus_contrib_http_util_jar_sources_0_31_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_opencensus_opencensus_contrib_http_util_jar_sources_0_31_1", - "sha256": "d55afd5f96dc724bd903a77a38b0a344d0e59f02a64b9ab2f32618bc582ea924", - "urls": [ - "https://repo1.maven.org/maven2/io/opencensus/opencensus-contrib-http-util/0.31.1/opencensus-contrib-http-util-0.31.1-sources.jar" - ], - "downloaded_file_path": "io/opencensus/opencensus-contrib-http-util/0.31.1/opencensus-contrib-http-util-0.31.1-sources.jar" - } - }, - "io_grpc_grpc_testing_jar_sources_1_56_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_testing_jar_sources_1_56_1", - "sha256": "0e1ee432e6ec26940bce1726d47344772ba2afd60af93750d0fad54596c936ee", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-testing/1.56.1/grpc-testing-1.56.1-sources.jar" - ], - "downloaded_file_path": "io/grpc/grpc-testing/1.56.1/grpc-testing-1.56.1-sources.jar" - } - }, - "io_prometheus_simpleclient_tracer_otel_0_15_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_tracer_otel_0_15_0", - "sha256": "0595251da49aa7997777b365ffdf97f5e2e88cd7f0dacf49add91b4fc8222b50", - "urls": [ - "https://repo1.maven.org/maven2/io/prometheus/simpleclient_tracer_otel/0.15.0/simpleclient_tracer_otel-0.15.0.jar" - ], - "downloaded_file_path": "io/prometheus/simpleclient_tracer_otel/0.15.0/simpleclient_tracer_otel-0.15.0.jar" - } - }, - "org_apache_httpcomponents_httpclient_4_5_13": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_apache_httpcomponents_httpclient_4_5_13", - "sha256": "6fe9026a566c6a5001608cf3fc32196641f6c1e5e1986d1037ccdbd5f31ef743", - "urls": [ - "https://repo1.maven.org/maven2/org/apache/httpcomponents/httpclient/4.5.13/httpclient-4.5.13.jar" - ], - "downloaded_file_path": "org/apache/httpcomponents/httpclient/4.5.13/httpclient-4.5.13.jar" - } - }, - "org_apache_httpcomponents_httpclient_4_5_14": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_apache_httpcomponents_httpclient_4_5_14", - "sha256": "c8bc7e1c51a6d4ce72f40d2ebbabf1c4b68bfe76e732104b04381b493478e9d6", - "urls": [ - "https://repo1.maven.org/maven2/org/apache/httpcomponents/httpclient/4.5.14/httpclient-4.5.14.jar", - "https://maven.google.com/org/apache/httpcomponents/httpclient/4.5.14/httpclient-4.5.14.jar" - ], - "downloaded_file_path": "org/apache/httpcomponents/httpclient/4.5.14/httpclient-4.5.14.jar" - } - }, - "com_google_guava_guava_jar_sources_32_1_1_jre": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_guava_guava_jar_sources_32_1_1_jre", - "sha256": "5e7b6cebd2e9087a536c1054bf52a2e6a49c284772421f146640cfadc54ba573", - "urls": [ - "https://repo1.maven.org/maven2/com/google/guava/guava/32.1.1-jre/guava-32.1.1-jre-sources.jar" - ], - "downloaded_file_path": "com/google/guava/guava/32.1.1-jre/guava-32.1.1-jre-sources.jar" - } - }, - "com_github_docker_java_docker_java_api_3_3_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_docker_java_docker_java_api_3_3_3", - "sha256": "8be2f41ddc33306b83f91e413fc1a07cee02db05e4c493456de3399e5bcb7b6c", - "urls": [ - "https://repo1.maven.org/maven2/com/github/docker-java/docker-java-api/3.3.3/docker-java-api-3.3.3.jar" - ], - "downloaded_file_path": "com/github/docker-java/docker-java-api/3.3.3/docker-java-api-3.3.3.jar" - } - }, - "io_grpc_grpc_core_1_56_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_core_1_56_1", - "sha256": "fddeafc25019b7e5600028d6398e9ed7383056d9aecaf95aec5c39c5085a4830", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-core/1.56.1/grpc-core-1.56.1.jar" - ], - "downloaded_file_path": "io/grpc/grpc-core/1.56.1/grpc-core-1.56.1.jar" - } - }, - "com_kohlschutter_junixsocket_junixsocket_native_common_2_6_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_kohlschutter_junixsocket_junixsocket_native_common_2_6_1", - "sha256": "61fbbd6cfd2b6df65c0e7b19b16ff4f755d6cb1d333b566f4286407f12f18670", - "urls": [ - "https://repo1.maven.org/maven2/com/kohlschutter/junixsocket/junixsocket-native-common/2.6.1/junixsocket-native-common-2.6.1.jar" - ], - "downloaded_file_path": "com/kohlschutter/junixsocket/junixsocket-native-common/2.6.1/junixsocket-native-common-2.6.1.jar" - } - }, - "com_google_cloud_google_cloud_storage_2_22_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_cloud_google_cloud_storage_2_22_3", - "sha256": "a9b6e2cf02c37dd3a09ca4b2a091fd07eb5487b95995691df898ec223bdad5ab", - "urls": [ - "https://repo1.maven.org/maven2/com/google/cloud/google-cloud-storage/2.22.3/google-cloud-storage-2.22.3.jar", - "https://maven.google.com/com/google/cloud/google-cloud-storage/2.22.3/google-cloud-storage-2.22.3.jar" - ], - "downloaded_file_path": "com/google/cloud/google-cloud-storage/2.22.3/google-cloud-storage-2.22.3.jar" - } - }, - "io_prometheus_simpleclient_hotspot_jar_sources_0_15_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_hotspot_jar_sources_0_15_0", - "sha256": "352f4a0940814a22691132e6b7abcea4add6a8ce322b22a88be5494064036437", - "urls": [ - "https://repo1.maven.org/maven2/io/prometheus/simpleclient_hotspot/0.15.0/simpleclient_hotspot-0.15.0-sources.jar" - ], - "downloaded_file_path": "io/prometheus/simpleclient_hotspot/0.15.0/simpleclient_hotspot-0.15.0-sources.jar" - } - }, - "jakarta_xml_bind_jakarta_xml_bind_api_2_3_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~jakarta_xml_bind_jakarta_xml_bind_api_2_3_2", - "sha256": "69156304079bdeed9fc0ae3b39389f19b3cc4ba4443bc80508995394ead742ea", - "urls": [ - "https://repo1.maven.org/maven2/jakarta/xml/bind/jakarta.xml.bind-api/2.3.2/jakarta.xml.bind-api-2.3.2.jar" - ], - "downloaded_file_path": "jakarta/xml/bind/jakarta.xml.bind-api/2.3.2/jakarta.xml.bind-api-2.3.2.jar" - } - }, - "com_google_errorprone_error_prone_annotation_jar_sources_2_22_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_errorprone_error_prone_annotation_jar_sources_2_22_0", - "sha256": "45507d9cb6e18174656fd09f5a34033700ba75562bfcb188ec1706da10c10157", - "urls": [ - "https://repo1.maven.org/maven2/com/google/errorprone/error_prone_annotation/2.22.0/error_prone_annotation-2.22.0-sources.jar" - ], - "downloaded_file_path": "com/google/errorprone/error_prone_annotation/2.22.0/error_prone_annotation-2.22.0-sources.jar" - } - }, - "org_pcollections_pcollections_3_1_4": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_pcollections_pcollections_3_1_4", - "sha256": "34f579ba075c8da2c8a0fedd0f04e21eac2fb6c660d90d0fabb573e8b4dc6918", - "urls": [ - "https://repo1.maven.org/maven2/org/pcollections/pcollections/3.1.4/pcollections-3.1.4.jar" - ], - "downloaded_file_path": "org/pcollections/pcollections/3.1.4/pcollections-3.1.4.jar" - } - }, - "io_grpc_grpc_context": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_context", - "generating_repository": "maven", - "target_name": "io_grpc_grpc_context" - } - }, - "javax_cache_cache_api_1_1_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~javax_cache_cache_api_1_1_1", - "sha256": "9f34e007edfa82a7b2a2e1b969477dcf5099ce7f4f926fb54ce7e27c4a0cd54b", - "urls": [ - "https://repo1.maven.org/maven2/javax/cache/cache-api/1.1.1/cache-api-1.1.1.jar" - ], - "downloaded_file_path": "javax/cache/cache-api/1.1.1/cache-api-1.1.1.jar" - } - }, - "org_ow2_asm_asm_util_jar_sources_9_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_ow2_asm_asm_util_jar_sources_9_2", - "sha256": "b631d4561a24e84eaeee2c0495added214e4961ed328b02300f7d9b1f407c853", - "urls": [ - "https://repo1.maven.org/maven2/org/ow2/asm/asm-util/9.2/asm-util-9.2-sources.jar" - ], - "downloaded_file_path": "org/ow2/asm/asm-util/9.2/asm-util-9.2-sources.jar" - } - }, - "com_google_auth_google_auth_library_credentials_jar_sources_1_19_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_auth_google_auth_library_credentials_jar_sources_1_19_0", - "sha256": "f83533db6683adaf971f98dad16d74e8ac34909e5085b720e3c45542a3f1552c", - "urls": [ - "https://repo1.maven.org/maven2/com/google/auth/google-auth-library-credentials/1.19.0/google-auth-library-credentials-1.19.0-sources.jar" - ], - "downloaded_file_path": "com/google/auth/google-auth-library-credentials/1.19.0/google-auth-library-credentials-1.19.0-sources.jar" - } - }, - "io_netty_netty_transport_classes_epoll_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport_classes_epoll_4_1_97_Final", - "sha256": "ee65fa17fe65f18fd22269f92bddad85bfb3a263cf65eba01e116a2f30b86ff5", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-transport-classes-epoll/4.1.97.Final/netty-transport-classes-epoll-4.1.97.Final.jar" - ], - "downloaded_file_path": "io/netty/netty-transport-classes-epoll/4.1.97.Final/netty-transport-classes-epoll-4.1.97.Final.jar" - } - }, - "org_ow2_asm_asm_analysis_jar_sources_9_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_ow2_asm_asm_analysis_jar_sources_9_2", - "sha256": "c5a6764bbcee9e4bcd8ee1ea33808f96b8b587371f329aa75a2f541f2ee1b0d5", - "urls": [ - "https://repo1.maven.org/maven2/org/ow2/asm/asm-analysis/9.2/asm-analysis-9.2-sources.jar" - ], - "downloaded_file_path": "org/ow2/asm/asm-analysis/9.2/asm-analysis-9.2-sources.jar" - } - }, - "com_google_code_findbugs_jsr305": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_code_findbugs_jsr305", - "generating_repository": "maven", - "target_name": "com_google_code_findbugs_jsr305" - } - }, - "com_amazonaws_aws_java_sdk_secretsmanager_jar_sources_1_12_544": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_amazonaws_aws_java_sdk_secretsmanager_jar_sources_1_12_544", - "sha256": "d264b64ad371a864f8ba3a0af6876abb8f4ab3fe293812bab84a24e27d0b0982", - "urls": [ - "https://repo1.maven.org/maven2/com/amazonaws/aws-java-sdk-secretsmanager/1.12.544/aws-java-sdk-secretsmanager-1.12.544-sources.jar" - ], - "downloaded_file_path": "com/amazonaws/aws-java-sdk-secretsmanager/1.12.544/aws-java-sdk-secretsmanager-1.12.544-sources.jar" - } - }, - "com_google_auth_google_auth_library_oauth2_http_jar_sources_1_19_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_auth_google_auth_library_oauth2_http_jar_sources_1_19_0", - "sha256": "3aabf134e1c21fb8b3573897f0aa9136ca58ebe0c76fb086ef9169b28e9f707e", - "urls": [ - "https://repo1.maven.org/maven2/com/google/auth/google-auth-library-oauth2-http/1.19.0/google-auth-library-oauth2-http-1.19.0-sources.jar" - ], - "downloaded_file_path": "com/google/auth/google-auth-library-oauth2-http/1.19.0/google-auth-library-oauth2-http-1.19.0-sources.jar" - } - }, - "io_netty_netty_transport": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_transport", - "generating_repository": "maven", - "target_name": "io_netty_netty_transport" - } - }, - "commons_logging_commons_logging_1_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~commons_logging_commons_logging_1_2", - "sha256": "daddea1ea0be0f56978ab3006b8ac92834afeefbd9b7e4e6316fca57df0fa636", - "urls": [ - "https://repo1.maven.org/maven2/commons-logging/commons-logging/1.2/commons-logging-1.2.jar" - ], - "downloaded_file_path": "commons-logging/commons-logging/1.2/commons-logging-1.2.jar" - } - }, - "jakarta_ws_rs_jakarta_ws_rs_api_2_1_6": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~jakarta_ws_rs_jakarta_ws_rs_api_2_1_6", - "sha256": "4cea299c846c8a6e6470cbfc2f7c391bc29b9caa2f9264ac1064ba91691f4adf", - "urls": [ - "https://repo1.maven.org/maven2/jakarta/ws/rs/jakarta.ws.rs-api/2.1.6/jakarta.ws.rs-api-2.1.6.jar" - ], - "downloaded_file_path": "jakarta/ws/rs/jakarta.ws.rs-api/2.1.6/jakarta.ws.rs-api-2.1.6.jar" - } - }, - "com_github_jnr_jffi": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_jnr_jffi", - "generating_repository": "maven", - "target_name": "com_github_jnr_jffi" - } - }, - "com_googlecode_json_simple_json_simple_jar_sources_1_1_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_googlecode_json_simple_json_simple_jar_sources_1_1_1", - "sha256": "26960e02aeb64dc06ada259495ad2a553dd53ded9aaf6a84c3f5974a56ce24d6", - "urls": [ - "https://repo1.maven.org/maven2/com/googlecode/json-simple/json-simple/1.1.1/json-simple-1.1.1-sources.jar" - ], - "downloaded_file_path": "com/googlecode/json-simple/json-simple/1.1.1/json-simple-1.1.1-sources.jar" - } - }, - "com_google_api_gax_2_28_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_api_gax_2_28_1", - "sha256": "dddd191a2621bc5a747800c417005618f9c1f03d3d5056cb0208905400f17fac", - "urls": [ - "https://repo1.maven.org/maven2/com/google/api/gax/2.28.1/gax-2.28.1.jar", - "https://maven.google.com/com/google/api/gax/2.28.1/gax-2.28.1.jar" - ], - "downloaded_file_path": "com/google/api/gax/2.28.1/gax-2.28.1.jar" - } - }, - "com_github_docker_java_docker_java_transport_jar_sources_3_3_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_docker_java_docker_java_transport_jar_sources_3_3_3", - "sha256": "0ec44c8b9349365c3dd2740ad41f9e65af079fd9a68bfc68a2d3efe5776ff687", - "urls": [ - "https://repo1.maven.org/maven2/com/github/docker-java/docker-java-transport/3.3.3/docker-java-transport-3.3.3-sources.jar" - ], - "downloaded_file_path": "com/github/docker-java/docker-java-transport/3.3.3/docker-java-transport-3.3.3-sources.jar" - } - }, - "software_amazon_awssdk_metrics_spi_2_20_78": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~software_amazon_awssdk_metrics_spi_2_20_78", - "sha256": "41680096cb566090be0504eaf207dab91d680c16d57f68239260860871d7ab8f", - "urls": [ - "https://repo1.maven.org/maven2/software/amazon/awssdk/metrics-spi/2.20.78/metrics-spi-2.20.78.jar", - "https://maven.google.com/software/amazon/awssdk/metrics-spi/2.20.78/metrics-spi-2.20.78.jar" - ], - "downloaded_file_path": "software/amazon/awssdk/metrics-spi/2.20.78/metrics-spi-2.20.78.jar" - } - }, - "org_conscrypt_conscrypt_openjdk_uber_2_5_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_conscrypt_conscrypt_openjdk_uber_2_5_2", - "sha256": "eaf537d98e033d0f0451cd1b8cc74e02d7b55ec882da63c88060d806ba89c348", - "urls": [ - "https://repo1.maven.org/maven2/org/conscrypt/conscrypt-openjdk-uber/2.5.2/conscrypt-openjdk-uber-2.5.2.jar", - "https://maven.google.com/org/conscrypt/conscrypt-openjdk-uber/2.5.2/conscrypt-openjdk-uber-2.5.2.jar" - ], - "downloaded_file_path": "org/conscrypt/conscrypt-openjdk-uber/2.5.2/conscrypt-openjdk-uber-2.5.2.jar" - } - }, - "com_github_ben_manes_caffeine_caffeine_jar_sources_3_0_5": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_ben_manes_caffeine_caffeine_jar_sources_3_0_5", - "sha256": "2cca8d1cdfdf33c1d0eec0214cdc6d93ff8a95136bf798465b10a5924a69bc65", - "urls": [ - "https://repo1.maven.org/maven2/com/github/ben-manes/caffeine/caffeine/3.0.5/caffeine-3.0.5-sources.jar" - ], - "downloaded_file_path": "com/github/ben-manes/caffeine/caffeine/3.0.5/caffeine-3.0.5-sources.jar" - } - }, - "com_github_docker_java_docker_java_api_jar_sources_3_3_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_docker_java_docker_java_api_jar_sources_3_3_3", - "sha256": "cb262504c43a1ed7f79235a9f93611c322016bd6ca91a0ab37cfe21a55460a8b", - "urls": [ - "https://repo1.maven.org/maven2/com/github/docker-java/docker-java-api/3.3.3/docker-java-api-3.3.3-sources.jar" - ], - "downloaded_file_path": "com/github/docker-java/docker-java-api/3.3.3/docker-java-api-3.3.3-sources.jar" - } - }, - "org_checkerframework_checker_qual": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_checkerframework_checker_qual", - "generating_repository": "maven", - "target_name": "org_checkerframework_checker_qual" - } - }, - "org_glassfish_hk2_hk2_api_jar_sources_2_6_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_glassfish_hk2_hk2_api_jar_sources_2_6_1", - "sha256": "636e56f6454a7c680271dd8e2e49d1fd50625bb9e206555a14ccf900188cc18c", - "urls": [ - "https://repo1.maven.org/maven2/org/glassfish/hk2/hk2-api/2.6.1/hk2-api-2.6.1-sources.jar" - ], - "downloaded_file_path": "org/glassfish/hk2/hk2-api/2.6.1/hk2-api-2.6.1-sources.jar" - } - }, - "io_grpc_grpc_netty_jar_sources_1_56_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_netty_jar_sources_1_56_1", - "sha256": "3ce30acc50ab39f160948bae09c1c832093d6b23a533a20d1473466ca30a3783", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-netty/1.56.1/grpc-netty-1.56.1-sources.jar" - ], - "downloaded_file_path": "io/grpc/grpc-netty/1.56.1/grpc-netty-1.56.1-sources.jar" - } - }, - "junit_junit_jar_sources_4_13_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~junit_junit_jar_sources_4_13_2", - "sha256": "34181df6482d40ea4c046b063cb53c7ffae94bdf1b1d62695bdf3adf9dea7e3a", - "urls": [ - "https://repo1.maven.org/maven2/junit/junit/4.13.2/junit-4.13.2-sources.jar" - ], - "downloaded_file_path": "junit/junit/4.13.2/junit-4.13.2-sources.jar" - } - }, - "org_ow2_asm_asm_commons_9_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_ow2_asm_asm_commons_9_2", - "sha256": "be4ce53138a238bb522cd781cf91f3ba5ce2f6ca93ec62d46a162a127225e0a6", - "urls": [ - "https://repo1.maven.org/maven2/org/ow2/asm/asm-commons/9.2/asm-commons-9.2.jar" - ], - "downloaded_file_path": "org/ow2/asm/asm-commons/9.2/asm-commons-9.2.jar" - } - }, - "com_google_protobuf_protobuf_java_3_23_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_protobuf_protobuf_java_3_23_1", - "sha256": "d9fd335a65165c760f53ae718878448627ce742ab6e9102dffe9bc2ea7b136ca", - "urls": [ - "https://repo1.maven.org/maven2/com/google/protobuf/protobuf-java/3.23.1/protobuf-java-3.23.1.jar", - "https://maven.google.com/com/google/protobuf/protobuf-java/3.23.1/protobuf-java-3.23.1.jar" - ], - "downloaded_file_path": "com/google/protobuf/protobuf-java/3.23.1/protobuf-java-3.23.1.jar" - } - }, - "org_luaj_luaj_jse_3_0_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_luaj_luaj_jse_3_0_1", - "sha256": "9b1f0a3e8f68427c6d74c2bf00ae0e6dbfce35994d3001fed4cef6ecda50be55", - "urls": [ - "https://repo1.maven.org/maven2/org/luaj/luaj-jse/3.0.1/luaj-jse-3.0.1.jar" - ], - "downloaded_file_path": "org/luaj/luaj-jse/3.0.1/luaj-jse-3.0.1.jar" - } - }, - "org_glassfish_hk2_hk2_locator_jar_sources_2_6_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_glassfish_hk2_hk2_locator_jar_sources_2_6_1", - "sha256": "d76811aeabe487e35001fb4a0ab3d986a091c331f4d61962c33f6c98f94e5053", - "urls": [ - "https://repo1.maven.org/maven2/org/glassfish/hk2/hk2-locator/2.6.1/hk2-locator-2.6.1-sources.jar" - ], - "downloaded_file_path": "org/glassfish/hk2/hk2-locator/2.6.1/hk2-locator-2.6.1-sources.jar" - } - }, - "org_reflections_reflections_jar_sources_0_10_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_reflections_reflections_jar_sources_0_10_2", - "sha256": "7c8f0b91e298556ac8eebcbbb33de537baa146d80a7e5a6500e44cd8f76a91f4", - "urls": [ - "https://repo1.maven.org/maven2/org/reflections/reflections/0.10.2/reflections-0.10.2-sources.jar" - ], - "downloaded_file_path": "org/reflections/reflections/0.10.2/reflections-0.10.2-sources.jar" - } - }, - "org_apache_commons_commons_pool2": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_apache_commons_commons_pool2", - "generating_repository": "maven", - "target_name": "org_apache_commons_commons_pool2" - } - }, - "io_github_java_diff_utils_java_diff_utils_4_12": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_github_java_diff_utils_java_diff_utils_4_12", - "sha256": "9990a2039778f6b4cc94790141c2868864eacee0620c6c459451121a901cd5b5", - "urls": [ - "https://repo1.maven.org/maven2/io/github/java-diff-utils/java-diff-utils/4.12/java-diff-utils-4.12.jar" - ], - "downloaded_file_path": "io/github/java-diff-utils/java-diff-utils/4.12/java-diff-utils-4.12.jar" - } - }, - "maven": { - "bzlFile": "@@rules_jvm_external~5.3//:coursier.bzl", - "ruleClassName": "pinned_coursier_fetch", - "attributes": { - "name": "rules_jvm_external~5.3~maven~maven", - "repositories": [ - "{ \"repo_url\": \"https://repo1.maven.org/maven2\" }" - ], - "artifacts": [ - "{ \"group\": \"com.amazonaws\", \"artifact\": \"aws-java-sdk-s3\", \"version\": \"1.12.544\" }", - "{ \"group\": \"com.amazonaws\", \"artifact\": \"aws-java-sdk-secretsmanager\", \"version\": \"1.12.544\" }", - "{ \"group\": \"com.fasterxml.jackson.core\", \"artifact\": \"jackson-databind\", \"version\": \"2.15.0\" }", - "{ \"group\": \"com.github.ben-manes.caffeine\", \"artifact\": \"caffeine\", \"version\": \"2.9.0\" }", - "{ \"group\": \"com.github.docker-java\", \"artifact\": \"docker-java\", \"version\": \"3.3.3\" }", - "{ \"group\": \"com.github.fppt\", \"artifact\": \"jedis-mock\", \"version\": \"1.0.10\" }", - "{ \"group\": \"com.github.jnr\", \"artifact\": \"jffi\", \"version\": \"1.3.11\" }", - "{ \"group\": \"com.github.jnr\", \"artifact\": \"jffi\", \"version\": \"1.3.11\", \"packaging\": \"jar\", \"classifier\": \"native\" }", - "{ \"group\": \"com.github.jnr\", \"artifact\": \"jnr-constants\", \"version\": \"0.10.4\" }", - "{ \"group\": \"com.github.jnr\", \"artifact\": \"jnr-ffi\", \"version\": \"2.2.14\" }", - "{ \"group\": \"com.github.jnr\", \"artifact\": \"jnr-posix\", \"version\": \"3.1.17\" }", - "{ \"group\": \"com.github.pcj\", \"artifact\": \"google-options\", \"version\": \"1.0.0\" }", - "{ \"group\": \"com.github.serceman\", \"artifact\": \"jnr-fuse\", \"version\": \"0.5.7\" }", - "{ \"group\": \"com.github.luben\", \"artifact\": \"zstd-jni\", \"version\": \"1.5.5-7\" }", - "{ \"group\": \"com.github.oshi\", \"artifact\": \"oshi-core\", \"version\": \"6.4.5\" }", - "{ \"group\": \"com.google.auth\", \"artifact\": \"google-auth-library-credentials\", \"version\": \"1.19.0\" }", - "{ \"group\": \"com.google.auth\", \"artifact\": \"google-auth-library-oauth2-http\", \"version\": \"1.19.0\" }", - "{ \"group\": \"com.google.code.findbugs\", \"artifact\": \"jsr305\", \"version\": \"3.0.2\" }", - "{ \"group\": \"com.google.code.gson\", \"artifact\": \"gson\", \"version\": \"2.10.1\" }", - "{ \"group\": \"com.google.errorprone\", \"artifact\": \"error_prone_annotations\", \"version\": \"2.22.0\" }", - "{ \"group\": \"com.google.errorprone\", \"artifact\": \"error_prone_core\", \"version\": \"2.22.0\" }", - "{ \"group\": \"com.google.guava\", \"artifact\": \"failureaccess\", \"version\": \"1.0.1\" }", - "{ \"group\": \"com.google.guava\", \"artifact\": \"guava\", \"version\": \"32.1.1-jre\" }", - "{ \"group\": \"com.google.j2objc\", \"artifact\": \"j2objc-annotations\", \"version\": \"2.8\" }", - "{ \"group\": \"com.google.jimfs\", \"artifact\": \"jimfs\", \"version\": \"1.3.0\" }", - "{ \"group\": \"com.google.protobuf\", \"artifact\": \"protobuf-java-util\", \"version\": \"3.19.1\" }", - "{ \"group\": \"com.google.protobuf\", \"artifact\": \"protobuf-java\", \"version\": \"3.19.1\" }", - "{ \"group\": \"com.google.truth\", \"artifact\": \"truth\", \"version\": \"1.1.5\" }", - "{ \"group\": \"org.slf4j\", \"artifact\": \"slf4j-simple\", \"version\": \"2.0.9\" }", - "{ \"group\": \"com.googlecode.json-simple\", \"artifact\": \"json-simple\", \"version\": \"1.1.1\" }", - "{ \"group\": \"com.jayway.jsonpath\", \"artifact\": \"json-path\", \"version\": \"2.8.0\" }", - "{ \"group\": \"org.bouncycastle\", \"artifact\": \"bcprov-jdk15on\", \"version\": \"1.70\" }", - "{ \"group\": \"net.jcip\", \"artifact\": \"jcip-annotations\", \"version\": \"1.0\" }", - "{ \"group\": \"io.netty\", \"artifact\": \"netty-buffer\", \"version\": \"4.1.97.Final\" }", - "{ \"group\": \"io.netty\", \"artifact\": \"netty-codec\", \"version\": \"4.1.97.Final\" }", - "{ \"group\": \"io.netty\", \"artifact\": \"netty-codec-http\", \"version\": \"4.1.97.Final\" }", - "{ \"group\": \"io.netty\", \"artifact\": \"netty-codec-http2\", \"version\": \"4.1.97.Final\" }", - "{ \"group\": \"io.netty\", \"artifact\": \"netty-codec-socks\", \"version\": \"4.1.97.Final\" }", - "{ \"group\": \"io.netty\", \"artifact\": \"netty-common\", \"version\": \"4.1.97.Final\" }", - "{ \"group\": \"io.netty\", \"artifact\": \"netty-handler\", \"version\": \"4.1.97.Final\" }", - "{ \"group\": \"io.netty\", \"artifact\": \"netty-handler-proxy\", \"version\": \"4.1.97.Final\" }", - "{ \"group\": \"io.netty\", \"artifact\": \"netty-resolver\", \"version\": \"4.1.97.Final\" }", - "{ \"group\": \"io.netty\", \"artifact\": \"netty-transport\", \"version\": \"4.1.97.Final\" }", - "{ \"group\": \"io.netty\", \"artifact\": \"netty-transport-native-epoll\", \"version\": \"4.1.97.Final\" }", - "{ \"group\": \"io.netty\", \"artifact\": \"netty-transport-native-kqueue\", \"version\": \"4.1.97.Final\" }", - "{ \"group\": \"io.netty\", \"artifact\": \"netty-transport-native-unix-common\", \"version\": \"4.1.97.Final\" }", - "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-api\", \"version\": \"1.56.1\" }", - "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-auth\", \"version\": \"1.56.1\" }", - "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-core\", \"version\": \"1.56.1\" }", - "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-context\", \"version\": \"1.56.1\" }", - "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-netty\", \"version\": \"1.56.1\" }", - "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-stub\", \"version\": \"1.56.1\" }", - "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-protobuf\", \"version\": \"1.56.1\" }", - "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-testing\", \"version\": \"1.56.1\" }", - "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-services\", \"version\": \"1.56.1\" }", - "{ \"group\": \"io.grpc\", \"artifact\": \"grpc-netty-shaded\", \"version\": \"1.56.1\" }", - "{ \"group\": \"io.prometheus\", \"artifact\": \"simpleclient\", \"version\": \"0.15.0\" }", - "{ \"group\": \"io.prometheus\", \"artifact\": \"simpleclient_hotspot\", \"version\": \"0.15.0\" }", - "{ \"group\": \"io.prometheus\", \"artifact\": \"simpleclient_httpserver\", \"version\": \"0.15.0\" }", - "{ \"group\": \"junit\", \"artifact\": \"junit\", \"version\": \"4.13.2\" }", - "{ \"group\": \"javax.annotation\", \"artifact\": \"javax.annotation-api\", \"version\": \"1.3.2\" }", - "{ \"group\": \"net.javacrumbs.future-converter\", \"artifact\": \"future-converter-java8-guava\", \"version\": \"1.2.0\" }", - "{ \"group\": \"org.apache.commons\", \"artifact\": \"commons-compress\", \"version\": \"1.23.0\" }", - "{ \"group\": \"org.apache.commons\", \"artifact\": \"commons-pool2\", \"version\": \"2.11.1\" }", - "{ \"group\": \"org.apache.commons\", \"artifact\": \"commons-lang3\", \"version\": \"3.13.0\" }", - "{ \"group\": \"commons-io\", \"artifact\": \"commons-io\", \"version\": \"2.13.0\" }", - "{ \"group\": \"me.dinowernli\", \"artifact\": \"java-grpc-prometheus\", \"version\": \"0.6.0\" }", - "{ \"group\": \"org.apache.tomcat\", \"artifact\": \"annotations-api\", \"version\": \"6.0.53\" }", - "{ \"group\": \"org.checkerframework\", \"artifact\": \"checker-qual\", \"version\": \"3.38.0\" }", - "{ \"group\": \"org.mockito\", \"artifact\": \"mockito-core\", \"version\": \"2.25.0\" }", - "{ \"group\": \"org.openjdk.jmh\", \"artifact\": \"jmh-core\", \"version\": \"1.37\" }", - "{ \"group\": \"org.openjdk.jmh\", \"artifact\": \"jmh-generator-annprocess\", \"version\": \"1.37\" }", - "{ \"group\": \"org.redisson\", \"artifact\": \"redisson\", \"version\": \"3.23.4\" }", - "{ \"group\": \"org.threeten\", \"artifact\": \"threetenbp\", \"version\": \"1.6.8\" }", - "{ \"group\": \"org.xerial\", \"artifact\": \"sqlite-jdbc\", \"version\": \"3.34.0\" }", - "{ \"group\": \"org.jetbrains\", \"artifact\": \"annotations\", \"version\": \"16.0.2\" }", - "{ \"group\": \"org.yaml\", \"artifact\": \"snakeyaml\", \"version\": \"2.2\" }", - "{ \"group\": \"org.projectlombok\", \"artifact\": \"lombok\", \"version\": \"1.18.30\" }" - ], - "fetch_sources": true, - "fetch_javadoc": false, - "generate_compat_repositories": false, - "maven_install_json": "@@//:maven_install.json", - "override_targets": {}, - "strict_visibility": false, - "strict_visibility_value": [ - "@@//visibility:private" - ], - "jetify": false, - "jetify_include_list": [ - "*" - ], - "additional_netrc_lines": [], - "fail_if_repin_required": true, - "use_starlark_android_rules": false, - "aar_import_bzl_label": "@build_bazel_rules_android//android:rules.bzl", - "duplicate_version_warning": "warn" - } - }, - "com_github_jnr_jnr_a64asm_1_0_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_jnr_jnr_a64asm_1_0_0", - "sha256": "53ae5ea7fa5c284e8279aa348e7b9de4548b0cae10bfd058fa217c791875e4cf", - "urls": [ - "https://repo1.maven.org/maven2/com/github/jnr/jnr-a64asm/1.0.0/jnr-a64asm-1.0.0.jar" - ], - "downloaded_file_path": "com/github/jnr/jnr-a64asm/1.0.0/jnr-a64asm-1.0.0.jar" - } - }, - "io_grpc_grpc_protobuf_jar_sources_1_56_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_protobuf_jar_sources_1_56_1", - "sha256": "62b6675a187374f8f4ea8d645d602930b587383fbb0979fa19e708f885499934", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-protobuf/1.56.1/grpc-protobuf-1.56.1-sources.jar" - ], - "downloaded_file_path": "io/grpc/grpc-protobuf/1.56.1/grpc-protobuf-1.56.1-sources.jar" - } - }, - "com_esotericsoftware_kryo_5_5_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_esotericsoftware_kryo_5_5_0", - "sha256": "4b902a21d99f7b4c32e6f7400e91f9284fd184db881bb9e18328e14d8127f7f9", - "urls": [ - "https://repo1.maven.org/maven2/com/esotericsoftware/kryo/5.5.0/kryo-5.5.0.jar" - ], - "downloaded_file_path": "com/esotericsoftware/kryo/5.5.0/kryo-5.5.0.jar" - } - }, - "io_prometheus_simpleclient_httpserver": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_httpserver", - "generating_repository": "maven", - "target_name": "io_prometheus_simpleclient_httpserver" - } - }, - "io_prometheus_simpleclient_0_15_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_prometheus_simpleclient_0_15_0", - "sha256": "a43d6c00e3964a7063c1360ddcddc598df4f8e659a8313b27f90e4c555badb1d", - "urls": [ - "https://repo1.maven.org/maven2/io/prometheus/simpleclient/0.15.0/simpleclient-0.15.0.jar" - ], - "downloaded_file_path": "io/prometheus/simpleclient/0.15.0/simpleclient-0.15.0.jar" - } - }, - "com_google_cloud_google_cloud_core_grpc_2_18_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_cloud_google_cloud_core_grpc_2_18_1", - "sha256": "3021f5ac856552155edfb459a1f4c0b0bf3c5363e6fa4923a82af3e531ff33ad", - "urls": [ - "https://repo1.maven.org/maven2/com/google/cloud/google-cloud-core-grpc/2.18.1/google-cloud-core-grpc-2.18.1.jar", - "https://maven.google.com/com/google/cloud/google-cloud-core-grpc/2.18.1/google-cloud-core-grpc-2.18.1.jar" - ], - "downloaded_file_path": "com/google/cloud/google-cloud-core-grpc/2.18.1/google-cloud-core-grpc-2.18.1.jar" - } - }, - "jakarta_annotation_jakarta_annotation_api_1_3_5": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~jakarta_annotation_jakarta_annotation_api_1_3_5", - "sha256": "85fb03fc054cdf4efca8efd9b6712bbb418e1ab98241c4539c8585bbc23e1b8a", - "urls": [ - "https://repo1.maven.org/maven2/jakarta/annotation/jakarta.annotation-api/1.3.5/jakarta.annotation-api-1.3.5.jar" - ], - "downloaded_file_path": "jakarta/annotation/jakarta.annotation-api/1.3.5/jakarta.annotation-api-1.3.5.jar" - } - }, - "org_bouncycastle_bcprov_jdk15on": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_bouncycastle_bcprov_jdk15on", - "generating_repository": "maven", - "target_name": "org_bouncycastle_bcprov_jdk15on" - } - }, - "io_grpc_grpc_auth": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_auth", - "generating_repository": "maven", - "target_name": "io_grpc_grpc_auth" - } - }, - "org_glassfish_hk2_external_aopalliance_repackaged_jar_sources_2_6_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_glassfish_hk2_external_aopalliance_repackaged_jar_sources_2_6_1", - "sha256": "13392e5ad2540a5718abb1dc7c380ebd754c1b95c7d6140dd38bfeade1e6dd21", - "urls": [ - "https://repo1.maven.org/maven2/org/glassfish/hk2/external/aopalliance-repackaged/2.6.1/aopalliance-repackaged-2.6.1-sources.jar" - ], - "downloaded_file_path": "org/glassfish/hk2/external/aopalliance-repackaged/2.6.1/aopalliance-repackaged-2.6.1-sources.jar" - } - }, - "net_jcip_jcip_annotations_jar_sources_1_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~net_jcip_jcip_annotations_jar_sources_1_0", - "sha256": "e3ad6ae439e3cf8a25372de838efaa1a95f8ef9b5053d5d94fafe89c8c09814e", - "urls": [ - "https://repo1.maven.org/maven2/net/jcip/jcip-annotations/1.0/jcip-annotations-1.0-sources.jar" - ], - "downloaded_file_path": "net/jcip/jcip-annotations/1.0/jcip-annotations-1.0-sources.jar" - } - }, - "org_glassfish_jersey_core_jersey_common_jar_sources_2_30_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_glassfish_jersey_core_jersey_common_jar_sources_2_30_1", - "sha256": "bbc91b531c2aa801e578fc6737498159071f3030688714e44ed80001e17813f7", - "urls": [ - "https://repo1.maven.org/maven2/org/glassfish/jersey/core/jersey-common/2.30.1/jersey-common-2.30.1-sources.jar" - ], - "downloaded_file_path": "org/glassfish/jersey/core/jersey-common/2.30.1/jersey-common-2.30.1-sources.jar" - } - }, - "org_yaml_snakeyaml_2_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_yaml_snakeyaml_2_2", - "sha256": "1467931448a0817696ae2805b7b8b20bfb082652bf9c4efaed528930dc49389b", - "urls": [ - "https://repo1.maven.org/maven2/org/yaml/snakeyaml/2.2/snakeyaml-2.2.jar" - ], - "downloaded_file_path": "org/yaml/snakeyaml/2.2/snakeyaml-2.2.jar" - } - }, - "org_glassfish_jersey_connectors_jersey_apache_connector_2_30_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_glassfish_jersey_connectors_jersey_apache_connector_2_30_1", - "sha256": "28e87f2edc5284e293072941cea5e8ff462bb60f41c67b4ad7b906de2a7a8bd8", - "urls": [ - "https://repo1.maven.org/maven2/org/glassfish/jersey/connectors/jersey-apache-connector/2.30.1/jersey-apache-connector-2.30.1.jar" - ], - "downloaded_file_path": "org/glassfish/jersey/connectors/jersey-apache-connector/2.30.1/jersey-apache-connector-2.30.1.jar" - } - }, - "com_fasterxml_jackson_dataformat_jackson_dataformat_yaml_2_15_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_dataformat_jackson_dataformat_yaml_2_15_2", - "sha256": "37795cc1e8cb94b18d860dc3abd2e593617ce402149ae45aa89ed8bfb881c851", - "urls": [ - "https://repo1.maven.org/maven2/com/fasterxml/jackson/dataformat/jackson-dataformat-yaml/2.15.2/jackson-dataformat-yaml-2.15.2.jar" - ], - "downloaded_file_path": "com/fasterxml/jackson/dataformat/jackson-dataformat-yaml/2.15.2/jackson-dataformat-yaml-2.15.2.jar" - } - }, - "org_redisson_redisson": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_redisson_redisson", - "generating_repository": "maven", - "target_name": "org_redisson_redisson" - } - }, - "org_glassfish_jersey_core_jersey_common_2_30_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_glassfish_jersey_core_jersey_common_2_30_1", - "sha256": "273c3ea4e3ff9b960eb8dbb7c74e0127436678e486ccd94a351729f22a249830", - "urls": [ - "https://repo1.maven.org/maven2/org/glassfish/jersey/core/jersey-common/2.30.1/jersey-common-2.30.1.jar" - ], - "downloaded_file_path": "org/glassfish/jersey/core/jersey-common/2.30.1/jersey-common-2.30.1.jar" - } - }, - "org_xerial_sqlite_jdbc": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_xerial_sqlite_jdbc", - "generating_repository": "maven", - "target_name": "org_xerial_sqlite_jdbc" - } - }, - "com_amazonaws_aws_java_sdk_kms_1_12_544": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_amazonaws_aws_java_sdk_kms_1_12_544", - "sha256": "a79a3768887ea675f2e7b617b361d5250b2128413dbd5d8fa43755a9ecc1b032", - "urls": [ - "https://repo1.maven.org/maven2/com/amazonaws/aws-java-sdk-kms/1.12.544/aws-java-sdk-kms-1.12.544.jar" - ], - "downloaded_file_path": "com/amazonaws/aws-java-sdk-kms/1.12.544/aws-java-sdk-kms-1.12.544.jar" - } - }, - "net_bytebuddy_byte_buddy_1_14_5": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~net_bytebuddy_byte_buddy_1_14_5", - "sha256": "e99761a526df0fefbbd3fe14436b0f953000cdfa5151dc63c0b18d37d9c46f1c", - "urls": [ - "https://repo1.maven.org/maven2/net/bytebuddy/byte-buddy/1.14.5/byte-buddy-1.14.5.jar" - ], - "downloaded_file_path": "net/bytebuddy/byte-buddy/1.14.5/byte-buddy-1.14.5.jar" - } - }, - "junit_junit": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~junit_junit", - "generating_repository": "maven", - "target_name": "junit_junit" - } - }, - "com_google_auto_service_auto_service_annotations_jar_sources_1_0_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_auto_service_auto_service_annotations_jar_sources_1_0_1", - "sha256": "b013ca159b0fea3a0041d3d5fbb3b7e49a819da80a172a01fb17dd28fd98e72b", - "urls": [ - "https://repo1.maven.org/maven2/com/google/auto/service/auto-service-annotations/1.0.1/auto-service-annotations-1.0.1-sources.jar" - ], - "downloaded_file_path": "com/google/auto/service/auto-service-annotations/1.0.1/auto-service-annotations-1.0.1-sources.jar" - } - }, - "com_fasterxml_jackson_jaxrs_jackson_jaxrs_base_jar_sources_2_10_3": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_jaxrs_jackson_jaxrs_base_jar_sources_2_10_3", - "sha256": "6b979c532efa4f68686d85779d7d1f6d4c3de1fa53fbe6996132812b813b1349", - "urls": [ - "https://repo1.maven.org/maven2/com/fasterxml/jackson/jaxrs/jackson-jaxrs-base/2.10.3/jackson-jaxrs-base-2.10.3-sources.jar" - ], - "downloaded_file_path": "com/fasterxml/jackson/jaxrs/jackson-jaxrs-base/2.10.3/jackson-jaxrs-base-2.10.3-sources.jar" - } - }, - "org_apache_commons_commons_pool2_2_11_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_apache_commons_commons_pool2_2_11_1", - "sha256": "ea0505ee7515e58b1ac0e686e4d1a5d9f7d808e251a61bc371aa0595b9963f83", - "urls": [ - "https://repo1.maven.org/maven2/org/apache/commons/commons-pool2/2.11.1/commons-pool2-2.11.1.jar" - ], - "downloaded_file_path": "org/apache/commons/commons-pool2/2.11.1/commons-pool2-2.11.1.jar" - } - }, - "com_google_errorprone_error_prone_annotations_2_22_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_errorprone_error_prone_annotations_2_22_0", - "sha256": "82a027b86541f58d1f9ee020cdf6bebe82acc7a267d3c53a2ea5cd6335932bbd", - "urls": [ - "https://repo1.maven.org/maven2/com/google/errorprone/error_prone_annotations/2.22.0/error_prone_annotations-2.22.0.jar" - ], - "downloaded_file_path": "com/google/errorprone/error_prone_annotations/2.22.0/error_prone_annotations-2.22.0.jar" - } - }, - "io_netty_netty_codec_http": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_codec_http", - "generating_repository": "maven", - "target_name": "io_netty_netty_codec_http" - } - }, - "io_grpc_grpc_services": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_services", - "generating_repository": "maven", - "target_name": "io_grpc_grpc_services" - } - }, - "org_glassfish_jersey_core_jersey_client_2_30_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_glassfish_jersey_core_jersey_client_2_30_1", - "sha256": "fe0aa736ce216e9efb6e17392142b87e704cf09e75a0cb6b3fd2d146937225c1", - "urls": [ - "https://repo1.maven.org/maven2/org/glassfish/jersey/core/jersey-client/2.30.1/jersey-client-2.30.1.jar" - ], - "downloaded_file_path": "org/glassfish/jersey/core/jersey-client/2.30.1/jersey-client-2.30.1.jar" - } - }, - "org_ow2_asm_asm_commons_jar_sources_9_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_ow2_asm_asm_commons_jar_sources_9_2", - "sha256": "6d98839136be45d5b1ffdca0fd2647eb8eaf92cff576648cbbf96f08afd3ed6d", - "urls": [ - "https://repo1.maven.org/maven2/org/ow2/asm/asm-commons/9.2/asm-commons-9.2-sources.jar" - ], - "downloaded_file_path": "org/ow2/asm/asm-commons/9.2/asm-commons-9.2-sources.jar" - } - }, - "net_jcip_jcip_annotations": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~net_jcip_jcip_annotations", - "generating_repository": "maven", - "target_name": "net_jcip_jcip_annotations" - } - }, - "org_bouncycastle_bcprov_jdk18on_1_75": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_bouncycastle_bcprov_jdk18on_1_75", - "sha256": "7f24018e9212dbda61c69212f8d7b1524c28efb978f10df590df3b4ccac47bd5", - "urls": [ - "https://repo1.maven.org/maven2/org/bouncycastle/bcprov-jdk18on/1.75/bcprov-jdk18on-1.75.jar" - ], - "downloaded_file_path": "org/bouncycastle/bcprov-jdk18on/1.75/bcprov-jdk18on-1.75.jar" - } - }, - "org_apache_commons_commons_compress": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_apache_commons_commons_compress", - "generating_repository": "maven", - "target_name": "org_apache_commons_commons_compress" - } - }, - "net_javacrumbs_future_converter_future_converter_java8_common_jar_sources_1_2_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~net_javacrumbs_future_converter_future_converter_java8_common_jar_sources_1_2_0", - "sha256": "8a0f6e7ead50cf9687ae7093bdd8e7f20cd26e42b848105206e18b245ebbc107", - "urls": [ - "https://repo1.maven.org/maven2/net/javacrumbs/future-converter/future-converter-java8-common/1.2.0/future-converter-java8-common-1.2.0-sources.jar" - ], - "downloaded_file_path": "net/javacrumbs/future-converter/future-converter-java8-common/1.2.0/future-converter-java8-common-1.2.0-sources.jar" - } - }, - "com_fasterxml_jackson_core_jackson_databind_jar_sources_2_15_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_fasterxml_jackson_core_jackson_databind_jar_sources_2_15_2", - "sha256": "6dafb34ba03f003c998dac3f786bcfd468dfcec39eaf465180bc433ce8566d30", - "urls": [ - "https://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-databind/2.15.2/jackson-databind-2.15.2-sources.jar" - ], - "downloaded_file_path": "com/fasterxml/jackson/core/jackson-databind/2.15.2/jackson-databind-2.15.2-sources.jar" - } - }, - "com_google_api_gax_grpc_2_28_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_api_gax_grpc_2_28_1", - "sha256": "e9e40d1d7354e8f857b05be2208c11722c1b97dc7aaa4b4b125fcf0457b45a03", - "urls": [ - "https://repo1.maven.org/maven2/com/google/api/gax-grpc/2.28.1/gax-grpc-2.28.1.jar", - "https://maven.google.com/com/google/api/gax-grpc/2.28.1/gax-grpc-2.28.1.jar" - ], - "downloaded_file_path": "com/google/api/gax-grpc/2.28.1/gax-grpc-2.28.1.jar" - } - }, - "com_github_oshi_oshi_core": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_oshi_oshi_core", - "generating_repository": "maven", - "target_name": "com_github_oshi_oshi_core" - } - }, - "com_google_errorprone_error_prone_core": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_errorprone_error_prone_core", - "generating_repository": "maven", - "target_name": "com_google_errorprone_error_prone_core" - } - }, - "com_amazonaws_aws_java_sdk_secretsmanager_1_12_544": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_amazonaws_aws_java_sdk_secretsmanager_1_12_544", - "sha256": "b6a0953948949282b46769896c9d1eb1660ed77632c52137fdb72b8372fe685e", - "urls": [ - "https://repo1.maven.org/maven2/com/amazonaws/aws-java-sdk-secretsmanager/1.12.544/aws-java-sdk-secretsmanager-1.12.544.jar" - ], - "downloaded_file_path": "com/amazonaws/aws-java-sdk-secretsmanager/1.12.544/aws-java-sdk-secretsmanager-1.12.544.jar" - } - }, - "software_amazon_ion_ion_java_1_0_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~software_amazon_ion_ion_java_1_0_2", - "sha256": "0d127b205a1fce0abc2a3757a041748651bc66c15cf4c059bac5833b27d471a5", - "urls": [ - "https://repo1.maven.org/maven2/software/amazon/ion/ion-java/1.0.2/ion-java-1.0.2.jar" - ], - "downloaded_file_path": "software/amazon/ion/ion-java/1.0.2/ion-java-1.0.2.jar" - } - }, - "com_amazonaws_aws_java_sdk_kms_jar_sources_1_12_544": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_amazonaws_aws_java_sdk_kms_jar_sources_1_12_544", - "sha256": "cc195a2be0a245eaee362cacd7c2f119522cea9c8f8b89db49f0634f05b15831", - "urls": [ - "https://repo1.maven.org/maven2/com/amazonaws/aws-java-sdk-kms/1.12.544/aws-java-sdk-kms-1.12.544-sources.jar" - ], - "downloaded_file_path": "com/amazonaws/aws-java-sdk-kms/1.12.544/aws-java-sdk-kms-1.12.544-sources.jar" - } - }, - "org_yaml_snakeyaml_jar_sources_2_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_yaml_snakeyaml_jar_sources_2_2", - "sha256": "8f7cf911cf63db55fd980a926d155bd846317737351a2f48ef1c1088c414538a", - "urls": [ - "https://repo1.maven.org/maven2/org/yaml/snakeyaml/2.2/snakeyaml-2.2-sources.jar" - ], - "downloaded_file_path": "org/yaml/snakeyaml/2.2/snakeyaml-2.2-sources.jar" - } - }, - "com_github_docker_java_docker_java": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_github_docker_java_docker_java", - "generating_repository": "maven", - "target_name": "com_github_docker_java_docker_java" - } - }, - "commons_codec_commons_codec_1_15": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~commons_codec_commons_codec_1_15", - "sha256": "b3e9f6d63a790109bf0d056611fbed1cf69055826defeb9894a71369d246ed63", - "urls": [ - "https://repo1.maven.org/maven2/commons-codec/commons-codec/1.15/commons-codec-1.15.jar" - ], - "downloaded_file_path": "commons-codec/commons-codec/1.15/commons-codec-1.15.jar" - } - }, - "io_grpc_grpc_googleapis_1_55_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_grpc_grpc_googleapis_1_55_1", - "sha256": "d77f33f3c78b99c0c604def7efe27f912b9cee49219698180101a064d67bd268", - "urls": [ - "https://repo1.maven.org/maven2/io/grpc/grpc-googleapis/1.55.1/grpc-googleapis-1.55.1.jar", - "https://maven.google.com/io/grpc/grpc-googleapis/1.55.1/grpc-googleapis-1.55.1.jar" - ], - "downloaded_file_path": "io/grpc/grpc-googleapis/1.55.1/grpc-googleapis-1.55.1.jar" - } - }, - "org_apache_commons_commons_lang3": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_apache_commons_commons_lang3", - "generating_repository": "maven", - "target_name": "org_apache_commons_commons_lang3" - } - }, - "com_google_guava_guava": { - "bzlFile": "@@rules_jvm_external~5.3//private:compat_repository.bzl", - "ruleClassName": "compat_repository", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_guava_guava", - "generating_repository": "maven", - "target_name": "com_google_guava_guava" - } - }, - "com_google_code_findbugs_jsr305_jar_sources_3_0_2": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~com_google_code_findbugs_jsr305_jar_sources_3_0_2", - "sha256": "1c9e85e272d0708c6a591dc74828c71603053b48cc75ae83cce56912a2aa063b", - "urls": [ - "https://repo1.maven.org/maven2/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2-sources.jar" - ], - "downloaded_file_path": "com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2-sources.jar" - } - }, - "io_netty_netty_common_4_1_97_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_common_4_1_97_Final", - "sha256": "a8aca0c8e9347acc75c885ecc749195d9775369aa520b9276f2d1128210a6c17", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-common/4.1.97.Final/netty-common-4.1.97.Final.jar" - ], - "downloaded_file_path": "io/netty/netty-common/4.1.97.Final/netty-common-4.1.97.Final.jar" - } - }, - "io_netty_netty_handler_4_1_86_Final": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~io_netty_netty_handler_4_1_86_Final", - "sha256": "e69b42292929b278dc522e25177ddf7c54025484b55879f8227349adfbe1c04d", - "urls": [ - "https://repo1.maven.org/maven2/io/netty/netty-handler/4.1.86.Final/netty-handler-4.1.86.Final.jar", - "https://maven.google.com/io/netty/netty-handler/4.1.86.Final/netty-handler-4.1.86.Final.jar" - ], - "downloaded_file_path": "io/netty/netty-handler/4.1.86.Final/netty-handler-4.1.86.Final.jar" - } - }, - "org_slf4j_slf4j_api_jar_sources_2_0_9": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_slf4j_slf4j_api_jar_sources_2_0_9", - "sha256": "0d83bc49452416dd121ee41cebf41cdc64b69e7f7fdc97c2762ec406336c7ad3", - "urls": [ - "https://repo1.maven.org/maven2/org/slf4j/slf4j-api/2.0.9/slf4j-api-2.0.9-sources.jar" - ], - "downloaded_file_path": "org/slf4j/slf4j-api/2.0.9/slf4j-api-2.0.9-sources.jar" - } - }, - "redis_clients_jedis_4_3_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~redis_clients_jedis_4_3_1", - "sha256": "597894244e42e1b3171470e9294781824dbf617949e77aa0230eaa3ec4772db4", - "urls": [ - "https://repo1.maven.org/maven2/redis/clients/jedis/4.3.1/jedis-4.3.1.jar" - ], - "downloaded_file_path": "redis/clients/jedis/4.3.1/jedis-4.3.1.jar" - } - }, - "org_glassfish_jersey_connectors_jersey_apache_connector_jar_sources_2_30_1": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_glassfish_jersey_connectors_jersey_apache_connector_jar_sources_2_30_1", - "sha256": "189accdc78e1ac392d6ae16d62d98b3567ca4fb836524d4f79e485c5455a9b93", - "urls": [ - "https://repo1.maven.org/maven2/org/glassfish/jersey/connectors/jersey-apache-connector/2.30.1/jersey-apache-connector-2.30.1-sources.jar" - ], - "downloaded_file_path": "org/glassfish/jersey/connectors/jersey-apache-connector/2.30.1/jersey-apache-connector-2.30.1-sources.jar" - } - }, - "org_xerial_sqlite_jdbc_jar_sources_3_34_0": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_file", - "attributes": { - "name": "rules_jvm_external~5.3~maven~org_xerial_sqlite_jdbc_jar_sources_3_34_0", - "sha256": "e0c494fe9e7b719a0fe270bf19e63b26c821fce0a29c9066f5d1c39b9d38a6c0", - "urls": [ - "https://repo1.maven.org/maven2/org/xerial/sqlite-jdbc/3.34.0/sqlite-jdbc-3.34.0-sources.jar" - ], - "downloaded_file_path": "org/xerial/sqlite-jdbc/3.34.0/sqlite-jdbc-3.34.0-sources.jar" - } - } - } - } - } - } -} From 1fa529baa7d25314c0c62f9ba535e675ed84d722 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Wed, 6 Mar 2024 07:19:02 -0800 Subject: [PATCH 227/311] build: add cgroup-tools to the ubuntu base images (#1662) --- ci/base-worker-image/jammy/Dockerfile | 2 +- ci/base-worker-image/mantic/Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/base-worker-image/jammy/Dockerfile b/ci/base-worker-image/jammy/Dockerfile index 2e54a2804e..b2cb2fed9a 100644 --- a/ci/base-worker-image/jammy/Dockerfile +++ b/ci/base-worker-image/jammy/Dockerfile @@ -3,4 +3,4 @@ FROM ubuntu:22.04 RUN apt-get update -RUN apt-get -y install default-jre default-jdk build-essential libfuse2 +RUN apt-get -y install default-jre default-jdk build-essential libfuse2 cgroup-tools diff --git a/ci/base-worker-image/mantic/Dockerfile b/ci/base-worker-image/mantic/Dockerfile index 3dc2802331..ed7c200317 100644 --- a/ci/base-worker-image/mantic/Dockerfile +++ b/ci/base-worker-image/mantic/Dockerfile @@ -3,4 +3,4 @@ FROM ubuntu:23.04 RUN apt-get update -RUN apt-get -y install default-jre default-jdk build-essential libfuse2 +RUN apt-get -y install default-jre default-jdk build-essential libfuse2 cgroup-tools From 04ff2163d7c22fa533b375fae747b0edfd4f3b8e Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Wed, 6 Mar 2024 09:29:37 -0800 Subject: [PATCH 228/311] build: remove docker download install pkgs actions (#1663) * build: use pre-built ubuntu-mantic image * chore: prune unused images --- BUILD | 32 ++------------------------------ images.bzl | 22 ---------------------- 2 files changed, 2 insertions(+), 52 deletions(-) diff --git a/BUILD b/BUILD index b93df8471e..fa514b78e0 100644 --- a/BUILD +++ b/BUILD @@ -1,7 +1,5 @@ load("@buildifier_prebuilt//:rules.bzl", "buildifier") -load("@io_bazel_rules_docker//container:container.bzl", "container_image", "container_push") -load("@io_bazel_rules_docker//docker/package_managers:download_pkgs.bzl", "download_pkgs") -load("@io_bazel_rules_docker//docker/package_managers:install_pkgs.bzl", "install_pkgs") +load("@io_bazel_rules_docker//container:container.bzl", "container_push") load("@io_bazel_rules_docker//java:image.bzl", "java_image") load("//:jvm_flags.bzl", "server_jvm_flags", "worker_jvm_flags") @@ -136,36 +134,10 @@ java_image( ], ) -# A worker image may need additional packages installed that are not in the base image. -# We use download/install rules to extend an upstream image. -# Download cgroup-tools so that the worker is able to restrict actions via control groups. -download_pkgs( - name = "worker_pkgs", - image_tar = "@ubuntu-mantic//image", - packages = ["cgroup-tools"], - tags = ["container"], -) - -install_pkgs( - name = "worker_pkgs_image", - image_tar = "@ubuntu-mantic//image", - installables_tar = ":worker_pkgs.tar", - installation_cleanup_commands = "rm -rf /var/lib/apt/lists/*", - output_image_name = "worker_pkgs_image", - tags = ["container"], -) - -# This becomes the new base image when creating worker images. -container_image( - name = "worker_pkgs_image_wrapper", - base = ":worker_pkgs_image.tar", - tags = ["container"], -) - java_image( name = "buildfarm-shard-worker", args = ["/app/build_buildfarm/examples/config.minimal.yml"], - base = ":worker_pkgs_image_wrapper", + base = "@ubuntu-mantic//image", classpath_resources = [ "//src/main/java/build/buildfarm:configs", ], diff --git a/images.bzl b/images.bzl index 800615160d..9b7afcacba 100644 --- a/images.bzl +++ b/images.bzl @@ -12,20 +12,6 @@ def buildfarm_images(): container_deps() - container_pull( - name = "java_image_base", - digest = "sha256:8c1769cb253bdecc257470f7fba05446a55b70805fa686f227a11655a90dfe9e", - registry = "gcr.io", - repository = "distroless/java", - ) - - container_pull( - name = "java_debug_image_base", - digest = "sha256:57c99181c9dea202a185970678f723496861b4ce3c534f35f29fe58964eb720c", - registry = "gcr.io", - repository = "distroless/java", - ) - # Base mantic worker image for public releases (built via github action from ci/base-worker-image/mantic/Dockerfile) container_pull( name = "ubuntu-mantic", @@ -34,14 +20,6 @@ def buildfarm_images(): tag = "mantic", ) - # Base worker image for public releases (built via github action from ci/base-worker-image/jammy/Dockerfile) - container_pull( - name = "ubuntu-jammy", - registry = "index.docker.io", - repository = "bazelbuild/buildfarm-worker-base", - tag = "jammy", - ) - # Server base image container_pull( name = "amazon_corretto_java_image_base", From bc4156d6c9897c5db2ead1770aee50576289389e Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Thu, 7 Mar 2024 10:57:07 -0800 Subject: [PATCH 229/311] fix(common): do not log redis password on start-up Do not log passwords on start-up. --- src/main/java/build/buildfarm/common/config/Backplane.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/build/buildfarm/common/config/Backplane.java b/src/main/java/build/buildfarm/common/config/Backplane.java index 1693e378e6..81eba924cd 100644 --- a/src/main/java/build/buildfarm/common/config/Backplane.java +++ b/src/main/java/build/buildfarm/common/config/Backplane.java @@ -8,6 +8,7 @@ import lombok.AccessLevel; import lombok.Data; import lombok.Getter; +import lombok.ToString; import oshi.util.FileUtil; import redis.clients.jedis.util.JedisURIHelper; @@ -53,6 +54,7 @@ public enum BACKPLANE_TYPE { private boolean priorityQueue = false; private Queue[] queues = {}; private String redisCredentialFile; + @ToString.Exclude // Do not log the password on start-up. private String redisPassword; private int timeout = 10000; private String[] redisNodes = {}; From 2490ada368f023727b26972638580f9fdec75357 Mon Sep 17 00:00:00 2001 From: Masaki Muranaka Date: Sat, 9 Mar 2024 09:29:47 +0000 Subject: [PATCH 230/311] [helm] Support autoscaling/{v2beta2,v2} for HPA. --- .../helm-charts/buildfarm/templates/_helpers.tpl | 12 ++++++++++++ .../buildfarm/templates/shard-worker/autoscaler.yaml | 11 ++++++++++- kubernetes/helm-charts/buildfarm/values.yaml | 10 +++++++++- 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/kubernetes/helm-charts/buildfarm/templates/_helpers.tpl b/kubernetes/helm-charts/buildfarm/templates/_helpers.tpl index dffd8587bd..fe8826bb59 100644 --- a/kubernetes/helm-charts/buildfarm/templates/_helpers.tpl +++ b/kubernetes/helm-charts/buildfarm/templates/_helpers.tpl @@ -61,6 +61,18 @@ Create the name of the service account to use {{- end }} {{- end }} +{{/* +Create the APIsersion of the holizontal pod autoscaler +*/}} +{{- define "buildfarm.autoscalingVersion" -}} +{{- if (.Capabilities.APIVersions.Has "autoscaling/v2") -}} +autoscaling/v2 +{{- else if (.Capabilities.APIVersions.Has "autoscaling/v2beta2") -}} +autoscaling/v2beta2 +{{- else -}} +autoscaling/v1 +{{- end -}} +{{- end -}} {{/* Checks for `externalRedis` */}} {{- if .Values.externalRedis.host }} diff --git a/kubernetes/helm-charts/buildfarm/templates/shard-worker/autoscaler.yaml b/kubernetes/helm-charts/buildfarm/templates/shard-worker/autoscaler.yaml index 5cdfe05e1f..fecd104fbc 100644 --- a/kubernetes/helm-charts/buildfarm/templates/shard-worker/autoscaler.yaml +++ b/kubernetes/helm-charts/buildfarm/templates/shard-worker/autoscaler.yaml @@ -1,5 +1,5 @@ {{- if .Values.shardWorker.autoscaling.enabled -}} -apiVersion: autoscaling/v1 +apiVersion: {{ include "buildfarm.autoscalingVersion" . }} kind: HorizontalPodAutoscaler metadata: name: {{ include "buildfarm.fullname" . }}-shard-worker @@ -17,5 +17,14 @@ spec: apiVersion: apps/v1 kind: StatefulSet name: {{ include "buildfarm.fullname" . }}-shard-worker + {{- if contains "autoscaling/v2" (include "buildfarm.autoscalingVersion" . ) }} + {{- if .Values.shardWorker.autoscaling.behavior }} + behavior: + {{- toYaml .Values.shardWorker.autoscaling.behavior | nindent 4 }} + {{- end }} + metrics: + {{- toYaml .Values.shardWorker.autoscaling.metrics | nindent 4 }} + {{- else }} targetCPUUtilizationPercentage: {{ .Values.shardWorker.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} {{- end }} diff --git a/kubernetes/helm-charts/buildfarm/values.yaml b/kubernetes/helm-charts/buildfarm/values.yaml index ff3f0c7ae2..d7fdb2ae32 100644 --- a/kubernetes/helm-charts/buildfarm/values.yaml +++ b/kubernetes/helm-charts/buildfarm/values.yaml @@ -109,7 +109,15 @@ shardWorker: enabled: true minReplicas: 2 maxReplicas: 4 - targetCPUUtilizationPercentage: 50 + behavior: {} # effective only in `v2*` + metrics: # effective only in `v2*` + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 50 + targetCPUUtilizationPercentage: 50 # effective only in `v1` resources: { } # We usually recommend not to specify default resources and to leave this as a conscious From 7376458cc31b6899d6893e22995b04d0baef01f0 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Mon, 11 Mar 2024 11:05:02 -0700 Subject: [PATCH 231/311] chores: bump google-java-format to 1.20.0 (#1649) * chores: bump google-java-format to 1.20.0 * style: apply google-java-format 1.20.0 * style: drop extra semicolons * docs: update documentation URL Updating the documentation link. --- .bazelci/format.sh | 2 +- .../cas/ContentAddressableStorages.java | 4 +- .../java/build/buildfarm/cas/GrpcCAS.java | 6 +- .../java/build/buildfarm/cas/MemoryCAS.java | 5 +- .../build/buildfarm/cas/cfc/CASFileCache.java | 58 ++-- .../cas/cfc/CasFallbackDelegate.java | 3 + .../build/buildfarm/common/LoggingMain.java | 6 +- .../buildfarm/common/OperationFailer.java | 3 +- .../java/build/buildfarm/common/Write.java | 1 + .../common/config/BuildfarmConfigs.java | 3 +- .../build/buildfarm/common/grpc/Retrier.java | 10 +- .../buildfarm/common/redis/Timestamp.java | 4 +- .../build/buildfarm/instance/Instance.java | 1 + .../java/build/buildfarm/instance/Utils.java | 2 +- .../instance/server/NodeInstance.java | 14 +- .../instance/shard/JedisClusterFactory.java | 13 +- .../instance/shard/OperationQueue.java | 8 +- .../buildfarm/instance/shard/Operations.java | 1 + .../instance/shard/RedisShardBackplane.java | 12 +- .../instance/shard/RedisShardSubscriber.java | 4 +- .../shard/RemoteInputStreamFactory.java | 2 +- .../instance/shard/ServerInstance.java | 44 +-- .../buildfarm/instance/shard/Writes.java | 2 +- .../buildfarm/instance/stub/StubInstance.java | 9 +- .../metrics/AbstractMetricsPublisher.java | 8 +- .../proxy/http/AuthAndTLSOptions.java | 4 +- .../proxy/http/BlobWriteObserver.java | 3 +- .../buildfarm/proxy/http/HttpBlobStore.java | 2 +- .../build/buildfarm/proxy/http/HttpProxy.java | 2 +- .../build/buildfarm/proxy/http/Utils.java | 1 + .../server/services/CapabilitiesService.java | 4 +- .../java/build/buildfarm/tools/CacheLoad.java | 6 +- src/main/java/build/buildfarm/tools/Cat.java | 6 +- .../java/build/buildfarm/tools/Executor.java | 2 +- .../buildfarm/tools/GracefulShutdown.java | 3 +- .../build/buildfarm/tools/WorkerProfile.java | 3 +- .../worker/DequeueMatchEvaluator.java | 1 + .../buildfarm/worker/DockerExecutor.java | 15 + .../buildfarm/worker/ExecDirException.java | 2 +- .../java/build/buildfarm/worker/Executor.java | 4 +- .../java/build/buildfarm/worker/FuseCAS.java | 2 +- .../build/buildfarm/worker/InputFetcher.java | 7 +- .../build/buildfarm/worker/MatchStage.java | 3 +- .../buildfarm/worker/OperationContext.java | 16 +- .../java/build/buildfarm/worker/Pipeline.java | 1 + .../build/buildfarm/worker/PipelineStage.java | 2 +- .../buildfarm/worker/ReportResultStage.java | 3 +- .../worker/SuperscalarPipelineStage.java | 2 +- .../build/buildfarm/worker/cgroup/Group.java | 5 +- .../resources/LocalResourceSetMetrics.java | 3 +- .../worker/resources/ResourceLimits.java | 1 + .../worker/shard/LocalCasWriter.java | 2 +- .../worker/shard/RemoteCasWriter.java | 4 +- .../worker/shard/ShardCASFileCache.java | 2 +- .../worker/shard/ShardWorkerContext.java | 6 +- .../build/buildfarm/worker/shard/Worker.java | 14 +- .../worker/shard/WorkerInstance.java | 6 +- .../java/build/buildfarm/cas/GrpcCASTest.java | 17 +- .../buildfarm/cas/cfc/CASFileCacheTest.java | 108 ++++---- .../cas/cfc/DirectoriesIndexTest.java | 20 +- .../common/grpc/ByteStreamHelperTest.java | 4 +- .../common/grpc/ByteStreamServiceWriter.java | 2 +- .../grpc/StubWriteOutputStreamTest.java | 16 +- .../buildfarm/common/io/DirectoriesTest.java | 9 +- .../services/ByteStreamServiceTest.java | 4 +- .../instance/server/NodeInstanceTest.java | 142 +++++----- .../instance/shard/DispatchedMonitorTest.java | 2 +- .../shard/RedisShardBackplaneTest.java | 10 +- .../shard/RedisShardSubscriberTest.java | 4 +- .../instance/shard/ServerInstanceTest.java | 35 +-- .../instance/shard/UnobservableWatcher.java | 2 +- .../buildfarm/instance/shard/UtilTest.java | 10 +- .../instance/stub/ByteStreamUploaderTest.java | 6 +- .../instance/stub/StubInstanceTest.java | 4 +- .../metrics/MetricsPublisherTest.java | 12 +- .../proxy/http/ByteStreamServiceTest.java | 4 +- .../worker/ExecuteActionStageTest.java | 2 +- .../build/buildfarm/worker/FuseCASTest.java | 28 +- .../buildfarm/worker/InputFetcherTest.java | 6 +- .../buildfarm/worker/PipelineStageTest.java | 3 +- .../worker/ReportResultStageTest.java | 6 +- .../worker/SuperscalarPipelineStageTest.java | 6 +- .../persistent/ProtoCoordinatorTest.java | 3 +- .../worker/resources/ResourceDeciderTest.java | 261 +++++++++--------- .../shard/EmptyInputStreamFactoryTest.java | 4 +- .../shard/FailoverInputStreamFactoryTest.java | 12 +- .../worker/shard/ShardWorkerContextTest.java | 36 +-- .../worker/shard/WorkerInstanceTest.java | 38 +-- 88 files changed, 602 insertions(+), 576 deletions(-) diff --git a/.bazelci/format.sh b/.bazelci/format.sh index f1255c9c2e..d88f698cfd 100755 --- a/.bazelci/format.sh +++ b/.bazelci/format.sh @@ -5,7 +5,7 @@ FORMAT_JAVA=true REMOVE_NEWLINES_AFTER_START_BRACKET=true -JAVA_FORMATTER_URL=https://github.com/google/google-java-format/releases/download/google-java-format-1.7/google-java-format-1.7-all-deps.jar +JAVA_FORMATTER_URL=https://github.com/google/google-java-format/releases/download/v1.20.0/google-java-format-1.20.0-all-deps.jar LOCAL_FORMATTER="java_formatter.jar" FORMAT_PROTO=true diff --git a/src/main/java/build/buildfarm/cas/ContentAddressableStorages.java b/src/main/java/build/buildfarm/cas/ContentAddressableStorages.java index e1df38fae4..5956296ba2 100644 --- a/src/main/java/build/buildfarm/cas/ContentAddressableStorages.java +++ b/src/main/java/build/buildfarm/cas/ContentAddressableStorages.java @@ -78,8 +78,8 @@ public static ContentAddressableStorage createFilesystemCAS(Cas config) config, configs.getMaxEntrySizeBytes(), DigestUtil.forHash("SHA256"), - /* expireService=*/ newDirectExecutorService(), - /* accessRecorder=*/ directExecutor()) { + /* expireService= */ newDirectExecutorService(), + /* accessRecorder= */ directExecutor()) { @Override protected InputStream newExternalInput( Compressor.Value compressor, Digest digest, long offset) throws IOException { diff --git a/src/main/java/build/buildfarm/cas/GrpcCAS.java b/src/main/java/build/buildfarm/cas/GrpcCAS.java index 5640962456..be660e9b7b 100644 --- a/src/main/java/build/buildfarm/cas/GrpcCAS.java +++ b/src/main/java/build/buildfarm/cas/GrpcCAS.java @@ -121,7 +121,7 @@ private InputStream newStreamInput(String resourceName, long offset) throws IOEx bsStub, NO_RETRIES::newBackoff, NO_RETRIES::isRetriable, - /* retryService=*/ null); + /* retryService= */ null); } private String readResourceName(Compressor.Value compressor, Digest digest) { @@ -237,7 +237,7 @@ public ListenableFuture> getAllFuture(Iterable digests) { @Override public Blob get(Digest digest) { try (InputStream in = - newStreamInput(readResourceName(Compressor.Value.IDENTITY, digest), /* offset=*/ 0)) { + newStreamInput(readResourceName(Compressor.Value.IDENTITY, digest), /* offset= */ 0)) { ByteString content = ByteString.readFrom(in); if (content.size() != digest.getSizeBytes()) { throw new IOException( @@ -282,7 +282,7 @@ public static Write newWrite( resourceName, Functions.identity(), digest.getSizeBytes(), - /* autoflush=*/ false); + /* autoflush= */ false); } @Override diff --git a/src/main/java/build/buildfarm/cas/MemoryCAS.java b/src/main/java/build/buildfarm/cas/MemoryCAS.java index 08ac8540c2..2fe77528e8 100644 --- a/src/main/java/build/buildfarm/cas/MemoryCAS.java +++ b/src/main/java/build/buildfarm/cas/MemoryCAS.java @@ -63,7 +63,7 @@ public class MemoryCAS implements ContentAddressableStorage { private final Writes writes = new Writes(this); public MemoryCAS(long maxSizeInBytes) { - this(maxSizeInBytes, (digest) -> {}, /* delegate=*/ null); + this(maxSizeInBytes, (digest) -> {}, /* delegate= */ null); } public MemoryCAS( @@ -281,7 +281,8 @@ private synchronized boolean add(Blob blob, Runnable onExpiration) { log.log( Level.WARNING, String.format( - "Out of nodes to remove, sizeInBytes = %d, maxSizeInBytes = %d, storage = %d, list = %d", + "Out of nodes to remove, sizeInBytes = %d, maxSizeInBytes = %d, storage = %d, list =" + + " %d", sizeInBytes, maxSizeInBytes, storage.size(), size())); } diff --git a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java index d6b47490df..a0515d6b1b 100644 --- a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java +++ b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java @@ -232,7 +232,7 @@ public Write load(BlobWriteKey key) { @Override public SettableFuture load(Digest digest) { SettableFuture future = SettableFuture.create(); - if (containsLocal(digest, /* result=*/ null, (key) -> {})) { + if (containsLocal(digest, /* result= */ null, (key) -> {})) { future.set(digest.getSizeBytes()); } return future; @@ -324,12 +324,12 @@ public CASFileCache( digestUtil, expireService, accessRecorder, - /* storage=*/ Maps.newConcurrentMap(), - /* directoriesIndexDbName=*/ DEFAULT_DIRECTORIES_INDEX_NAME, - /* onPut=*/ (digest) -> {}, - /* onExpire=*/ (digests) -> {}, - /* delegate=*/ null, - /* delegateSkipLoad=*/ false); + /* storage= */ Maps.newConcurrentMap(), + /* directoriesIndexDbName= */ DEFAULT_DIRECTORIES_INDEX_NAME, + /* onPut= */ (digest) -> {}, + /* onExpire= */ (digests) -> {}, + /* delegate= */ null, + /* delegateSkipLoad= */ false); } public CASFileCache( @@ -598,7 +598,7 @@ public InputStream newInput(Compressor.Value compressor, Digest digest, long off @Override public Blob get(Digest digest) { - try (InputStream in = newInput(Compressor.Value.IDENTITY, digest, /* offset=*/ 0)) { + try (InputStream in = newInput(Compressor.Value.IDENTITY, digest, /* offset= */ 0)) { return new Blob(ByteString.readFrom(in), digest); } catch (NoSuchFileException e) { return null; @@ -634,7 +634,7 @@ public void get( boolean readThrough = shouldReadThrough(requestMetadata); InputStream in; try { - if (readThrough && !contains(digest, /* result=*/ null)) { + if (readThrough && !contains(digest, /* result= */ null)) { // really need to be able to reuse/restart the same write over // multiple requests - if we get successive read throughs for a single // digest, we should pick up from where we were last time @@ -760,9 +760,9 @@ public void put(Blob blob, Runnable onExpiration) throws InterruptedException { UUID.randomUUID(), () -> completeWrite(blob.getDigest()), blob.getDigest().getSizeBytes(), - /* isExecutable=*/ false, + /* isExecutable= */ false, () -> invalidateWrite(blob.getDigest()), - /* isReset=*/ true); + /* isReset= */ true); boolean referenced = out == null; try { if (out != null) { @@ -871,7 +871,7 @@ public void close() throws IOException { super.close(); } } finally { - onClosed.accept(/* cancelled=*/ false); + onClosed.accept(/* cancelled= */ false); } } @@ -880,7 +880,7 @@ public void cancel() throws IOException { try { out.cancel(); } finally { - onClosed.accept(/* cancelled=*/ true); + onClosed.accept(/* cancelled= */ true); } } } @@ -959,7 +959,7 @@ synchronized long getCommittedSizeFromOut() { public synchronized boolean isComplete() { return getFuture().isDone() || ((closedFuture == null || closedFuture.isDone()) - && containsLocal(key.getDigest(), /* result=*/ null, (key) -> {})); + && containsLocal(key.getDigest(), /* result= */ null, (key) -> {})); } @Override @@ -1107,7 +1107,7 @@ CancellableOutputStream newOutput( uuid, () -> completeWrite(digest), digest.getSizeBytes(), - /* isExecutable=*/ false, + /* isExecutable= */ false, () -> invalidateWrite(digest), isReset); } catch (InterruptedException e) { @@ -1156,14 +1156,14 @@ public void write(byte[] b, int off, int len) throws IOException { @Override public void cancel() throws IOException { - if (closed.compareAndSet(/* expected=*/ false, /* update=*/ true)) { + if (closed.compareAndSet(/* expected= */ false, /* update= */ true)) { cancellableOut.cancel(); } } @Override public void close() throws IOException { - if (closed.compareAndSet(/* expected=*/ false, /* update=*/ true)) { + if (closed.compareAndSet(/* expected= */ false, /* update= */ true)) { try { out.close(); decrementReference(key); @@ -1182,7 +1182,7 @@ public long getWrittenForClose() { @Override public void put(Blob blob) throws InterruptedException { - put(blob, /* onExpiration=*/ null); + put(blob, /* onExpiration= */ null); } @Override @@ -1209,7 +1209,7 @@ public void lock() { public void lockInterruptibly() throws InterruptedException { // attempt to atomically synchronize synchronized (locked) { - while (!locked.compareAndSet(/* expected=*/ false, /* update=*/ true)) { + while (!locked.compareAndSet(/* expected= */ false, /* update= */ true)) { locked.wait(); } } @@ -1236,7 +1236,7 @@ public boolean tryLock(long time, TimeUnit unit) { @Override public void unlock() { - if (!locked.compareAndSet(/* expected=*/ true, /* update=*/ false)) { + if (!locked.compareAndSet(/* expected= */ true, /* update= */ false)) { throw new IllegalMonitorStateException("the lock was not held"); } synchronized (locked) { @@ -1840,7 +1840,8 @@ private Entry waitForLastUnreferencedEntry(long blobSizeInBytes) throws Interrup log.log( Level.INFO, format( - "CASFileCache::expireEntry(%d) unreferenced list is empty, %d bytes, %d keys with %d references, min(%d, %s), max(%d, %s)", + "CASFileCache::expireEntry(%d) unreferenced list is empty, %d bytes, %d keys with %d" + + " references, min(%d, %s), max(%d, %s)", blobSizeInBytes, sizeInBytes, keys, references, min, minkey, max, maxkey)); wait(); if (sizeInBytes <= maxSizeInBytes) { @@ -2005,7 +2006,8 @@ private ListenableFuture expireEntry(long blobSizeInBytes, ExecutorServic e = waitForLastUnreferencedEntry(blobSizeInBytes)) { if (e.referenceCount != 0) { throw new IllegalStateException( - "ERROR: Reference counts lru ordering has not been maintained correctly, attempting to expire referenced (or negatively counted) content " + "ERROR: Reference counts lru ordering has not been maintained correctly, attempting to" + + " expire referenced (or negatively counted) content " + e.key + " with " + e.referenceCount @@ -2319,7 +2321,8 @@ private ListenableFuture putDirectorySynchronized( log.log( Level.SEVERE, format( - "CASFileCache::putDirectory(%s) exists, but input %s does not, purging it with fire and resorting to fetch", + "CASFileCache::putDirectory(%s) exists, but input %s does not, purging it with" + + " fire and resorting to fetch", DigestUtil.toString(digest), input)); e = null; break; @@ -2334,12 +2337,13 @@ private ListenableFuture putDirectorySynchronized( if (e != null) { log.log(Level.FINER, format("found existing entry for %s", path.getFileName())); if (directoryEntryExists(path, e, directoriesByDigest)) { - return immediateFuture(new PathResult(path, /* missed=*/ false)); + return immediateFuture(new PathResult(path, /* missed= */ false)); } log.log( Level.SEVERE, format( - "directory %s does not exist in cache, purging it with fire and resorting to fetch", + "directory %s does not exist in cache, purging it with fire and resorting to" + + " fetch", path.getFileName())); } @@ -2467,7 +2471,7 @@ private ListenableFuture putDirectorySynchronized( : directoriesByDigest.get(digest), Deadline.after(10, SECONDS)); directoryStorage.put(digest, e); - return new PathResult(path, /* missed=*/ true); + return new PathResult(path, /* missed= */ true); }, service); } @@ -2502,7 +2506,7 @@ Path putAndCopy(Digest digest, boolean isExecutable) throws IOException, Interru digest.getSizeBytes(), isExecutable, () -> invalidateWrite(digest), - /* isReset=*/ true); + /* isReset= */ true); if (out != null) { boolean complete = false; try { diff --git a/src/main/java/build/buildfarm/cas/cfc/CasFallbackDelegate.java b/src/main/java/build/buildfarm/cas/cfc/CasFallbackDelegate.java index 5404e6383b..35cf2c2ad5 100644 --- a/src/main/java/build/buildfarm/cas/cfc/CasFallbackDelegate.java +++ b/src/main/java/build/buildfarm/cas/cfc/CasFallbackDelegate.java @@ -52,6 +52,7 @@ public static void start( fileCacheDelegate.start(onStartPut, removeDirectoryService, skipLoad); } } + /** * @brief Get an inputstream to read the given digest data. * @details Creates the delegate's inputstream if possible. @@ -74,6 +75,7 @@ public static InputStream newInput( } return delegate.newInput(compressor, digest, offset); } + /** * @brief Query delegate CAS to find missing blobs. * @details Will not query delegate if there are no missing blobs given. @@ -92,6 +94,7 @@ public static Iterable findMissingBlobs( return delegate.findMissingBlobs(missingDigests); } + /** * @brief Check if delegate CAS contains blob. * @details Will be false if CAS delegate is unavailable. diff --git a/src/main/java/build/buildfarm/common/LoggingMain.java b/src/main/java/build/buildfarm/common/LoggingMain.java index 4e60a6286a..605f3ca3ef 100644 --- a/src/main/java/build/buildfarm/common/LoggingMain.java +++ b/src/main/java/build/buildfarm/common/LoggingMain.java @@ -21,8 +21,8 @@ protected LoggingMain(String applicationName) { Runtime.getRuntime() .addShutdownHook( new Thread( - /* group=*/ null, - /* target=*/ this::shutdown, - /* name=*/ applicationName + "-Shutdown")); + /* group= */ null, + /* target= */ this::shutdown, + /* name= */ applicationName + "-Shutdown")); } } diff --git a/src/main/java/build/buildfarm/common/OperationFailer.java b/src/main/java/build/buildfarm/common/OperationFailer.java index c06b0f2dcc..6e0f1f9a73 100644 --- a/src/main/java/build/buildfarm/common/OperationFailer.java +++ b/src/main/java/build/buildfarm/common/OperationFailer.java @@ -30,8 +30,7 @@ */ public class OperationFailer { public static Operation get(Operation operation, ExecuteEntry executeEntry, Status status) { - return operation - .toBuilder() + return operation.toBuilder() .setDone(true) .setName(executeEntry.getOperationName()) .setMetadata( diff --git a/src/main/java/build/buildfarm/common/Write.java b/src/main/java/build/buildfarm/common/Write.java index ff4f5ccac9..e7f90d0448 100644 --- a/src/main/java/build/buildfarm/common/Write.java +++ b/src/main/java/build/buildfarm/common/Write.java @@ -66,6 +66,7 @@ public FeedbackOutputStream getOutput( /** Discards the specified byte. */ @Override public void write(int b) {} + /** Discards the specified byte array. */ @Override public void write(byte[] b) { diff --git a/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java b/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java index 05d7915b27..3f9b5461c4 100644 --- a/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java +++ b/src/main/java/build/buildfarm/common/config/BuildfarmConfigs.java @@ -311,7 +311,8 @@ private static void checkExecutionWrapperAvailability(BuildfarmConfigs configs) if (Files.notExists(Paths.get(tool))) { String message = String.format( - "the execution wrapper %s is missing and therefore the following features will not be available: %s", + "the execution wrapper %s is missing and therefore the following" + + " features will not be available: %s", tool, String.join(", ", features)); log.warning(message); } diff --git a/src/main/java/build/buildfarm/common/grpc/Retrier.java b/src/main/java/build/buildfarm/common/grpc/Retrier.java index 6fd7802e79..3e81bbf528 100644 --- a/src/main/java/build/buildfarm/common/grpc/Retrier.java +++ b/src/main/java/build/buildfarm/common/grpc/Retrier.java @@ -100,10 +100,10 @@ public int getRetryAttempts() { static Supplier sequential(int maxAttempts) { return exponential( - /* initial=*/ Duration.ZERO, - /* max=*/ Duration.ZERO, - /* multiplier=*/ 1.1, - /* jitter=*/ 0.0, + /* initial= */ Duration.ZERO, + /* max= */ Duration.ZERO, + /* multiplier= */ 1.1, + /* jitter= */ 0.0, maxAttempts); } @@ -203,7 +203,7 @@ public int getRetryAttempts() { @SuppressWarnings("Guava") public Retrier(Supplier backoffSupplier, Predicate isRetriable) { - this(backoffSupplier, isRetriable, /* retryScheduler=*/ null); + this(backoffSupplier, isRetriable, /* retryScheduler= */ null); } @SuppressWarnings("Guava") diff --git a/src/main/java/build/buildfarm/common/redis/Timestamp.java b/src/main/java/build/buildfarm/common/redis/Timestamp.java index 5ada4bbeb5..cdf810eccf 100644 --- a/src/main/java/build/buildfarm/common/redis/Timestamp.java +++ b/src/main/java/build/buildfarm/common/redis/Timestamp.java @@ -3,9 +3,9 @@ public class Timestamp { public Long getMillis() { return System.currentTimeMillis(); - }; + } public Long getNanos() { return System.nanoTime(); - }; + } } diff --git a/src/main/java/build/buildfarm/instance/Instance.java b/src/main/java/build/buildfarm/instance/Instance.java index aeba238743..5ae73f24ce 100644 --- a/src/main/java/build/buildfarm/instance/Instance.java +++ b/src/main/java/build/buildfarm/instance/Instance.java @@ -127,6 +127,7 @@ ListenableFuture execute( boolean putAndValidateOperation(Operation operation) throws InterruptedException; boolean pollOperation(String operationName, ExecutionStage.Value stage); + // returns nextPageToken suitable for list restart String listOperations( int pageSize, String pageToken, String filter, ImmutableList.Builder operations); diff --git a/src/main/java/build/buildfarm/instance/Utils.java b/src/main/java/build/buildfarm/instance/Utils.java index 01f8b91336..0efc86b855 100644 --- a/src/main/java/build/buildfarm/instance/Utils.java +++ b/src/main/java/build/buildfarm/instance/Utils.java @@ -47,7 +47,7 @@ public static ByteString getBlob( RequestMetadata requestMetadata) throws IOException, InterruptedException { return getBlob( - instance, compressor, blobDigest, /* offset=*/ 0, 60, TimeUnit.SECONDS, requestMetadata); + instance, compressor, blobDigest, /* offset= */ 0, 60, TimeUnit.SECONDS, requestMetadata); } public static ByteString getBlob( diff --git a/src/main/java/build/buildfarm/instance/server/NodeInstance.java b/src/main/java/build/buildfarm/instance/server/NodeInstance.java index e44305f32e..37741aa1b1 100644 --- a/src/main/java/build/buildfarm/instance/server/NodeInstance.java +++ b/src/main/java/build/buildfarm/instance/server/NodeInstance.java @@ -417,7 +417,7 @@ public ListenableFuture> getAllBlobsFuture(Iterable diges } protected ByteString getBlob(Digest blobDigest) throws InterruptedException { - return getBlob(blobDigest, /* count=*/ blobDigest.getSizeBytes()); + return getBlob(blobDigest, /* count= */ blobDigest.getSizeBytes()); } ByteString getBlob(Digest blobDigest, long count) throws IndexOutOfBoundsException { @@ -445,7 +445,7 @@ ByteString getBlob(Digest blobDigest, long count) throws IndexOutOfBoundsExcepti protected ListenableFuture getBlobFuture( Compressor.Value compressor, Digest blobDigest, RequestMetadata requestMetadata) { return getBlobFuture( - compressor, blobDigest, /* count=*/ blobDigest.getSizeBytes(), requestMetadata); + compressor, blobDigest, /* count= */ blobDigest.getSizeBytes(), requestMetadata); } protected ListenableFuture getBlobFuture( @@ -454,7 +454,7 @@ protected ListenableFuture getBlobFuture( getBlob( compressor, blobDigest, - /* offset=*/ 0, + /* offset= */ 0, count, new ServerCallStreamObserver() { ByteString content = ByteString.EMPTY; @@ -980,7 +980,7 @@ protected ListenableFuture getTreeFuture( Tree.Builder tree = Tree.newBuilder().setRootDigest(inputRoot); TokenizableIterator iterator = - createTreeIterator(reason, inputRoot, /* pageToken=*/ ""); + createTreeIterator(reason, inputRoot, /* pageToken= */ ""); while (iterator.hasNext()) { DirectoryEntry entry = iterator.next(); Directory directory = entry.getDirectory(); @@ -1862,8 +1862,7 @@ protected void errorOperation( .setRequestMetadata(requestMetadata) .build(); putOperation( - operation - .toBuilder() + operation.toBuilder() .setDone(true) .setMetadata(Any.pack(completedMetadata)) .setResponse(Any.pack(ExecuteResponse.newBuilder().setStatus(status).build())) @@ -1891,8 +1890,7 @@ protected void expireOperation(Operation operation) throws InterruptedException } metadata = metadata.toBuilder().setStage(ExecutionStage.Value.COMPLETED).build(); putOperation( - operation - .toBuilder() + operation.toBuilder() .setDone(true) .setMetadata(Any.pack(metadata)) .setResponse(Any.pack(executeResponse)) diff --git a/src/main/java/build/buildfarm/instance/shard/JedisClusterFactory.java b/src/main/java/build/buildfarm/instance/shard/JedisClusterFactory.java index 2bfb48ac9e..693f1193e2 100644 --- a/src/main/java/build/buildfarm/instance/shard/JedisClusterFactory.java +++ b/src/main/java/build/buildfarm/instance/shard/JedisClusterFactory.java @@ -160,13 +160,13 @@ private static Supplier createJedisClusterFactory( return () -> new JedisCluster( new HostAndPort(redisUri.getHost(), redisUri.getPort()), - /* connectionTimeout=*/ Integer.max(2000, timeout), - /* soTimeout=*/ Integer.max(2000, timeout), + /* connectionTimeout= */ Integer.max(2000, timeout), + /* soTimeout= */ Integer.max(2000, timeout), Integer.max(5, maxAttempts), password, identifier, poolConfig, - /* ssl=*/ JedisURIHelper.isRedisSSLScheme(redisUri)); + /* ssl= */ JedisURIHelper.isRedisSSLScheme(redisUri)); } /** @@ -190,14 +190,15 @@ private static Supplier createJedisClusterFactory( return () -> new JedisCluster( redisUrisNodes, - /* connectionTimeout=*/ Integer.max(2000, timeout), - /* soTimeout=*/ Integer.max(2000, timeout), + /* connectionTimeout= */ Integer.max(2000, timeout), + /* soTimeout= */ Integer.max(2000, timeout), Integer.max(5, maxAttempts), password, identifier, poolConfig, - /* ssl=*/ false); + /* ssl= */ false); } + /** * @brief Create a jedis pool config. * @details Use configuration to build the appropriate jedis pool configuration. diff --git a/src/main/java/build/buildfarm/instance/shard/OperationQueue.java b/src/main/java/build/buildfarm/instance/shard/OperationQueue.java index 78dd77c769..8d341f301c 100644 --- a/src/main/java/build/buildfarm/instance/shard/OperationQueue.java +++ b/src/main/java/build/buildfarm/instance/shard/OperationQueue.java @@ -332,9 +332,11 @@ private void throwNoEligibleQueueException(List provisions) { } throw new RuntimeException( - "there are no eligible queues for the provided execution requirements." - + " One solution to is to configure a provision queue with no requirements which would be eligible to all operations." - + " See https://github.com/bazelbuild/bazel-buildfarm/wiki/Shard-Platform-Operation-Queue for details. " + "There are no eligible queues for the provided execution requirements. One solution to is" + + " to configure a provision queue with no requirements which would be eligible to all" + + " operations. See" + + " https://bazelbuild.github.io/bazel-buildfarm/docs/architecture/queues/" + + " for details. " + eligibilityResults); } diff --git a/src/main/java/build/buildfarm/instance/shard/Operations.java b/src/main/java/build/buildfarm/instance/shard/Operations.java index c114fe32ef..50e4fbf0f8 100644 --- a/src/main/java/build/buildfarm/instance/shard/Operations.java +++ b/src/main/java/build/buildfarm/instance/shard/Operations.java @@ -30,6 +30,7 @@ */ public class Operations { private static BuildfarmConfigs configs = BuildfarmConfigs.getInstance(); + /** * @field operationIds * @brief A mapping from operationID -> operation diff --git a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java index 5977cc1a5b..6fc4c7844d 100644 --- a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java +++ b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java @@ -490,14 +490,14 @@ private void startSubscriptionThread() { operationSubscription = new RedisShardSubscription( subscriber, - /* onUnsubscribe=*/ () -> { + /* onUnsubscribe= */ () -> { subscriptionThread = null; if (onUnsubscribe != null) { onUnsubscribe.runInterruptibly(); } }, - /* onReset=*/ this::updateWatchedIfDone, - /* subscriptions=*/ subscriber::subscribedChannels, + /* onReset= */ this::updateWatchedIfDone, + /* subscriptions= */ subscriber::subscribedChannels, client); // use Executors... @@ -655,7 +655,7 @@ public boolean removeWorker(String name, String reason) throws IOException { String workerChangeJson = JsonFormat.printer().print(workerChange); return storageWorkers.remove(name) != null && client.call( - jedis -> removeWorkerAndPublish(jedis, name, workerChangeJson, /* storage=*/ true)); + jedis -> removeWorkerAndPublish(jedis, name, workerChangeJson, /* storage= */ true)); } @SuppressWarnings("ConstantConditions") @@ -800,11 +800,11 @@ private void removeInvalidWorkers( } private Map fetchAndExpireStorageWorkers(JedisCluster jedis) { - return fetchAndExpireWorkers(jedis, state.storageWorkers.asMap(jedis), /* storage=*/ true); + return fetchAndExpireWorkers(jedis, state.storageWorkers.asMap(jedis), /* storage= */ true); } private Map fetchAndExpireExecuteWorkers(JedisCluster jedis) { - return fetchAndExpireWorkers(jedis, state.executeWorkers.asMap(jedis), /* storage=*/ false); + return fetchAndExpireWorkers(jedis, state.executeWorkers.asMap(jedis), /* storage= */ false); } private Map fetchAndExpireWorkers( diff --git a/src/main/java/build/buildfarm/instance/shard/RedisShardSubscriber.java b/src/main/java/build/buildfarm/instance/shard/RedisShardSubscriber.java index 9e68f0f41a..69f6aaebdd 100644 --- a/src/main/java/build/buildfarm/instance/shard/RedisShardSubscriber.java +++ b/src/main/java/build/buildfarm/instance/shard/RedisShardSubscriber.java @@ -175,7 +175,7 @@ public void resetWatchers(String channel, Instant expiresAt) { private void terminateExpiredWatchers(String channel, Instant now, boolean force) { onOperation( channel, - /* operation=*/ null, + /* operation= */ null, (watcher) -> { boolean expired = force || watcher.isExpiredAt(now); if (expired) { @@ -187,7 +187,7 @@ private void terminateExpiredWatchers(String channel, Instant now, boolean force } return expired; }, - /* expiresAt=*/ null); + /* expiresAt= */ null); } public void onOperation(String channel, Operation operation, Instant expiresAt) { diff --git a/src/main/java/build/buildfarm/instance/shard/RemoteInputStreamFactory.java b/src/main/java/build/buildfarm/instance/shard/RemoteInputStreamFactory.java index 8a00e9ae96..e3c8b5a4ca 100644 --- a/src/main/java/build/buildfarm/instance/shard/RemoteInputStreamFactory.java +++ b/src/main/java/build/buildfarm/instance/shard/RemoteInputStreamFactory.java @@ -72,7 +72,7 @@ public interface UnavailableConsumer { Random rand, LoadingCache workerStubs, UnavailableConsumer onUnavailable) { - this(/* publicName=*/ null, backplane, rand, workerStubs, onUnavailable); + this(/* publicName= */ null, backplane, rand, workerStubs, onUnavailable); } @SuppressWarnings("NullableProblems") diff --git a/src/main/java/build/buildfarm/instance/shard/ServerInstance.java b/src/main/java/build/buildfarm/instance/shard/ServerInstance.java index 5f7173150c..aa8d442f5f 100644 --- a/src/main/java/build/buildfarm/instance/shard/ServerInstance.java +++ b/src/main/java/build/buildfarm/instance/shard/ServerInstance.java @@ -269,7 +269,7 @@ private static Backplane createBackplane(String identifier) throws Configuration if (configs.getBackplane().getType().equals(SHARD)) { return new RedisShardBackplane( identifier, - /* subscribeToBackplane=*/ true, + /* subscribeToBackplane= */ true, configs.getServer().isRunFailsafeOperation(), ServerInstance::stripOperation, ServerInstance::stripQueuedOperation); @@ -285,7 +285,7 @@ public ServerInstance(String name, String identifier, DigestUtil digestUtil, Run digestUtil, createBackplane(identifier), onStop, - /* actionCacheFetchService=*/ BuildfarmExecutors.getActionCacheFetchServicePool()); + /* actionCacheFetchService= */ BuildfarmExecutors.getActionCacheFetchServicePool()); } private ServerInstance( @@ -360,11 +360,11 @@ public ServerInstance( super( name, digestUtil, - /* contentAddressableStorage=*/ null, - /* actionCache=*/ actionCache, - /* outstandingOperations=*/ null, - /* completedOperations=*/ null, - /* activeBlobWrites=*/ null, + /* contentAddressableStorage= */ null, + /* actionCache= */ actionCache, + /* outstandingOperations= */ null, + /* completedOperations= */ null, + /* activeBlobWrites= */ null, ensureOutputsPresent); this.backplane = backplane; this.actionCache = actionCache; @@ -453,7 +453,8 @@ public void onFailure(Throwable t) { log.log( Level.FINER, format( - "OperationQueuer: Dispatched To Transform %s: %dus in canQueue, %dus in transform dispatch", + "OperationQueuer: Dispatched To Transform %s: %dus in canQueue, %dus in" + + " transform dispatch", operationName, canQueueUSecs, operationTransformDispatchUSecs)); return queueFuture; } catch (Throwable t) { @@ -1710,7 +1711,10 @@ protected void validatePlatform( .setSubject(INVALID_PLATFORM) .setDescription( format( - "properties are not valid for queue eligibility: %s. If you think your queue should still accept these poperties without them being specified in queue configuration, consider configuring the queue with `allow_unmatched: True`", + "properties are not valid for queue eligibility: %s. If you think your queue" + + " should still accept these poperties without them being specified in queue" + + " configuration, consider configuring the queue with `allow_unmatched:" + + " True`", platform.getPropertiesList())); } @@ -2113,8 +2117,7 @@ public ListenableFuture execute( if (inDenyList(requestMetadata)) { watcher.observe( - operation - .toBuilder() + operation.toBuilder() .setDone(true) .setResponse(Any.pack(denyActionResponse(actionDigest, BLOCK_LIST_ERROR))) .build()); @@ -2124,7 +2127,7 @@ public ListenableFuture execute( return watchOperation( operation, newActionResultWatcher(DigestUtil.asActionKey(actionDigest), watcher), - /* initial=*/ false); + /* initial= */ false); } catch (IOException e) { return immediateFailedFuture(e); } @@ -2197,8 +2200,7 @@ private void deliverCachedActionResult( .build(); Operation completedOperation = - operation - .toBuilder() + operation.toBuilder() .setDone(true) .setResponse( Any.pack( @@ -2375,7 +2377,8 @@ private ListenableFuture transformAndQueue( log.log( Level.FINER, format( - "ServerInstance(%s): queue(%s): fetched action %s transforming queuedOperation", + "ServerInstance(%s): queue(%s): fetched action %s transforming" + + " queuedOperation", getName(), operation.getName(), actionDigest.getHash())); Stopwatch transformStopwatch = Stopwatch.createStarted(); return transform( @@ -2479,7 +2482,8 @@ public void onSuccess(ProfiledQueuedOperationMetadata profiledQueuedMetadata) { log.log( Level.FINER, format( - "ServerInstance(%s): queue(%s): %dus checkCache, %dus transform, %dus validate, %dus upload, %dus queue, %dus elapsed", + "ServerInstance(%s): queue(%s): %dus checkCache, %dus transform, %dus" + + " validate, %dus upload, %dus queue, %dus elapsed", getName(), queueOperation.getName(), checkCacheUSecs, @@ -2674,7 +2678,7 @@ public ListenableFuture watchOperation(String operationName, Watcher watch .withDescription(String.format("Operation not found: %s", operationName)) .asException()); } - return watchOperation(operation, watcher, /* initial=*/ true); + return watchOperation(operation, watcher, /* initial= */ true); } private static Operation stripOperation(Operation operation) { @@ -2688,8 +2692,7 @@ private static Operation stripOperation(Operation operation) { private static Operation stripQueuedOperation(Operation operation) { if (operation.getMetadata().is(QueuedOperationMetadata.class)) { operation = - operation - .toBuilder() + operation.toBuilder() .setMetadata(Any.pack(expectExecuteOperationMetadata(operation))) .build(); } @@ -2789,8 +2792,7 @@ protected CacheCapabilities getCacheCapabilities() { configs.isAllowSymlinkTargetAbsolute() ? SymlinkAbsolutePathStrategy.Value.ALLOWED : SymlinkAbsolutePathStrategy.Value.DISALLOWED; - return super.getCacheCapabilities() - .toBuilder() + return super.getCacheCapabilities().toBuilder() .setSymlinkAbsolutePathStrategy(symlinkAbsolutePathStrategy) .build(); } diff --git a/src/main/java/build/buildfarm/instance/shard/Writes.java b/src/main/java/build/buildfarm/instance/shard/Writes.java index 4b0c1526c1..95e6166dca 100644 --- a/src/main/java/build/buildfarm/instance/shard/Writes.java +++ b/src/main/java/build/buildfarm/instance/shard/Writes.java @@ -117,7 +117,7 @@ public ListenableFuture getFuture() { } Writes(Supplier instanceSupplier) { - this(instanceSupplier, /* writeExpiresAfter=*/ 1); + this(instanceSupplier, /* writeExpiresAfter= */ 1); } Writes(Supplier instanceSupplier, long writeExpiresAfter) { diff --git a/src/main/java/build/buildfarm/instance/stub/StubInstance.java b/src/main/java/build/buildfarm/instance/stub/StubInstance.java index 84ff692ab6..bc744682cd 100644 --- a/src/main/java/build/buildfarm/instance/stub/StubInstance.java +++ b/src/main/java/build/buildfarm/instance/stub/StubInstance.java @@ -184,7 +184,7 @@ public StubInstance( DigestUtil digestUtil, ManagedChannel channel, Duration grpcTimeout) { - this(name, identifier, digestUtil, channel, grpcTimeout, NO_RETRIES, /* retryService=*/ null); + this(name, identifier, digestUtil, channel, grpcTimeout, NO_RETRIES, /* retryService= */ null); } public StubInstance( @@ -502,7 +502,7 @@ public Write getOperationStreamWrite(String name) { name, Functions.identity(), StubWriteOutputStream.UNLIMITED_EXPECTED_SIZE, - /* autoflush=*/ true, + /* autoflush= */ true, RequestMetadata.getDefaultInstance()); } @@ -536,6 +536,7 @@ static class ReadBlobInterchange implements ClientResponseObserver blobObserver; private ClientCallStreamObserver requestStream; + // Guard against spurious onReady() calls caused by a race between onNext() and // onReady(). If the transport toggles isReady() from false to true while onNext() // is executing, but before onNext() checks isReady(). request(1) would be called @@ -543,9 +544,11 @@ static class ReadBlobInterchange implements ClientResponseObserver responseObserver) { numberOfRemoteInvocations.inc(); responseObserver.onNext( - instance - .getCapabilities() - .toBuilder() + instance.getCapabilities().toBuilder() .setLowApiVersion(SemVer.newBuilder().setMajor(2)) .setHighApiVersion(SemVer.newBuilder().setMajor(2)) .build()); diff --git a/src/main/java/build/buildfarm/tools/CacheLoad.java b/src/main/java/build/buildfarm/tools/CacheLoad.java index 1694f32da9..7686ae63da 100644 --- a/src/main/java/build/buildfarm/tools/CacheLoad.java +++ b/src/main/java/build/buildfarm/tools/CacheLoad.java @@ -67,10 +67,10 @@ public static void main(String[] args) throws Exception { new LocalCASFileCache( root, configs.getWorker().getStorages().get(0), - /* maxSizeInBytes=*/ Size.gbToBytes(500), + /* maxSizeInBytes= */ Size.gbToBytes(500), new DigestUtil(HashFunction.SHA1), - /* expireService=*/ newDirectExecutorService(), - /* accessRecorder=*/ directExecutor()); + /* expireService= */ newDirectExecutorService(), + /* accessRecorder= */ directExecutor()); // Start cache and measure startup time (reported internally). StartupCacheResults results = fileCache.start(newDirectExecutorService(), true); diff --git a/src/main/java/build/buildfarm/tools/Cat.java b/src/main/java/build/buildfarm/tools/Cat.java index f80e579f64..06fdf92b82 100644 --- a/src/main/java/build/buildfarm/tools/Cat.java +++ b/src/main/java/build/buildfarm/tools/Cat.java @@ -929,7 +929,8 @@ protected void run(Instance instance, Digest digest) throws Exception { static class TreeLayout extends DigestsCommand { @Override public String description() { - return "Rich tree layout of root directory [digests...], with weighting and missing tolerance"; + return "Rich tree layout of root directory [digests...], with weighting and missing" + + " tolerance"; } @Override @@ -1009,7 +1010,8 @@ protected void run(Instance instance, ByteString blob) { static class DumpQueuedOperation extends BlobCommand { @Override public String description() { - return "Binary QueuedOperation [digests...] content, suitable for retention in local 'blobs' directory and use with bf-executor"; + return "Binary QueuedOperation [digests...] content, suitable for retention in local 'blobs'" + + " directory and use with bf-executor"; } @Override diff --git a/src/main/java/build/buildfarm/tools/Executor.java b/src/main/java/build/buildfarm/tools/Executor.java index 901ff33a95..4d18a28084 100644 --- a/src/main/java/build/buildfarm/tools/Executor.java +++ b/src/main/java/build/buildfarm/tools/Executor.java @@ -369,7 +369,7 @@ private static List findMissingBlobs( FileStore fileStore = Files.getFileStore(blobsDir); try (DirectoryStream stream = Files.newDirectoryStream(blobsDir)) { for (Path file : stream) { - FileStatus stat = stat(file, /* followSymlinks=*/ false, fileStore); + FileStatus stat = stat(file, /* followSymlinks= */ false, fileStore); Digest digest = DigestUtil.buildDigest(file.getFileName().toString().split("_")[0], stat.getSize()); diff --git a/src/main/java/build/buildfarm/tools/GracefulShutdown.java b/src/main/java/build/buildfarm/tools/GracefulShutdown.java index 689edfeff1..337b68be02 100644 --- a/src/main/java/build/buildfarm/tools/GracefulShutdown.java +++ b/src/main/java/build/buildfarm/tools/GracefulShutdown.java @@ -94,7 +94,8 @@ public static void main(String[] args) { break; default: System.out.println( - "The action your choose is wrong. Please choose one from ShutDown, PrepareWorker, and DisableProtection"); + "The action your choose is wrong. Please choose one from ShutDown, PrepareWorker, and" + + " DisableProtection"); break; } } diff --git a/src/main/java/build/buildfarm/tools/WorkerProfile.java b/src/main/java/build/buildfarm/tools/WorkerProfile.java index 69dbb8cdee..c4f226a948 100644 --- a/src/main/java/build/buildfarm/tools/WorkerProfile.java +++ b/src/main/java/build/buildfarm/tools/WorkerProfile.java @@ -154,7 +154,8 @@ private static void workerProfile(String[] args) throws IOException { } if (workers == null || workers.isEmpty()) { System.out.println( - "cannot find any workers, check the redis url and make sure there are workers in the cluster"); + "cannot find any workers, check the redis url and make sure there are workers in the" + + " cluster"); } else { // remove the unregistered workers for (String existingWorker : workersToChannels.keySet()) { diff --git a/src/main/java/build/buildfarm/worker/DequeueMatchEvaluator.java b/src/main/java/build/buildfarm/worker/DequeueMatchEvaluator.java index 8f9d712481..b3443fcabb 100644 --- a/src/main/java/build/buildfarm/worker/DequeueMatchEvaluator.java +++ b/src/main/java/build/buildfarm/worker/DequeueMatchEvaluator.java @@ -42,6 +42,7 @@ */ public class DequeueMatchEvaluator { private static BuildfarmConfigs configs = BuildfarmConfigs.getInstance(); + /** * @brief Decide whether the worker should keep the operation or put it back on the queue. * @details Compares the platform properties of the worker to the operation's platform properties. diff --git a/src/main/java/build/buildfarm/worker/DockerExecutor.java b/src/main/java/build/buildfarm/worker/DockerExecutor.java index 924821f5c4..22ce3cb0fb 100644 --- a/src/main/java/build/buildfarm/worker/DockerExecutor.java +++ b/src/main/java/build/buildfarm/worker/DockerExecutor.java @@ -85,6 +85,7 @@ public static Code runActionWithDocker( cleanUpContainer(dockerClient, containerId); return Code.OK; } + /** * @brief Setup the container for the action. * @details This ensures the image is fetched, the container is started, and that the container @@ -113,6 +114,7 @@ private static String prepareRequestedContainer( // container is ready for running actions return containerId; } + /** * @brief Fetch the user requested image for running the action. * @details The image will not be fetched if it already exists. @@ -130,6 +132,7 @@ private static void fetchImageIfMissing( .awaitCompletion(fetchTimeout.getSeconds(), TimeUnit.SECONDS); } } + /** * @brief Check to see if the image was already available. * @details Checking to see if the image is already available can avoid having to re-fetch it. @@ -148,6 +151,7 @@ private static boolean isLocalImagePresent(DockerClient dockerClient, String ima } return true; } + /** * @brief Get all the host paths that should be populated into the container. * @details Paths with use docker's copy archive API. @@ -161,6 +165,7 @@ private static List getPopulatePaths(Path execDir) { paths.addAll(Utils.getSymbolicLinkReferences(execDir)); return paths; } + /** * @brief Populate the container as needed by copying files into it. * @details This may or may not be necessary depending on mounts / volumes. @@ -174,6 +179,7 @@ private static void populateContainer( copyPathIntoContainer(dockerClient, containerId, path); } } + /** * @brief Copies the file or directory into the container. * @details Copies all folder descendants. @@ -190,6 +196,7 @@ private static void copyPathIntoContainer( cmd.withRemotePath(path.toAbsolutePath().toString()); cmd.exec(); } + /** * @brief Get the exit code of the action that was executed inside the container. * @details Docker stores the exit code after the execution and it can be queried with an execId. @@ -203,6 +210,7 @@ private static void extractExitCode( InspectExecResponse response = inspectExecCmd.exec(); resultBuilder.setExitCode(response.getExitCodeLong().intValue()); } + /** * @brief Extract information from the container after the action ran. * @details This can include exit code, output artifacts, and various docker information. @@ -222,6 +230,7 @@ private static void extractInformationFromContainer( extractExitCode(dockerClient, execId, resultBuilder); copyOutputsOutOfContainer(dockerClient, settings, containerId); } + /** * @brief Copies action outputs out of the container. * @details The outputs are known by the operation context. @@ -241,6 +250,7 @@ private static void copyOutputsOutOfContainer( outputDirPath.toFile().mkdirs(); } } + /** * @brief Delete the container. * @details Forces container deletion. @@ -254,6 +264,7 @@ private static void cleanUpContainer(DockerClient dockerClient, String container log.log(Level.SEVERE, "couldn't shutdown container: ", e); } } + /** * @brief Assuming the container is already created and properly populated/mounted with data, this * can be used to spawn an action inside of it. @@ -289,6 +300,7 @@ private static String runActionInsideContainer( return execId; } + /** * @brief Create a docker container for the action to run in. * @details We can use a separate container per action or keep containers alive and re-use them. @@ -317,6 +329,7 @@ private static String createContainer( // container is ready and started return response.getId(); } + /** * @brief Create a host config used for container creation. * @details This can determine container mounts and volumes. @@ -329,6 +342,7 @@ private static HostConfig getHostConfig(Path execDir) { mountExecRoot(config, execDir); return config; } + /** * @brief Add paths needed to mount the exec root. * @details These are added to the host config. @@ -350,6 +364,7 @@ private static void mountExecRoot(HostConfig config, Path execDir) { config.withBinds(binds); } + /** * @brief Copy the given file out of the container to the same host path. * @details The file is extracted as a tar and deserialized. diff --git a/src/main/java/build/buildfarm/worker/ExecDirException.java b/src/main/java/build/buildfarm/worker/ExecDirException.java index 40c625232c..c7c909597f 100644 --- a/src/main/java/build/buildfarm/worker/ExecDirException.java +++ b/src/main/java/build/buildfarm/worker/ExecDirException.java @@ -113,7 +113,7 @@ Status.Builder toStatus(Status.Builder status) { if (putDirCause instanceof IOException) { Violation.Builder violation = preconditionFailure.addViolationsBuilder(); ViolationException.toViolation( - violation, putDirCause, /* path=*/ null, /* isExecutable=*/ false); + violation, putDirCause, /* path= */ null, /* isExecutable= */ false); if (putDirCause instanceof NoSuchFileException) { violation.setSubject("blobs/" + putDirCause.getMessage()); } else { diff --git a/src/main/java/build/buildfarm/worker/Executor.java b/src/main/java/build/buildfarm/worker/Executor.java index 2891488f52..de8a7d0fcf 100644 --- a/src/main/java/build/buildfarm/worker/Executor.java +++ b/src/main/java/build/buildfarm/worker/Executor.java @@ -114,9 +114,7 @@ private long runInterruptible(Stopwatch stopwatch, ResourceLimits limits) } Operation operation = - operationContext - .operation - .toBuilder() + operationContext.operation.toBuilder() .setMetadata( Any.pack( ExecutingOperationMetadata.newBuilder() diff --git a/src/main/java/build/buildfarm/worker/FuseCAS.java b/src/main/java/build/buildfarm/worker/FuseCAS.java index b9697d0133..391b3ce3b7 100644 --- a/src/main/java/build/buildfarm/worker/FuseCAS.java +++ b/src/main/java/build/buildfarm/worker/FuseCAS.java @@ -399,7 +399,7 @@ private synchronized void incMounts() throws IOException { log.log(Level.INFO, "Mounting FuseCAS"); String[] fuseOpts = {"-o", "max_write=131072", "-o", "big_writes"}; try { - mount(mountPath, /* blocking=*/ false, /* debug=*/ false, /* fuseOpts=*/ fuseOpts); + mount(mountPath, /* blocking= */ false, /* debug= */ false, /* fuseOpts= */ fuseOpts); } catch (FuseException e) { throw new IOException(e); } diff --git a/src/main/java/build/buildfarm/worker/InputFetcher.java b/src/main/java/build/buildfarm/worker/InputFetcher.java index 23a0d6af2f..df841cbc4c 100644 --- a/src/main/java/build/buildfarm/worker/InputFetcher.java +++ b/src/main/java/build/buildfarm/worker/InputFetcher.java @@ -218,9 +218,7 @@ long fetchPolled(Stopwatch stopwatch) throws InterruptedException { String programName = queuedOperation.getCommand().getArguments(0); Directory root = directoriesIndex.get(queuedOperation.getTree().getRootDigest()); Command command = - queuedOperation - .getCommand() - .toBuilder() + queuedOperation.getCommand().toBuilder() .clearArguments() .addArguments(getExecutablePath(programName, root, directoriesIndex)) .addAllArguments(Iterables.skip(queuedOperation.getCommand().getArgumentsList(), 1)) @@ -262,8 +260,7 @@ private void proceedToOutput(Action action, Command command, Path execDir, Tree Deadline.after(10, DAYS)); OperationContext fetchedOperationContext = - operationContext - .toBuilder() + operationContext.toBuilder() .setExecDir(execDir) .setAction(action) .setCommand(command) diff --git a/src/main/java/build/buildfarm/worker/MatchStage.java b/src/main/java/build/buildfarm/worker/MatchStage.java index 663aee3c52..48c60a91f1 100644 --- a/src/main/java/build/buildfarm/worker/MatchStage.java +++ b/src/main/java/build/buildfarm/worker/MatchStage.java @@ -81,8 +81,7 @@ public boolean onEntry(@Nullable QueueEntry queueEntry) throws InterruptedExcept Preconditions.checkState(poller == null); operationContext = - operationContext - .toBuilder() + operationContext.toBuilder() .setQueueEntry(queueEntry) .setPoller(workerContext.createPoller("MatchStage", queueEntry, QUEUED)) .build(); diff --git a/src/main/java/build/buildfarm/worker/OperationContext.java b/src/main/java/build/buildfarm/worker/OperationContext.java index 7220fc100b..027d364afd 100644 --- a/src/main/java/build/buildfarm/worker/OperationContext.java +++ b/src/main/java/build/buildfarm/worker/OperationContext.java @@ -124,14 +124,14 @@ public OperationContext build() { public static Builder newBuilder() { return new Builder( - /* executeResponse=*/ ExecuteResponse.newBuilder(), - /* operation=*/ null, - /* poller=*/ null, - /* execDir=*/ null, - /* action=*/ null, - /* command=*/ null, - /* tree=*/ null, - /* queueEntry=*/ null); + /* executeResponse= */ ExecuteResponse.newBuilder(), + /* operation= */ null, + /* poller= */ null, + /* execDir= */ null, + /* action= */ null, + /* command= */ null, + /* tree= */ null, + /* queueEntry= */ null); } public Builder toBuilder() { diff --git a/src/main/java/build/buildfarm/worker/Pipeline.java b/src/main/java/build/buildfarm/worker/Pipeline.java index 6b2d4f2a7d..a753cf3fe1 100644 --- a/src/main/java/build/buildfarm/worker/Pipeline.java +++ b/src/main/java/build/buildfarm/worker/Pipeline.java @@ -27,6 +27,7 @@ public class Pipeline { private final Map stageClosePriorities; private Thread joiningThread = null; private boolean closing = false; + // FIXME ThreadGroup? public Pipeline() { diff --git a/src/main/java/build/buildfarm/worker/PipelineStage.java b/src/main/java/build/buildfarm/worker/PipelineStage.java index 49bd392a2e..b33cf9ea5e 100644 --- a/src/main/java/build/buildfarm/worker/PipelineStage.java +++ b/src/main/java/build/buildfarm/worker/PipelineStage.java @@ -246,7 +246,7 @@ public PipelineStage error() { public static class NullStage extends PipelineStage { public NullStage() { - this(/* workerContext=*/ null, /* output=*/ null); + this(/* workerContext= */ null, /* output= */ null); } public NullStage(WorkerContext workerContext, PipelineStage output) { diff --git a/src/main/java/build/buildfarm/worker/ReportResultStage.java b/src/main/java/build/buildfarm/worker/ReportResultStage.java index d7bf8eeba2..a0ae1968b6 100644 --- a/src/main/java/build/buildfarm/worker/ReportResultStage.java +++ b/src/main/java/build/buildfarm/worker/ReportResultStage.java @@ -174,8 +174,7 @@ private OperationContext reportPolled(OperationContext operationContext) .build(); Operation completedOperation = - operation - .toBuilder() + operation.toBuilder() .setDone(true) .setMetadata(Any.pack(completedMetadata)) .setResponse(Any.pack(executeResponse)) diff --git a/src/main/java/build/buildfarm/worker/SuperscalarPipelineStage.java b/src/main/java/build/buildfarm/worker/SuperscalarPipelineStage.java index ed7e610a10..192835455c 100644 --- a/src/main/java/build/buildfarm/worker/SuperscalarPipelineStage.java +++ b/src/main/java/build/buildfarm/worker/SuperscalarPipelineStage.java @@ -95,7 +95,7 @@ synchronized void waitForReleaseOrCatastrophe(BlockingQueue qu releaseClaim(operationContext.operation.getName(), claimsRequired(operationContext)); } else { try { - wait(/* timeout=*/ 10); + wait(/* timeout= */ 10); } catch (InterruptedException e) { interrupted = Thread.interrupted() || interrupted; // ignore, we will throw it eventually diff --git a/src/main/java/build/buildfarm/worker/cgroup/Group.java b/src/main/java/build/buildfarm/worker/cgroup/Group.java index 53fd9c8cbd..d8906ed344 100644 --- a/src/main/java/build/buildfarm/worker/cgroup/Group.java +++ b/src/main/java/build/buildfarm/worker/cgroup/Group.java @@ -27,7 +27,7 @@ @Log public final class Group { - private static final Group root = new Group(/* name=*/ null, /* parent=*/ null); + private static final Group root = new Group(/* name= */ null, /* parent= */ null); private static final Path rootPath = Paths.get("/sys/fs/cgroup"); private @Nullable final String name; @@ -127,7 +127,8 @@ private List getPids(String controllerName) throws IOException { @SuppressWarnings("StatementWithEmptyBody") public void killUntilEmpty(String controllerName) throws IOException { - while (!killAllProcs(controllerName)) ; + while (!killAllProcs(controllerName)) + ; } void create(String controllerName) throws IOException { diff --git a/src/main/java/build/buildfarm/worker/resources/LocalResourceSetMetrics.java b/src/main/java/build/buildfarm/worker/resources/LocalResourceSetMetrics.java index 787a7840e5..d219d56612 100644 --- a/src/main/java/build/buildfarm/worker/resources/LocalResourceSetMetrics.java +++ b/src/main/java/build/buildfarm/worker/resources/LocalResourceSetMetrics.java @@ -41,6 +41,7 @@ public class LocalResourceSetMetrics { .name("local_resource_requesters") .labelNames("resource_name") .help( - "Tracks how many actions have requested local resources. This can help determine if resources are being hogged by some actions.") + "Tracks how many actions have requested local resources. This can help determine if" + + " resources are being hogged by some actions.") .register(); } diff --git a/src/main/java/build/buildfarm/worker/resources/ResourceLimits.java b/src/main/java/build/buildfarm/worker/resources/ResourceLimits.java index e20f2c9c27..e40ce738a2 100644 --- a/src/main/java/build/buildfarm/worker/resources/ResourceLimits.java +++ b/src/main/java/build/buildfarm/worker/resources/ResourceLimits.java @@ -163,6 +163,7 @@ public class ResourceLimits { * @details This can be used to debug execution behavior. */ public final ArrayList description = new ArrayList<>(); + /** * @field persistentWorkerKey * @brief Hash of tool inputs for remote persistent workers diff --git a/src/main/java/build/buildfarm/worker/shard/LocalCasWriter.java b/src/main/java/build/buildfarm/worker/shard/LocalCasWriter.java index 0cdb88810c..f5285a2cfd 100644 --- a/src/main/java/build/buildfarm/worker/shard/LocalCasWriter.java +++ b/src/main/java/build/buildfarm/worker/shard/LocalCasWriter.java @@ -62,7 +62,7 @@ private void insertStream(Digest digest, IOSupplier suppliedStream) Write write = getLocalWrite(digest); try (OutputStream out = - write.getOutput(/* deadlineAfter=*/ 1, /* deadlineAfterUnits=*/ DAYS, () -> {}); + write.getOutput(/* deadlineAfter= */ 1, /* deadlineAfterUnits= */ DAYS, () -> {}); InputStream in = suppliedStream.get()) { ByteStreams.copy(in, out); } catch (IOException e) { diff --git a/src/main/java/build/buildfarm/worker/shard/RemoteCasWriter.java b/src/main/java/build/buildfarm/worker/shard/RemoteCasWriter.java index 7c379077a6..e16c2888c7 100644 --- a/src/main/java/build/buildfarm/worker/shard/RemoteCasWriter.java +++ b/src/main/java/build/buildfarm/worker/shard/RemoteCasWriter.java @@ -151,8 +151,8 @@ private ListenableFuture streamIntoWriteFuture(InputStream in, Write write // the callback closes the stream and prepares the future. FeedbackOutputStream out = write.getOutput( - /* deadlineAfter=*/ 1, - /* deadlineAfterUnits=*/ DAYS, + /* deadlineAfter= */ 1, + /* deadlineAfterUnits= */ DAYS, () -> { try { FeedbackOutputStream outStream = (FeedbackOutputStream) write; diff --git a/src/main/java/build/buildfarm/worker/shard/ShardCASFileCache.java b/src/main/java/build/buildfarm/worker/shard/ShardCASFileCache.java index b03cbe6f32..81a9042e1c 100644 --- a/src/main/java/build/buildfarm/worker/shard/ShardCASFileCache.java +++ b/src/main/java/build/buildfarm/worker/shard/ShardCASFileCache.java @@ -56,7 +56,7 @@ class ShardCASFileCache extends CASFileCache { digestUtil, expireService, accessRecorder, - /* storage=*/ Maps.newConcurrentMap(), + /* storage= */ Maps.newConcurrentMap(), DEFAULT_DIRECTORIES_INDEX_NAME, onPut, onExpire, diff --git a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java index 71bc76e9e4..006db931fa 100644 --- a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java +++ b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java @@ -538,7 +538,8 @@ private void uploadOutputFile( if (maxEntrySize != UNLIMITED_ENTRY_SIZE_MAX && size > maxEntrySize) { String message = String.format( - "ReportResultStage: The output %s could not be uploaded because it exceeded the maximum size of an entry (%d > %d)", + "ReportResultStage: The output %s could not be uploaded because it exceeded the" + + " maximum size of an entry (%d > %d)", outputPath, size, maxEntrySize); preconditionFailure .addViolationsBuilder() @@ -696,7 +697,8 @@ private void visitRegularFile(Path file, BasicFileAttributes attrs) throws IOExc .setType(entrySizeViolationType) .setSubject("blobs/" + DigestUtil.toString(digest)) .setDescription( - "An output could not be uploaded because it exceeded the maximum size of an entry"); + "An output could not be uploaded because it exceeded the maximum size of an" + + " entry"); } } diff --git a/src/main/java/build/buildfarm/worker/shard/Worker.java b/src/main/java/build/buildfarm/worker/shard/Worker.java index ecfd68e15f..844f1f1e72 100644 --- a/src/main/java/build/buildfarm/worker/shard/Worker.java +++ b/src/main/java/build/buildfarm/worker/shard/Worker.java @@ -144,11 +144,13 @@ public final class Worker extends LoggingMain { public void prepareWorkerForGracefulShutdown() { if (configs.getWorker().getGracefulShutdownSeconds() == 0) { log.info( - "Graceful Shutdown is not enabled. Worker is shutting down without finishing executions in progress."); + "Graceful Shutdown is not enabled. Worker is shutting down without finishing executions" + + " in progress."); } else { inGracefulShutdown = true; log.info( - "Graceful Shutdown - The current worker will not be registered again and should be shutdown gracefully!"); + "Graceful Shutdown - The current worker will not be registered again and should be" + + " shutdown gracefully!"); pipeline.stopMatchingOperations(); int scanRate = 30; // check every 30 seconds int timeWaited = 0; @@ -384,8 +386,8 @@ private ExecFileSystem createCFCExecFileSystem( configs.isAllowSymlinkTargetAbsolute(), removeDirectoryService, accessRecorder - /* deadlineAfter=*/ - /* deadlineAfterUnits=*/ ); + /* deadlineAfter= */ + /* deadlineAfterUnits= */ ); } private void onStoragePut(Digest digest) { @@ -541,8 +543,8 @@ public void start() throws ConfigurationException, InterruptedException, IOExcep backplane = new RedisShardBackplane( identifier, - /* subscribeToBackplane=*/ false, - /* runFailsafeOperation=*/ false, + /* subscribeToBackplane= */ false, + /* runFailsafeOperation= */ false, this::stripOperation, this::stripQueuedOperation); backplane.start(configs.getWorker().getPublicName()); diff --git a/src/main/java/build/buildfarm/worker/shard/WorkerInstance.java b/src/main/java/build/buildfarm/worker/shard/WorkerInstance.java index e100417f53..e2af59aec3 100644 --- a/src/main/java/build/buildfarm/worker/shard/WorkerInstance.java +++ b/src/main/java/build/buildfarm/worker/shard/WorkerInstance.java @@ -351,8 +351,7 @@ protected static ExecuteOperationMetadata expectExecuteOperationMetadata(Operati } public Operation stripOperation(Operation operation) { - return operation - .toBuilder() + return operation.toBuilder() .setMetadata(Any.pack(expectExecuteOperationMetadata(operation))) .build(); } @@ -360,8 +359,7 @@ public Operation stripOperation(Operation operation) { public Operation stripQueuedOperation(Operation operation) { if (operation.getMetadata().is(QueuedOperationMetadata.class)) { operation = - operation - .toBuilder() + operation.toBuilder() .setMetadata(Any.pack(expectExecuteOperationMetadata(operation))) .build(); } diff --git a/src/test/java/build/buildfarm/cas/GrpcCASTest.java b/src/test/java/build/buildfarm/cas/GrpcCASTest.java index dfe0c60fd8..ed84cc02d1 100644 --- a/src/test/java/build/buildfarm/cas/GrpcCASTest.java +++ b/src/test/java/build/buildfarm/cas/GrpcCASTest.java @@ -110,7 +110,7 @@ public void read(ReadRequest request, StreamObserver responseObser GrpcCAS cas = new GrpcCAS( instanceName, - /* readonly=*/ true, + /* readonly= */ true, InProcessChannelBuilder.forName(fakeServerName).directExecutor().build(), mock(ByteStreamUploader.class), onExpirations); @@ -140,7 +140,7 @@ public void read(ReadRequest request, StreamObserver responseObser GrpcCAS cas = new GrpcCAS( instanceName, - /* readonly=*/ true, + /* readonly= */ true, InProcessChannelBuilder.forName(fakeServerName).directExecutor().build(), mock(ByteStreamUploader.class), onExpirations); @@ -158,7 +158,8 @@ public void putAddsExpiration() throws IOException, InterruptedException { MultimapBuilder.hashKeys().arrayListValues().build(); Channel channel = InProcessChannelBuilder.forName(fakeServerName).directExecutor().build(); ByteStreamUploader uploader = mock(ByteStreamUploader.class); - GrpcCAS cas = new GrpcCAS(instanceName, /* readonly=*/ false, channel, uploader, onExpirations); + GrpcCAS cas = + new GrpcCAS(instanceName, /* readonly= */ false, channel, uploader, onExpirations); Runnable onExpiration = mock(Runnable.class); cas.put(new Blob(uploadContent, digest), onExpiration); verify(uploader, times(1)) @@ -185,7 +186,7 @@ public void writeIsResumable() throws Exception { Channel channel = InProcessChannelBuilder.forName(fakeServerName).directExecutor().build(); GrpcCAS cas = new GrpcCAS( - instanceName, /* readonly=*/ false, channel, /* uploader=*/ null, onExpirations); + instanceName, /* readonly= */ false, channel, /* uploader= */ null, onExpirations); RequestMetadata requestMetadata = RequestMetadata.getDefaultInstance(); Write initialWrite = cas.getWrite(Compressor.Value.IDENTITY, digest, uuid, requestMetadata); try (OutputStream writeOut = initialWrite.getOutput(1, SECONDS, () -> {})) { @@ -207,9 +208,9 @@ public void writeIsNullForReadonly() throws Exception { GrpcCAS cas = new GrpcCAS( instanceName, - /* readonly=*/ true, - /* channel=*/ null, - /* uploader=*/ null, + /* readonly= */ true, + /* channel= */ null, + /* uploader= */ null, onExpirations); RequestMetadata requestMetadata = RequestMetadata.getDefaultInstance(); @@ -221,7 +222,7 @@ public void writeIsNullForReadonly() throws Exception { public void findMissingBlobsSwallowsFilteredList() throws Exception { Channel channel = InProcessChannelBuilder.forName(fakeServerName).directExecutor().build(); Runnable onExpiration = mock(Runnable.class); - GrpcCAS cas = new GrpcCAS("test", /* readonly=*/ false, channel, null, onExpirations); + GrpcCAS cas = new GrpcCAS("test", /* readonly= */ false, channel, null, onExpirations); ContentAddressableStorageImplBase casService = spy(ContentAddressableStorageImplBase.class); serviceRegistry.addService(casService); // Mutable calls bindService, and clearInvocations is undesirable diff --git a/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java b/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java index 48a57ee8c7..e24c14262f 100644 --- a/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java +++ b/src/test/java/build/buildfarm/cas/cfc/CASFileCacheTest.java @@ -148,20 +148,20 @@ public void setUp() throws IOException, InterruptedException { fileCache = new CASFileCache( root, - /* maxSizeInBytes=*/ 1024, - /* maxEntrySizeInBytes=*/ 1024, - /* hexBucketLevels=*/ 1, + /* maxSizeInBytes= */ 1024, + /* maxEntrySizeInBytes= */ 1024, + /* hexBucketLevels= */ 1, storeFileDirsIndexInMemory, - /* execRootFallback=*/ false, + /* execRootFallback= */ false, DIGEST_UTIL, expireService, - /* accessRecorder=*/ directExecutor(), + /* accessRecorder= */ directExecutor(), storage, - /* directoriesIndexDbName=*/ ":memory:", + /* directoriesIndexDbName= */ ":memory:", onPut, onExpire, delegate, - /* delegateSkipLoad=*/ false) { + /* delegateSkipLoad= */ false) { @Override protected InputStream newExternalInput( Compressor.Value compressor, Digest digest, long offset) throws IOException { @@ -207,7 +207,7 @@ public void putEmptyFileThrowsIllegalStateException() throws IOException, Interr ByteString blob = ByteString.copyFromUtf8(""); Digest blobDigest = DIGEST_UTIL.compute(blob); // supply an empty input stream if called for test clarity - when(mockInputStreamFactory.newInput(Compressor.Value.IDENTITY, blobDigest, /* offset=*/ 0)) + when(mockInputStreamFactory.newInput(Compressor.Value.IDENTITY, blobDigest, /* offset= */ 0)) .thenReturn(ByteString.EMPTY.newInput()); try { fileCache.put(blobDigest, false); @@ -374,7 +374,7 @@ public void startSkipsLoadingExistingBlob() throws IOException, InterruptedExcep Files.write(execPath, blob.toByteArray()); EvenMoreFiles.setReadOnlyPerms(execPath, true, fileStore); - StartupCacheResults results = fileCache.start(/* skipLoad=*/ true); + StartupCacheResults results = fileCache.start(/* skipLoad= */ true); // check the startup results to ensure our two files were processed assertThat(results.load.loadSkipped).isTrue(); @@ -399,7 +399,7 @@ public void startRemovesInvalidEntries() throws IOException, InterruptedExceptio Files.write( invalidExec, validBlob.toByteArray()); // content would match but for invalid exec field - fileCache.start(/* skipLoad=*/ false); + fileCache.start(/* skipLoad= */ false); assertThat(!Files.exists(tooFewComponents)).isTrue(); assertThat(!Files.exists(tooManyComponents)).isTrue(); @@ -434,7 +434,7 @@ public void expireEntryWaitsForUnreferencedEntry() ByteString bigContent = ByteString.copyFrom(bigData); Digest bigDigest = DIGEST_UTIL.compute(bigContent); blobs.put(bigDigest, bigContent); - Path bigPath = fileCache.put(bigDigest, /* isExecutable=*/ false); + Path bigPath = fileCache.put(bigDigest, /* isExecutable= */ false); AtomicBoolean started = new AtomicBoolean(false); ExecutorService service = newSingleThreadExecutor(); @@ -445,7 +445,7 @@ public void expireEntryWaitsForUnreferencedEntry() ByteString content = ByteString.copyFromUtf8("CAS Would Exceed Max Size"); Digest digest = DIGEST_UTIL.compute(content); blobs.put(digest, content); - fileCache.put(digest, /* isExecutable=*/ false); + fileCache.put(digest, /* isExecutable= */ false); return null; }); while (!started.get()) { @@ -475,10 +475,10 @@ public void containsRecordsAccess() throws IOException, InterruptedException { Digest digestThree = DIGEST_UTIL.compute(contentThree); blobs.put(digestThree, contentThree); - String pathOne = fileCache.put(digestOne, /* isExecutable=*/ false).getFileName().toString(); - String pathTwo = fileCache.put(digestTwo, /* isExecutable=*/ false).getFileName().toString(); + String pathOne = fileCache.put(digestOne, /* isExecutable= */ false).getFileName().toString(); + String pathTwo = fileCache.put(digestTwo, /* isExecutable= */ false).getFileName().toString(); String pathThree = - fileCache.put(digestThree, /* isExecutable=*/ false).getFileName().toString(); + fileCache.put(digestThree, /* isExecutable= */ false).getFileName().toString(); fileCache.decrementReferences( ImmutableList.of(pathOne, pathTwo, pathThree), ImmutableList.of()); /* three -> two -> one */ @@ -499,8 +499,8 @@ public void mismatchedSizeIsNotContained() throws InterruptedException { fileCache.put(blob); Digest mismatchedDigest = digest.toBuilder().setSizeBytes(digest.getSizeBytes() + 1).build(); - assertThat(fileCache.contains(digest, /* result=*/ null)).isTrue(); - assertThat(fileCache.contains(mismatchedDigest, /* result=*/ null)).isFalse(); + assertThat(fileCache.contains(digest, /* result= */ null)).isTrue(); + assertThat(fileCache.contains(mismatchedDigest, /* result= */ null)).isFalse(); } @Test @@ -696,14 +696,14 @@ public void readRemovesNonexistentEntry() throws IOException, InterruptedExcepti Blob blob = new Blob(content, DIGEST_UTIL); fileCache.put(blob); - String key = fileCache.getKey(blob.getDigest(), /* isExecutable=*/ false); + String key = fileCache.getKey(blob.getDigest(), /* isExecutable= */ false); // putCreatesFile verifies this Files.delete(fileCache.getPath(key)); // update entry with expired deadline storage.get(key).existsDeadline = Deadline.after(0, SECONDS); try (InputStream in = - fileCache.newInput(Compressor.Value.IDENTITY, blob.getDigest(), /* offset=*/ 0)) { + fileCache.newInput(Compressor.Value.IDENTITY, blob.getDigest(), /* offset= */ 0)) { fail("should not get here"); } catch (NoSuchFileException e) { // success @@ -877,18 +877,18 @@ public void duplicateExpiredEntrySuppressesDigestExpiration() } blobs.put(expiringBlob.getDigest(), expiringBlob.getData()); decrementReference( - fileCache.put(expiringBlob.getDigest(), /* isExecutable=*/ false)); // expected eviction + fileCache.put(expiringBlob.getDigest(), /* isExecutable= */ false)); // expected eviction blobs.clear(); decrementReference( fileCache.put( expiringBlob.getDigest(), - /* isExecutable=*/ true)); // should be fed from storage directly, not through delegate + /* isExecutable= */ true)); // should be fed from storage directly, not through delegate fileCache.put(new Blob(ByteString.copyFromUtf8("Hello, World"), DIGEST_UTIL)); verifyNoInteractions(onExpire); // assert expiration of non-executable digest - String expiringKey = fileCache.getKey(expiringBlob.getDigest(), /* isExecutable=*/ false); + String expiringKey = fileCache.getKey(expiringBlob.getDigest(), /* isExecutable= */ false); assertThat(storage.containsKey(expiringKey)).isFalse(); assertThat(Files.exists(fileCache.getPath(expiringKey))).isFalse(); } @@ -1112,20 +1112,20 @@ public void copyExternalInputRetries() throws Exception { CASFileCache flakyExternalCAS = new CASFileCache( root, - /* maxSizeInBytes=*/ 1024, - /* maxEntrySizeInBytes=*/ 1024, - /* hexBucketLevels=*/ 1, + /* maxSizeInBytes= */ 1024, + /* maxEntrySizeInBytes= */ 1024, + /* hexBucketLevels= */ 1, storeFileDirsIndexInMemory, - /* execRootFallback=*/ false, + /* execRootFallback= */ false, DIGEST_UTIL, expireService, - /* accessRecorder=*/ directExecutor(), + /* accessRecorder= */ directExecutor(), storage, - /* directoriesIndexDbName=*/ ":memory:", - /* onPut=*/ digest -> {}, - /* onExpire=*/ digests -> {}, - /* delegate=*/ null, - /* delegateSkipLoad=*/ false) { + /* directoriesIndexDbName= */ ":memory:", + /* onPut= */ digest -> {}, + /* onExpire= */ digests -> {}, + /* delegate= */ null, + /* delegateSkipLoad= */ false) { boolean throwUnavailable = true; @Override @@ -1175,20 +1175,20 @@ public void newInputThrowsNoSuchFileExceptionWithoutDelegate() throws Exception ContentAddressableStorage undelegatedCAS = new CASFileCache( root, - /* maxSizeInBytes=*/ 1024, - /* maxEntrySizeInBytes=*/ 1024, - /* hexBucketLevels=*/ 1, + /* maxSizeInBytes= */ 1024, + /* maxEntrySizeInBytes= */ 1024, + /* hexBucketLevels= */ 1, storeFileDirsIndexInMemory, - /* execRootFallback=*/ false, + /* execRootFallback= */ false, DIGEST_UTIL, expireService, - /* accessRecorder=*/ directExecutor(), + /* accessRecorder= */ directExecutor(), storage, - /* directoriesIndexDbName=*/ ":memory:", - /* onPut=*/ digest -> {}, - /* onExpire=*/ digests -> {}, - /* delegate=*/ null, - /* delegateSkipLoad=*/ false) { + /* directoriesIndexDbName= */ ":memory:", + /* onPut= */ digest -> {}, + /* onExpire= */ digests -> {}, + /* delegate= */ null, + /* delegateSkipLoad= */ false) { @Override protected InputStream newExternalInput( Compressor.Value compressor, Digest digest, long offset) throws IOException { @@ -1204,7 +1204,7 @@ protected InputStream newExternalInput( Digest blobDigest = DIGEST_UTIL.compute(blob); NoSuchFileException expected = null; try (InputStream in = - undelegatedCAS.newInput(Compressor.Value.IDENTITY, blobDigest, /* offset=*/ 0)) { + undelegatedCAS.newInput(Compressor.Value.IDENTITY, blobDigest, /* offset= */ 0)) { fail("should not get here"); } catch (NoSuchFileException e) { expected = e; @@ -1250,7 +1250,8 @@ public void testConcurrentWrites() throws Exception { writeStreamObserver.registerCallback(); writeStreamObserver.ownStream(); // this thread will get the ownership of stream barrier.await(); // let both the threads get same write stream. - while (write1.getState() != WAITING) ; // wait for first request to go in wait state + while (write1.getState() != WAITING) + ; // wait for first request to go in wait state writeStreamObserver.write(blob); writeStreamObserver.close(); } catch (Exception e) { @@ -1302,6 +1303,7 @@ public void onFailure(Throwable t) { synchronized void ownStream() throws Exception { this.out = write.getOutput(10, MILLISECONDS, () -> {}); } + /** * Request 1 may invoke this method for request 2 or vice-versa via callback on * write.getFuture(). Synchronization is necessary to prevent conflicts when this method is @@ -1354,8 +1356,7 @@ public OsXFileDirsIndexInMemoryCASFileCacheTest() { super( Iterables.getFirst( Jimfs.newFileSystem( - Configuration.osX() - .toBuilder() + Configuration.osX().toBuilder() .setAttributeViews("basic", "owner", "posix", "unix") .build()) .getRootDirectories(), @@ -1370,8 +1371,7 @@ public OsXFileDirsIndexInSqliteCASFileCacheTest() { super( Iterables.getFirst( Jimfs.newFileSystem( - Configuration.osX() - .toBuilder() + Configuration.osX().toBuilder() .setAttributeViews("basic", "owner", "posix", "unix") .build()) .getRootDirectories(), @@ -1386,8 +1386,7 @@ public UnixFileDirsIndexInMemoryCASFileCacheTest() { super( Iterables.getFirst( Jimfs.newFileSystem( - Configuration.unix() - .toBuilder() + Configuration.unix().toBuilder() .setAttributeViews("basic", "owner", "posix", "unix") .build()) .getRootDirectories(), @@ -1402,8 +1401,7 @@ public UnixFileDirsIndexInSqliteCASFileCacheTest() { super( Iterables.getFirst( Jimfs.newFileSystem( - Configuration.unix() - .toBuilder() + Configuration.unix().toBuilder() .setAttributeViews("basic", "owner", "posix", "unix") .build()) .getRootDirectories(), @@ -1418,8 +1416,7 @@ public WindowsFileDirsIndexInMemoryCASFileCacheTest() { super( Iterables.getFirst( Jimfs.newFileSystem( - Configuration.windows() - .toBuilder() + Configuration.windows().toBuilder() .setAttributeViews("basic", "owner", "dos", "acl", "posix", "user") .build()) .getRootDirectories(), @@ -1434,8 +1431,7 @@ public WindowsFileDirsIndexInSqliteCASFileCacheTest() { super( Iterables.getFirst( Jimfs.newFileSystem( - Configuration.windows() - .toBuilder() + Configuration.windows().toBuilder() .setAttributeViews("basic", "owner", "dos", "acl", "posix", "user") .build()) .getRootDirectories(), diff --git a/src/test/java/build/buildfarm/cas/cfc/DirectoriesIndexTest.java b/src/test/java/build/buildfarm/cas/cfc/DirectoriesIndexTest.java index 3eec66def7..3a2a2bba0d 100644 --- a/src/test/java/build/buildfarm/cas/cfc/DirectoriesIndexTest.java +++ b/src/test/java/build/buildfarm/cas/cfc/DirectoriesIndexTest.java @@ -40,7 +40,7 @@ public class DirectoriesIndexTest { private final DirectoriesIndex directoriesIndex; protected DirectoriesIndexTest(Path root, DirectoriesIndexType type) { - entryPathStrategy = new HexBucketEntryPathStrategy(root, /*levels=*/ 0); + entryPathStrategy = new HexBucketEntryPathStrategy(root, /* levels= */ 0); if (type == DirectoriesIndexType.Sqlite) { String jdbcIndexUrl = "jdbc:sqlite::memory:"; directoriesIndex = new SqliteFileDirectoriesIndex(jdbcIndexUrl, entryPathStrategy); @@ -112,8 +112,7 @@ public WindowsSqliteDirectoriesIndexTest() { super( Iterables.getFirst( Jimfs.newFileSystem( - Configuration.windows() - .toBuilder() + Configuration.windows().toBuilder() .setAttributeViews("basic", "owner", "dos", "acl", "posix", "user") .build()) .getRootDirectories(), @@ -128,8 +127,7 @@ public UnixSqliteDirectoriesIndexTest() { super( Iterables.getFirst( Jimfs.newFileSystem( - Configuration.unix() - .toBuilder() + Configuration.unix().toBuilder() .setAttributeViews("basic", "owner", "posix", "unix") .build()) .getRootDirectories(), @@ -144,8 +142,7 @@ public OsSqliteDirectoriesIndexTest() { super( Iterables.getFirst( Jimfs.newFileSystem( - Configuration.osX() - .toBuilder() + Configuration.osX().toBuilder() .setAttributeViews("basic", "owner", "posix", "unix") .build()) .getRootDirectories(), @@ -161,8 +158,7 @@ public WindowsMemoryFileDirectoriesIndexTest() { super( Iterables.getFirst( Jimfs.newFileSystem( - Configuration.windows() - .toBuilder() + Configuration.windows().toBuilder() .setAttributeViews("basic", "owner", "dos", "acl", "posix", "user") .build()) .getRootDirectories(), @@ -177,8 +173,7 @@ public UnixMemoryFileDirectoriesIndexTest() { super( Iterables.getFirst( Jimfs.newFileSystem( - Configuration.unix() - .toBuilder() + Configuration.unix().toBuilder() .setAttributeViews("basic", "owner", "posix", "unix") .build()) .getRootDirectories(), @@ -193,8 +188,7 @@ public OsMemoryFileDirectoriesIndexTest() { super( Iterables.getFirst( Jimfs.newFileSystem( - Configuration.osX() - .toBuilder() + Configuration.osX().toBuilder() .setAttributeViews("basic", "owner", "posix", "unix") .build()) .getRootDirectories(), diff --git a/src/test/java/build/buildfarm/common/grpc/ByteStreamHelperTest.java b/src/test/java/build/buildfarm/common/grpc/ByteStreamHelperTest.java index 6f456a5f31..b262217f7a 100644 --- a/src/test/java/build/buildfarm/common/grpc/ByteStreamHelperTest.java +++ b/src/test/java/build/buildfarm/common/grpc/ByteStreamHelperTest.java @@ -87,11 +87,11 @@ public void newInputThrowsOnNotFound() { try (InputStream in = ByteStreamHelper.newInput( resourceName, - /* offset=*/ 0, + /* offset= */ 0, Suppliers.ofInstance(ByteStreamGrpc.newStub(channel)), NO_RETRIES::newBackoff, NO_RETRIES::isRetriable, - /* retryService=*/ null)) { + /* retryService= */ null)) { fail("should not get here"); } catch (IOException e) { assertThat(e).isInstanceOf(NoSuchFileException.class); diff --git a/src/test/java/build/buildfarm/common/grpc/ByteStreamServiceWriter.java b/src/test/java/build/buildfarm/common/grpc/ByteStreamServiceWriter.java index ebcfe68044..bdfd2e1a72 100644 --- a/src/test/java/build/buildfarm/common/grpc/ByteStreamServiceWriter.java +++ b/src/test/java/build/buildfarm/common/grpc/ByteStreamServiceWriter.java @@ -34,7 +34,7 @@ public class ByteStreamServiceWriter extends ByteStreamImplBase { private final ByteString.Output out; public ByteStreamServiceWriter(String resourceName, SettableFuture content) { - this(resourceName, content, /* expectedSize=*/ 0); + this(resourceName, content, /* expectedSize= */ 0); } public ByteStreamServiceWriter( diff --git a/src/test/java/build/buildfarm/common/grpc/StubWriteOutputStreamTest.java b/src/test/java/build/buildfarm/common/grpc/StubWriteOutputStreamTest.java index 1c4c93c88a..4e176eba7a 100644 --- a/src/test/java/build/buildfarm/common/grpc/StubWriteOutputStreamTest.java +++ b/src/test/java/build/buildfarm/common/grpc/StubWriteOutputStreamTest.java @@ -101,8 +101,8 @@ public void queryWriteStatus( Suppliers.ofInstance(ByteStreamGrpc.newStub(channel)), unimplementedResourceName, Functions.identity(), - /* expectedSize=*/ StubWriteOutputStream.UNLIMITED_EXPECTED_SIZE, - /* autoflush=*/ true); + /* expectedSize= */ StubWriteOutputStream.UNLIMITED_EXPECTED_SIZE, + /* autoflush= */ true); assertThat(write.getCommittedSize()).isEqualTo(0); write = @@ -111,8 +111,8 @@ public void queryWriteStatus( Suppliers.ofInstance(ByteStreamGrpc.newStub(channel)), notFoundResourceName, Functions.identity(), - /* expectedSize=*/ StubWriteOutputStream.UNLIMITED_EXPECTED_SIZE, - /* autoflush=*/ true); + /* expectedSize= */ StubWriteOutputStream.UNLIMITED_EXPECTED_SIZE, + /* autoflush= */ true); assertThat(write.getCommittedSize()).isEqualTo(0); } @@ -135,8 +135,8 @@ public StreamObserver write( Suppliers.ofInstance(ByteStreamGrpc.newStub(channel)), resourceName, Functions.identity(), - /* expectedSize=*/ StubWriteOutputStream.UNLIMITED_EXPECTED_SIZE, - /* autoflush=*/ true); + /* expectedSize= */ StubWriteOutputStream.UNLIMITED_EXPECTED_SIZE, + /* autoflush= */ true); ByteString content = ByteString.copyFromUtf8("Hello, World"); try (OutputStream out = write.getOutput(1, SECONDS, () -> {})) { content.writeTo(out); @@ -159,8 +159,8 @@ public void getOutputCallback() throws IOException { Suppliers.ofInstance(ByteStreamGrpc.newStub(channel)), resourceName, Functions.identity(), - /* expectedSize=*/ StubWriteOutputStream.UNLIMITED_EXPECTED_SIZE, - /* autoflush=*/ true); + /* expectedSize= */ StubWriteOutputStream.UNLIMITED_EXPECTED_SIZE, + /* autoflush= */ true); boolean callbackTimedOut = false; try (OutputStream out = diff --git a/src/test/java/build/buildfarm/common/io/DirectoriesTest.java b/src/test/java/build/buildfarm/common/io/DirectoriesTest.java index 1759154bef..e9c707b124 100644 --- a/src/test/java/build/buildfarm/common/io/DirectoriesTest.java +++ b/src/test/java/build/buildfarm/common/io/DirectoriesTest.java @@ -142,8 +142,7 @@ public OsXDirectoriesTest() { super( Iterables.getFirst( Jimfs.newFileSystem( - Configuration.osX() - .toBuilder() + Configuration.osX().toBuilder() .setAttributeViews("basic", "owner", "posix", "unix") .build()) .getRootDirectories(), @@ -157,8 +156,7 @@ public UnixDirectoriesTest() { super( Iterables.getFirst( Jimfs.newFileSystem( - Configuration.unix() - .toBuilder() + Configuration.unix().toBuilder() .setAttributeViews("basic", "owner", "posix", "unix") .build()) .getRootDirectories(), @@ -172,8 +170,7 @@ public WindowsDirectoriesTest() { super( Iterables.getFirst( Jimfs.newFileSystem( - Configuration.windows() - .toBuilder() + Configuration.windows().toBuilder() .setAttributeViews("basic", "owner", "dos", "acl", "posix", "user") .build()) .getRootDirectories(), diff --git a/src/test/java/build/buildfarm/common/services/ByteStreamServiceTest.java b/src/test/java/build/buildfarm/common/services/ByteStreamServiceTest.java index 85b16dacf5..0ad0714a0b 100644 --- a/src/test/java/build/buildfarm/common/services/ByteStreamServiceTest.java +++ b/src/test/java/build/buildfarm/common/services/ByteStreamServiceTest.java @@ -159,7 +159,7 @@ public boolean isReady() { HashCode hash = HashCode.fromString(digest.getHash()); String resourceName = ByteStreamUploader.uploadResourceName( - /* instanceName=*/ null, uuid, hash, digest.getSizeBytes()); + /* instanceName= */ null, uuid, hash, digest.getSizeBytes()); Channel channel = InProcessChannelBuilder.forName(fakeServerName).directExecutor().build(); ByteStreamStub service = ByteStreamGrpc.newStub(channel); @@ -232,7 +232,7 @@ public boolean isReady() { HashCode hash = HashCode.fromString(digest.getHash()); String resourceName = ByteStreamUploader.uploadResourceName( - /* instanceName=*/ null, uuid, hash, digest.getSizeBytes()); + /* instanceName= */ null, uuid, hash, digest.getSizeBytes()); Channel channel = InProcessChannelBuilder.forName(fakeServerName).directExecutor().build(); ByteStreamStub service = ByteStreamGrpc.newStub(channel); diff --git a/src/test/java/build/buildfarm/instance/server/NodeInstanceTest.java b/src/test/java/build/buildfarm/instance/server/NodeInstanceTest.java index 454440281f..9ebade96e5 100644 --- a/src/test/java/build/buildfarm/instance/server/NodeInstanceTest.java +++ b/src/test/java/build/buildfarm/instance/server/NodeInstanceTest.java @@ -106,18 +106,18 @@ static class DummyServerInstance extends NodeInstance { DummyServerInstance( ContentAddressableStorage contentAddressableStorage, ActionCache actionCache) { super( - /* name=*/ null, - /* digestUtil=*/ null, + /* name= */ null, + /* digestUtil= */ null, contentAddressableStorage, actionCache, - /* outstandingOperations=*/ null, - /* completedOperations=*/ null, - /* activeBlobWrites=*/ null, + /* outstandingOperations= */ null, + /* completedOperations= */ null, + /* activeBlobWrites= */ null, false); } DummyServerInstance() { - this(/* contentAddressableStorage=*/ null, /* actionCache=*/ null); + this(/* contentAddressableStorage= */ null, /* actionCache= */ null); } @Override @@ -269,13 +269,13 @@ public void duplicateFileInputIsInvalid() { FileNode.newBuilder().setName("foo").build(), FileNode.newBuilder().setName("foo").build())) .build(), - /* pathDigests=*/ new Stack<>(), - /* visited=*/ Sets.newHashSet(), - /* directoriesIndex=*/ Maps.newHashMap(), - /* allowSymlinkTargetAbsolute=*/ false, - /* onInputFile=*/ file -> {}, - /* onInputDirectorie=*/ directory -> {}, - /* onInputDigest=*/ digest -> {}, + /* pathDigests= */ new Stack<>(), + /* visited= */ Sets.newHashSet(), + /* directoriesIndex= */ Maps.newHashMap(), + /* allowSymlinkTargetAbsolute= */ false, + /* onInputFile= */ file -> {}, + /* onInputDirectorie= */ directory -> {}, + /* onInputDigest= */ digest -> {}, preconditionFailure); assertThat(preconditionFailure.getViolationsCount()).isEqualTo(1); @@ -304,13 +304,13 @@ public void duplicateEmptyDirectoryCheckPasses() throws StatusException { .setDigest(emptyDirectoryDigest) .build())) .build(), - /* pathDigests=*/ new Stack<>(), - /* visited=*/ Sets.newHashSet(), - /* directoriesIndex=*/ ImmutableMap.of(Digest.getDefaultInstance(), emptyDirectory), - /* allowSymlinkTargetAbsolute=*/ false, - /* onInputFiles=*/ file -> {}, - /* onInputDirectories=*/ directory -> {}, - /* onInputDigests=*/ digest -> {}, + /* pathDigests= */ new Stack<>(), + /* visited= */ Sets.newHashSet(), + /* directoriesIndex= */ ImmutableMap.of(Digest.getDefaultInstance(), emptyDirectory), + /* allowSymlinkTargetAbsolute= */ false, + /* onInputFiles= */ file -> {}, + /* onInputDirectories= */ directory -> {}, + /* onInputDigests= */ digest -> {}, preconditionFailure); checkPreconditionFailure( @@ -328,13 +328,13 @@ public void unsortedFileInputIsInvalid() { FileNode.newBuilder().setName("foo").build(), FileNode.newBuilder().setName("bar").build())) .build(), - /* pathDigests=*/ new Stack<>(), - /* visited=*/ Sets.newHashSet(), - /* directoriesIndex=*/ Maps.newHashMap(), - /* allowSymlinkTargetAbsolute=*/ false, - /* onInputFiles=*/ file -> {}, - /* onInputDirectories=*/ directory -> {}, - /* onInputDigests=*/ digest -> {}, + /* pathDigests= */ new Stack<>(), + /* visited= */ Sets.newHashSet(), + /* directoriesIndex= */ Maps.newHashMap(), + /* allowSymlinkTargetAbsolute= */ false, + /* onInputFiles= */ file -> {}, + /* onInputDirectories= */ directory -> {}, + /* onInputDigests= */ digest -> {}, preconditionFailure); assertThat(preconditionFailure.getViolationsCount()).isEqualTo(1); @@ -363,13 +363,13 @@ public void duplicateDirectoryInputIsInvalid() { .setDigest(emptyDirectoryDigest) .build())) .build(), - /* pathDigests=*/ new Stack<>(), - /* visited=*/ Sets.newHashSet(), - /* directoriesIndex=*/ ImmutableMap.of(emptyDirectoryDigest, emptyDirectory), - /* allowSymlinkTargetAbsolute=*/ false, - /* onInputFiles=*/ file -> {}, - /* onInputDirectories=*/ directory -> {}, - /* onInputDigests=*/ digest -> {}, + /* pathDigests= */ new Stack<>(), + /* visited= */ Sets.newHashSet(), + /* directoriesIndex= */ ImmutableMap.of(emptyDirectoryDigest, emptyDirectory), + /* allowSymlinkTargetAbsolute= */ false, + /* onInputFiles= */ file -> {}, + /* onInputDirectories= */ directory -> {}, + /* onInputDigests= */ digest -> {}, preconditionFailure); assertThat(preconditionFailure.getViolationsCount()).isEqualTo(1); @@ -398,13 +398,13 @@ public void unsortedDirectoryInputIsInvalid() { .setDigest(emptyDirectoryDigest) .build())) .build(), - /* pathDigests=*/ new Stack<>(), - /* visited=*/ Sets.newHashSet(), - /* directoriesIndex=*/ ImmutableMap.of(emptyDirectoryDigest, emptyDirectory), - /* allowSymlinkTargetAbsolute=*/ false, - /* onInputFiles=*/ file -> {}, - /* onInputDirectories=*/ directory -> {}, - /* onInputDigests=*/ digest -> {}, + /* pathDigests= */ new Stack<>(), + /* visited= */ Sets.newHashSet(), + /* directoriesIndex= */ ImmutableMap.of(emptyDirectoryDigest, emptyDirectory), + /* allowSymlinkTargetAbsolute= */ false, + /* onInputFiles= */ file -> {}, + /* onInputDirectories= */ directory -> {}, + /* onInputDigests= */ digest -> {}, preconditionFailure); assertThat(preconditionFailure.getViolationsCount()).isEqualTo(1); @@ -425,13 +425,13 @@ public void shouldValidateIfSymlinkTargetAbsolute() { NodeInstance.validateActionInputDirectory( ACTION_INPUT_ROOT_DIRECTORY_PATH, absoluteSymlinkDirectory, - /* pathDigests=*/ new Stack<>(), - /* visited=*/ Sets.newHashSet(), - /* directoriesIndex=*/ Maps.newHashMap(), - /* allowSymlinkTargetAbsolute=*/ false, - /* onInputFile=*/ file -> {}, - /* onInputDirectorie=*/ directory -> {}, - /* onInputDigest=*/ digest -> {}, + /* pathDigests= */ new Stack<>(), + /* visited= */ Sets.newHashSet(), + /* directoriesIndex= */ Maps.newHashMap(), + /* allowSymlinkTargetAbsolute= */ false, + /* onInputFile= */ file -> {}, + /* onInputDirectorie= */ directory -> {}, + /* onInputDigest= */ digest -> {}, preconditionFailure); assertThat(preconditionFailure.getViolationsCount()).isEqualTo(1); @@ -445,13 +445,13 @@ public void shouldValidateIfSymlinkTargetAbsolute() { NodeInstance.validateActionInputDirectory( ACTION_INPUT_ROOT_DIRECTORY_PATH, absoluteSymlinkDirectory, - /* pathDigests=*/ new Stack<>(), - /* visited=*/ Sets.newHashSet(), - /* directoriesIndex=*/ Maps.newHashMap(), - /* allowSymlinkTargetAbsolute=*/ true, - /* onInputFile=*/ file -> {}, - /* onInputDirectorie=*/ directory -> {}, - /* onInputDigest=*/ digest -> {}, + /* pathDigests= */ new Stack<>(), + /* visited= */ Sets.newHashSet(), + /* directoriesIndex= */ Maps.newHashMap(), + /* allowSymlinkTargetAbsolute= */ true, + /* onInputFile= */ file -> {}, + /* onInputDirectorie= */ directory -> {}, + /* onInputDigest= */ digest -> {}, preconditionFailure); assertThat(preconditionFailure.getViolationsCount()).isEqualTo(0); } @@ -593,13 +593,13 @@ public void multipleIdenticalDirectoryMissingAreAllPreconditionFailures() { NodeInstance.validateActionInputDirectory( ACTION_INPUT_ROOT_DIRECTORY_PATH, root, - /* pathDigests=*/ new Stack<>(), - /* visited=*/ Sets.newHashSet(), - /* directoriesIndex=*/ ImmutableMap.of(), - /* allowSymlinkTargetAbsolute=*/ false, - /* onInputFiles=*/ file -> {}, - /* onInputDirectories=*/ directory -> {}, - /* onInputDigests=*/ digest -> {}, + /* pathDigests= */ new Stack<>(), + /* visited= */ Sets.newHashSet(), + /* directoriesIndex= */ ImmutableMap.of(), + /* allowSymlinkTargetAbsolute= */ false, + /* onInputFiles= */ file -> {}, + /* onInputDirectories= */ directory -> {}, + /* onInputDigests= */ digest -> {}, preconditionFailure); String missingSubject = "blobs/" + DigestUtil.toString(missingDirectoryDigest); @@ -655,13 +655,13 @@ public void validationRevisitReplicatesPreconditionFailures() { NodeInstance.validateActionInputDirectory( ACTION_INPUT_ROOT_DIRECTORY_PATH, root, - /* pathDigests=*/ new Stack<>(), - /* visited=*/ Sets.newHashSet(), - /* directoriesIndex=*/ ImmutableMap.of(fooDigest, foo), - /* allowSymlinkTargetAbsolute=*/ false, - /* onInputFiles=*/ file -> {}, - /* onInputDirectories=*/ directory -> {}, - /* onInputDigests=*/ digest -> {}, + /* pathDigests= */ new Stack<>(), + /* visited= */ Sets.newHashSet(), + /* directoriesIndex= */ ImmutableMap.of(fooDigest, foo), + /* allowSymlinkTargetAbsolute= */ false, + /* onInputFiles= */ file -> {}, + /* onInputDirectories= */ directory -> {}, + /* onInputDigests= */ digest -> {}, preconditionFailure); String missingSubject = "blobs/" + DigestUtil.toString(missingDirectoryDigest); @@ -696,7 +696,7 @@ private static void doBlob( .get( eq(Compressor.Value.IDENTITY), eq(digest), - /* offset=*/ eq(0L), + /* offset= */ eq(0L), eq(digest.getSizeBytes()), any(ServerCallStreamObserver.class), eq(requestMetadata)); @@ -765,7 +765,7 @@ public void outputDirectoriesFilesAreEnsuredPresent() throws Exception { .get( eq(Compressor.Value.IDENTITY), eq(treeDigest), - /* offset=*/ eq(0L), + /* offset= */ eq(0L), eq(treeDigest.getSizeBytes()), any(ServerCallStreamObserver.class), eq(requestMetadata)); diff --git a/src/test/java/build/buildfarm/instance/shard/DispatchedMonitorTest.java b/src/test/java/build/buildfarm/instance/shard/DispatchedMonitorTest.java index 3066570526..777f78a2e3 100644 --- a/src/test/java/build/buildfarm/instance/shard/DispatchedMonitorTest.java +++ b/src/test/java/build/buildfarm/instance/shard/DispatchedMonitorTest.java @@ -58,7 +58,7 @@ public void setUp() throws InterruptedException, IOException { MockitoAnnotations.initMocks(this); when(requeuer.apply(any(QueueEntry.class), any(Duration.class))) .thenReturn(immediateFailedFuture(new RuntimeException("unexpected requeue"))); - dispatchedMonitor = new DispatchedMonitor(backplane, requeuer, /* intervalSeconds=*/ 0); + dispatchedMonitor = new DispatchedMonitor(backplane, requeuer, /* intervalSeconds= */ 0); } @Test diff --git a/src/test/java/build/buildfarm/instance/shard/RedisShardBackplaneTest.java b/src/test/java/build/buildfarm/instance/shard/RedisShardBackplaneTest.java index bf7360eeee..f0dd36c4fb 100644 --- a/src/test/java/build/buildfarm/instance/shard/RedisShardBackplaneTest.java +++ b/src/test/java/build/buildfarm/instance/shard/RedisShardBackplaneTest.java @@ -73,8 +73,8 @@ public void setUp() throws IOException { public RedisShardBackplane createBackplane(String name) { return new RedisShardBackplane( name, - /* subscribeToBackplane=*/ false, - /* runFailsafeOperation=*/ false, + /* subscribeToBackplane= */ false, + /* runFailsafeOperation= */ false, o -> o, o -> o, mockJedisClusterFactory); @@ -368,9 +368,11 @@ public void testGetWorkersStartTime() throws IOException { Map workersJson = Map.of( "worker1", - "{\"endpoint\": \"worker1\", \"expireAt\": \"9999999999999\", \"workerType\": 3, \"firstRegisteredAt\": \"1685292624000\"}", + "{\"endpoint\": \"worker1\", \"expireAt\": \"9999999999999\", \"workerType\": 3," + + " \"firstRegisteredAt\": \"1685292624000\"}", "worker2", - "{\"endpoint\": \"worker2\", \"expireAt\": \"9999999999999\", \"workerType\": 3, \"firstRegisteredAt\": \"1685282624000\"}"); + "{\"endpoint\": \"worker2\", \"expireAt\": \"9999999999999\", \"workerType\": 3," + + " \"firstRegisteredAt\": \"1685282624000\"}"); when(jedisCluster.hgetAll(storageWorkerKey)).thenReturn(workersJson); Map workersStartTime = backplane.getWorkersStartTimeInEpochSecs(workerNames); assertThat(workersStartTime.size()).isEqualTo(2); diff --git a/src/test/java/build/buildfarm/instance/shard/RedisShardSubscriberTest.java b/src/test/java/build/buildfarm/instance/shard/RedisShardSubscriberTest.java index 671181cbca..9a1851170e 100644 --- a/src/test/java/build/buildfarm/instance/shard/RedisShardSubscriberTest.java +++ b/src/test/java/build/buildfarm/instance/shard/RedisShardSubscriberTest.java @@ -123,11 +123,11 @@ public void flush() { RedisShardSubscriber createSubscriber( ListMultimap watchers, Executor executor) { - return new RedisShardSubscriber(watchers, /* workers=*/ null, "worker-channel", executor); + return new RedisShardSubscriber(watchers, /* workers= */ null, "worker-channel", executor); } RedisShardSubscriber createSubscriber(ListMultimap watchers) { - return createSubscriber(watchers, /* executor=*/ null); + return createSubscriber(watchers, /* executor= */ null); } @Test diff --git a/src/test/java/build/buildfarm/instance/shard/ServerInstanceTest.java b/src/test/java/build/buildfarm/instance/shard/ServerInstanceTest.java index 3fc6f30707..f97cc750dc 100644 --- a/src/test/java/build/buildfarm/instance/shard/ServerInstanceTest.java +++ b/src/test/java/build/buildfarm/instance/shard/ServerInstanceTest.java @@ -156,17 +156,17 @@ public void setUp() throws InterruptedException { DIGEST_UTIL, mockBackplane, actionCache, - /* runDispatchedMonitor=*/ false, - /* dispatchedMonitorIntervalSeconds=*/ 0, - /* runOperationQueuer=*/ false, - /* maxBlobSize=*/ 0, - /* maxCpu=*/ 1, - /* maxRequeueAttempts=*/ 1, - /* maxActionTimeout=*/ Duration.getDefaultInstance(), - /* useDenyList=*/ true, + /* runDispatchedMonitor= */ false, + /* dispatchedMonitorIntervalSeconds= */ 0, + /* runOperationQueuer= */ false, + /* maxBlobSize= */ 0, + /* maxCpu= */ 1, + /* maxRequeueAttempts= */ 1, + /* maxActionTimeout= */ Duration.getDefaultInstance(), + /* useDenyList= */ true, mockOnStop, CacheBuilder.newBuilder().build(mockInstanceLoader), - /* actionCacheFetchService=*/ listeningDecorator(newSingleThreadExecutor()), + /* actionCacheFetchService= */ listeningDecorator(newSingleThreadExecutor()), false); instance.start("startTime/test:0000"); } @@ -177,11 +177,11 @@ public void tearDown() throws InterruptedException { } private Action createAction() throws Exception { - return createAction(/* provideAction=*/ true, /* provideCommand=*/ true, SIMPLE_COMMAND); + return createAction(/* provideAction= */ true, /* provideCommand= */ true, SIMPLE_COMMAND); } private Action createAction(boolean provideAction) throws Exception { - return createAction(provideAction, /* provideCommand=*/ true, SIMPLE_COMMAND); + return createAction(provideAction, /* provideCommand= */ true, SIMPLE_COMMAND); } private Action createAction(boolean provideAction, boolean provideCommand) throws Exception { @@ -276,11 +276,11 @@ public void executeCallsPrequeueWithAction() throws IOException { Watcher mockWatcher = mock(Watcher.class); instance.execute( actionDigest, - /* skipCacheLookup=*/ false, + /* skipCacheLookup= */ false, ExecutionPolicy.getDefaultInstance(), ResultsCachePolicy.getDefaultInstance(), RequestMetadata.getDefaultInstance(), - /* watcher=*/ mockWatcher); + /* watcher= */ mockWatcher); verify(mockWatcher, times(1)).observe(any(Operation.class)); ArgumentCaptor executeEntryCaptor = ArgumentCaptor.forClass(ExecuteEntry.class); verify(mockBackplane, times(1)).prequeue(executeEntryCaptor.capture(), any(Operation.class)); @@ -383,7 +383,10 @@ public void queueActionFailsQueueEligibility() throws Exception { .setType(VIOLATION_TYPE_INVALID) .setSubject(INVALID_PLATFORM) .setDescription( - "properties are not valid for queue eligibility: []. If you think your queue should still accept these poperties without them being specified in queue configuration, consider configuring the queue with `allow_unmatched: True`")) + "properties are not valid for queue eligibility: []. If you think your" + + " queue should still accept these poperties without them being" + + " specified in queue configuration, consider configuring the queue" + + " with `allow_unmatched: True`")) .build(); ExecuteResponse executeResponse = ExecuteResponse.newBuilder() @@ -714,11 +717,11 @@ public void duplicateExecutionsServedFromCacheAreForcedToSkipLookup() throws Exc Watcher mockWatcher = mock(Watcher.class); instance.execute( actionDigest, - /* skipCacheLookup=*/ false, + /* skipCacheLookup= */ false, ExecutionPolicy.getDefaultInstance(), ResultsCachePolicy.getDefaultInstance(), requestMetadata, - /* watcher=*/ mockWatcher); + /* watcher= */ mockWatcher); verify(mockWatcher, times(1)).observe(any(Operation.class)); ArgumentCaptor executeEntryCaptor = ArgumentCaptor.forClass(ExecuteEntry.class); verify(mockBackplane, times(1)).prequeue(executeEntryCaptor.capture(), any(Operation.class)); diff --git a/src/test/java/build/buildfarm/instance/shard/UnobservableWatcher.java b/src/test/java/build/buildfarm/instance/shard/UnobservableWatcher.java index a6070f1c2f..993e86343b 100644 --- a/src/test/java/build/buildfarm/instance/shard/UnobservableWatcher.java +++ b/src/test/java/build/buildfarm/instance/shard/UnobservableWatcher.java @@ -19,7 +19,7 @@ class UnobservableWatcher extends TimedWatcher { UnobservableWatcher() { - this(/* expiresAt=*/ Instant.now()); + this(/* expiresAt= */ Instant.now()); } UnobservableWatcher(Instant expiresAt) { diff --git a/src/test/java/build/buildfarm/instance/shard/UtilTest.java b/src/test/java/build/buildfarm/instance/shard/UtilTest.java index e02dcedda6..c8e7ddbcbb 100644 --- a/src/test/java/build/buildfarm/instance/shard/UtilTest.java +++ b/src/test/java/build/buildfarm/instance/shard/UtilTest.java @@ -80,7 +80,7 @@ public void correctMissingBlobChecksAllWorkers() throws Exception { correctMissingBlob( backplane, workerSet, - /* originalLocationSet=*/ ImmutableSet.of(), + /* originalLocationSet= */ ImmutableSet.of(), workerInstanceFactory, digest, directExecutor(), @@ -120,7 +120,7 @@ public void correctMissingBlobFailsImmediatelyOnUnretriable() throws Interrupted correctMissingBlob( backplane, workerSet, - /* originalLocationSet=*/ ImmutableSet.of(), + /* originalLocationSet= */ ImmutableSet.of(), workerInstanceFactory, digest, directExecutor(), @@ -170,7 +170,7 @@ public void correctMissingBlobIgnoresUnavailableWorkers() throws Exception { correctMissingBlob( backplane, workerSet, - /* originalLocationSet=*/ ImmutableSet.of(), + /* originalLocationSet= */ ImmutableSet.of(), workerInstanceFactory, digest, directExecutor(), @@ -207,7 +207,7 @@ public void correctMissingBlobRetriesRetriable() throws Exception { correctMissingBlob( backplane, workerSet, - /* originalLocationSet=*/ ImmutableSet.of(), + /* originalLocationSet= */ ImmutableSet.of(), workerInstanceFactory, digest, directExecutor(), @@ -247,7 +247,7 @@ public void correctMissingBlobIgnoresBackplaneException() throws Exception { correctMissingBlob( backplane, workerSet, - /* originalLocationSet=*/ ImmutableSet.of(), + /* originalLocationSet= */ ImmutableSet.of(), workerInstanceFactory, digest, directExecutor(), diff --git a/src/test/java/build/buildfarm/instance/stub/ByteStreamUploaderTest.java b/src/test/java/build/buildfarm/instance/stub/ByteStreamUploaderTest.java index 6d3e25cac7..711374e942 100644 --- a/src/test/java/build/buildfarm/instance/stub/ByteStreamUploaderTest.java +++ b/src/test/java/build/buildfarm/instance/stub/ByteStreamUploaderTest.java @@ -79,10 +79,10 @@ public void onCompleted() {} }); ByteStreamUploader uploader = new ByteStreamUploader( - /* instanceName=*/ null, + /* instanceName= */ null, InProcessChannelBuilder.forName(fakeServerName).directExecutor().build(), - /* callCredentials=*/ null, - /* callTimeoutSecs=*/ 1, + /* callCredentials= */ null, + /* callTimeoutSecs= */ 1, NO_RETRIES); Chunker chunker = Chunker.builder().setInput(ByteString.copyFromUtf8("Hello, World!")).build(); uploader.uploadBlob(HashCode.fromInt(42), chunker); diff --git a/src/test/java/build/buildfarm/instance/stub/StubInstanceTest.java b/src/test/java/build/buildfarm/instance/stub/StubInstanceTest.java index da355098ad..1b3ba336ac 100644 --- a/src/test/java/build/buildfarm/instance/stub/StubInstanceTest.java +++ b/src/test/java/build/buildfarm/instance/stub/StubInstanceTest.java @@ -112,7 +112,7 @@ public void reflectsNameAndDigestUtil() { String test1Name = "test1"; ByteString test1Blob = ByteString.copyFromUtf8(test1Name); DigestUtil test1DigestUtil = new DigestUtil(DigestUtil.HashFunction.SHA256); - Instance test1Instance = new StubInstance(test1Name, test1DigestUtil, /* channel=*/ null); + Instance test1Instance = new StubInstance(test1Name, test1DigestUtil, /* channel= */ null); assertThat(test1Instance.getName()).isEqualTo(test1Name); assertThat(test1Instance.getDigestUtil().compute(test1Blob)) .isEqualTo(test1DigestUtil.compute(test1Blob)); @@ -121,7 +121,7 @@ public void reflectsNameAndDigestUtil() { String test2Name = "test2"; ByteString test2Blob = ByteString.copyFromUtf8(test2Name); DigestUtil test2DigestUtil = new DigestUtil(DigestUtil.HashFunction.MD5); - Instance test2Instance = new StubInstance(test2Name, test2DigestUtil, /* channel=*/ null); + Instance test2Instance = new StubInstance(test2Name, test2DigestUtil, /* channel= */ null); assertThat(test2Instance.getName()).isEqualTo(test2Name); assertThat(test2Instance.getDigestUtil().compute(test2Blob)) .isEqualTo(test2DigestUtil.compute(test2Blob)); diff --git a/src/test/java/build/buildfarm/metrics/MetricsPublisherTest.java b/src/test/java/build/buildfarm/metrics/MetricsPublisherTest.java index f30adb55c6..a775f7744c 100644 --- a/src/test/java/build/buildfarm/metrics/MetricsPublisherTest.java +++ b/src/test/java/build/buildfarm/metrics/MetricsPublisherTest.java @@ -41,14 +41,12 @@ public class MetricsPublisherTest { private final ExecuteOperationMetadata defaultExecuteOperationMetadata = ExecuteOperationMetadata.getDefaultInstance(); private final RequestMetadata defaultRequestMetadata = - RequestMetadata.getDefaultInstance() - .toBuilder() + RequestMetadata.getDefaultInstance().toBuilder() .setCorrelatedInvocationsId( "http://user@host-name?uuid_source\\u003d%2Fproc%2Fsys%2Fkernel%2Frandom%2Fuuid\\u0026OSTYPE\\u003dlinux-gnu#c09a5efa-f015-4d7b-b889-8ee0d097dff7") .build(); private final Operation defaultOperation = - Operation.getDefaultInstance() - .toBuilder() + Operation.getDefaultInstance().toBuilder() .setDone(true) .setName("shard/operations/123") .build(); @@ -74,8 +72,7 @@ public void setUp() throws IOException { @Test public void publishCompleteMetricsTest() throws InvalidProtocolBufferException { Operation operation = - defaultOperation - .toBuilder() + defaultOperation.toBuilder() .setResponse(Any.pack(defaultExecuteResponse)) .setMetadata(Any.pack(defaultExecuteOperationMetadata)) .build(); @@ -128,8 +125,7 @@ public void preconditionFailureTest() { Status.getDefaultInstance().toBuilder().addDetails(Any.pack(preconditionFailure)).build(); Operation operation = - defaultOperation - .toBuilder() + defaultOperation.toBuilder() .setResponse(Any.pack(defaultExecuteResponse.toBuilder().setStatus(status).build())) .setMetadata(Any.pack(defaultExecuteOperationMetadata)) .build(); diff --git a/src/test/java/build/buildfarm/proxy/http/ByteStreamServiceTest.java b/src/test/java/build/buildfarm/proxy/http/ByteStreamServiceTest.java index ea57f15dc5..fd81cf4c49 100644 --- a/src/test/java/build/buildfarm/proxy/http/ByteStreamServiceTest.java +++ b/src/test/java/build/buildfarm/proxy/http/ByteStreamServiceTest.java @@ -90,7 +90,7 @@ public void tearDown() throws Exception { } static String createBlobUploadResourceName(String id, Digest digest) { - return createBlobUploadResourceName(/* instanceName=*/ "", id, digest); + return createBlobUploadResourceName(/* instanceName= */ "", id, digest); } static String createBlobUploadResourceName(String instanceName, String id, Digest digest) { @@ -100,7 +100,7 @@ static String createBlobUploadResourceName(String instanceName, String id, Diges } private String createBlobDownloadResourceName(Digest digest) { - return createBlobDownloadResourceName(/* instanceName=*/ "", digest); + return createBlobDownloadResourceName(/* instanceName= */ "", digest); } private String createBlobDownloadResourceName(String instanceName, Digest digest) { diff --git a/src/test/java/build/buildfarm/worker/ExecuteActionStageTest.java b/src/test/java/build/buildfarm/worker/ExecuteActionStageTest.java index 284c08d34d..c22178c4f9 100644 --- a/src/test/java/build/buildfarm/worker/ExecuteActionStageTest.java +++ b/src/test/java/build/buildfarm/worker/ExecuteActionStageTest.java @@ -44,7 +44,7 @@ public void errorPathDestroysExecDir() throws Exception { .setExecDir(Paths.get("error-operation-path")) .build(); - PipelineStage executeActionStage = new ExecuteActionStage(context, /* output=*/ null, error); + PipelineStage executeActionStage = new ExecuteActionStage(context, /* output= */ null, error); executeActionStage.error().put(errorContext); verify(context, times(1)).destroyExecDir(errorContext.execDir); verify(error, times(1)).put(errorContext); diff --git a/src/test/java/build/buildfarm/worker/FuseCASTest.java b/src/test/java/build/buildfarm/worker/FuseCASTest.java index 34e4a3cb9e..5d1319acaa 100644 --- a/src/test/java/build/buildfarm/worker/FuseCASTest.java +++ b/src/test/java/build/buildfarm/worker/FuseCASTest.java @@ -371,14 +371,14 @@ public void writeExtendsAndOverwrites() { ByteString data = ByteString.copyFromUtf8("Hello, World\n"); Pointer buf = pointerFromByteString(data); - assertThat(fuseCAS.write("/foo", buf, data.size(), /* offset=*/ 0, fi)).isEqualTo(data.size()); + assertThat(fuseCAS.write("/foo", buf, data.size(), /* offset= */ 0, fi)).isEqualTo(data.size()); FileStat fileStat = createFileStat(); fuseCAS.getattr("/foo", fileStat); assertThat(fileStat.st_size.longValue()).isEqualTo(data.size()); ByteString overwriteData = ByteString.copyFromUtf8("Goodbye"); Pointer overwriteBuf = pointerFromByteString(overwriteData); - fuseCAS.write("/foo", overwriteBuf, overwriteData.size(), /* offset=*/ 0, fi); + fuseCAS.write("/foo", overwriteBuf, overwriteData.size(), /* offset= */ 0, fi); fuseCAS.getattr("/foo", fileStat); assertThat(fileStat.st_size.longValue()).isEqualTo(data.size()); } @@ -404,7 +404,8 @@ public void readAtEndIsEmpty() { FuseFileInfo fi = new SystemFuseFileInfo(); //noinspection OctalInteger fuseCAS.create("/foo", 0644, fi); - assertThat(fuseCAS.read("/foo", /* buf=*/ null, /* size=*/ 1, /* offset=*/ 0, fi)).isEqualTo(0); + assertThat(fuseCAS.read("/foo", /* buf= */ null, /* size= */ 1, /* offset= */ 0, fi)) + .isEqualTo(0); } @Test @@ -415,12 +416,12 @@ public void readWritten() { ByteString data = ByteString.copyFromUtf8("Hello, World\n"); Pointer buf = pointerFromByteString(data); - fuseCAS.write("/foo", buf, data.size(), /* offset=*/ 0, fi); + fuseCAS.write("/foo", buf, data.size(), /* offset= */ 0, fi); byte[] readData = new byte[5]; u8[] array = Struct.arrayOf(Runtime.getSystemRuntime(), u8.class, readData.length); Pointer readBuf = ((DelegatingMemoryIO) Struct.getMemory(array[0])).getDelegatedMemoryIO(); - assertThat(fuseCAS.read("/foo", readBuf, /* size=*/ readData.length, /* offset=*/ 7, fi)) + assertThat(fuseCAS.read("/foo", readBuf, /* size= */ readData.length, /* offset= */ 7, fi)) .isEqualTo(readData.length); readBuf.get(0, readData, 0, readData.length); assertThat(new String(readData, 0)).isEqualTo("World"); @@ -436,7 +437,8 @@ public void readInputRooted() throws IOException, InterruptedException { fi.flags.set(0); assertThat(fuseCAS.open("/test/file", fi)).isEqualTo(0); assertThat( - fuseCAS.read("/test/file", /* buf=*/ buf, /* size=*/ data.length, /* offset=*/ 0, fi)) + fuseCAS.read( + "/test/file", /* buf= */ buf, /* size= */ data.length, /* offset= */ 0, fi)) .isEqualTo(data.length); buf.get(0, data, 0, data.length); assertThat(new String(data, 0)).isEqualTo("Peanut"); @@ -448,8 +450,8 @@ public void fallocatePunchHole() { fuseCAS.fallocate( "/op_not_supp", /* FALLOC_FL_PUNCH_HOLE */ 2, - /* off=*/ -1, - /* length=*/ -1, + /* off= */ -1, + /* length= */ -1, new SystemFuseFileInfo())) .isEqualTo(-ErrorCodes.EOPNOTSUPP()); } @@ -459,7 +461,7 @@ public void fallocateDirectory() { fuseCAS.mkdir("/foo", 755); assertThat( fuseCAS.fallocate( - "/foo", /* mode=*/ 0, /* off=*/ -1, /* length=*/ -1, new SystemFuseFileInfo())) + "/foo", /* mode= */ 0, /* off= */ -1, /* length= */ -1, new SystemFuseFileInfo())) .isEqualTo(-ErrorCodes.EISDIR()); } @@ -469,9 +471,9 @@ public void fallocateReadOnly() throws IOException, InterruptedException { assertThat( fuseCAS.fallocate( "/test/file", - /* mode=*/ 0, - /* off=*/ -1, - /* length=*/ -1, + /* mode= */ 0, + /* off= */ -1, + /* length= */ -1, new SystemFuseFileInfo())) .isEqualTo(-ErrorCodes.EPERM()); } @@ -482,7 +484,7 @@ public void fallocateResize() { fuseCAS.create("/foo", 0644, new SystemFuseFileInfo()); assertThat( fuseCAS.fallocate( - "/foo", /* mode=*/ 0, /* off=*/ 0, /* length=*/ 1024, new SystemFuseFileInfo())) + "/foo", /* mode= */ 0, /* off= */ 0, /* length= */ 1024, new SystemFuseFileInfo())) .isEqualTo(0); FileStat fileStat = createFileStat(); fuseCAS.getattr("/foo", fileStat); diff --git a/src/test/java/build/buildfarm/worker/InputFetcherTest.java b/src/test/java/build/buildfarm/worker/InputFetcherTest.java index ec69ad2f0e..eac2abdd67 100644 --- a/src/test/java/build/buildfarm/worker/InputFetcherTest.java +++ b/src/test/java/build/buildfarm/worker/InputFetcherTest.java @@ -94,7 +94,7 @@ public Path createExecDir( new ViolationException( Digest.getDefaultInstance(), root.resolve("input"), - /* isExecutable=*/ false, + /* isExecutable= */ false, new NoSuchFileException("input-digest")), new PutDirectoryException( root.resolve("dir"), @@ -107,9 +107,9 @@ public int getInputFetchStageWidth() { return 1; } }; - InputFetchStage owner = new InputFetchStage(workerContext, /* output=*/ null, error); + InputFetchStage owner = new InputFetchStage(workerContext, /* output= */ null, error); InputFetcher inputFetcher = new InputFetcher(workerContext, operationContext, owner); - inputFetcher.fetchPolled(/* stopwatch=*/ null); + inputFetcher.fetchPolled(/* stopwatch= */ null); Operation failedOperation = checkNotNull(failedOperationRef.get()); verify(error, times(1)).put(any(OperationContext.class)); ExecuteResponse executeResponse = failedOperation.getResponse().unpack(ExecuteResponse.class); diff --git a/src/test/java/build/buildfarm/worker/PipelineStageTest.java b/src/test/java/build/buildfarm/worker/PipelineStageTest.java index ef49bab367..c89ed66a50 100644 --- a/src/test/java/build/buildfarm/worker/PipelineStageTest.java +++ b/src/test/java/build/buildfarm/worker/PipelineStageTest.java @@ -96,7 +96,8 @@ OperationContext take() { }; Thread stageThread = new Thread(stage); stageThread.start(); - while (count.get() != 1) ; + while (count.get() != 1) + ; stage.cancelTick(); stageThread.join(); assertThat(count.get()).isEqualTo(2); diff --git a/src/test/java/build/buildfarm/worker/ReportResultStageTest.java b/src/test/java/build/buildfarm/worker/ReportResultStageTest.java index 2586e0dc33..b5f2da06d8 100644 --- a/src/test/java/build/buildfarm/worker/ReportResultStageTest.java +++ b/src/test/java/build/buildfarm/worker/ReportResultStageTest.java @@ -57,7 +57,7 @@ static class SingleOutputSink extends PipelineStage { OperationContext operationContext = null; public SingleOutputSink() { - super("SingleOutputSink", /* workerContext=*/ null, /* output=*/ null, /* error=*/ null); + super("SingleOutputSink", /* workerContext= */ null, /* output= */ null, /* error= */ null); } @Override @@ -110,7 +110,7 @@ public void execDirDestroyedAfterComplete() throws Exception { .build(); when(context.putOperation(any(Operation.class))).thenReturn(true); - PipelineStage reportResultStage = new ReportResultStage(context, output, /* error=*/ null); + PipelineStage reportResultStage = new ReportResultStage(context, output, /* error= */ null); reportResultStage.put(reportedContext); reportResultStage.run(); verify(context, times(1)).destroyExecDir(reportedContext.execDir); @@ -159,7 +159,7 @@ public void operationErrorOnStatusException() throws Exception { eq(erroringContext.execDir), eq(Command.getDefaultInstance())); - PipelineStage reportResultStage = new ReportResultStage(context, output, /* error=*/ null); + PipelineStage reportResultStage = new ReportResultStage(context, output, /* error= */ null); reportResultStage.put(erroringContext); reportResultStage.run(); verify(context, times(1)).destroyExecDir(erroringContext.execDir); diff --git a/src/test/java/build/buildfarm/worker/SuperscalarPipelineStageTest.java b/src/test/java/build/buildfarm/worker/SuperscalarPipelineStageTest.java index 3716513102..5ded1c590c 100644 --- a/src/test/java/build/buildfarm/worker/SuperscalarPipelineStageTest.java +++ b/src/test/java/build/buildfarm/worker/SuperscalarPipelineStageTest.java @@ -82,7 +82,7 @@ public int getSlotUsage() { @Test public void interruptedClaimReleasesPartial() throws InterruptedException { AbstractSuperscalarPipelineStage stage = - new AbstractSuperscalarPipelineStage("too-narrow", /* output=*/ null, /* width=*/ 3) { + new AbstractSuperscalarPipelineStage("too-narrow", /* output= */ null, /* width= */ 3) { @Override protected int claimsRequired(OperationContext operationContext) { return 5; @@ -107,7 +107,7 @@ protected int claimsRequired(OperationContext operationContext) { // start a thread, when the stage is exhausted, interrupt this one try { - stage.claim(/* operationContext=*/ null); + stage.claim(/* operationContext= */ null); fail("should not get here"); } catch (InterruptedException e) { // ignore @@ -126,7 +126,7 @@ public void takeReleasesQueueClaims() throws InterruptedException { BlockingQueue queue = new ArrayBlockingQueue<>(1); PipelineStage output = new PipelineStageTest.StubPipelineStage("unclosed-sink"); PipelineStage stage = - new AbstractSuperscalarPipelineStage("queue-claimed", output, /* width=*/ 3) { + new AbstractSuperscalarPipelineStage("queue-claimed", output, /* width= */ 3) { @Override protected int claimsRequired(OperationContext operationContext) { return 2; diff --git a/src/test/java/build/buildfarm/worker/persistent/ProtoCoordinatorTest.java b/src/test/java/build/buildfarm/worker/persistent/ProtoCoordinatorTest.java index 908a1746e4..9f6db2609d 100644 --- a/src/test/java/build/buildfarm/worker/persistent/ProtoCoordinatorTest.java +++ b/src/test/java/build/buildfarm/worker/persistent/ProtoCoordinatorTest.java @@ -56,8 +56,7 @@ public Path jimFsRoot() { rootDir = Iterables.getFirst( Jimfs.newFileSystem( - Configuration.unix() - .toBuilder() + Configuration.unix().toBuilder() .setAttributeViews("basic", "owner", "posix", "unix") .build()) .getRootDirectories(), diff --git a/src/test/java/build/buildfarm/worker/resources/ResourceDeciderTest.java b/src/test/java/build/buildfarm/worker/resources/ResourceDeciderTest.java index 9c531c7e78..2f1d740b98 100644 --- a/src/test/java/build/buildfarm/worker/resources/ResourceDeciderTest.java +++ b/src/test/java/build/buildfarm/worker/resources/ResourceDeciderTest.java @@ -53,11 +53,11 @@ public void decideResourceLimitationsTestCoreSetting() throws Exception { ResourceDecider.decideResourceLimitations( command, "worker", - /* defaultMaxCores=*/ 0, - /* onlyMulticoreTests=*/ false, - /* limitGlobalExecution=*/ false, - /* executeStageWidth=*/ 100, - /* allowBringYourOwnContainer=*/ false, + /* defaultMaxCores= */ 0, + /* onlyMulticoreTests= */ false, + /* limitGlobalExecution= */ false, + /* executeStageWidth= */ 100, + /* allowBringYourOwnContainer= */ false, new SandboxSettings()); // ASSERT @@ -88,10 +88,10 @@ public void decideResourceLimitationsTestCoreSettingDefaultedOnNontest() throws command, "worker", defaultMaxCores, - /* onlyMulticoreTests=*/ true, - /* limitGlobalExecution=*/ false, - /* executeStageWidth=*/ 100, - /* allowBringYourOwnContainer=*/ false, + /* onlyMulticoreTests= */ true, + /* limitGlobalExecution= */ false, + /* executeStageWidth= */ 100, + /* allowBringYourOwnContainer= */ false, new SandboxSettings()); // ASSERT @@ -120,11 +120,11 @@ public void decideResourceLimitationsEnsureClaimsOne() throws Exception { ResourceDecider.decideResourceLimitations( command, "worker", - /* defaultMaxCores=*/ 0, - /* onlyMulticoreTests=*/ false, - /* limitGlobalExecution=*/ false, - /* executeStageWidth=*/ 100, - /* allowBringYourOwnContainer=*/ false, + /* defaultMaxCores= */ 0, + /* onlyMulticoreTests= */ false, + /* limitGlobalExecution= */ false, + /* executeStageWidth= */ 100, + /* allowBringYourOwnContainer= */ false, new SandboxSettings()); // ASSERT @@ -152,11 +152,11 @@ public void decideResourceLimitationsEnsureLimitGlobalSet() throws Exception { ResourceDecider.decideResourceLimitations( command, "worker", - /* defaultMaxCores=*/ 0, - /* onlyMulticoreTests=*/ false, - /* limitGlobalExecution=*/ true, - /* executeStageWidth=*/ 100, - /* allowBringYourOwnContainer=*/ false, + /* defaultMaxCores= */ 0, + /* onlyMulticoreTests= */ false, + /* limitGlobalExecution= */ true, + /* executeStageWidth= */ 100, + /* allowBringYourOwnContainer= */ false, new SandboxSettings()); // ASSERT @@ -184,11 +184,11 @@ public void decideResourceLimitationsEnsureNoLimitNoGlobalSet() throws Exception ResourceDecider.decideResourceLimitations( command, "worker", - /* defaultMaxCores=*/ 0, - /* onlyMulticoreTests=*/ false, - /* limitGlobalExecution=*/ false, - /* executeStageWidth=*/ 100, - /* allowBringYourOwnContainer=*/ false, + /* defaultMaxCores= */ 0, + /* onlyMulticoreTests= */ false, + /* limitGlobalExecution= */ false, + /* executeStageWidth= */ 100, + /* allowBringYourOwnContainer= */ false, new SandboxSettings()); // ASSERT @@ -216,11 +216,11 @@ public void decideResourceLimitationsEnsureClaimsAreMin() throws Exception { ResourceDecider.decideResourceLimitations( command, "worker", - /* defaultMaxCores=*/ 0, - /* onlyMulticoreTests=*/ false, - /* limitGlobalExecution=*/ false, - /* executeStageWidth=*/ 100, - /* allowBringYourOwnContainer=*/ false, + /* defaultMaxCores= */ 0, + /* onlyMulticoreTests= */ false, + /* limitGlobalExecution= */ false, + /* executeStageWidth= */ 100, + /* allowBringYourOwnContainer= */ false, new SandboxSettings()); // ASSERT @@ -247,11 +247,11 @@ public void decideResourceLimitationsTestMemSetting() throws Exception { ResourceDecider.decideResourceLimitations( command, "worker", - /* defaultMaxCores=*/ 0, - /* onlyMulticoreTests=*/ false, - /* limitGlobalExecution=*/ false, - /* executeStageWidth=*/ 100, - /* allowBringYourOwnContainer=*/ false, + /* defaultMaxCores= */ 0, + /* onlyMulticoreTests= */ false, + /* limitGlobalExecution= */ false, + /* executeStageWidth= */ 100, + /* allowBringYourOwnContainer= */ false, new SandboxSettings()); // ASSERT @@ -273,11 +273,11 @@ public void decideResourceLimitationsTestDefaultEnvironmentParse() throws Except ResourceDecider.decideResourceLimitations( command, "worker", - /* defaultMaxCores=*/ 0, - /* onlyMulticoreTests=*/ false, - /* limitGlobalExecution=*/ false, - /* executeStageWidth=*/ 100, - /* allowBringYourOwnContainer=*/ false, + /* defaultMaxCores= */ 0, + /* onlyMulticoreTests= */ false, + /* limitGlobalExecution= */ false, + /* executeStageWidth= */ 100, + /* allowBringYourOwnContainer= */ false, new SandboxSettings()); // ASSERT @@ -303,11 +303,11 @@ public void decideResourceLimitationsTestEmptyEnvironmentParse() throws Exceptio ResourceDecider.decideResourceLimitations( command, "worker", - /* defaultMaxCores=*/ 0, - /* onlyMulticoreTests=*/ false, - /* limitGlobalExecution=*/ false, - /* executeStageWidth=*/ 100, - /* allowBringYourOwnContainer=*/ false, + /* defaultMaxCores= */ 0, + /* onlyMulticoreTests= */ false, + /* limitGlobalExecution= */ false, + /* executeStageWidth= */ 100, + /* allowBringYourOwnContainer= */ false, new SandboxSettings()); // ASSERT @@ -336,11 +336,11 @@ public void decideResourceLimitationsTestSingleEnvironmentParse() throws Excepti ResourceDecider.decideResourceLimitations( command, "worker", - /* defaultMaxCores=*/ 0, - /* onlyMulticoreTests=*/ false, - /* limitGlobalExecution=*/ false, - /* executeStageWidth=*/ 100, - /* allowBringYourOwnContainer=*/ false, + /* defaultMaxCores= */ 0, + /* onlyMulticoreTests= */ false, + /* limitGlobalExecution= */ false, + /* executeStageWidth= */ 100, + /* allowBringYourOwnContainer= */ false, new SandboxSettings()); // ASSERT @@ -371,11 +371,11 @@ public void decideResourceLimitationsTestDoubleEnvironmentParse() throws Excepti ResourceDecider.decideResourceLimitations( command, "worker", - /* defaultMaxCores=*/ 0, - /* onlyMulticoreTests=*/ false, - /* limitGlobalExecution=*/ false, - /* executeStageWidth=*/ 100, - /* allowBringYourOwnContainer=*/ false, + /* defaultMaxCores= */ 0, + /* onlyMulticoreTests= */ false, + /* limitGlobalExecution= */ false, + /* executeStageWidth= */ 100, + /* allowBringYourOwnContainer= */ false, new SandboxSettings()); // ASSERT @@ -408,11 +408,11 @@ public void decideResourceLimitationsTestMalformedEnvironmentParse() throws Exce ResourceDecider.decideResourceLimitations( command, "worker", - /* defaultMaxCores=*/ 0, - /* onlyMulticoreTests=*/ false, - /* limitGlobalExecution=*/ false, - /* executeStageWidth=*/ 100, - /* allowBringYourOwnContainer=*/ false, + /* defaultMaxCores= */ 0, + /* onlyMulticoreTests= */ false, + /* limitGlobalExecution= */ false, + /* executeStageWidth= */ 100, + /* allowBringYourOwnContainer= */ false, new SandboxSettings()); // ASSERT @@ -437,7 +437,8 @@ public void decideResourceLimitationsTestEnvironmentMustacheResolution() throws Platform.Property.newBuilder() .setName("env-vars") .setValue( - "{\"foo\": \"{{limits.cpu.min}}\", \"bar\": \"{{limits.cpu.max}}\"}"))) + "{\"foo\": \"{{limits.cpu.min}}\", \"bar\":" + + " \"{{limits.cpu.max}}\"}"))) .build(); // ACT @@ -445,11 +446,11 @@ public void decideResourceLimitationsTestEnvironmentMustacheResolution() throws ResourceDecider.decideResourceLimitations( command, "worker", - /* defaultMaxCores=*/ 0, - /* onlyMulticoreTests=*/ false, - /* limitGlobalExecution=*/ false, - /* executeStageWidth=*/ 100, - /* allowBringYourOwnContainer=*/ false, + /* defaultMaxCores= */ 0, + /* onlyMulticoreTests= */ false, + /* limitGlobalExecution= */ false, + /* executeStageWidth= */ 100, + /* allowBringYourOwnContainer= */ false, new SandboxSettings()); // ASSERT @@ -480,11 +481,11 @@ public void decideResourceLimitationsTestIndividualEnvironmentVarParse() throws ResourceDecider.decideResourceLimitations( command, "worker", - /* defaultMaxCores=*/ 0, - /* onlyMulticoreTests=*/ false, - /* limitGlobalExecution=*/ false, - /* executeStageWidth=*/ 100, - /* allowBringYourOwnContainer=*/ false, + /* defaultMaxCores= */ 0, + /* onlyMulticoreTests= */ false, + /* limitGlobalExecution= */ false, + /* executeStageWidth= */ 100, + /* allowBringYourOwnContainer= */ false, new SandboxSettings()); // ASSERT @@ -516,11 +517,11 @@ public void decideResourceLimitationsTestTwoIndividualEnvironmentVarParse() thro ResourceDecider.decideResourceLimitations( command, "worker", - /* defaultMaxCores=*/ 0, - /* onlyMulticoreTests=*/ false, - /* limitGlobalExecution=*/ false, - /* executeStageWidth=*/ 100, - /* allowBringYourOwnContainer=*/ false, + /* defaultMaxCores= */ 0, + /* onlyMulticoreTests= */ false, + /* limitGlobalExecution= */ false, + /* executeStageWidth= */ 100, + /* allowBringYourOwnContainer= */ false, new SandboxSettings()); // ASSERT @@ -552,11 +553,11 @@ public void decideResourceLimitationsTestEmptyEnvironmentVarParse() throws Excep ResourceDecider.decideResourceLimitations( command, "worker", - /* defaultMaxCores=*/ 0, - /* onlyMulticoreTests=*/ false, - /* limitGlobalExecution=*/ false, - /* executeStageWidth=*/ 100, - /* allowBringYourOwnContainer=*/ false, + /* defaultMaxCores= */ 0, + /* onlyMulticoreTests= */ false, + /* limitGlobalExecution= */ false, + /* executeStageWidth= */ 100, + /* allowBringYourOwnContainer= */ false, new SandboxSettings()); // ASSERT @@ -589,11 +590,11 @@ public void decideResourceLimitationsTestDebugBeforeParse() throws Exception { ResourceDecider.decideResourceLimitations( command, "worker", - /* defaultMaxCores=*/ 0, - /* onlyMulticoreTests=*/ false, - /* limitGlobalExecution=*/ false, - /* executeStageWidth=*/ 100, - /* allowBringYourOwnContainer=*/ false, + /* defaultMaxCores= */ 0, + /* onlyMulticoreTests= */ false, + /* limitGlobalExecution= */ false, + /* executeStageWidth= */ 100, + /* allowBringYourOwnContainer= */ false, new SandboxSettings()); // ASSERT @@ -624,11 +625,11 @@ public void decideResourceLimitationsTestDebugAfterParse() throws Exception { ResourceDecider.decideResourceLimitations( command, "worker", - /* defaultMaxCores=*/ 0, - /* onlyMulticoreTests=*/ false, - /* limitGlobalExecution=*/ false, - /* executeStageWidth=*/ 100, - /* allowBringYourOwnContainer=*/ false, + /* defaultMaxCores= */ 0, + /* onlyMulticoreTests= */ false, + /* limitGlobalExecution= */ false, + /* executeStageWidth= */ 100, + /* allowBringYourOwnContainer= */ false, new SandboxSettings()); // ASSERT @@ -659,11 +660,11 @@ public void decideResourceLimitationsTestInvalidDebugParse() throws Exception { ResourceDecider.decideResourceLimitations( command, "worker", - /* defaultMaxCores=*/ 0, - /* onlyMulticoreTests=*/ false, - /* limitGlobalExecution=*/ false, - /* executeStageWidth=*/ 100, - /* allowBringYourOwnContainer=*/ false, + /* defaultMaxCores= */ 0, + /* onlyMulticoreTests= */ false, + /* limitGlobalExecution= */ false, + /* executeStageWidth= */ 100, + /* allowBringYourOwnContainer= */ false, new SandboxSettings()); // ASSERT @@ -683,11 +684,11 @@ public void decideResourceLimitationsTestWorkerName() throws Exception { ResourceDecider.decideResourceLimitations( command, "foo", - /* defaultMaxCores=*/ 0, - /* onlyMulticoreTests=*/ false, - /* limitGlobalExecution=*/ false, - /* executeStageWidth=*/ 100, - /* allowBringYourOwnContainer=*/ false, + /* defaultMaxCores= */ 0, + /* onlyMulticoreTests= */ false, + /* limitGlobalExecution= */ false, + /* executeStageWidth= */ 100, + /* allowBringYourOwnContainer= */ false, new SandboxSettings()); // ASSERT @@ -707,11 +708,11 @@ public void decideResourceLimitationsSanboxOffDefault() throws Exception { ResourceDecider.decideResourceLimitations( command, "foo", - /* defaultMaxCores=*/ 0, - /* onlyMulticoreTests=*/ false, - /* limitGlobalExecution=*/ false, - /* executeStageWidth=*/ 100, - /* allowBringYourOwnContainer=*/ false, + /* defaultMaxCores= */ 0, + /* onlyMulticoreTests= */ false, + /* limitGlobalExecution= */ false, + /* executeStageWidth= */ 100, + /* allowBringYourOwnContainer= */ false, new SandboxSettings()); // ASSERT @@ -733,11 +734,11 @@ public void decideResourceLimitationsAlwaysUseSandbox() throws Exception { ResourceDecider.decideResourceLimitations( command, "foo", - /* defaultMaxCores=*/ 0, - /* onlyMulticoreTests=*/ false, - /* limitGlobalExecution=*/ false, - /* executeStageWidth=*/ 100, - /* allowBringYourOwnContainer=*/ false, + /* defaultMaxCores= */ 0, + /* onlyMulticoreTests= */ false, + /* limitGlobalExecution= */ false, + /* executeStageWidth= */ 100, + /* allowBringYourOwnContainer= */ false, sandboxSettings); // ASSERT @@ -767,11 +768,11 @@ public void decideResourceLimitationsSandboxChosenViaBlockNetwork() throws Excep ResourceDecider.decideResourceLimitations( command, "foo", - /* defaultMaxCores=*/ 0, - /* onlyMulticoreTests=*/ false, - /* limitGlobalExecution=*/ false, - /* executeStageWidth=*/ 100, - /* allowBringYourOwnContainer=*/ false, + /* defaultMaxCores= */ 0, + /* onlyMulticoreTests= */ false, + /* limitGlobalExecution= */ false, + /* executeStageWidth= */ 100, + /* allowBringYourOwnContainer= */ false, sandboxSettings); // ASSERT @@ -801,11 +802,11 @@ public void decideResourceLimitationsSandboxNotChosenViaBlockNetwork() throws Ex ResourceDecider.decideResourceLimitations( command, "foo", - /* defaultMaxCores=*/ 0, - /* onlyMulticoreTests=*/ false, - /* limitGlobalExecution=*/ false, - /* executeStageWidth=*/ 100, - /* allowBringYourOwnContainer=*/ false, + /* defaultMaxCores= */ 0, + /* onlyMulticoreTests= */ false, + /* limitGlobalExecution= */ false, + /* executeStageWidth= */ 100, + /* allowBringYourOwnContainer= */ false, sandboxSettings); // ASSERT @@ -835,11 +836,11 @@ public void decideResourceLimitationsSandboxChosenViaTmpFs() throws Exception { ResourceDecider.decideResourceLimitations( command, "foo", - /* defaultMaxCores=*/ 0, - /* onlyMulticoreTests=*/ false, - /* limitGlobalExecution=*/ false, - /* executeStageWidth=*/ 100, - /* allowBringYourOwnContainer=*/ false, + /* defaultMaxCores= */ 0, + /* onlyMulticoreTests= */ false, + /* limitGlobalExecution= */ false, + /* executeStageWidth= */ 100, + /* allowBringYourOwnContainer= */ false, sandboxSettings); // ASSERT @@ -869,11 +870,11 @@ public void decideResourceLimitationsSandboxNotChosenViaTmpFs() throws Exception ResourceDecider.decideResourceLimitations( command, "foo", - /* defaultMaxCores=*/ 0, - /* onlyMulticoreTests=*/ false, - /* limitGlobalExecution=*/ false, - /* executeStageWidth=*/ 100, - /* allowBringYourOwnContainer=*/ false, + /* defaultMaxCores= */ 0, + /* onlyMulticoreTests= */ false, + /* limitGlobalExecution= */ false, + /* executeStageWidth= */ 100, + /* allowBringYourOwnContainer= */ false, sandboxSettings); // ASSERT diff --git a/src/test/java/build/buildfarm/worker/shard/EmptyInputStreamFactoryTest.java b/src/test/java/build/buildfarm/worker/shard/EmptyInputStreamFactoryTest.java index ee995f7c89..5d622fb3ba 100644 --- a/src/test/java/build/buildfarm/worker/shard/EmptyInputStreamFactoryTest.java +++ b/src/test/java/build/buildfarm/worker/shard/EmptyInputStreamFactoryTest.java @@ -39,7 +39,7 @@ public void emptyDigestIsNotDelegated() throws IOException, InterruptedException }); InputStream in = emptyFactory.newInput( - Compressor.Value.IDENTITY, Digest.getDefaultInstance(), /* offset=*/ 0); + Compressor.Value.IDENTITY, Digest.getDefaultInstance(), /* offset= */ 0); assertThat(in.read()).isEqualTo(-1); } @@ -56,7 +56,7 @@ public void nonEmptyDigestIsDelegated() throws IOException, InterruptedException throw new IOException("invalid"); }); InputStream in = - emptyFactory.newInput(Compressor.Value.IDENTITY, contentDigest, /* offset=*/ 0); + emptyFactory.newInput(Compressor.Value.IDENTITY, contentDigest, /* offset= */ 0); assertThat(ByteString.readFrom(in)).isEqualTo(content); } } diff --git a/src/test/java/build/buildfarm/worker/shard/FailoverInputStreamFactoryTest.java b/src/test/java/build/buildfarm/worker/shard/FailoverInputStreamFactoryTest.java index 78055cafc8..9b14951144 100644 --- a/src/test/java/build/buildfarm/worker/shard/FailoverInputStreamFactoryTest.java +++ b/src/test/java/build/buildfarm/worker/shard/FailoverInputStreamFactoryTest.java @@ -37,17 +37,17 @@ public void DigestInPrimaryIsNotDelegated() throws IOException, InterruptedExcep Digest contentDigest = DIGEST_UTIL.compute(content); FailoverInputStreamFactory failoverFactory = new FailoverInputStreamFactory( - /* primary=*/ (compressor, digest, offset) -> { + /* primary= */ (compressor, digest, offset) -> { if (digest.equals(contentDigest)) { return content.newInput(); } throw new NoSuchFileException(DigestUtil.toString(digest)); }, - /* failover=*/ (compressor, digest, offset) -> { + /* failover= */ (compressor, digest, offset) -> { throw new IOException("invalid"); }); InputStream in = - failoverFactory.newInput(Compressor.Value.IDENTITY, contentDigest, /* offset=*/ 0); + failoverFactory.newInput(Compressor.Value.IDENTITY, contentDigest, /* offset= */ 0); assertThat(ByteString.readFrom(in)).isEqualTo(content); } @@ -57,17 +57,17 @@ public void missingDigestIsDelegated() throws IOException, InterruptedException Digest contentDigest = DIGEST_UTIL.compute(content); FailoverInputStreamFactory failoverFactory = new FailoverInputStreamFactory( - /* primary=*/ (compressor, digest, offset) -> { + /* primary= */ (compressor, digest, offset) -> { throw new NoSuchFileException(DigestUtil.toString(digest)); }, - /* failover=*/ (compressor, digest, offset) -> { + /* failover= */ (compressor, digest, offset) -> { if (digest.equals(contentDigest)) { return content.newInput(); } throw new IOException("invalid"); }); InputStream in = - failoverFactory.newInput(Compressor.Value.IDENTITY, contentDigest, /* offset=*/ 0); + failoverFactory.newInput(Compressor.Value.IDENTITY, contentDigest, /* offset= */ 0); assertThat(ByteString.readFrom(in)).isEqualTo(content); } } diff --git a/src/test/java/build/buildfarm/worker/shard/ShardWorkerContextTest.java b/src/test/java/build/buildfarm/worker/shard/ShardWorkerContextTest.java index cf93a1cd4f..e0a66db27c 100644 --- a/src/test/java/build/buildfarm/worker/shard/ShardWorkerContextTest.java +++ b/src/test/java/build/buildfarm/worker/shard/ShardWorkerContextTest.java @@ -90,34 +90,34 @@ public void setUp() throws Exception { } WorkerContext createTestContext() { - return createTestContext(/* policies=*/ ImmutableList.of()); + return createTestContext(/* policies= */ ImmutableList.of()); } WorkerContext createTestContext(Iterable policies) { return new ShardWorkerContext( "test", - /* operationPollPeriod=*/ Duration.getDefaultInstance(), - /* operationPoller=*/ (queueEntry, stage, requeueAt) -> false, - /* inlineContentLimit=*/ - /* inputFetchStageWidth=*/ 0, - /* executeStageWidth=*/ 0, - /* inputFetchDeadline=*/ 60, + /* operationPollPeriod= */ Duration.getDefaultInstance(), + /* operationPoller= */ (queueEntry, stage, requeueAt) -> false, + /* inlineContentLimit= */ + /* inputFetchStageWidth= */ 0, + /* executeStageWidth= */ 0, + /* inputFetchDeadline= */ 60, backplane, execFileSystem, inputStreamFactory, policies, instance, - /* deadlineAfter=*/ - /* deadlineAfterUnits=*/ - /* defaultActionTimeout=*/ Duration.getDefaultInstance(), - /* maximumActionTimeout=*/ Duration.getDefaultInstance(), - /* defaultMaxCores=*/ 0, - /* limitGlobalExecution=*/ false, - /* onlyMulticoreTests=*/ false, - /* allowBringYourOwnContainer=*/ false, - /* errorOperationRemainingResources=*/ false, - /* errorOperationOutputSizeExceeded=*/ false, - /* resourceSet=*/ new LocalResourceSet(), + /* deadlineAfter= */ + /* deadlineAfterUnits= */ + /* defaultActionTimeout= */ Duration.getDefaultInstance(), + /* maximumActionTimeout= */ Duration.getDefaultInstance(), + /* defaultMaxCores= */ 0, + /* limitGlobalExecution= */ false, + /* onlyMulticoreTests= */ false, + /* allowBringYourOwnContainer= */ false, + /* errorOperationRemainingResources= */ false, + /* errorOperationOutputSizeExceeded= */ false, + /* resourceSet= */ new LocalResourceSet(), writer); } diff --git a/src/test/java/build/buildfarm/worker/shard/WorkerInstanceTest.java b/src/test/java/build/buildfarm/worker/shard/WorkerInstanceTest.java index 3df73187bb..3c07ec31d4 100644 --- a/src/test/java/build/buildfarm/worker/shard/WorkerInstanceTest.java +++ b/src/test/java/build/buildfarm/worker/shard/WorkerInstanceTest.java @@ -116,7 +116,7 @@ public void putActionResultDelegatesToBackplane() throws IOException { public void listOperationsIsUnsupported() { ImmutableList.Builder operations = new ImmutableList.Builder<>(); instance.listOperations( - /* pageSize=*/ 0, /* pageToken=*/ "", /* filter=*/ "", /* operations=*/ operations); + /* pageSize= */ 0, /* pageToken= */ "", /* filter= */ "", /* operations= */ operations); } @Test(expected = UnsupportedOperationException.class) @@ -127,49 +127,49 @@ public void readResourceNameIsUnsupported() { @Test(expected = UnsupportedOperationException.class) public void getTreeIsUnsupported() { instance.getTree( - /* rootDigest=*/ Digest.getDefaultInstance(), - /* pageSize=*/ 0, - /* pageToken=*/ "", - /* tree=*/ Tree.newBuilder()); + /* rootDigest= */ Digest.getDefaultInstance(), + /* pageSize= */ 0, + /* pageToken= */ "", + /* tree= */ Tree.newBuilder()); } @Test(expected = UnsupportedOperationException.class) public void getOperationStreamWriteIsUnsupported() { - instance.getOperationStreamWrite(/* name=*/ null); + instance.getOperationStreamWrite(/* name= */ null); } @Test(expected = UnsupportedOperationException.class) public void newOperationStreamInputIsUnsupported() { instance.newOperationStreamInput( - /* name=*/ null, - /* offset=*/ 0, - /* deadlineAfter=*/ - /* deadlineAfterUnits=*/ RequestMetadata.getDefaultInstance()); + /* name= */ null, + /* offset= */ 0, + /* deadlineAfter= */ + /* deadlineAfterUnits= */ RequestMetadata.getDefaultInstance()); } @Test(expected = UnsupportedOperationException.class) public void executeIsUnsupported() { instance.execute( - /* actionDigest=*/ null, - /* skipCacheLookup=*/ false, - /* executionPolicy=*/ null, - /* resultsCachePolicy=*/ null, - /* requestMetadata=*/ null, - /* watcher=*/ null); + /* actionDigest= */ null, + /* skipCacheLookup= */ false, + /* executionPolicy= */ null, + /* resultsCachePolicy= */ null, + /* requestMetadata= */ null, + /* watcher= */ null); } @Test(expected = UnsupportedOperationException.class) public void matchIsUnsupported() throws InterruptedException { - instance.match(/* platform=*/ null, /* listener=*/ null); + instance.match(/* platform= */ null, /* listener= */ null); } @Test(expected = UnsupportedOperationException.class) public void cancelOperationIsUnsupported() throws InterruptedException { - instance.cancelOperation(/* name=*/ null); + instance.cancelOperation(/* name= */ null); } @Test(expected = UnsupportedOperationException.class) public void deleteOperation() throws InterruptedException { - instance.deleteOperation(/* name=*/ null); + instance.deleteOperation(/* name= */ null); } } From 898033add44bf94bd4fd4ed16a792e2fb0d4e50d Mon Sep 17 00:00:00 2001 From: George Gensure Date: Wed, 13 Mar 2024 11:06:36 -0400 Subject: [PATCH 232/311] Include resources description --- _site/docs/configuration/configuration.md | 32 ++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/_site/docs/configuration/configuration.md b/_site/docs/configuration/configuration.md index 5ca58b303e..2ee316abbf 100644 --- a/_site/docs/configuration/configuration.md +++ b/_site/docs/configuration/configuration.md @@ -319,9 +319,10 @@ Note: In order for these settings to take effect, you must also configure `limit ### Dequeue Match -| Configuration | Accepted and _Default_ Values | Description | -|------------------|-------------------------------|-------------| -| allowUnmatched | boolean, _false_ | | +| Configuration | Accepted and _Default_ Values | Description | +|------------------|-------------------------------|------------------------------------------------------------------| +| allowUnmatched | boolean, _false_ | | +| properties | List of name/value pairs | Pairs of provisions available to match against action properties | Example: @@ -329,6 +330,31 @@ Example: worker: dequeueMatchSettings: allowUnmatched: false + properties: + - "gpu": "nvidia RTX 2090" +``` + +### Resources + +A list of limited resources that are available to the worker to be depleted by actions which execute containing a "resource:": "N" property. +Note that in order to accept resources from a configured queue, the dequeueMatchSettings must either: + * specify `allowUnmatched: true` + * contain "resource:" in properties, with either a specific limited resource count as the only accepted value for the action property or "*" + +| Configuration | Accepted Values | Description | +|-------------------------------------------------------------------------| +| name | string | Resource identifier present on worker | +| amount | Integer | Resource count depleted by actions | + +Example: +```yaml +worker: + dequeueMatchSettings: + properties: + - "resource:special-compiler-license": "1" # only actions which request one compiler license at a time will be accepted + resources: + name: "special-compiler-license" + amount: 3 ``` ### Worker CAS From 581d30f565838cb4e0174d742db424d58bc6ca7b Mon Sep 17 00:00:00 2001 From: George Gensure Date: Wed, 13 Mar 2024 11:07:44 -0400 Subject: [PATCH 233/311] Correct typo in resource table definitions --- _site/docs/configuration/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_site/docs/configuration/configuration.md b/_site/docs/configuration/configuration.md index 2ee316abbf..9dae48db8f 100644 --- a/_site/docs/configuration/configuration.md +++ b/_site/docs/configuration/configuration.md @@ -342,7 +342,7 @@ Note that in order to accept resources from a configured queue, the dequeueMatch * contain "resource:" in properties, with either a specific limited resource count as the only accepted value for the action property or "*" | Configuration | Accepted Values | Description | -|-------------------------------------------------------------------------| +|---------------|-----------------|---------------------------------------| | name | string | Resource identifier present on worker | | amount | Integer | Resource count depleted by actions | From 3b1b99add13f80456329d3e1efe1fd6dd9fc35e8 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Fri, 15 Mar 2024 09:32:26 -0700 Subject: [PATCH 234/311] build(bzlmod): Switch to rules_oci (#1667) * build: swap rules_docker for rules_oci * build: remove images.bzl * build: convert java_library to pkg_tar for various container things * build: add container tests Add tests from container_structure_test * build: Sort out the selector() for env vars * chore: typos * fix(helm): update helm chart Updating helm chart's image, and move CONFIG_PATH from an arg to an env var. --- .bazelci/docker_unit_test.sh | 2 +- .bazelci/presubmit.yml | 4 +- .bazelrc | 2 - BUILD | 201 +++++++++++++----- MODULE.bazel | 28 +++ WORKSPACE | 4 - container/BUILD | 1 + container/defs.bzl | 28 +++ container/test/BUILD | 32 +++ container/test/example_config.yaml | 15 ++ container/test/server.yaml | 17 ++ container/test/telemetry_tools.yaml | 7 + container/test/worker.yaml | 21 ++ container/test/worker_wrappers.yaml | 47 ++++ defs.bzl | 6 - deps.bzl | 8 - images.bzl | 29 --- .../templates/server/deployment.yaml | 7 +- .../templates/shard-worker/statefulsets.yaml | 6 +- 19 files changed, 348 insertions(+), 117 deletions(-) create mode 100644 container/BUILD create mode 100644 container/defs.bzl create mode 100644 container/test/BUILD create mode 100644 container/test/example_config.yaml create mode 100644 container/test/server.yaml create mode 100644 container/test/telemetry_tools.yaml create mode 100644 container/test/worker.yaml create mode 100644 container/test/worker_wrappers.yaml delete mode 100644 images.bzl diff --git a/.bazelci/docker_unit_test.sh b/.bazelci/docker_unit_test.sh index 84d8881508..13ed343f2d 100755 --- a/.bazelci/docker_unit_test.sh +++ b/.bazelci/docker_unit_test.sh @@ -4,4 +4,4 @@ # Build a container for unit tests and run them cp `which bazel` bazel docker build -t buildfarm . -docker run buildfarm /bin/bash -c "cd buildfarm; ./bazel test --build_tests_only --test_tag_filters=-integration,-redis ..." \ No newline at end of file +docker run buildfarm /bin/bash -c "cd buildfarm; ./bazel test --build_tests_only --test_tag_filters=-container,-integration,-redis ..." \ No newline at end of file diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index 687ffc1781..675beb237c 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -67,7 +67,7 @@ tasks: build_targets: - "..." test_flags: - - "--test_tag_filters=-integration,-redis" + - "--test_tag_filters=-container,-integration,-redis" test_targets: - "..." windows: @@ -78,7 +78,7 @@ tasks: - "..." test_flags: - "--@rules_jvm_external//settings:stamp_manifest=False" - - "--test_tag_filters=-integration,-redis" + - "--test_tag_filters=-container,-integration,-redis" test_targets: - "..." rpm_builds: diff --git a/.bazelrc b/.bazelrc index 5a5d45b6ba..8d13a79d36 100644 --- a/.bazelrc +++ b/.bazelrc @@ -4,8 +4,6 @@ build --java_runtime_version=remotejdk_17 build --tool_java_language_version=17 build --tool_java_runtime_version=remotejdk_17 -# Prevents rules_docker issues when building with bazel 7 -build --@io_bazel_rules_docker//transitions:enable=false common --enable_platform_specific_config diff --git a/BUILD b/BUILD index fa514b78e0..586415898f 100644 --- a/BUILD +++ b/BUILD @@ -1,7 +1,8 @@ load("@buildifier_prebuilt//:rules.bzl", "buildifier") -load("@io_bazel_rules_docker//container:container.bzl", "container_push") -load("@io_bazel_rules_docker//java:image.bzl", "java_image") +load("@rules_oci//oci:defs.bzl", "oci_image", "oci_image_index", "oci_push", "oci_tarball") +load("@rules_pkg//:pkg.bzl", "pkg_tar") load("//:jvm_flags.bzl", "server_jvm_flags", "worker_jvm_flags") +load("//container:defs.bzl", "oci_image_env") package(default_visibility = ["//visibility:public"]) @@ -16,6 +17,17 @@ buildifier( # For example, "debgging tools", "introspection tools", and "exeution wrappers" are examples of dependencies # that many need included within deployed containers. This BUILD file creates docker images that bundle # additional dependencies alongside the buildfarm agents. +ARCH = [ + # keep sorted + # "aarch64", # TODO + "amd64", +] + +DEFAULT_IMAGE_LABELS = { + "org.opencontainers.image.source": "https://github.com/bazelbuild/bazel-buildfarm", +} + +DEFAULT_PACKAGE_DIR = "app/build_buildfarm" # == Execution Wrappers == # Execution wrappers are programs that buildfarm chooses to use when running REAPI actions. They are used for @@ -31,9 +43,9 @@ buildifier( # bazel version is used in buildfarm agents as is used by bazel clients. There has not been any known issues due # to version mismatch, but we state the possibility here. Some execution wrappers will not be compatible with all # operating systems. We make a best effort and ensure they all work in the below images. -java_library( +pkg_tar( name = "execution_wrappers", - data = [ + srcs = [ ":as-nobody", ":delay", ":linux-sandbox.binary", @@ -41,15 +53,18 @@ java_library( ":process-wrapper.binary", ":skip_sleep.binary", ":skip_sleep.preload", - ":tini.binary", ], + package_dir = DEFAULT_PACKAGE_DIR, + tags = ["container"], ) -java_library( +pkg_tar( name = "telemetry_tools", - data = [ + srcs = [ ":opentelemetry-javaagent", ], + package_dir = DEFAULT_PACKAGE_DIR, + tags = ["container"], ) genrule( @@ -113,66 +128,140 @@ sh_binary( srcs = ["macos-wrapper.sh"], ) -# Docker images for buildfarm components -java_image( - name = "buildfarm-server", - args = ["/app/build_buildfarm/examples/config.minimal.yml"], - base = "@amazon_corretto_java_image_base//image", - classpath_resources = [ - "//src/main/java/build/buildfarm:configs", - ], - data = [ - "//examples:example_configs", - "//src/main/java/build/buildfarm:configs", +pkg_tar( + name = "layer_tini_amd64", + srcs = ["@tini//file"], + mode = "0555", + remap_paths = {"/downloaded": "/tini"}, + tags = ["container"], +) + +pkg_tar( + name = "layer_buildfarm_server", + srcs = ["//src/main/java/build/buildfarm:buildfarm-server_deploy.jar"], + package_dir = DEFAULT_PACKAGE_DIR, + tags = ["container"], +) + +pkg_tar( + name = "layer_buildfarm_worker", + srcs = ["//src/main/java/build/buildfarm:buildfarm-shard-worker_deploy.jar"], + package_dir = DEFAULT_PACKAGE_DIR, + tags = ["container"], +) + +pkg_tar( + name = "layer_minimal_config", + srcs = ["@build_buildfarm//examples:example_configs"], + package_dir = DEFAULT_PACKAGE_DIR, + tags = ["container"], +) + +pkg_tar( + name = "layer_logging_config", + srcs = ["@build_buildfarm//src/main/java/build/buildfarm:configs"], + package_dir = DEFAULT_PACKAGE_DIR + "/src/main/java/build/buildfarm", + tags = ["container"], +) + +oci_image_env( + name = "env_server", + configpath = "/" + DEFAULT_PACKAGE_DIR + "/config.minimal.yml", + jvm_args = server_jvm_flags(), +) + +oci_image( + name = "buildfarm-server_linux_amd64", + base = "@amazon_corretto_java_image_base", + entrypoint = [ + "java", + "-jar", + "/" + DEFAULT_PACKAGE_DIR + "/buildfarm-server_deploy.jar", ], - jvm_flags = server_jvm_flags(), - main_class = "build.buildfarm.server.BuildFarmServer", + env = ":env_server", + labels = DEFAULT_IMAGE_LABELS, tags = ["container"], - runtime_deps = [ + tars = [ + # do not sort + ":layer_logging_config", + ":layer_minimal_config", ":telemetry_tools", - "//src/main/java/build/buildfarm/server", + ":layer_buildfarm_server", ], ) -java_image( - name = "buildfarm-shard-worker", - args = ["/app/build_buildfarm/examples/config.minimal.yml"], - base = "@ubuntu-mantic//image", - classpath_resources = [ - "//src/main/java/build/buildfarm:configs", - ], - data = [ - "//examples:example_configs", - "//src/main/java/build/buildfarm:configs", +oci_image_env( + name = "env_worker", + configpath = "/" + DEFAULT_PACKAGE_DIR + "/config.minimal.yml", + jvm_args = worker_jvm_flags(), +) + +oci_image( + name = "buildfarm-worker_linux_amd64", + base = "@ubuntu_mantic", + entrypoint = [ + # do not sort + "/tini", + "--", + "java", + "-jar", + "/" + DEFAULT_PACKAGE_DIR + "/buildfarm-shard-worker_deploy.jar", ], - jvm_flags = worker_jvm_flags(), - main_class = "build.buildfarm.worker.shard.Worker", + env = ":env_worker", + labels = DEFAULT_IMAGE_LABELS, tags = ["container"], - runtime_deps = [ + tars = [ + # do not sort + ":layer_tini_amd64", + ":layer_logging_config", + ":layer_minimal_config", ":execution_wrappers", ":telemetry_tools", - "//src/main/java/build/buildfarm/worker/shard", + ":layer_buildfarm_worker", ], ) -# Below targets push public docker images to bazelbuild dockerhub. +[ + oci_image_index( + name = "buildfarm-%s" % image, + images = [ + ":buildfarm-%s_linux_%s" % (image, arch) + for arch in ARCH + ], + tags = ["container"], + ) + for image in [ + "server", + "worker", + ] +] -container_push( - name = "public_push_buildfarm-server", - format = "Docker", - image = ":buildfarm-server", - registry = "index.docker.io", - repository = "bazelbuild/buildfarm-server", - tag = "$(release_version)", - tags = ["container"], -) - -container_push( - name = "public_push_buildfarm-worker", - format = "Docker", - image = ":buildfarm-shard-worker", - registry = "index.docker.io", - repository = "bazelbuild/buildfarm-worker", - tag = "$(release_version)", - tags = ["container"], -) +###### +# Helpers to write to the local Docker Desktop's registry +# Usage: `bazel run //:tarball_server_amd64 && docker run --rm buildfarm-server:amd64` +# #### +[ + [ + oci_tarball( + name = "tarball_%s_%s" % (image, arch), + image = ":buildfarm-%s_linux_%s" % (image, arch), + repo_tags = ["buildfarm-%s:%s" % (image, arch)], + tags = ["container"], + ), + # Below targets push public docker images to bazelbuild dockerhub. + oci_push( + name = "public_push_buildfarm-%s" % image, + image = ":buildfarm-%s" % image, + remote_tags = [ + "$(release_version)", + ], + repository = "index.docker.io/bazelbuild/buildfarm-%s" % image, + tags = ["container"], + ), + ] + for arch in ARCH + for image in [ + "server", + "worker", + ] +] diff --git a/MODULE.bazel b/MODULE.bazel index dd4df9eb00..9b46e315ad 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -12,9 +12,37 @@ bazel_dep(name = "rules_cc", version = "0.0.9") bazel_dep(name = "rules_go", version = "0.43.0", repo_name = "io_bazel_rules_go") bazel_dep(name = "rules_jvm_external", version = "5.3") bazel_dep(name = "rules_license", version = "0.0.7") +bazel_dep(name = "rules_oci", version = "1.7.4") +bazel_dep(name = "container_structure_test", version = "1.16.0") bazel_dep( name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True, ) + +oci = use_extension("@rules_oci//oci:extensions.bzl", "oci") + +# Server base image +oci.pull( + # This is a multi-arch image! + name = "amazon_corretto_java_image_base", + digest = "sha256:f0e6040a09168500a1e96d02fef42a26176aaec8e0f136afba081366cb98e2f6", # tag:21 as of today. + image = "public.ecr.aws/amazoncorretto/amazoncorretto", + platforms = [ + "linux/amd64", + "linux/arm64/v8", + ], +) + +# Worker base image +oci.pull( + name = "ubuntu_mantic", + image = "index.docker.io/bazelbuild/buildfarm-worker-base", + tag = "mantic", +) +use_repo( + oci, + "amazon_corretto_java_image_base", + "ubuntu_mantic", +) diff --git a/WORKSPACE b/WORKSPACE index 3ce5827108..2f1599f516 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -12,10 +12,6 @@ load("@maven//:compat.bzl", "compat_repositories") compat_repositories() -load(":images.bzl", "buildfarm_images") - -buildfarm_images() - # Find rpmbuild if it exists. load("@rules_pkg//toolchains/rpm:rpmbuild_configure.bzl", "find_system_rpmbuild") diff --git a/container/BUILD b/container/BUILD new file mode 100644 index 0000000000..52e577c30a --- /dev/null +++ b/container/BUILD @@ -0,0 +1 @@ +# Intentionally Empty diff --git a/container/defs.bzl b/container/defs.bzl new file mode 100644 index 0000000000..ba7cbddeb7 --- /dev/null +++ b/container/defs.bzl @@ -0,0 +1,28 @@ +"""Rules for ENV""" + +def _oci_image_env_impl(ctx): + """ + Helper method to write out a "key=value" pair on separate lines. This file is fed into oci_image() in the `env` kwargs. + """ + envs = { + "CONFIG_PATH": ctx.attr.configpath, + "JAVA_TOOL_OPTIONS": " ".join(ctx.attr.jvm_args), + } + builder = ctx.actions.declare_file("_%s.env.txt" % ctx.label.name) + ctx.actions.write( + output = builder, + content = "\n".join(["{}={}".format(key, value) for (key, value) in envs.items()]), + ) + return [ + DefaultInfo( + files = depset([builder]), + ), + ] + +oci_image_env = rule( + implementation = _oci_image_env_impl, + attrs = { + "configpath": attr.string(mandatory = True), + "jvm_args": attr.string_list(mandatory = True, allow_empty = False), + }, +) diff --git a/container/test/BUILD b/container/test/BUILD new file mode 100644 index 0000000000..d0f760b4bc --- /dev/null +++ b/container/test/BUILD @@ -0,0 +1,32 @@ +"""Tests for our OCI image outputs""" + +load("@container_structure_test//:defs.bzl", "container_structure_test") + +DRIVER = "docker" # Use tar if your host is not amd64, but it's a lot slower. (for example, you use hardware from Apple and you have aarch64) + +container_structure_test( + name = "worker_test", + configs = [ + # keep sorted + "example_config.yaml", + "telemetry_tools.yaml", + "worker.yaml", + "worker_wrappers.yaml", + ], + driver = DRIVER, + image = "//:buildfarm-worker_linux_amd64", + tags = ["container"], +) + +container_structure_test( + name = "server_test", + configs = [ + # keep sorted + "example_config.yaml", + "server.yaml", + "telemetry_tools.yaml", + ], + driver = DRIVER, + image = "//:buildfarm-server_linux_amd64", + tags = ["container"], +) diff --git a/container/test/example_config.yaml b/container/test/example_config.yaml new file mode 100644 index 0000000000..100d20289f --- /dev/null +++ b/container/test/example_config.yaml @@ -0,0 +1,15 @@ +--- +schemaVersion: "2.0.0" + +fileExistenceTests: + - name: "config.minimal.yaml" + path: '/app/build_buildfarm/config.minimal.yml' + shouldExist: true + - name: 'logging.properties' + path: '/app/build_buildfarm/src/main/java/build/buildfarm/logging.properties' + shouldExist: true + +metadataTest: + envVars: + - key: CONFIG_PATH + value: /app/build_buildfarm/config.minimal.yml diff --git a/container/test/server.yaml b/container/test/server.yaml new file mode 100644 index 0000000000..780d00b101 --- /dev/null +++ b/container/test/server.yaml @@ -0,0 +1,17 @@ +--- +schemaVersion: "2.0.0" + +fileExistenceTests: + + - name: "JAR" + path: '/app/build_buildfarm/buildfarm-server_deploy.jar' + shouldExist: true + +metadataTest: + envVars: + - key: JAVA_TOOL_OPTIONS + value: 'UseContainerSupport' + isRegex: true + labels: + - key: 'org.opencontainers.image.source' + value: 'https://github.com/bazelbuild/bazel-buildfarm' diff --git a/container/test/telemetry_tools.yaml b/container/test/telemetry_tools.yaml new file mode 100644 index 0000000000..233faafaeb --- /dev/null +++ b/container/test/telemetry_tools.yaml @@ -0,0 +1,7 @@ +--- +schemaVersion: "2.0.0" + +fileExistenceTests: + - name: "opentelemetry-javaagent" + path: '/app/build_buildfarm/opentelemetry-javaagent.jar' + shouldExist: true diff --git a/container/test/worker.yaml b/container/test/worker.yaml new file mode 100644 index 0000000000..c670f4a682 --- /dev/null +++ b/container/test/worker.yaml @@ -0,0 +1,21 @@ +--- +schemaVersion: "2.0.0" + +fileExistenceTests: + - name: "JAR" + path: '/app/build_buildfarm/buildfarm-shard-worker_deploy.jar' + shouldExist: true + + - name: "tini" + path: '/tini' + shouldExist: true + permissions: '-r-xr-xr-x' + +metadataTest: + envVars: + - key: JAVA_TOOL_OPTIONS + value: 'UseContainerSupport' + isRegex: true + labels: + - key: 'org.opencontainers.image.source' + value: 'https://github.com/bazelbuild/bazel-buildfarm' \ No newline at end of file diff --git a/container/test/worker_wrappers.yaml b/container/test/worker_wrappers.yaml new file mode 100644 index 0000000000..4df0da7afe --- /dev/null +++ b/container/test/worker_wrappers.yaml @@ -0,0 +1,47 @@ +--- +schemaVersion: "2.0.0" +# These align with the default paths in //src/main/java/build/buildfarm/common/config/ExecutionWrappers.java +fileExistenceTests: + - name: "cgroups cexec" + path: "/usr/bin/cgexec" + shouldExist: true + permissions: '-rwxr-xr-x' + + - name: "unshare" + path: "/usr/bin/unshare" + shouldExist: true + permissions: '-rwxr-xr-x' + + - name: "as-nobody wrapper" + path: '/app/build_buildfarm/as-nobody' + shouldExist: true + permissions: '-r-xr-xr-x' + + - name: "process-wrapper" + path: '/app/build_buildfarm/process-wrapper' + shouldExist: true + permissions: '-r-xr-xr-x' + + - name: "skip-sleep" + path: '/app/build_buildfarm/skip_sleep' + shouldExist: true + permissions: '-r-xr-xr-x' + + - name: "skip-sleep-preload" + path: '/app/build_buildfarm/skip_sleep_preload.so' + shouldExist: true + + - name: "delay.sh" + path: '/app/build_buildfarm/delay.sh' + shouldExist: true + permissions: '-r-xr-xr-x' +#----- +# These are documented in //:execution_wrappers + - name: "linux-sandbox" + path: '/app/build_buildfarm/linux-sandbox' + shouldExist: true + permissions: '-r-xr-xr-x' + - name: "macos-wrapper" + path: '/app/build_buildfarm/macos-wrapper.sh' + shouldExist: true + permissions: '-r-xr-xr-x' diff --git a/defs.bzl b/defs.bzl index 55d4a4db45..1a17751bd7 100644 --- a/defs.bzl +++ b/defs.bzl @@ -4,10 +4,6 @@ buildfarm definitions that can be imported into other WORKSPACE files load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") load("@com_grail_bazel_toolchain//toolchain:rules.bzl", "llvm_toolchain") -load( - "@io_bazel_rules_docker//repositories:repositories.bzl", - container_repositories = "repositories", -) load("@io_grpc_grpc_java//:repositories.bzl", "IO_GRPC_GRPC_JAVA_OVERRIDE_TARGETS", "grpc_java_repositories") load("@remote_apis//:repository_rules.bzl", "switched_rules_by_language") load("@rules_jvm_external//:defs.bzl", "maven_install") @@ -126,8 +122,6 @@ def buildfarm_init(name = "buildfarm"): java = True, ) - container_repositories() - protobuf_deps() grpc_java_repositories() diff --git a/deps.bzl b/deps.bzl index 975bc7aad9..0ca0458e89 100644 --- a/deps.bzl +++ b/deps.bzl @@ -55,14 +55,6 @@ def archive_dependencies(third_party): "patches": ["%s:clang_toolchain.patch" % third_party], }, - # Used to build release container images - { - "name": "io_bazel_rules_docker", - "sha256": "b1e80761a8a8243d03ebca8845e9cc1ba6c82ce7c5179ce2b295cd36f7e394bf", - "urls": ["https://github.com/bazelbuild/rules_docker/releases/download/v0.25.0/rules_docker-v0.25.0.tar.gz"], - "patch_args": ["-p0"], - "patches": ["%s:docker_go_toolchain.patch" % third_party], - }, # Bazel is referenced as a dependency so that buildfarm can access the linux-sandbox as a potential execution wrapper. { "name": "bazel", diff --git a/images.bzl b/images.bzl deleted file mode 100644 index 9b7afcacba..0000000000 --- a/images.bzl +++ /dev/null @@ -1,29 +0,0 @@ -""" -buildfarm images that can be imported into other WORKSPACE files -""" - -load("@io_bazel_rules_docker//container:container.bzl", "container_pull") -load("@io_bazel_rules_docker//repositories:deps.bzl", container_deps = "deps") - -def buildfarm_images(): - """ - Pull the necessary base containers to be used for image definitions. - """ - - container_deps() - - # Base mantic worker image for public releases (built via github action from ci/base-worker-image/mantic/Dockerfile) - container_pull( - name = "ubuntu-mantic", - registry = "index.docker.io", - repository = "bazelbuild/buildfarm-worker-base", - tag = "mantic", - ) - - # Server base image - container_pull( - name = "amazon_corretto_java_image_base", - registry = "public.ecr.aws/amazoncorretto", - repository = "amazoncorretto", - tag = "21", - ) diff --git a/kubernetes/helm-charts/buildfarm/templates/server/deployment.yaml b/kubernetes/helm-charts/buildfarm/templates/server/deployment.yaml index e56261f1fd..577f697b13 100644 --- a/kubernetes/helm-charts/buildfarm/templates/server/deployment.yaml +++ b/kubernetes/helm-charts/buildfarm/templates/server/deployment.yaml @@ -31,12 +31,9 @@ spec: - name: buildfarm-server image: "{{ .Values.server.image.repository }}:{{ .Values.server.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.server.image.pullPolicy }} - command: - - bash - - /app/build_buildfarm/buildfarm-server.binary - args: - - /config/config.yml env: + - name: CONFIG_PATH + value: /config/config.yml {{- if .Values.server.extraEnv }} {{- toYaml .Values.server.extraEnv | nindent 12 }} {{- end }} diff --git a/kubernetes/helm-charts/buildfarm/templates/shard-worker/statefulsets.yaml b/kubernetes/helm-charts/buildfarm/templates/shard-worker/statefulsets.yaml index 8582807d8e..8f1c6dc5c9 100644 --- a/kubernetes/helm-charts/buildfarm/templates/shard-worker/statefulsets.yaml +++ b/kubernetes/helm-charts/buildfarm/templates/shard-worker/statefulsets.yaml @@ -39,12 +39,10 @@ spec: image: "{{ .Values.shardWorker.image.repository }}:{{ .Values.shardWorker.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.shardWorker.image.pullPolicy }} args: - - /config/config.yml - --public_name=$(POD_IP):8982 - command: - - bash - - /app/build_buildfarm/buildfarm-shard-worker.binary env: + - name: CONFIG_PATH + value: /config/config.yml - name: POD_IP valueFrom: fieldRef: From 59689656b8b49f9f34900f18844cd929a34faeb7 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Mon, 18 Mar 2024 16:37:20 -0700 Subject: [PATCH 235/311] build: bump maven version to latest (#1670) Bumping the maven version to the latest. --- admin/main/mvn/wrapper/maven-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/main/mvn/wrapper/maven-wrapper.properties b/admin/main/mvn/wrapper/maven-wrapper.properties index cd0d451ccd..3c1106457a 100644 --- a/admin/main/mvn/wrapper/maven-wrapper.properties +++ b/admin/main/mvn/wrapper/maven-wrapper.properties @@ -1 +1 @@ -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip From 9c4014f4d8d12c3e5b3acb843c280aaeb65e18f6 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Mon, 18 Mar 2024 16:39:25 -0700 Subject: [PATCH 236/311] ci: Fix rules_oci docker publish (#1671) * ci: fix docker image push * docs(README): add Docker download badge to README --- .github/workflows/buildfarm-images-build-and-deploy.yml | 4 ++-- .github/workflows/buildfarm-release-build-and-deploy.yml | 4 ++-- BUILD | 6 ++---- README.md | 1 + 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/.github/workflows/buildfarm-images-build-and-deploy.yml b/.github/workflows/buildfarm-images-build-and-deploy.yml index 97936b3fe9..3e72ae34a6 100644 --- a/.github/workflows/buildfarm-images-build-and-deploy.yml +++ b/.github/workflows/buildfarm-images-build-and-deploy.yml @@ -24,8 +24,8 @@ jobs: - name: Build Server Image id: buildAndPushServerImage - run: bazel run public_push_buildfarm-server --define release_version=latest + run: bazel run public_push_buildfarm-server -- --tag latest - name: Build Worker Image id: buildAndPushWorkerImage - run: bazel run public_push_buildfarm-worker --define release_version=latest + run: bazel run public_push_buildfarm-worker -- --tag latest diff --git a/.github/workflows/buildfarm-release-build-and-deploy.yml b/.github/workflows/buildfarm-release-build-and-deploy.yml index 537919bbbc..db9fe8dcf1 100644 --- a/.github/workflows/buildfarm-release-build-and-deploy.yml +++ b/.github/workflows/buildfarm-release-build-and-deploy.yml @@ -23,8 +23,8 @@ jobs: - name: Build Server Image id: buildAndPushServerImage - run: bazel run public_push_buildfarm-server --define release_version=${{ github.event.release.tag_name }} + run: bazel run public_push_buildfarm-server -- --tag ${{ github.event.release.tag_name }} - name: Build Worker Image id: buildAndPushWorkerImage - run: bazel run public_push_buildfarm-worker --define release_version=${{ github.event.release.tag_name }} + run: bazel run public_push_buildfarm-worker -- --tag ${{ github.event.release.tag_name }} diff --git a/BUILD b/BUILD index 586415898f..d37e4925f1 100644 --- a/BUILD +++ b/BUILD @@ -239,7 +239,7 @@ oci_image( ###### # Helpers to write to the local Docker Desktop's registry # Usage: `bazel run //:tarball_server_amd64 && docker run --rm buildfarm-server:amd64` -# #### +###### [ [ oci_tarball( @@ -252,10 +252,8 @@ oci_image( oci_push( name = "public_push_buildfarm-%s" % image, image = ":buildfarm-%s" % image, - remote_tags = [ - "$(release_version)", - ], repository = "index.docker.io/bazelbuild/buildfarm-%s" % image, + # Specify the tag with `bazel run public_push_buildfarm-server public_push_buildfarm-worker -- --tag latest` tags = ["container"], ), ] diff --git a/README.md b/README.md index 67037a566c..079f453ac3 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/bazelbuild/bazel-buildfarm/badge)](https://securityscorecards.dev/viewer/?uri=github.com/bazelbuild/bazel-buildfarm) ![GitHub License](https://img.shields.io/github/license/bazelbuild/bazel-buildfarm) ![GitHub Release](https://img.shields.io/github/v/release/bazelbuild/bazel-buildfarm) +![Docker Pulls](https://img.shields.io/docker/pulls/bazelbuild/buildfarm-server) This repository hosts the [Bazel](https://bazel.build) remote caching and execution system. From f0d43d0f7c05130eb6ab6005d36f02a5b36ede26 Mon Sep 17 00:00:00 2001 From: Stefano Baghino Date: Wed, 20 Mar 2024 16:40:30 +0100 Subject: [PATCH 237/311] Fix link to IJ screenshot --- _site/docs/contribute/local_development.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_site/docs/contribute/local_development.md b/_site/docs/contribute/local_development.md index 5799aa9739..156f847ab7 100644 --- a/_site/docs/contribute/local_development.md +++ b/_site/docs/contribute/local_development.md @@ -75,4 +75,4 @@ bazel run //src/main/java/build/buildfarm:buildfarm-shard-worker $PWD/examples/c Now, you should have something like this, and you can now run / debug Buildfarm Server from inside of IntelliJ, just like any other program: -![IntelliJ Buildfarm Server run configuration]]({{site.url}}{{site.baseurl}}/assets/images/intellij-server-run-config.png) +![IntelliJ Buildfarm Server run configuration]({{site.url}}{{site.baseurl}}/assets/images/intellij-server-run-config.png) From 0918eef9f2b364962c9fa4bb6ecb2a78b89f5cae Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Tue, 19 Mar 2024 15:56:37 -0700 Subject: [PATCH 238/311] chore(MODULE.bazel): bump gazelle --- MODULE.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MODULE.bazel b/MODULE.bazel index 9b46e315ad..a97fabe3c7 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -5,7 +5,7 @@ module( repo_name = "build_buildfarm", ) -bazel_dep(name = "gazelle", version = "0.34.0", repo_name = "bazel_gazelle") +bazel_dep(name = "gazelle", version = "0.35.0", repo_name = "bazel_gazelle") bazel_dep(name = "platforms", version = "0.0.8") bazel_dep(name = "protobuf", version = "23.1", repo_name = "com_google_protobuf") bazel_dep(name = "rules_cc", version = "0.0.9") From 6dcf73731b1c4db78dadaf8315564fa69997a44a Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Tue, 19 Mar 2024 16:24:26 -0700 Subject: [PATCH 239/311] build: declare container_structure_test as dev dependency --- MODULE.bazel | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/MODULE.bazel b/MODULE.bazel index a97fabe3c7..c359b59b40 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -13,8 +13,13 @@ bazel_dep(name = "rules_go", version = "0.43.0", repo_name = "io_bazel_rules_go" bazel_dep(name = "rules_jvm_external", version = "5.3") bazel_dep(name = "rules_license", version = "0.0.7") bazel_dep(name = "rules_oci", version = "1.7.4") -bazel_dep(name = "container_structure_test", version = "1.16.0") +# Test dependencies +bazel_dep( + name = "container_structure_test", + version = "1.16.0", + dev_dependency = True, +) bazel_dep( name = "buildifier_prebuilt", version = "6.4.0", From 14ba613ce195780a54fdad9b46c0a33aea5a2f72 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Tue, 19 Mar 2024 15:55:38 -0700 Subject: [PATCH 240/311] chore(MODULE.bazel): bump rules_go --- MODULE.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MODULE.bazel b/MODULE.bazel index c359b59b40..c7fae06a6c 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -9,7 +9,7 @@ bazel_dep(name = "gazelle", version = "0.35.0", repo_name = "bazel_gazelle") bazel_dep(name = "platforms", version = "0.0.8") bazel_dep(name = "protobuf", version = "23.1", repo_name = "com_google_protobuf") bazel_dep(name = "rules_cc", version = "0.0.9") -bazel_dep(name = "rules_go", version = "0.43.0", repo_name = "io_bazel_rules_go") +bazel_dep(name = "rules_go", version = "0.44.2", repo_name = "io_bazel_rules_go") bazel_dep(name = "rules_jvm_external", version = "5.3") bazel_dep(name = "rules_license", version = "0.0.7") bazel_dep(name = "rules_oci", version = "1.7.4") From 236fb8cc604a10c8415a169d1eef465028919fff Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Fri, 15 Mar 2024 10:11:09 -0700 Subject: [PATCH 241/311] build: pin ubuntu-mantic image --- MODULE.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MODULE.bazel b/MODULE.bazel index c7fae06a6c..1624d4adc9 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -43,8 +43,8 @@ oci.pull( # Worker base image oci.pull( name = "ubuntu_mantic", + digest = "sha256:2520e0725493c8f63452dd8aa153fbf0b489a9442096b7693641193709a765b7", # tag: mantic image = "index.docker.io/bazelbuild/buildfarm-worker-base", - tag = "mantic", ) use_repo( oci, From 04478ccea756731314603afcee37a34c6fd29381 Mon Sep 17 00:00:00 2001 From: Andrew Rothstein Date: Thu, 14 Mar 2024 20:20:05 +0000 Subject: [PATCH 242/311] add ingress for the server --- .../buildfarm/templates/server/ingress.yaml | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 kubernetes/helm-charts/buildfarm/templates/server/ingress.yaml diff --git a/kubernetes/helm-charts/buildfarm/templates/server/ingress.yaml b/kubernetes/helm-charts/buildfarm/templates/server/ingress.yaml new file mode 100644 index 0000000000..9a2510b1c5 --- /dev/null +++ b/kubernetes/helm-charts/buildfarm/templates/server/ingress.yaml @@ -0,0 +1,62 @@ +{{- $ingress := .Values.server.ingress -}} +{{- if $ingress.enabled -}} +{{- $fullName := include "buildfarm.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- if and $ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey $ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set $ingress.annotations "kubernetes.io/ingress.class" $ingress.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include "buildfarm.labels" . | nindent 4 }} + {{- with $ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and $ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ $ingress.className }} + {{- end }} + {{- if $ingress.tls }} + tls: + {{- range $ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range $ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ .pathType }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} From f65309102c0cbc30e3820290f206e6bacc6d58fb Mon Sep 17 00:00:00 2001 From: Andrew Rothstein Date: Mon, 18 Mar 2024 14:53:37 +0000 Subject: [PATCH 243/311] fix service.port reference --- .../helm-charts/buildfarm/templates/server/ingress.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kubernetes/helm-charts/buildfarm/templates/server/ingress.yaml b/kubernetes/helm-charts/buildfarm/templates/server/ingress.yaml index 9a2510b1c5..053f8be693 100644 --- a/kubernetes/helm-charts/buildfarm/templates/server/ingress.yaml +++ b/kubernetes/helm-charts/buildfarm/templates/server/ingress.yaml @@ -1,7 +1,8 @@ -{{- $ingress := .Values.server.ingress -}} +{{- $server := .Values.server -}} +{{- $ingress := $server.ingress -}} {{- if $ingress.enabled -}} {{- $fullName := include "buildfarm.fullname" . -}} -{{- $svcPort := .Values.service.port -}} +{{- $svcPort := $server.service.port -}} {{- if and $ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} {{- if not (hasKey $ingress.annotations "kubernetes.io/ingress.class") }} {{- $_ := set $ingress.annotations "kubernetes.io/ingress.class" $ingress.className}} From abd088126757b27e01553c3afa32630126358d2f Mon Sep 17 00:00:00 2001 From: George Gensure Date: Thu, 26 Oct 2023 17:39:29 -0400 Subject: [PATCH 244/311] Switch to jedis-5 --- .bazelci/cache_test.sh | 2 +- .bazelci/integration_test.sh | 2 +- .bazelci/redis_unit_tests.sh | 4 +- .bazelci/run_server_test.sh | 2 +- defs.bzl | 15 +- deps.bzl | 21 - src/main/java/build/buildfarm/common/BUILD | 4 +- .../buildfarm/common/BuildfarmExecutors.java | 6 + .../build/buildfarm/common/ScanCount.java | 39 +- .../build/buildfarm/common/WorkerIndexer.java | 45 +- .../java/build/buildfarm/common/config/BUILD | 2 +- .../java/build/buildfarm/common/redis/BUILD | 2 +- .../common/redis/BalancedRedisQueue.java | 154 ++++-- .../common/redis/QueueInterface.java | 25 +- .../buildfarm/common/redis/RedisClient.java | 19 +- .../buildfarm/common/redis/RedisHashMap.java | 30 +- .../buildfarm/common/redis/RedisMap.java | 52 +- .../common/redis/RedisNodeHashes.java | 125 ++--- .../common/redis/RedisPriorityQueue.java | 48 +- .../buildfarm/common/redis/RedisQueue.java | 70 ++- ...edisQueueFactory.java => RedisQueues.java} | 22 +- .../common/redis/RedisSlotToHash.java | 31 +- .../build/buildfarm/common/resources/BUILD | 2 +- .../java/build/buildfarm/instance/shard/BUILD | 2 +- .../instance/shard/JedisCasWorkerMap.java | 24 +- .../instance/shard/JedisClusterFactory.java | 98 +++- .../instance/shard/OperationQueue.java | 20 +- .../buildfarm/instance/shard/Operations.java | 12 +- .../instance/shard/RedisShardBackplane.java | 87 +-- .../instance/shard/RedisShardSubscriber.java | 36 +- .../shard/RedisShardSubscription.java | 8 +- .../build/buildfarm/operations/finder/BUILD | 2 +- .../finder/EnrichedOperationBuilder.java | 10 +- .../operations/finder/OperationsFinder.java | 81 +-- src/main/java/build/buildfarm/tools/BUILD | 4 +- .../build/buildfarm/tools/WorkerProfile.java | 4 +- src/test/java/build/buildfarm/common/BUILD | 2 +- .../java/build/buildfarm/common/redis/BUILD | 3 +- .../redis/BalancedRedisQueueMockTest.java | 237 +++----- .../common/redis/BalancedRedisQueueTest.java | 507 +++++++++--------- .../common/redis/RedisClientTest.java | 6 +- .../common/redis/RedisHashMapTest.java | 4 +- .../common/redis/RedisNodeHashesMockTest.java | 72 ++- .../redis/RedisPriorityQueueMockTest.java | 22 +- .../common/redis/RedisPriorityQueueTest.java | 66 ++- .../common/redis/RedisQueueMockTest.java | 48 +- .../common/redis/RedisQueueTest.java | 31 +- .../common/redis/RedisSlotToHashTest.java | 9 +- .../build/buildfarm/common/resources/BUILD | 2 +- src/test/java/build/buildfarm/examples/BUILD | 2 +- .../java/build/buildfarm/instance/shard/BUILD | 15 +- .../shard/RedisShardBackplaneTest.java | 216 ++++---- .../shard/RedisShardSubscriberTest.java | 126 +++-- third_party/jedis/BUILD | 14 - third_party/jedis/LICENSE | 22 - 55 files changed, 1369 insertions(+), 1145 deletions(-) rename src/main/java/build/buildfarm/common/redis/{RedisQueueFactory.java => RedisQueues.java} (69%) delete mode 100644 third_party/jedis/BUILD delete mode 100644 third_party/jedis/LICENSE diff --git a/.bazelci/cache_test.sh b/.bazelci/cache_test.sh index 678fc72019..53f05964cf 100755 --- a/.bazelci/cache_test.sh +++ b/.bazelci/cache_test.sh @@ -5,7 +5,7 @@ # We ensure that the system can build a set of bazel targets. # Run redis container -docker run -d --name buildfarm-redis --network host redis:5.0.9 --bind localhost +docker run -d --name buildfarm-redis --network host redis:7.2.4 --bind localhost # Build a container for buildfarm services cp `which bazel` bazel diff --git a/.bazelci/integration_test.sh b/.bazelci/integration_test.sh index 9a9acf8c14..e3cf5344f3 100755 --- a/.bazelci/integration_test.sh +++ b/.bazelci/integration_test.sh @@ -5,7 +5,7 @@ # We ensure that the system can build a set of bazel targets. # Run redis container -docker run -d --name buildfarm-redis --network host redis:5.0.9 --bind localhost +docker run -d --name buildfarm-redis --network host redis:7.2.4 --bind localhost # Build a container for buildfarm services cp `which bazel` bazel diff --git a/.bazelci/redis_unit_tests.sh b/.bazelci/redis_unit_tests.sh index 4eddd046ef..d3298c34ff 100755 --- a/.bazelci/redis_unit_tests.sh +++ b/.bazelci/redis_unit_tests.sh @@ -3,7 +3,9 @@ # However this runs unit tests that interact directly with redis. # Run redis container -docker run -d --rm --name buildfarm-redis --network host redis:5.0.9 --bind localhost +docker run -d --rm --name buildfarm-redis --network host redis:7.2.4 --bind localhost # Run tests that rely on redis bazel test --build_tests_only --test_tag_filters=redis src/test/java/... + +docker stop buildfarm-redis diff --git a/.bazelci/run_server_test.sh b/.bazelci/run_server_test.sh index 54e4658b16..6169e63b5c 100755 --- a/.bazelci/run_server_test.sh +++ b/.bazelci/run_server_test.sh @@ -1,7 +1,7 @@ #!/bin/bash # Start redis container -docker run -d --rm --name buildfarm-redis --network host redis:5.0.9 --bind localhost +docker run -d --rm --name buildfarm-redis --network host redis:7.2.4 --bind localhost # Build worker and server targets bazel build //src/main/java/build/buildfarm:buildfarm-shard-worker diff --git a/defs.bzl b/defs.bzl index 1a17751bd7..ff380e378f 100644 --- a/defs.bzl +++ b/defs.bzl @@ -55,7 +55,7 @@ def buildfarm_init(name = "buildfarm"): "com.fasterxml.jackson.core:jackson-databind:2.15.0", "com.github.ben-manes.caffeine:caffeine:2.9.0", "com.github.docker-java:docker-java:3.3.3", - "com.github.fppt:jedis-mock:1.0.10", + "com.github.fppt:jedis-mock:1.0.13", "com.github.jnr:jffi:1.3.11", "com.github.jnr:jffi:jar:native:1.3.11", "com.github.jnr:jnr-constants:0.10.4", @@ -78,7 +78,6 @@ def buildfarm_init(name = "buildfarm"): "com.google.protobuf:protobuf-java-util:3.19.1", "com.google.protobuf:protobuf-java:3.19.1", "com.google.truth:truth:1.1.5", - "org.slf4j:slf4j-simple:2.0.9", "com.googlecode.json-simple:json-simple:1.1.1", "com.jayway.jsonpath:json-path:2.8.0", "org.bouncycastle:bcprov-jdk15on:1.70", @@ -89,15 +88,16 @@ def buildfarm_init(name = "buildfarm"): "io.prometheus:simpleclient:0.15.0", "io.prometheus:simpleclient_hotspot:0.15.0", "io.prometheus:simpleclient_httpserver:0.15.0", - "junit:junit:4.13.2", "javax.annotation:javax.annotation-api:1.3.2", + "junit:junit:4.13.2", "net.javacrumbs.future-converter:future-converter-java8-guava:1.2.0", + "net.jcip:jcip-annotations:1.0", "org.apache.commons:commons-compress:1.23.0", "org.apache.commons:commons-pool2:2.11.1", "org.apache.commons:commons-lang3:3.13.0", - "commons-io:commons-io:2.13.0", "me.dinowernli:java-grpc-prometheus:0.6.0", "org.apache.tomcat:annotations-api:6.0.53", + "org.bouncycastle:bcprov-jdk15on:1.70", "org.checkerframework:checker-qual:3.38.0", "org.mockito:mockito-core:5.10.0", "org.openjdk.jmh:jmh-core:1.37", @@ -108,6 +108,8 @@ def buildfarm_init(name = "buildfarm"): "org.jetbrains:annotations:16.0.2", "org.yaml:snakeyaml:2.2", "org.projectlombok:lombok:1.18.30", + "org.slf4j:slf4j-simple:2.0.9", + "redis.clients:jedis:5.1.0", ], generate_compat_repositories = True, override_targets = IO_GRPC_GRPC_JAVA_OVERRIDE_TARGETS, @@ -126,11 +128,6 @@ def buildfarm_init(name = "buildfarm"): grpc_java_repositories() - native.bind( - name = "jar/redis/clients/jedis", - actual = "@jedis//jar", - ) - llvm_toolchain( name = "llvm_toolchain", llvm_version = "16.0.0", diff --git a/deps.bzl b/deps.bzl index 0ca0458e89..df8d20db86 100644 --- a/deps.bzl +++ b/deps.bzl @@ -89,27 +89,6 @@ def buildfarm_dependencies(repository_name = "build_buildfarm"): name = params.pop("name") maybe(http_archive, name, **params) - # Enhanced jedis 3.2.0 containing several convenience, performance, and - # robustness changes. - # Notable features include: - # Cluster request pipelining, used for batching requests for operation - # monitors and CAS index. - # Blocking request (b* prefix) interruptibility, using client - # connection reset. - # Singleton-redis-as-cluster - support treating a non-clustered redis - # endpoint as a cluster of 1 node. - # Other changes are redis version-forward treatment of spop and visibility - # into errors in cluster unreachable and cluster retry exhaustion. - # Details at https://github.com/werkt/jedis/releases/tag/3.2.0-594c20da20 - maybe( - http_jar, - "jedis", - sha256 = "72c749c02b775c0371cfc8ebcf713032910b7c6f365d958c3c000838f43f6a65", - urls = [ - "https://github.com/werkt/jedis/releases/download/3.2.0-594c20da20/jedis-3.2.0-594c20da20.jar", - ], - ) - maybe( http_jar, "opentelemetry", diff --git a/src/main/java/build/buildfarm/common/BUILD b/src/main/java/build/buildfarm/common/BUILD index a214140840..1b0b73f372 100644 --- a/src/main/java/build/buildfarm/common/BUILD +++ b/src/main/java/build/buildfarm/common/BUILD @@ -15,7 +15,6 @@ java_library( "//src/main/java/build/buildfarm/common/resources", "//src/main/java/build/buildfarm/common/resources:resource_java_proto", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "//third_party/jedis", "@googleapis//:google_longrunning_operations_java_proto", "@googleapis//:google_rpc_code_java_proto", "@googleapis//:google_rpc_error_details_java_proto", @@ -37,6 +36,7 @@ java_library( "@maven//:org_apache_commons_commons_compress", "@maven//:org_projectlombok_lombok", "@maven//:org_threeten_threetenbp", + "@maven//:redis_clients_jedis", "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) @@ -54,7 +54,6 @@ java_library( "//src/main/java/build/buildfarm/common/resources", "//src/main/java/build/buildfarm/common/resources:resource_java_proto", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "//third_party/jedis", "@googleapis//:google_longrunning_operations_java_proto", "@googleapis//:google_rpc_code_java_proto", "@googleapis//:google_rpc_error_details_java_proto", @@ -76,6 +75,7 @@ java_library( "@maven//:org_apache_commons_commons_compress", "@maven//:org_projectlombok_lombok", "@maven//:org_threeten_threetenbp", + "@maven//:redis_clients_jedis", "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/common/BuildfarmExecutors.java b/src/main/java/build/buildfarm/common/BuildfarmExecutors.java index 844c4366d1..f685ca5118 100644 --- a/src/main/java/build/buildfarm/common/BuildfarmExecutors.java +++ b/src/main/java/build/buildfarm/common/BuildfarmExecutors.java @@ -59,6 +59,12 @@ public static ExecutorService getSubscriberPool() { nThreads, new ThreadFactoryBuilder().setNameFormat(threadNameFormat).build()); } + public static ExecutorService getDequeuePool() { + String threadNameFormat = "dequeue-pool-%d"; + return Executors.newCachedThreadPool( + new ThreadFactoryBuilder().setNameFormat(threadNameFormat).build()); + } + public static ListeningExecutorService getTransformServicePool() { int nThreads = 24; String threadNameFormat = "transform-service-pool-%d"; diff --git a/src/main/java/build/buildfarm/common/ScanCount.java b/src/main/java/build/buildfarm/common/ScanCount.java index 0f4b8392e1..420a656875 100644 --- a/src/main/java/build/buildfarm/common/ScanCount.java +++ b/src/main/java/build/buildfarm/common/ScanCount.java @@ -16,10 +16,10 @@ import com.google.common.collect.Sets; import java.util.Set; -import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisCluster; -import redis.clients.jedis.ScanParams; -import redis.clients.jedis.ScanResult; +import redis.clients.jedis.UnifiedJedis; +import redis.clients.jedis.params.ScanParams; +import redis.clients.jedis.resps.ScanResult; /** * @class ScanCount @@ -39,21 +39,26 @@ public class ScanCount { * @return Total number of query results. * @note Suggested return identifier: count. */ - public static int get(JedisCluster cluster, String query, int scanCount) { + public static int get(UnifiedJedis jedis, String query, int scanCount) { Set keys = Sets.newHashSet(); - // JedisCluster only supports SCAN commands with MATCH patterns containing hash-tags. - // This prevents us from using the cluster's SCAN to traverse all existing keys. - // That's why we choose to scan each of the jedisNode's individually. - cluster - .getClusterNodes() - .values() - .forEach( - pool -> { - try (Jedis node = pool.getResource()) { - addKeys(node, keys, query, scanCount); - } - }); + if (jedis instanceof JedisCluster) { + JedisCluster cluster = (JedisCluster) jedis; + // JedisCluster only supports SCAN commands with MATCH patterns containing hash-tags. + // This prevents us from using the cluster's SCAN to traverse all existing keys. + // That's why we choose to scan each of the jedisNode's individually. + cluster + .getClusterNodes() + .values() + .forEach( + pool -> { + try (UnifiedJedis node = new UnifiedJedis(pool.getResource())) { + addKeys(node, keys, query, scanCount); + } + }); + } else { + addKeys(jedis, keys, query, scanCount); + } return keys.size(); } @@ -67,7 +72,7 @@ public static int get(JedisCluster cluster, String query, int scanCount) { * @param scanCount The count per scan. */ @SuppressWarnings({"unchecked", "rawtypes"}) - private static void addKeys(Jedis node, Set keys, String query, int scanCount) { + private static void addKeys(UnifiedJedis node, Set keys, String query, int scanCount) { // construct query ScanParams params = new ScanParams(); params.match(query); diff --git a/src/main/java/build/buildfarm/common/WorkerIndexer.java b/src/main/java/build/buildfarm/common/WorkerIndexer.java index d366bf95cc..0531b63ae6 100644 --- a/src/main/java/build/buildfarm/common/WorkerIndexer.java +++ b/src/main/java/build/buildfarm/common/WorkerIndexer.java @@ -19,10 +19,10 @@ import java.util.Set; import java.util.stream.Collectors; import lombok.extern.java.Log; -import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisCluster; -import redis.clients.jedis.ScanParams; -import redis.clients.jedis.ScanResult; +import redis.clients.jedis.UnifiedJedis; +import redis.clients.jedis.params.ScanParams; +import redis.clients.jedis.resps.ScanResult; /** * @class WorkerIndexer @@ -55,21 +55,26 @@ public class WorkerIndexer { * @note Suggested return identifier: indexResults. */ public static CasIndexResults removeWorkerIndexesFromCas( - JedisCluster cluster, CasIndexSettings settings) { + UnifiedJedis jedis, CasIndexSettings settings) { CasIndexResults results = new CasIndexResults(); - // JedisCluster only supports SCAN commands with MATCH patterns containing hash-tags. - // This prevents us from using the cluster's SCAN to traverse all of the CAS. - // That's why we choose to scan each of the jedisNode's individually. - cluster - .getClusterNodes() - .values() - .forEach( - pool -> { - try (Jedis node = pool.getResource()) { - reindexNode(cluster, node, settings, results); - } - }); + if (jedis instanceof JedisCluster) { + JedisCluster cluster = (JedisCluster) jedis; + // JedisCluster only supports SCAN commands with MATCH patterns containing hash-tags. + // This prevents us from using the cluster's SCAN to traverse all of the CAS. + // That's why we choose to scan each of the jedisNode's individually. + cluster + .getClusterNodes() + .values() + .forEach( + pool -> { + try (UnifiedJedis node = new UnifiedJedis(pool.getResource())) { + reindexNode(cluster, node, settings, results); + } + }); + } else { + reindexNode(jedis, jedis, settings, results); + } return results; } @@ -83,7 +88,7 @@ public static CasIndexResults removeWorkerIndexesFromCas( */ @SuppressWarnings({"unchecked", "rawtypes"}) private static void reindexNode( - JedisCluster cluster, Jedis node, CasIndexSettings settings, CasIndexResults results) { + UnifiedJedis cluster, UnifiedJedis node, CasIndexSettings settings, CasIndexResults results) { Long totalKeys = 0L; Long removedKeys = 0L; Long removedHosts = 0L; @@ -91,7 +96,7 @@ private static void reindexNode( log.info( String.format( "Initializing CAS Indexer for Node %s with %d active workers.", - node.getClient().getHost(), activeWorkers.size())); + node.toString(), activeWorkers.size())); // iterate over all CAS entries via scanning // and remove worker from the CAS keys. @@ -128,7 +133,7 @@ private static void reindexNode( results.totalKeys += totalKeys; results.removedKeys += removedKeys; results.removedHosts += removedHosts; - indexerHostsRemovedGauge.labels(node.getClient().getHost()).set(removedHosts); - indexerKeysRemovedGauge.labels(node.getClient().getHost()).set(removedKeys); + indexerHostsRemovedGauge.labels(node.toString()).set(removedHosts); + indexerKeysRemovedGauge.labels(node.toString()).set(removedKeys); } } diff --git a/src/main/java/build/buildfarm/common/config/BUILD b/src/main/java/build/buildfarm/common/config/BUILD index 843774e2a0..40be76887d 100644 --- a/src/main/java/build/buildfarm/common/config/BUILD +++ b/src/main/java/build/buildfarm/common/config/BUILD @@ -10,7 +10,6 @@ java_library( "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "@googleapis//:google_longrunning_operations_java_proto", "@googleapis//:google_rpc_code_java_proto", - "@jedis//jar", "@maven//:com_github_oshi_oshi_core", "@maven//:com_github_pcj_google_options", "@maven//:com_google_code_findbugs_jsr305", @@ -22,5 +21,6 @@ java_library( "@maven//:org_projectlombok_lombok", "@maven//:org_redisson_redisson", "@maven//:org_yaml_snakeyaml", + "@maven//:redis_clients_jedis", ], ) diff --git a/src/main/java/build/buildfarm/common/redis/BUILD b/src/main/java/build/buildfarm/common/redis/BUILD index 0aee37062a..19b5c77456 100644 --- a/src/main/java/build/buildfarm/common/redis/BUILD +++ b/src/main/java/build/buildfarm/common/redis/BUILD @@ -6,9 +6,9 @@ java_library( "//src/main/java/build/buildfarm/common", "//src/main/java/build/buildfarm/common/config", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "//third_party/jedis", "@maven//:com_google_guava_guava", "@maven//:io_grpc_grpc_api", "@maven//:org_redisson_redisson", + "@maven//:redis_clients_jedis", ], ) diff --git a/src/main/java/build/buildfarm/common/redis/BalancedRedisQueue.java b/src/main/java/build/buildfarm/common/redis/BalancedRedisQueue.java index 044a3b25ce..069e0915b1 100644 --- a/src/main/java/build/buildfarm/common/redis/BalancedRedisQueue.java +++ b/src/main/java/build/buildfarm/common/redis/BalancedRedisQueue.java @@ -17,10 +17,17 @@ import build.buildfarm.common.StringVisitor; import build.buildfarm.common.config.Queue; import build.buildfarm.v1test.QueueStatus; +import com.google.common.collect.ImmutableList; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.concurrent.ExecutorService; +import redis.clients.jedis.Connection; +import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.JedisPooled; +import redis.clients.jedis.UnifiedJedis; +import redis.clients.jedis.util.JedisClusterCRC16; /** * @class BalancedRedisQueue @@ -44,13 +51,6 @@ public class BalancedRedisQueue { */ private final String name; - /** - * @field queueType - * @brief Type of the queue. - * @details It's used for selecting between regular and priority queues - */ - private final Queue.QUEUE_TYPE queueType; - /** * @field originalHashtag * @brief The original hashtag of the name provided to the queue. @@ -76,7 +76,7 @@ public class BalancedRedisQueue { * @details Although these are multiple queues, the balanced redis queue treats them as one in its * interface. */ - private final List queues = new ArrayList<>(); + private final List queues; /** * @field currentPushQueue @@ -140,11 +140,14 @@ public BalancedRedisQueue(String name, List hashtags, int maxQueueSize) */ public BalancedRedisQueue( String name, List hashtags, int maxQueueSize, Queue.QUEUE_TYPE queueType) { + this(name, maxQueueSize, createHashedQueues(name, hashtags, queueType)); + } + + public BalancedRedisQueue(String name, int maxQueueSize, List queues) { this.originalHashtag = RedisHashtags.existingHash(name); this.name = RedisHashtags.unhashedName(name); - this.queueType = queueType; this.maxQueueSize = maxQueueSize; - createHashedQueues(this.name, hashtags, this.queueType); + this.queues = queues; } /** @@ -152,8 +155,11 @@ public BalancedRedisQueue( * @details Adds the value into one of the internal backend redis queues. * @param val The value to push onto the queue. */ - public void push(JedisCluster jedis, String val) { - queues.get(roundRobinPushIndex()).push(jedis, val); + public void push(UnifiedJedis unified, String val) { + QueueInterface queue = queues.get(roundRobinPushIndex()); + try (Jedis jedis = getJedisFromKey(unified, queue.getName())) { + queue.push(jedis, val); + } } /** @@ -161,8 +167,11 @@ public void push(JedisCluster jedis, String val) { * @details Adds the value into one of the internal backend redis queues. * @param val The value to push onto the queue. */ - public void push(JedisCluster jedis, String val, double priority) { - queues.get(roundRobinPushIndex()).push(jedis, val, priority); + public void push(UnifiedJedis unified, String val, double priority) { + QueueInterface queue = queues.get(roundRobinPushIndex()); + try (Jedis jedis = getJedisFromKey(unified, queue.getName())) { + queue.push(jedis, val, priority); + } } /** @@ -172,10 +181,12 @@ public void push(JedisCluster jedis, String val, double priority) { * @return Whether or not the value was removed. * @note Suggested return identifier: wasRemoved. */ - public boolean removeFromDequeue(JedisCluster jedis, String val) { + public boolean removeFromDequeue(UnifiedJedis unified, String val) { for (QueueInterface queue : partialIterationQueueOrder()) { - if (queue.removeFromDequeue(jedis, val)) { - return true; + try (Jedis jedis = getJedisFromKey(unified, queue.getName())) { + if (queue.removeFromDequeue(jedis, val)) { + return true; + } } } return false; @@ -189,7 +200,7 @@ public boolean removeFromDequeue(JedisCluster jedis, String val) { * @return The value of the transfered element. null if the thread was interrupted. * @note Suggested return identifier: val. */ - public String dequeue(JedisCluster jedis) throws InterruptedException { + public String dequeue(UnifiedJedis unified, ExecutorService service) throws InterruptedException { // The conditions of this algorithm are as followed: // - from a client's perspective we want to block indefinitely. // (so this function should not return null under any normal circumstances.) @@ -215,16 +226,23 @@ public String dequeue(JedisCluster jedis) throws InterruptedException { while (true) { final String val; QueueInterface queue = queues.get(roundRobinPopIndex()); - if (blocking) { - val = queue.dequeue(jedis, currentTimeout_s); - } else { - val = queue.nonBlockingDequeue(jedis); + try (Jedis jedis = getJedisFromKey(unified, queue.getName())) { + if (blocking) { + val = queue.dequeue(jedis, currentTimeout_s, service); + } else { + val = queue.nonBlockingDequeue(jedis); + } } // return if found if (val != null) { return val; } + // not quite immediate yet... + if (Thread.currentThread().isInterrupted()) { + throw new InterruptedException(); + } + if (currentPopQueue == startQueue) { // advance timeout if blocking on queue and not at max each queue cycle if (blocking) { @@ -236,15 +254,32 @@ public String dequeue(JedisCluster jedis) throws InterruptedException { } } + private static Jedis getJedisFromKey(UnifiedJedis jedis, String name) { + Connection connection = null; + if (jedis instanceof JedisCluster) { + JedisCluster cluster = (JedisCluster) jedis; + connection = cluster.getConnectionFromSlot(JedisClusterCRC16.getSlot(name)); + } else if (jedis instanceof JedisPooled) { + JedisPooled pooled = (JedisPooled) jedis; + connection = pooled.getPool().getResource(); + } + if (connection == null) { + throw new IllegalArgumentException(jedis.toString()); + } + return new Jedis(connection); + } + /** * @brief Pop element into internal dequeue and return value. * @details Null is returned if the queue is empty. * @return The value of the transfered element. null if queue is empty or thread was interrupted. * @note Suggested return identifier: val. */ - public String nonBlockingDequeue(JedisCluster jedis) throws InterruptedException { + public String nonBlockingDequeue(UnifiedJedis unified) throws InterruptedException { QueueInterface queue = queues.get(roundRobinPopIndex()); - return queue.nonBlockingDequeue(jedis); + try (Jedis jedis = getJedisFromKey(unified, queue.getName())) { + return queue.nonBlockingDequeue(jedis); + } } /** @@ -306,11 +341,13 @@ public String getName() { * @return The current length of the queue. * @note Suggested return identifier: length. */ - public long size(JedisCluster jedis) { + public long size(UnifiedJedis unified) { // the accumulated size of all of the queues long size = 0; for (QueueInterface queue : queues) { - size += queue.size(jedis); + try (Jedis jedis = getJedisFromKey(unified, queue.getName())) { + size += queue.size(jedis); + } } return size; } @@ -321,19 +358,23 @@ public long size(JedisCluster jedis) { * @return The current status of the queue. * @note Suggested return identifier: status. */ - public QueueStatus status(JedisCluster jedis) { + public QueueStatus status(UnifiedJedis unified) { // get properties - long size = size(jedis); - List sizes = new ArrayList<>(); + long size = 0; + ImmutableList.Builder sizes = ImmutableList.builder(); for (QueueInterface queue : queues) { - sizes.add(queue.size(jedis)); + try (Jedis jedis = getJedisFromKey(unified, queue.getName())) { + long queueSize = queue.size(jedis); + sizes.add(queueSize); + size += queueSize; + } } // build proto return QueueStatus.newBuilder() .setName(RedisHashtags.hashedName(name, originalHashtag)) .setSize(size) - .addAllInternalSizes(sizes) + .addAllInternalSizes(sizes.build()) .build(); } @@ -342,9 +383,11 @@ public QueueStatus status(JedisCluster jedis) { * @details Enacts a visitor over each element in the queue. * @param visitor A visitor for each visited element in the queue. */ - public void visit(JedisCluster jedis, StringVisitor visitor) { + public void visit(UnifiedJedis unified, StringVisitor visitor) { for (QueueInterface queue : fullIterationQueueOrder()) { - queue.visit(jedis, visitor); + try (Jedis jedis = getJedisFromKey(unified, queue.getName())) { + queue.visit(jedis, visitor); + } } } @@ -353,9 +396,11 @@ public void visit(JedisCluster jedis, StringVisitor visitor) { * @details Enacts a visitor over each element in the dequeue. * @param visitor A visitor for each visited element in the queue. */ - public void visitDequeue(JedisCluster jedis, StringVisitor visitor) { + public void visitDequeue(UnifiedJedis unified, StringVisitor visitor) { for (QueueInterface queue : fullIterationQueueOrder()) { - queue.visitDequeue(jedis, visitor); + try (Jedis jedis = getJedisFromKey(unified, queue.getName())) { + queue.visitDequeue(jedis, visitor); + } } } @@ -367,11 +412,15 @@ public void visitDequeue(JedisCluster jedis, StringVisitor visitor) { * @return Whether or not the queues values are evenly distributed by internal queues. * @note Suggested return identifier: isEvenlyDistributed. */ - public boolean isEvenlyDistributed(JedisCluster jedis) { - long size = queues.get(0).size(jedis); + public boolean isEvenlyDistributed(UnifiedJedis unified) { + long size = -1; for (QueueInterface queue : partialIterationQueueOrder()) { - if (queue.size(jedis) != size) { - return false; + try (Jedis jedis = getJedisFromKey(unified, queue.getName())) { + long queueSize = queue.size(jedis); + if (size != -1 && queueSize != size) { + return false; + } + size = queueSize; } } return true; @@ -385,7 +434,7 @@ public boolean isEvenlyDistributed(JedisCluster jedis) { * @param jedis Jedis cluster client. * @return Whether are not a new element can be added to the queue based on its current size. */ - public boolean canQueue(JedisCluster jedis) { + public boolean canQueue(UnifiedJedis jedis) { return maxQueueSize < 0 || size(jedis) < maxQueueSize; } @@ -395,12 +444,10 @@ public boolean canQueue(JedisCluster jedis) { * @param name The global name of the queue. * @param hashtags Hashtags to distribute queue data. */ - private void createHashedQueues(String name, List hashtags, Queue.QUEUE_TYPE queueType) { - // create an internal queue for each of the provided hashtags - for (String hashtag : hashtags) { - queues.add( - new RedisQueueFactory().getQueue(queueType, RedisHashtags.hashedName(name, hashtag))); - } + private static List createHashedQueues( + String name, List hashtags, Queue.QUEUE_TYPE queueType) { + String unhashedName = RedisHashtags.unhashedName(name); + ImmutableList.Builder queues = ImmutableList.builder(); // if there were no hashtags, we'll create a single internal queue // so that the balanced redis queue can still function. // we'll use the basename provided to create the single internal queue and use the original @@ -409,15 +456,14 @@ private void createHashedQueues(String name, List hashtags, Queue.QUEUE_ // note: we must build the balanced queues internal queue with a hashtag because it will dequeue // to the same redis slot. if (hashtags.isEmpty()) { - if (!originalHashtag.isEmpty()) { - queues.add( - new RedisQueueFactory() - .getQueue(queueType, RedisHashtags.hashedName(name, originalHashtag))); - } else { - queues.add( - new RedisQueueFactory().getQueue(queueType, RedisHashtags.hashedName(name, "06S"))); - } + String originalHashtag = RedisHashtags.existingHash(name); + hashtags = ImmutableList.of(originalHashtag.isEmpty() ? "06S" : originalHashtag); + } + // create an internal queue for each of the provided hashtags + for (String hashtag : hashtags) { + queues.add(RedisQueues.create(queueType, RedisHashtags.hashedName(unhashedName, hashtag))); } + return queues.build(); } /** diff --git a/src/main/java/build/buildfarm/common/redis/QueueInterface.java b/src/main/java/build/buildfarm/common/redis/QueueInterface.java index b764d5a40a..f87f195f1f 100644 --- a/src/main/java/build/buildfarm/common/redis/QueueInterface.java +++ b/src/main/java/build/buildfarm/common/redis/QueueInterface.java @@ -15,7 +15,8 @@ package build.buildfarm.common.redis; import build.buildfarm.common.StringVisitor; -import redis.clients.jedis.JedisCluster; +import java.util.concurrent.ExecutorService; +import redis.clients.jedis.Jedis; /** * @class QueueInterface @@ -27,14 +28,14 @@ public abstract class QueueInterface { * @details Adds the value into the backend rdered set. * @param val The value to push onto the priority queue. */ - abstract void push(JedisCluster jedis, String val); + abstract void push(Jedis jedis, String val); /** * @brief Push a value onto the queue with defined priority. * @details Adds the value into the backend rdered set. * @param val The value to push onto the priority queue. */ - abstract void push(JedisCluster jedis, String val, double priority); + abstract void push(Jedis jedis, String val, double priority); /** * @brief Remove element from dequeue. @@ -43,7 +44,7 @@ public abstract class QueueInterface { * @return Whether or not the value was removed. * @note Suggested return identifier: wasRemoved. */ - abstract boolean removeFromDequeue(JedisCluster jedis, String val); + abstract boolean removeFromDequeue(Jedis jedis, String val); /** * @brief Remove all elements that match from queue. @@ -52,19 +53,21 @@ public abstract class QueueInterface { * @return Whether or not the value was removed. * @note Suggested return identifier: wasRemoved. */ - abstract boolean removeAll(JedisCluster jedis, String val); + abstract boolean removeAll(Jedis jedis, String val); /** * @brief Pop element into internal dequeue and return value. * @details This pops the element from one queue atomically into an internal list called the * dequeue. It will wait until the timeout has expired. Null is returned if the timeout has - * expired. + * expired. It is up to the caller to maintain the Jedis object and ensure it is valid for the + * queue operations. * @param timeout_s Timeout to wait if there is no item to dequeue. (units: seconds (s)) * @return The value of the transfered element. null if the thread was interrupted. * @note Overloaded. * @note Suggested return identifier: val. */ - abstract String dequeue(JedisCluster jedis, int timeout_s) throws InterruptedException; + abstract String dequeue(Jedis jedis, int timeout_s, ExecutorService service) + throws InterruptedException; /** * @brief Pop element into internal dequeue and return value. @@ -73,7 +76,7 @@ public abstract class QueueInterface { * @return The value of the transfered element. null if nothing was dequeued. * @note Suggested return identifier: val. */ - abstract String nonBlockingDequeue(JedisCluster jedis) throws InterruptedException; + abstract String nonBlockingDequeue(Jedis jedis) throws InterruptedException; /** * @brief Get name. @@ -98,7 +101,7 @@ public abstract class QueueInterface { * @return The current length of the queue. * @note Suggested return identifier: length. */ - abstract long size(JedisCluster jedis); + abstract long size(Jedis jedis); /** * @brief Visit each element in the queue. @@ -106,12 +109,12 @@ public abstract class QueueInterface { * @param visitor A visitor for each visited element in the queue. * @note Overloaded. */ - abstract void visit(JedisCluster jedis, StringVisitor visitor); + abstract void visit(Jedis jedis, StringVisitor visitor); /** * @brief Visit each element in the dequeue. * @details Enacts a visitor over each element in the dequeue. * @param visitor A visitor for each visited element in the queue. */ - abstract void visitDequeue(JedisCluster jedis, StringVisitor visitor); + abstract void visitDequeue(Jedis jedis, StringVisitor visitor); } diff --git a/src/main/java/build/buildfarm/common/redis/RedisClient.java b/src/main/java/build/buildfarm/common/redis/RedisClient.java index 6db7849df3..b5539f8bd5 100644 --- a/src/main/java/build/buildfarm/common/redis/RedisClient.java +++ b/src/main/java/build/buildfarm/common/redis/RedisClient.java @@ -23,24 +23,23 @@ import java.net.SocketTimeoutException; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; -import redis.clients.jedis.JedisCluster; -import redis.clients.jedis.exceptions.JedisClusterMaxAttemptsException; +import redis.clients.jedis.UnifiedJedis; +import redis.clients.jedis.exceptions.JedisClusterOperationException; import redis.clients.jedis.exceptions.JedisConnectionException; import redis.clients.jedis.exceptions.JedisDataException; import redis.clients.jedis.exceptions.JedisException; -import redis.clients.jedis.exceptions.JedisNoReachableClusterNodeException; public class RedisClient implements Closeable { private static final String MISCONF_RESPONSE = "MISCONF"; @FunctionalInterface public interface JedisContext { - T run(JedisCluster jedis) throws JedisException; + T run(UnifiedJedis jedis) throws JedisException; } @FunctionalInterface public interface JedisInterruptibleContext { - T run(JedisCluster jedis) throws InterruptedException, JedisException; + T run(UnifiedJedis jedis) throws InterruptedException, JedisException; } private static class JedisMisconfigurationException extends JedisDataException { @@ -57,11 +56,11 @@ public JedisMisconfigurationException(final String message, final Throwable caus } } - private final JedisCluster jedis; + private final UnifiedJedis jedis; private boolean closed = false; - public RedisClient(JedisCluster jedis) { + public RedisClient(UnifiedJedis jedis) { this.jedis = jedis; } @@ -81,7 +80,7 @@ private synchronized void throwIfClosed() throws IOException { } } - public void run(Consumer withJedis) throws IOException { + public void run(Consumer withJedis) throws IOException { call( (JedisContext) jedis -> { @@ -122,7 +121,7 @@ public T call(JedisContext withJedis) throws IOException { } throw e; } - } catch (JedisMisconfigurationException | JedisNoReachableClusterNodeException e) { + } catch (JedisMisconfigurationException | JedisClusterOperationException e) { // In regards to a Jedis misconfiguration, // the backplane is configured not to accept writes currently // as a result of an error. The error is meant to indicate @@ -154,8 +153,6 @@ public T call(JedisContext withJedis) throws IOException { } } throw new IOException(status.withCause(cause == null ? e : cause).asRuntimeException()); - } catch (JedisClusterMaxAttemptsException e) { - throw new IOException(Status.UNAVAILABLE.withCause(e.getCause()).asRuntimeException()); } } } diff --git a/src/main/java/build/buildfarm/common/redis/RedisHashMap.java b/src/main/java/build/buildfarm/common/redis/RedisHashMap.java index 374a64131a..e43dd385cf 100644 --- a/src/main/java/build/buildfarm/common/redis/RedisHashMap.java +++ b/src/main/java/build/buildfarm/common/redis/RedisHashMap.java @@ -18,8 +18,8 @@ import java.util.List; import java.util.Map; import java.util.Set; -import redis.clients.jedis.JedisCluster; -import redis.clients.jedis.JedisClusterPipeline; +import redis.clients.jedis.PipelineBase; +import redis.clients.jedis.UnifiedJedis; /** * @class RedisHashMap @@ -57,7 +57,7 @@ public RedisHashMap(String name) { * @return Whether a new key was inserted. If a key is overwritten with a new value, this would be * false. */ - public boolean insert(JedisCluster jedis, String key, String value) { + public boolean insert(UnifiedJedis jedis, String key, String value) { return jedis.hset(name, key, value) == 1; } @@ -69,7 +69,7 @@ public boolean insert(JedisCluster jedis, String key, String value) { * @param value The value for the key. * @return Whether a new key was inserted. If a key already exists, this would be false. */ - public boolean insertIfMissing(JedisCluster jedis, String key, String value) { + public boolean insertIfMissing(UnifiedJedis jedis, String key, String value) { return jedis.hsetnx(name, key, value) == 1; } @@ -80,7 +80,7 @@ public boolean insertIfMissing(JedisCluster jedis, String key, String value) { * @param key The name of the key. * @return Whether the key exists or not in the map. */ - public boolean exists(JedisCluster jedis, String key) { + public boolean exists(UnifiedJedis jedis, String key) { return jedis.hexists(name, key); } @@ -91,7 +91,7 @@ public boolean exists(JedisCluster jedis, String key) { * @param key The name of the key. * @return Whether the key was removed. */ - public boolean remove(JedisCluster jedis, String key) { + public boolean remove(UnifiedJedis jedis, String key) { return jedis.hdel(name, key) == 1; } @@ -101,12 +101,12 @@ public boolean remove(JedisCluster jedis, String key) { * @param jedis Jedis cluster client. * @param key The names of the keys. */ - public void remove(JedisCluster jedis, Iterable keys) { - JedisClusterPipeline p = jedis.pipelined(); - for (String key : keys) { - p.hdel(name, key); + public void remove(UnifiedJedis jedis, Iterable keys) { + try (PipelineBase p = jedis.pipelined()) { + for (String key : keys) { + p.hdel(name, key); + } } - p.sync(); } /** @@ -115,7 +115,7 @@ public void remove(JedisCluster jedis, Iterable keys) { * @return The size of the map. * @note Suggested return identifier: size. */ - public long size(JedisCluster jedis) { + public long size(UnifiedJedis jedis) { return jedis.hlen(name); } @@ -125,7 +125,7 @@ public long size(JedisCluster jedis) { * @param jedis Jedis cluster client. * @return The redis hashmap keys represented as a set. */ - public Set keys(JedisCluster jedis) { + public Set keys(UnifiedJedis jedis) { return jedis.hkeys(name); } @@ -135,7 +135,7 @@ public Set keys(JedisCluster jedis) { * @param jedis Jedis cluster client. * @return The redis hashmap represented as a java map. */ - public Map asMap(JedisCluster jedis) { + public Map asMap(UnifiedJedis jedis) { return jedis.hgetAll(name); } @@ -145,7 +145,7 @@ public Map asMap(JedisCluster jedis) { * @param fields The name of the fields. * @return Values associated with the specified fields */ - public List mget(JedisCluster jedis, Iterable fields) { + public List mget(UnifiedJedis jedis, Iterable fields) { return jedis.hmget(name, Iterables.toArray(fields, String.class)); } } diff --git a/src/main/java/build/buildfarm/common/redis/RedisMap.java b/src/main/java/build/buildfarm/common/redis/RedisMap.java index dcc6741246..8fd2e96158 100644 --- a/src/main/java/build/buildfarm/common/redis/RedisMap.java +++ b/src/main/java/build/buildfarm/common/redis/RedisMap.java @@ -20,9 +20,9 @@ import java.util.List; import java.util.Map; import java.util.stream.StreamSupport; -import redis.clients.jedis.JedisCluster; -import redis.clients.jedis.JedisClusterPipeline; +import redis.clients.jedis.PipelineBase; import redis.clients.jedis.Response; +import redis.clients.jedis.UnifiedJedis; /** * @class RedisMap @@ -78,7 +78,7 @@ public RedisMap(String name, int timeout_s) { * @param timeout_s Timeout to expire the entry. (units: seconds (s)) * @note Overloaded. */ - public void insert(JedisCluster jedis, String key, String value, int timeout_s) { + public void insert(UnifiedJedis jedis, String key, String value, int timeout_s) { jedis.setex(createKeyName(key), timeout_s, value); } @@ -91,7 +91,7 @@ public void insert(JedisCluster jedis, String key, String value, int timeout_s) * @param timeout_s Timeout to expire the entry. (units: seconds (s)) * @note Overloaded. */ - public void insert(JedisCluster jedis, String key, String value, long timeout_s) { + public void insert(UnifiedJedis jedis, String key, String value, long timeout_s) { // Jedis only provides int precision. this is fine as the units are seconds. // We supply an interface for longs as a convenience to callers. jedis.setex(createKeyName(key), (int) timeout_s, value); @@ -105,7 +105,7 @@ public void insert(JedisCluster jedis, String key, String value, long timeout_s) * @param value The value for the key. * @note Overloaded. */ - public void insert(JedisCluster jedis, String key, String value) { + public void insert(UnifiedJedis jedis, String key, String value) { // Jedis only provides int precision. this is fine as the units are seconds. // We supply an interface for longs as a convenience to callers. jedis.setex(createKeyName(key), expiration_s, value); @@ -118,7 +118,7 @@ public void insert(JedisCluster jedis, String key, String value) { * @param key The name of the key. * @note Overloaded. */ - public void remove(JedisCluster jedis, String key) { + public void remove(UnifiedJedis jedis, String key) { jedis.del(createKeyName(key)); } @@ -129,12 +129,12 @@ public void remove(JedisCluster jedis, String key) { * @param keys The name of the keys. * @note Overloaded. */ - public void remove(JedisCluster jedis, Iterable keys) { - JedisClusterPipeline p = jedis.pipelined(); - for (String key : keys) { - p.del(createKeyName(key)); + public void remove(UnifiedJedis jedis, Iterable keys) { + try (PipelineBase p = jedis.pipelined()) { + for (String key : keys) { + p.del(createKeyName(key)); + } } - p.sync(); } /** @@ -146,7 +146,7 @@ public void remove(JedisCluster jedis, Iterable keys) { * @note Overloaded. * @note Suggested return identifier: value. */ - public String get(JedisCluster jedis, String key) { + public String get(UnifiedJedis jedis, String key) { return jedis.get(createKeyName(key)); } @@ -159,19 +159,21 @@ public String get(JedisCluster jedis, String key) { * @note Overloaded. * @note Suggested return identifier: values. */ - public Iterable> get(JedisCluster jedis, Iterable keys) { + public Iterable> get(UnifiedJedis jedis, Iterable keys) { // Fetch items via pipeline - JedisClusterPipeline p = jedis.pipelined(); - List>> values = new ArrayList<>(); - StreamSupport.stream(keys.spliterator(), false) - .forEach(key -> values.add(new AbstractMap.SimpleEntry<>(key, p.get(createKeyName(key))))); - p.sync(); - - List> resolved = new ArrayList<>(); - for (Map.Entry> val : values) { - resolved.add(new AbstractMap.SimpleEntry<>(val.getKey(), val.getValue().get())); + try (PipelineBase p = jedis.pipelined()) { + List>> values = new ArrayList<>(); + StreamSupport.stream(keys.spliterator(), false) + .forEach( + key -> values.add(new AbstractMap.SimpleEntry<>(key, p.get(createKeyName(key))))); + p.sync(); + + List> resolved = new ArrayList<>(); + for (Map.Entry> val : values) { + resolved.add(new AbstractMap.SimpleEntry<>(val.getKey(), val.getValue().get())); + } + return resolved; } - return resolved; } /** @@ -182,7 +184,7 @@ public Iterable> get(JedisCluster jedis, Iterable>> SINGLETON_NODE_SLOT_RANGES = + ImmutableList.of(ImmutableList.of(ImmutableList.of(0l, CLUSTER_HASHSLOTS - 1l))); + /** * @brief Get a list of evenly distributing hashtags for the provided redis cluster. * @details Each hashtag will map to a slot on a different node. @@ -41,19 +46,22 @@ public class RedisNodeHashes { * @return Hashtags that will each has to a slot on a different node. * @note Suggested return identifier: hashtags. */ - @SuppressWarnings({"unchecked", "rawtypes"}) - public static List getEvenlyDistributedHashes(JedisCluster jedis) { - try { - List> slotRanges = getNodeSlotRanges(jedis); - ImmutableList.Builder hashTags = ImmutableList.builder(); - for (List slotRange : slotRanges) { - // we can use any slot that is in range for the node. - // in this case, we will use the first slot. - hashTags.add(RedisSlotToHash.correlate(slotRange.get(0))); + public static List getEvenlyDistributedHashes(UnifiedJedis jedis) { + if (jedis instanceof JedisCluster) { + try { + Iterable>> nodeSlotRanges = getNodeSlotRanges(jedis); + ImmutableList.Builder hashTags = ImmutableList.builder(); + for (List> slotRanges : nodeSlotRanges) { + // we can use any slot that is in range for the node. + // in this case, we will use the first slot in the first range. + hashTags.add(RedisSlotToHash.correlate(slotRanges.get(0).get(0))); + } + return hashTags.build(); + } catch (JedisException e) { + return ImmutableList.of(); } - return hashTags.build(); - } catch (JedisException e) { - return ImmutableList.of(); + } else { + return ImmutableList.of(""); } } @@ -65,21 +73,24 @@ public static List getEvenlyDistributedHashes(JedisCluster jedis) { * @return Hashtags that will each has to a slot on a different node. * @note Suggested return identifier: hashtags. */ - @SuppressWarnings({"unchecked", "rawtypes"}) public static List getEvenlyDistributedHashesWithPrefix( - JedisCluster jedis, String prefix) { - try { - List> slotRanges = getNodeSlotRanges(jedis); - ImmutableList.Builder hashTags = ImmutableList.builder(); - for (List slotRange : slotRanges) { - // we can use any slot that is in range for the node. - // in this case, we will use the first slot. - hashTags.add( - RedisSlotToHash.correlateRangeWithPrefix(slotRange.get(0), slotRange.get(1), prefix)); + UnifiedJedis jedis, String prefix) { + if (jedis instanceof JedisCluster) { + JedisCluster cluster = (JedisCluster) jedis; + Iterable>> nodeSlotRanges = getNodeSlotRanges(cluster); + try { + ImmutableList.Builder hashTags = ImmutableList.builder(); + for (List> slotRanges : nodeSlotRanges) { + // we can use any slot that is in range for the node. + // in this case, we will use the first slot. + hashTags.add(RedisSlotToHash.correlateRangesWithPrefix(slotRanges, prefix)); + } + return hashTags.build(); + } catch (JedisException e) { + return ImmutableList.of(); } - return hashTags.build(); - } catch (JedisException e) { - return ImmutableList.of(); + } else { + return ImmutableList.of(prefix); } } @@ -88,54 +99,30 @@ public static List getEvenlyDistributedHashesWithPrefix( * @details This information can be found from any of the redis nodes in the cluster. * @param jedis An established jedis client. * @return Slot ranges for all of the nodes in the cluster. - * @note Suggested return identifier: slotRanges. + * @note Suggested return identifier: nodeSlotRanges. */ - @SuppressWarnings("unchecked") - private static List> getNodeSlotRanges(JedisCluster jedis) { - // get slot information for each node - List slots = getClusterSlots(jedis); - Set nodes = new HashSet<>(); - - // convert slot information into a list of slot ranges - ImmutableList.Builder> slotRanges = ImmutableList.builder(); - for (Object slotInfoObj : slots) { - List slotInfo = (List) slotInfoObj; - List slotRangeNodes = (List) slotInfo.get(2); - // 2 is primary node id - String nodeId = (String) SafeEncoder.encode((byte[]) slotRangeNodes.get(2)); - if (nodes.add(nodeId)) { - List slotNums = slotInfoToSlotRange(slotInfo); - slotRanges.add(slotNums); - } + private static Iterable>> getNodeSlotRanges(UnifiedJedis jedis) { + if (jedis instanceof JedisCluster) { + // get slot range information for each shard + return transform(getClusterShards((JedisCluster) jedis), ClusterShardInfo::getSlots); + } else { + return SINGLETON_NODE_SLOT_RANGES; } - - return slotRanges.build(); - } - - /** - * @brief Convert a jedis slotInfo object to a range or slot numbers. - * @details Every redis node has a range of slots represented as integers. - * @param slotInfo Slot info objects from a redis node. - * @return The slot number range for the particular redis node. - * @note Suggested return identifier: slotRange. - */ - private static List slotInfoToSlotRange(List slotInfo) { - return ImmutableList.of((Long) slotInfo.get(0), (Long) slotInfo.get(1)); } /** - * @brief Query slot information for each redis node. + * @brief Query shard information from any redis node. * @details Obtains cluster information for understanding slot ranges for balancing. * @param jedis An established jedis client. * @return Cluster slot information. - * @note Suggested return identifier: clusterSlots. + * @note Suggested return identifier: clusterShards. */ - private static List getClusterSlots(JedisCluster jedis) { + private static List getClusterShards(JedisCluster jedis) { JedisException nodeException = null; - for (Map.Entry node : jedis.getClusterNodes().entrySet()) { - JedisPool pool = node.getValue(); - try (Jedis resource = pool.getResource()) { - return resource.clusterSlots(); + for (Map.Entry node : jedis.getClusterNodes().entrySet()) { + ConnectionPool pool = node.getValue(); + try (Jedis resource = new Jedis(pool.getResource())) { + return resource.clusterShards(); } catch (JedisException e) { nodeException = e; // log error with node @@ -144,6 +131,6 @@ private static List getClusterSlots(JedisCluster jedis) { if (nodeException != null) { throw nodeException; } - throw new JedisNoReachableClusterNodeException("No reachable node in cluster"); + throw new JedisClusterOperationException("No reachable node in cluster"); } } diff --git a/src/main/java/build/buildfarm/common/redis/RedisPriorityQueue.java b/src/main/java/build/buildfarm/common/redis/RedisPriorityQueue.java index 82ef45adbd..6346f87b98 100644 --- a/src/main/java/build/buildfarm/common/redis/RedisPriorityQueue.java +++ b/src/main/java/build/buildfarm/common/redis/RedisPriorityQueue.java @@ -17,12 +17,12 @@ import build.buildfarm.common.StringVisitor; import java.util.Arrays; import java.util.List; -import java.util.Set; -import redis.clients.jedis.JedisCluster; +import java.util.concurrent.ExecutorService; +import redis.clients.jedis.Jedis; /** - * @class RedisQueue - * @brief A redis queue. + * @class RedisPriorityQueue + * @brief A redis priority queue. * @details A redis queue is an implementation of a queue data structure which internally uses redis * to store and distribute the data. Its important to know that the lifetime of the queue * persists before and after the queue data structure is created (since it exists in redis). @@ -97,18 +97,19 @@ public RedisPriorityQueue(String name, Timestamp time, long pollIntervalMillis) * @param val The value to push onto the priority queue. */ @Override - public void push(JedisCluster jedis, String val) { + public void push(Jedis jedis, String val) { push(jedis, val, 0); } /** * @brief Push a value onto the queue with specified priority. - * @details Adds the value into the backend redis ordered set. + * @details Adds the value into the backend redis ordered set, with timestamp primary insertion to + * guarantee FIFO within a single priority level * @param val The value to push onto the priority queue. * @param priority The priority of action 0 means highest */ @Override - public void push(JedisCluster jedis, String val, double priority) { + public void push(Jedis jedis, String val, double priority) { jedis.zadd(name, priority, time.getNanos() + ":" + val); } @@ -120,7 +121,7 @@ public void push(JedisCluster jedis, String val, double priority) { * @note Suggested return identifier: wasRemoved. */ @Override - public boolean removeFromDequeue(JedisCluster jedis, String val) { + public boolean removeFromDequeue(Jedis jedis, String val) { return jedis.lrem(getDequeueName(), -1, val) != 0; } @@ -132,7 +133,7 @@ public boolean removeFromDequeue(JedisCluster jedis, String val) { * @note Suggested return identifier: wasRemoved. */ @Override - public boolean removeAll(JedisCluster jedis, String val) { + public boolean removeAll(Jedis jedis, String val) { return jedis.zrem(name, val) != 0; } @@ -147,7 +148,8 @@ public boolean removeAll(JedisCluster jedis, String val) { * @note Suggested return identifier: val. */ @Override - public String dequeue(JedisCluster jedis, int timeout_s) throws InterruptedException { + public String dequeue(Jedis jedis, int timeout_s, ExecutorService service) + throws InterruptedException { int maxAttempts = (int) (timeout_s / (pollIntervalMillis / 1000.0)); List args = Arrays.asList(name, getDequeueName(), "true"); String val; @@ -170,7 +172,7 @@ public String dequeue(JedisCluster jedis, int timeout_s) throws InterruptedExcep * @note Suggested return identifier: val. */ @Override - public String nonBlockingDequeue(JedisCluster jedis) throws InterruptedException { + public String nonBlockingDequeue(Jedis jedis) throws InterruptedException { List args = Arrays.asList(name, getDequeueName()); Object obj_val = jedis.eval(script, keys, args); String val = String.valueOf(obj_val); @@ -212,7 +214,7 @@ public String getDequeueName() { * @note Suggested return identifier: length. */ @Override - public long size(JedisCluster jedis) { + public long size(Jedis jedis) { return jedis.zcard(name); } @@ -223,7 +225,7 @@ public long size(JedisCluster jedis) { * @note Overloaded. */ @Override - public void visit(JedisCluster jedis, StringVisitor visitor) { + public void visit(Jedis jedis, StringVisitor visitor) { visit(jedis, name, visitor); } @@ -233,7 +235,7 @@ public void visit(JedisCluster jedis, StringVisitor visitor) { * @param visitor A visitor for each visited element in the queue. */ @Override - public void visitDequeue(JedisCluster jedis, StringVisitor visitor) { + public void visitDequeue(Jedis jedis, StringVisitor visitor) { int listPageSize = 10000; int index = 0; int nextIndex = listPageSize; @@ -256,11 +258,11 @@ public void visitDequeue(JedisCluster jedis, StringVisitor visitor) { * @param visitor A visitor for each visited element in the queue. * @note Overloaded. */ - private void visit(JedisCluster jedis, String queueName, StringVisitor visitor) { + private void visit(Jedis jedis, String queueName, StringVisitor visitor) { int listPageSize = 10000; int index = 0; int nextIndex = listPageSize; - Set entries; + List entries; do { entries = jedis.zrange(queueName, index, nextIndex - 1); @@ -290,14 +292,14 @@ private String getLuaScript() { "end", "assert(not isempty(zset), 'ERR1: zset missing')", "assert(not isempty(deqName), 'ERR2: dequeue missing')", - " local pped = redis.call('ZRANGE', zset, 0, 0)", - " if next(pped) ~= nil then", - " for _,item in ipairs(pped) do", - " val = item:gsub('^%d*:', '')", - " redis.call('ZREM', zset, item)", - " redis.call('LPUSH', deqName, val)", - " end", + "local pped = redis.call('ZRANGE', zset, 0, 0)", + "if next(pped) ~= nil then", + " for _,item in ipairs(pped) do", + " val = item.sub('^%d*:', '')", + " redis.call('ZREM', zset, item)", + " redis.call('LPUSH', deqName, val)", " end", + "end", "return val"); } diff --git a/src/main/java/build/buildfarm/common/redis/RedisQueue.java b/src/main/java/build/buildfarm/common/redis/RedisQueue.java index 834a7c06c7..c3871adb90 100644 --- a/src/main/java/build/buildfarm/common/redis/RedisQueue.java +++ b/src/main/java/build/buildfarm/common/redis/RedisQueue.java @@ -14,9 +14,16 @@ package build.buildfarm.common.redis; +import static redis.clients.jedis.args.ListDirection.LEFT; +import static redis.clients.jedis.args.ListDirection.RIGHT; + import build.buildfarm.common.StringVisitor; import java.util.List; -import redis.clients.jedis.JedisCluster; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import redis.clients.jedis.Jedis; /** * @class RedisQueue @@ -44,7 +51,7 @@ public class RedisQueue extends QueueInterface { public RedisQueue(String name) { // In order for dequeue properly, the queue needs to have a hashtag. Otherwise it will error // with: "No way to dispatch this command to Redis Cluster because keys have different slots." - // when trying to brpoplpush. If no hashtag was given we provide a default. + // when trying to blmove. If no hashtag was given we provide a default. this.name = name; } @@ -53,7 +60,7 @@ public RedisQueue(String name) { * @details Adds the value into the backend redis queue. * @param val The value to push onto the queue. */ - public void push(JedisCluster jedis, String val) { + public void push(Jedis jedis, String val) { push(jedis, val, 1); } @@ -62,7 +69,7 @@ public void push(JedisCluster jedis, String val) { * @details Adds the value into the backend redis queue. * @param val The value to push onto the queue. */ - public void push(JedisCluster jedis, String val, double priority) { + public void push(Jedis jedis, String val, double priority) { jedis.lpush(name, val); } @@ -73,7 +80,7 @@ public void push(JedisCluster jedis, String val, double priority) { * @return Whether the value was removed. * @note Suggested return identifier: wasRemoved. */ - public boolean removeFromDequeue(JedisCluster jedis, String val) { + public boolean removeFromDequeue(Jedis jedis, String val) { return jedis.lrem(getDequeueName(), -1, val) != 0; } @@ -84,7 +91,7 @@ public boolean removeFromDequeue(JedisCluster jedis, String val) { * @return Whether the value was removed. * @note Suggested return identifier: wasRemoved. */ - public boolean removeAll(JedisCluster jedis, String val) { + public boolean removeAll(Jedis jedis, String val) { return jedis.lrem(name, 0, val) != 0; } @@ -98,14 +105,41 @@ public boolean removeAll(JedisCluster jedis, String val) { * @note Overloaded. * @note Suggested return identifier: val. */ - public String dequeue(JedisCluster jedis, int timeout_s) throws InterruptedException { - for (int i = 0; i < timeout_s; ++i) { - String val = jedis.brpoplpush(name, getDequeueName(), 1); - if (val != null) { - return val; + public String dequeue(Jedis jedis, int timeout_s, ExecutorService service) + throws InterruptedException { + return interruptibleRequest( + () -> jedis.blmove(name, getDequeueName(), RIGHT, LEFT, timeout_s), + jedis::disconnect, + service); + } + + private T interruptibleRequest( + Callable command, Runnable onInterrupted, ExecutorService service) + throws InterruptedException { + Future reply = service.submit(command); + return getBlockingReply(reply, onInterrupted); + } + + private T getBlockingReply(Future reply, Runnable onInterrupted) + throws InterruptedException { + InterruptedException interruption = null; + for (; ; ) { + try { + return reply.get(); + } catch (ExecutionException e) { + Throwable cause = e.getCause(); + if (interruption != null) { + interruption.addSuppressed(cause); + Thread.currentThread().interrupt(); + throw interruption; + } + throw new RuntimeException(cause); + } catch (InterruptedException e) { + interruption = e; + Thread.interrupted(); + onInterrupted.run(); } } - return null; } /** @@ -115,8 +149,8 @@ public String dequeue(JedisCluster jedis, int timeout_s) throws InterruptedExcep * @return The value of the transfered element. null if nothing was dequeued. * @note Suggested return identifier: val. */ - public String nonBlockingDequeue(JedisCluster jedis) throws InterruptedException { - String val = jedis.rpoplpush(name, getDequeueName()); + public String nonBlockingDequeue(Jedis jedis) throws InterruptedException { + String val = jedis.lmove(name, getDequeueName(), RIGHT, LEFT); if (val != null) { return val; } @@ -153,7 +187,7 @@ public String getDequeueName() { * @return The current length of the queue. * @note Suggested return identifier: length. */ - public long size(JedisCluster jedis) { + public long size(Jedis jedis) { return jedis.llen(name); } @@ -163,7 +197,7 @@ public long size(JedisCluster jedis) { * @param visitor A visitor for each visited element in the queue. * @note Overloaded. */ - public void visit(JedisCluster jedis, StringVisitor visitor) { + public void visit(Jedis jedis, StringVisitor visitor) { visit(jedis, name, visitor); } @@ -172,7 +206,7 @@ public void visit(JedisCluster jedis, StringVisitor visitor) { * @details Enacts a visitor over each element in the dequeue. * @param visitor A visitor for each visited element in the queue. */ - public void visitDequeue(JedisCluster jedis, StringVisitor visitor) { + public void visitDequeue(Jedis jedis, StringVisitor visitor) { visit(jedis, getDequeueName(), visitor); } @@ -183,7 +217,7 @@ public void visitDequeue(JedisCluster jedis, StringVisitor visitor) { * @param visitor A visitor for each visited element in the queue. * @note Overloaded. */ - private void visit(JedisCluster jedis, String queueName, StringVisitor visitor) { + private void visit(Jedis jedis, String queueName, StringVisitor visitor) { int listPageSize = 10000; int index = 0; diff --git a/src/main/java/build/buildfarm/common/redis/RedisQueueFactory.java b/src/main/java/build/buildfarm/common/redis/RedisQueues.java similarity index 69% rename from src/main/java/build/buildfarm/common/redis/RedisQueueFactory.java rename to src/main/java/build/buildfarm/common/redis/RedisQueues.java index 4b569f0d3c..52679f523e 100644 --- a/src/main/java/build/buildfarm/common/redis/RedisQueueFactory.java +++ b/src/main/java/build/buildfarm/common/redis/RedisQueues.java @@ -15,24 +15,24 @@ package build.buildfarm.common.redis; import build.buildfarm.common.config.BuildfarmConfigs; -import build.buildfarm.common.config.Queue; +import build.buildfarm.common.config.Queue.QUEUE_TYPE; /** - * @class RedisQueueFactory - * @brief A redis queue factory. + * @class RedisQueues + * @brief Managed redis queue creation. */ -public class RedisQueueFactory { +public final class RedisQueues { private static BuildfarmConfigs configs = BuildfarmConfigs.getInstance(); - public QueueInterface getQueue(Queue.QUEUE_TYPE queueType, String name) { - if (queueType == null) { - return null; - } - if (queueType.equals(Queue.QUEUE_TYPE.standard)) { + private RedisQueues() {} + + public static QueueInterface create(QUEUE_TYPE queueType, String name) { + if (queueType == QUEUE_TYPE.standard) { return new RedisQueue(name); - } else if (queueType.equals(Queue.QUEUE_TYPE.priority)) { + } + if (queueType == QUEUE_TYPE.priority) { return new RedisPriorityQueue(name, configs.getBackplane().getPriorityPollIntervalMillis()); } - return null; + throw new IllegalArgumentException("Unknown queueType " + queueType); } } diff --git a/src/main/java/build/buildfarm/common/redis/RedisSlotToHash.java b/src/main/java/build/buildfarm/common/redis/RedisSlotToHash.java index e54d7629e2..d4a66a0082 100644 --- a/src/main/java/build/buildfarm/common/redis/RedisSlotToHash.java +++ b/src/main/java/build/buildfarm/common/redis/RedisSlotToHash.java @@ -14,7 +14,11 @@ package build.buildfarm.common.redis; -import static redis.clients.jedis.JedisCluster.HASHSLOTS; +import static com.google.common.collect.Iterables.all; +import static com.google.common.collect.Iterables.any; +import static com.google.common.collect.Iterables.transform; +import static com.google.common.collect.Ordering.natural; +import static redis.clients.jedis.Protocol.CLUSTER_HASHSLOTS; import com.google.common.base.Preconditions; import java.util.ArrayList; @@ -43,7 +47,7 @@ public class RedisSlotToHash { * @note Suggested return identifier: hashtag. */ public static String correlate(long slotNumber) { - Preconditions.checkState(slotNumber >= 0 && slotNumber < HASHSLOTS); + Preconditions.checkState(slotNumber >= 0 && slotNumber < CLUSTER_HASHSLOTS); return staticLookup(slotNumber); } @@ -58,7 +62,7 @@ public static String correlate(long slotNumber) { * @note Suggested return identifier: hashtag. */ public static String correlateRange(long start, long end) { - Preconditions.checkState(start >= 0 && end < HASHSLOTS); + Preconditions.checkState(start >= 0 && end < CLUSTER_HASHSLOTS); long hashNumber = 0; int slotNumber = JedisClusterCRC16.getSlot(Long.toString(hashNumber)); @@ -74,24 +78,31 @@ public static String correlateRange(long start, long end) { * range. * @details Dynamically generates hashtags and tests them for valid slot number. Slower than * static lookup, but less code. - * @param start The starting slot range number to find a hashable string for. - * @param end The ending slot range number to find a hashable string for. + * @param slotRanges The valid range of slots. * @param prefix A string prefix to include as part of the generated hashtag. * @return The string value to be used in a key's hashtag. * @note Suggested return identifier: hashtag. */ - public static String correlateRangeWithPrefix(long start, long end, String prefix) { - Preconditions.checkState(start >= 0 && end < HASHSLOTS); + public static String correlateRangesWithPrefix(Iterable> slotRanges, String prefix) { + Preconditions.checkState( + all(slotRanges, slotRange -> slotRange.size() == 2) + && natural().min(transform(slotRanges, slotRange -> slotRange.get(0))) >= 0 + && natural().max(transform(slotRanges, slotRange -> slotRange.get(1))) + < CLUSTER_HASHSLOTS); long hashNumber = 0; - int slotNumber = JedisClusterCRC16.getSlot(createHashtag(prefix, hashNumber)); - while (slotNumber < start || slotNumber > end) { + int slot = JedisClusterCRC16.getSlot(createHashtag(prefix, hashNumber)); + while (!slotRangesContainsSlot(slotRanges, slot)) { hashNumber++; - slotNumber = JedisClusterCRC16.getSlot(createHashtag(prefix, hashNumber)); + slot = JedisClusterCRC16.getSlot(createHashtag(prefix, hashNumber)); } return createHashtag(prefix, hashNumber); } + private static boolean slotRangesContainsSlot(Iterable> slotRanges, int slot) { + return any(slotRanges, range -> slot >= range.get(0) && slot <= range.get(1)); + } + /** * @brief Create hashtag. * @details Combine prefix with a generated number. diff --git a/src/main/java/build/buildfarm/common/resources/BUILD b/src/main/java/build/buildfarm/common/resources/BUILD index 7fce137e12..7f03c6def5 100644 --- a/src/main/java/build/buildfarm/common/resources/BUILD +++ b/src/main/java/build/buildfarm/common/resources/BUILD @@ -30,7 +30,6 @@ java_library( deps = [ "//src/main/java/build/buildfarm/common/resources:resource_java_proto", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "//third_party/jedis", "@googleapis//:google_longrunning_operations_java_proto", "@googleapis//:google_rpc_code_java_proto", "@googleapis//:google_rpc_error_details_java_proto", @@ -49,6 +48,7 @@ java_library( "@maven//:org_apache_commons_commons_compress", "@maven//:org_apache_commons_commons_lang3", "@maven//:org_threeten_threetenbp", + "@maven//:redis_clients_jedis", "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/instance/shard/BUILD b/src/main/java/build/buildfarm/instance/shard/BUILD index 9512f7fd70..03bf0d45dc 100644 --- a/src/main/java/build/buildfarm/instance/shard/BUILD +++ b/src/main/java/build/buildfarm/instance/shard/BUILD @@ -18,7 +18,6 @@ java_library( "//src/main/java/build/buildfarm/operations", "//src/main/java/build/buildfarm/operations/finder", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "//third_party/jedis", "@googleapis//:google_rpc_code_java_proto", "@googleapis//:google_rpc_error_details_java_proto", "@maven//:com_github_ben_manes_caffeine_caffeine", @@ -36,6 +35,7 @@ java_library( "@maven//:org_apache_commons_commons_pool2", "@maven//:org_projectlombok_lombok", "@maven//:org_redisson_redisson", + "@maven//:redis_clients_jedis", "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/instance/shard/JedisCasWorkerMap.java b/src/main/java/build/buildfarm/instance/shard/JedisCasWorkerMap.java index 65d1f06b87..ec379b898b 100644 --- a/src/main/java/build/buildfarm/instance/shard/JedisCasWorkerMap.java +++ b/src/main/java/build/buildfarm/instance/shard/JedisCasWorkerMap.java @@ -23,7 +23,7 @@ import java.time.Instant; import java.util.Map; import java.util.Set; -import redis.clients.jedis.JedisClusterPipeline; +import redis.clients.jedis.PipelineBase; /** * @class JedisCasWorkerMap @@ -117,13 +117,13 @@ public void addAll(RedisClient client, Iterable blobDigests, String work throws IOException { client.run( jedis -> { - JedisClusterPipeline p = jedis.pipelined(); - for (Digest blobDigest : blobDigests) { - String key = redisCasKey(blobDigest); - p.sadd(key, workerName); - p.expire(key, keyExpiration_s); + try (PipelineBase p = jedis.pipelined()) { + for (Digest blobDigest : blobDigests) { + String key = redisCasKey(blobDigest); + p.sadd(key, workerName); + p.expire(key, keyExpiration_s); + } } - p.sync(); }); } @@ -153,12 +153,12 @@ public void removeAll(RedisClient client, Iterable blobDigests, String w throws IOException { client.run( jedis -> { - JedisClusterPipeline p = jedis.pipelined(); - for (Digest blobDigest : blobDigests) { - String key = redisCasKey(blobDigest); - p.srem(key, workerName); + try (PipelineBase p = jedis.pipelined()) { + for (Digest blobDigest : blobDigests) { + String key = redisCasKey(blobDigest); + p.srem(key, workerName); + } } - p.sync(); }); } diff --git a/src/main/java/build/buildfarm/instance/shard/JedisClusterFactory.java b/src/main/java/build/buildfarm/instance/shard/JedisClusterFactory.java index 693f1193e2..14609ea129 100644 --- a/src/main/java/build/buildfarm/instance/shard/JedisClusterFactory.java +++ b/src/main/java/build/buildfarm/instance/shard/JedisClusterFactory.java @@ -16,6 +16,8 @@ import build.buildfarm.common.config.BuildfarmConfigs; import com.google.common.base.Strings; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; import java.net.URI; import java.net.URISyntaxException; import java.util.HashSet; @@ -23,13 +25,16 @@ import java.util.Set; import java.util.function.Supplier; import javax.naming.ConfigurationException; +import redis.clients.jedis.ConnectionPool; +import redis.clients.jedis.ConnectionPoolConfig; +import redis.clients.jedis.DefaultJedisClientConfig; import redis.clients.jedis.HostAndPort; -import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisCluster; -import redis.clients.jedis.JedisPool; -import redis.clients.jedis.JedisPoolConfig; -import redis.clients.jedis.ScanParams; -import redis.clients.jedis.ScanResult; +import redis.clients.jedis.JedisPooled; +import redis.clients.jedis.UnifiedJedis; +import redis.clients.jedis.exceptions.JedisClusterOperationException; +import redis.clients.jedis.params.ScanParams; +import redis.clients.jedis.resps.ScanResult; import redis.clients.jedis.util.JedisURIHelper; /** @@ -49,7 +54,7 @@ public class JedisClusterFactory { * @note Suggested return identifier: jedis. * @link Redis Client name */ - public static Supplier create(String identifier) throws ConfigurationException { + public static Supplier create(String identifier) throws ConfigurationException { // null password is required to elicit no auth in jedis String[] redisNodes = configs.getBackplane().getRedisNodes(); if (redisNodes != null && redisNodes.length > 0) { @@ -59,7 +64,7 @@ public static Supplier create(String identifier) throws Configurat configs.getBackplane().getTimeout(), configs.getBackplane().getMaxAttempts(), Strings.emptyToNull(configs.getBackplane().getRedisPassword()), - createJedisPoolConfig()); + createConnectionPoolConfig()); } // support "" as redis password. @@ -69,7 +74,7 @@ public static Supplier create(String identifier) throws Configurat configs.getBackplane().getTimeout(), configs.getBackplane().getMaxAttempts(), Strings.emptyToNull(configs.getBackplane().getRedisPassword()), - createJedisPoolConfig()); + createConnectionPoolConfig()); } /** @@ -79,8 +84,8 @@ public static Supplier create(String identifier) throws Configurat * @return An established test jedis client used to operate on a redis cluster. * @note Suggested return identifier: jedis. */ - public static JedisCluster createTest() throws Exception { - JedisCluster redis = JedisClusterFactory.create("test").get(); + public static UnifiedJedis createTest() throws Exception { + UnifiedJedis redis = JedisClusterFactory.create("test").get(); // use the client to create an empty redis cluster // this will prevent any persistent data across test runs @@ -96,10 +101,15 @@ public static JedisCluster createTest() throws Exception { * @param cluster An established jedis client to operate on a redis cluster. * @note Overloaded. */ - private static void deleteExistingKeys(JedisCluster cluster) throws Exception { - for (JedisPool pool : cluster.getClusterNodes().values()) { - Jedis node = pool.getResource(); - deleteExistingKeys(node); + private static void deleteExistingKeys(UnifiedJedis jedis) throws Exception { + if (jedis instanceof JedisCluster) { + JedisCluster cluster = (JedisCluster) jedis; + for (ConnectionPool pool : cluster.getClusterNodes().values()) { + UnifiedJedis node = new UnifiedJedis(pool.getResource()); + deleteNodeExistingKeys(node); + } + } else { + deleteNodeExistingKeys(jedis); } } @@ -111,7 +121,7 @@ private static void deleteExistingKeys(JedisCluster cluster) throws Exception { * @note Overloaded. */ @SuppressWarnings({"unchecked", "rawtypes"}) - private static void deleteExistingKeys(Jedis node) { + private static void deleteNodeExistingKeys(UnifiedJedis node) { String nextCursor = "0"; Set matchingKeys = new HashSet<>(); ScanParams params = new ScanParams(); @@ -139,6 +149,40 @@ private static void deleteExistingKeys(Jedis node) { } } + private static UnifiedJedis createJedis( + Set hostAndPorts, + int connectionTimeout, + int soTimeout, + int maxAttempts, + String password, + String identifier, + ConnectionPoolConfig poolConfig, + boolean ssl) { + try { + return new JedisCluster( + hostAndPorts, + connectionTimeout, + soTimeout, + maxAttempts, + password, + identifier, + poolConfig, + ssl); + } catch (JedisClusterOperationException e) { + // probably not a cluster + return new JedisPooled( + poolConfig, + Iterables.getOnlyElement(hostAndPorts), + DefaultJedisClientConfig.builder() + .connectionTimeoutMillis(connectionTimeout) + .socketTimeoutMillis(soTimeout) + .password(password) + .clientName(identifier) + .ssl(ssl) + .build()); + } + } + /** * @brief Create a jedis cluster instance with connection settings. * @details Use the URI, pool and connection information to connect to a redis cluster server and @@ -150,16 +194,16 @@ private static void deleteExistingKeys(Jedis node) { * @return An established jedis client used to operate on the redis cluster. * @note Suggested return identifier: jedis. */ - private static Supplier createJedisClusterFactory( + private static Supplier createJedisClusterFactory( String identifier, URI redisUri, int timeout, int maxAttempts, String password, - JedisPoolConfig poolConfig) { + ConnectionPoolConfig poolConfig) { return () -> - new JedisCluster( - new HostAndPort(redisUri.getHost(), redisUri.getPort()), + createJedis( + ImmutableSet.of(new HostAndPort(redisUri.getHost(), redisUri.getPort())), /* connectionTimeout= */ Integer.max(2000, timeout), /* soTimeout= */ Integer.max(2000, timeout), Integer.max(5, maxAttempts), @@ -180,15 +224,15 @@ private static Supplier createJedisClusterFactory( * @return An established jedis client used to operate on the redis cluster. * @note Suggested return identifier: jedis. */ - private static Supplier createJedisClusterFactory( + private static Supplier createJedisClusterFactory( String identifier, Set redisUrisNodes, int timeout, int maxAttempts, String password, - JedisPoolConfig poolConfig) { + ConnectionPoolConfig poolConfig) { return () -> - new JedisCluster( + createJedis( redisUrisNodes, /* connectionTimeout= */ Integer.max(2000, timeout), /* soTimeout= */ Integer.max(2000, timeout), @@ -200,15 +244,15 @@ private static Supplier createJedisClusterFactory( } /** - * @brief Create a jedis pool config. + * @brief Create a connection pool config. * @details Use configuration to build the appropriate jedis pool configuration. * @return A created jedis pool config. * @note Suggested return identifier: poolConfig. */ - private static JedisPoolConfig createJedisPoolConfig() { - JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); - jedisPoolConfig.setMaxTotal(configs.getBackplane().getJedisPoolMaxTotal()); - return jedisPoolConfig; + private static ConnectionPoolConfig createConnectionPoolConfig() { + ConnectionPoolConfig connectionPoolConfig = new ConnectionPoolConfig(); + connectionPoolConfig.setMaxTotal(configs.getBackplane().getJedisPoolMaxTotal()); + return connectionPoolConfig; } /** diff --git a/src/main/java/build/buildfarm/instance/shard/OperationQueue.java b/src/main/java/build/buildfarm/instance/shard/OperationQueue.java index 8d341f301c..4cd31cf2e7 100644 --- a/src/main/java/build/buildfarm/instance/shard/OperationQueue.java +++ b/src/main/java/build/buildfarm/instance/shard/OperationQueue.java @@ -25,7 +25,7 @@ import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; -import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.UnifiedJedis; /** * @class OperationQueue @@ -84,7 +84,7 @@ public OperationQueue(List queues, int maxQueueSize) { * @param jedis Jedis cluster client. * @param visitor A visitor for each visited element in the queue. */ - public void visitDequeue(JedisCluster jedis, StringVisitor visitor) { + public void visitDequeue(UnifiedJedis jedis, StringVisitor visitor) { for (ProvisionedRedisQueue provisionedQueue : queues) { provisionedQueue.queue().visitDequeue(jedis, visitor); } @@ -98,7 +98,7 @@ public void visitDequeue(JedisCluster jedis, StringVisitor visitor) { * @return Whether or not the value was removed. * @note Suggested return identifier: wasRemoved. */ - public boolean removeFromDequeue(JedisCluster jedis, String val) { + public boolean removeFromDequeue(UnifiedJedis jedis, String val) { for (ProvisionedRedisQueue provisionedQueue : queues) { if (provisionedQueue.queue().removeFromDequeue(jedis, val)) { return true; @@ -113,7 +113,7 @@ public boolean removeFromDequeue(JedisCluster jedis, String val) { * @param jedis Jedis cluster client. * @param visitor A visitor for each visited element in the queue. */ - public void visit(JedisCluster jedis, StringVisitor visitor) { + public void visit(UnifiedJedis jedis, StringVisitor visitor) { for (ProvisionedRedisQueue provisionedQueue : queues) { provisionedQueue.queue().visit(jedis, visitor); } @@ -126,7 +126,7 @@ public void visit(JedisCluster jedis, StringVisitor visitor) { * @return The current length of the queue. * @note Suggested return identifier: length. */ - public long size(JedisCluster jedis) { + public long size(UnifiedJedis jedis) { // the accumulated size of all of the queues return queues.stream().mapToInt(i -> (int) i.queue().size(jedis)).sum(); } @@ -178,7 +178,7 @@ public String getName(List provisions) { * @param val The value to push onto the queue. */ public void push( - JedisCluster jedis, List provisions, String val, int priority) { + UnifiedJedis jedis, List provisions, String val, int priority) { BalancedRedisQueue queue = chooseEligibleQueue(provisions); queue.push(jedis, val, (double) priority); } @@ -193,7 +193,7 @@ public void push( * @return The value of the transfered element. null if the thread was interrupted. * @note Suggested return identifier: val. */ - public String dequeue(JedisCluster jedis, List provisions) + public String dequeue(UnifiedJedis jedis, List provisions) throws InterruptedException { // Select all matched queues, and attempt dequeuing via round-robin. List queues = chooseEligibleQueues(provisions); @@ -217,7 +217,7 @@ public String dequeue(JedisCluster jedis, List provisions) * @note Overloaded. * @note Suggested return identifier: status. */ - public OperationQueueStatus status(JedisCluster jedis) { + public OperationQueueStatus status(UnifiedJedis jedis) { // get properties List provisions = new ArrayList<>(); for (ProvisionedRedisQueue provisionedQueue : queues) { @@ -240,7 +240,7 @@ public OperationQueueStatus status(JedisCluster jedis) { * @note Overloaded. * @note Suggested return identifier: status. */ - public QueueStatus status(JedisCluster jedis, List provisions) { + public QueueStatus status(UnifiedJedis jedis, List provisions) { BalancedRedisQueue queue = chooseEligibleQueue(provisions); return queue.status(jedis); } @@ -270,7 +270,7 @@ public boolean isEligible(List properties) { * @param jedis Jedis cluster client. * @return Whether are not a new element can be added to the queue based on its current size. */ - public boolean canQueue(JedisCluster jedis) { + public boolean canQueue(UnifiedJedis jedis) { return maxQueueSize < 0 || size(jedis) < maxQueueSize; } diff --git a/src/main/java/build/buildfarm/instance/shard/Operations.java b/src/main/java/build/buildfarm/instance/shard/Operations.java index 50e4fbf0f8..b3c37ae25d 100644 --- a/src/main/java/build/buildfarm/instance/shard/Operations.java +++ b/src/main/java/build/buildfarm/instance/shard/Operations.java @@ -18,7 +18,7 @@ import build.buildfarm.common.redis.RedisMap; import java.util.Map; import java.util.Set; -import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.UnifiedJedis; /** * @class Operations @@ -57,7 +57,7 @@ public Operations(String name, int timeout_s) { * @note Overloaded. * @note Suggested return identifier: operation. */ - public String get(JedisCluster jedis, String operationId) { + public String get(UnifiedJedis jedis, String operationId) { return operationIds.get(jedis, operationId); } @@ -70,7 +70,7 @@ public String get(JedisCluster jedis, String operationId) { * @note Overloaded. * @note Suggested return identifier: operations. */ - public Iterable> get(JedisCluster jedis, Iterable searchIds) { + public Iterable> get(UnifiedJedis jedis, Iterable searchIds) { return operationIds.get(jedis, searchIds); } @@ -83,7 +83,7 @@ public Iterable> get(JedisCluster jedis, Iterable getByInvocationId(JedisCluster jedis, String invocationId) { + public Set getByInvocationId(UnifiedJedis jedis, String invocationId) { return jedis.smembers(invocationId); } @@ -96,7 +96,7 @@ public Set getByInvocationId(JedisCluster jedis, String invocationId) { * @param operation Json of the operation. */ public void insert( - JedisCluster jedis, String invocationId, String operationId, String operation) { + UnifiedJedis jedis, String invocationId, String operationId, String operation) { operationIds.insert(jedis, operationId, operation); // We also store a mapping from invocationID -> operationIDs @@ -112,7 +112,7 @@ public void insert( * @param jedis Jedis cluster client. * @param operationId The ID of the operation. */ - public void remove(JedisCluster jedis, String operationId) { + public void remove(UnifiedJedis jedis, String operationId) { operationIds.remove(jedis, operationId); } } diff --git a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java index 6fc4c7844d..08686054b1 100644 --- a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java +++ b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java @@ -58,6 +58,7 @@ import build.buildfarm.v1test.ShardWorker; import build.buildfarm.v1test.WorkerChange; import build.buildfarm.v1test.WorkerType; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Suppliers; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableList; @@ -98,7 +99,7 @@ import javax.annotation.Nullable; import javax.naming.ConfigurationException; import lombok.extern.java.Log; -import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.UnifiedJedis; @Log public class RedisShardBackplane implements Backplane { @@ -133,7 +134,7 @@ public class RedisShardBackplane implements Backplane { private final boolean runFailsafeOperation; private final Function onPublish; private final Function onComplete; - private final Supplier jedisClusterFactory; + private final Supplier jedisClusterFactory; private @Nullable InterruptingRunnable onUnsubscribe = null; private Thread subscriptionThread = null; @@ -141,6 +142,7 @@ public class RedisShardBackplane implements Backplane { private RedisShardSubscriber subscriber = null; private RedisShardSubscription operationSubscription = null; private ExecutorService subscriberService = null; + private ExecutorService dequeueService = null; private @Nullable RedisClient client = null; private Deadline storageWorkersDeadline = null; @@ -171,7 +173,7 @@ public RedisShardBackplane( boolean runFailsafeOperation, Function onPublish, Function onComplete, - Supplier jedisClusterFactory) { + Supplier jedisClusterFactory) { this.source = source; this.subscribeToBackplane = subscribeToBackplane; this.runFailsafeOperation = runFailsafeOperation; @@ -236,7 +238,7 @@ private Instant convertToMilliInstant(String value, String key) { return null; } - private void scanProcessing(JedisCluster jedis, Consumer onOperationName, Instant now) { + private void scanProcessing(UnifiedJedis jedis, Consumer onOperationName, Instant now) { state.prequeue.visitDequeue( jedis, new ExecuteEntryListVisitor() { @@ -272,7 +274,7 @@ protected void visit(ExecuteEntry executeEntry, String executeEntryJson) { }); } - private void scanDispatching(JedisCluster jedis, Consumer onOperationName, Instant now) { + private void scanDispatching(UnifiedJedis jedis, Consumer onOperationName, Instant now) { state.operationQueue.visitDequeue( jedis, new QueueEntryListVisitor() { @@ -309,7 +311,7 @@ protected void visit(QueueEntry queueEntry, String queueEntryJson) { }); } - private void scanPrequeue(JedisCluster jedis, Consumer onOperationName) { + private void scanPrequeue(UnifiedJedis jedis, Consumer onOperationName) { state.prequeue.visit( jedis, new ExecuteEntryListVisitor() { @@ -320,7 +322,7 @@ protected void visit(ExecuteEntry executeEntry, String executeEntryJson) { }); } - private void scanQueue(JedisCluster jedis, Consumer onOperationName) { + private void scanQueue(UnifiedJedis jedis, Consumer onOperationName) { state.operationQueue.visit( jedis, new QueueEntryListVisitor() { @@ -331,13 +333,13 @@ protected void visit(QueueEntry queueEntry, String queueEntryJson) { }); } - private void scanDispatched(JedisCluster jedis, Consumer onOperationName) { + private void scanDispatched(UnifiedJedis jedis, Consumer onOperationName) { for (String operationName : state.dispatchedOperations.keys(jedis)) { onOperationName.accept(operationName); } } - private void updateWatchers(JedisCluster jedis) { + private void updateWatchers(UnifiedJedis jedis) { Instant now = Instant.now(); Instant expiresAt = nextExpiresAt(now); Set expiringChannels = Sets.newHashSet(subscriber.expiredWatchedOperationChannels(now)); @@ -397,7 +399,7 @@ static String printOperationChange(OperationChange operationChange) } void publish( - JedisCluster jedis, + UnifiedJedis jedis, String channel, Instant effectiveAt, OperationChange.Builder operationChange) { @@ -412,7 +414,7 @@ void publish( } } - void publishReset(JedisCluster jedis, Operation operation) { + void publishReset(UnifiedJedis jedis, Operation operation) { Instant effectiveAt = Instant.now(); Instant expiresAt = nextExpiresAt(effectiveAt); publish( @@ -434,7 +436,7 @@ static Timestamp toTimestamp(Instant instant) { .build(); } - void publishExpiration(JedisCluster jedis, String channel, Instant effectiveAt) { + void publishExpiration(UnifiedJedis jedis, String channel, Instant effectiveAt) { publish( jedis, channel, @@ -444,7 +446,7 @@ void publishExpiration(JedisCluster jedis, String channel, Instant effectiveAt) } @SuppressWarnings({"unchecked", "rawtypes"}) - public void updateWatchedIfDone(JedisCluster jedis) { + public void updateWatchedIfDone(UnifiedJedis jedis) { List operationChannels = subscriber.watchedOperationChannels(); if (operationChannels.isEmpty()) { return; @@ -483,6 +485,7 @@ private void startSubscriptionThread() { Multimaps.synchronizedListMultimap( MultimapBuilder.linkedHashKeys().arrayListValues().build()); subscriberService = BuildfarmExecutors.getSubscriberPool(); + dequeueService = BuildfarmExecutors.getDequeuePool(); subscriber = new RedisShardSubscriber( watchers, storageWorkers, configs.getBackplane().getWorkerChannel(), subscriberService); @@ -533,10 +536,19 @@ public void start(String clientPublicName) throws IOException { // Construct a single redis client to be used throughout the entire backplane. // We wish to avoid various synchronous and error handling issues that could occur when using // multiple clients. - client = new RedisClient(jedisClusterFactory.get()); + start(new RedisClient(jedisClusterFactory.get()), clientPublicName); + } + + private void start(RedisClient client, String clientPublicName) throws IOException { // Create containers that make up the backplane - state = DistributedStateCreator.create(client); + start(client, DistributedStateCreator.create(client), clientPublicName); + } + @VisibleForTesting + void start(RedisClient client, DistributedState state, String clientPublicName) + throws IOException { + this.client = client; + this.state = state; if (subscribeToBackplane) { startSubscriptionThread(); } @@ -564,10 +576,21 @@ public synchronized void stop() throws InterruptedException { } log.log(Level.FINER, "subscriptionThread has been stopped"); } + if (dequeueService != null) { + dequeueService.shutdown(); + if (dequeueService.awaitTermination(10, SECONDS)) { + log.log(Level.FINER, "dequeueService has been stopped"); + } else { + log.log(Level.WARNING, "dequeueService has not stopped"); + } + } if (subscriberService != null) { subscriberService.shutdown(); - subscriberService.awaitTermination(10, SECONDS); - log.log(Level.FINER, "subscriberService has been stopped"); + if (subscriberService.awaitTermination(10, SECONDS)) { + log.log(Level.FINER, "subscriberService has been stopped"); + } else { + log.log(Level.WARNING, "subscriberService has not stopped"); + } } if (client != null) { client.close(); @@ -619,7 +642,7 @@ public void addWorker(ShardWorker shardWorker) throws IOException { }); } - private boolean addWorkerByType(JedisCluster jedis, ShardWorker shardWorker, String json) { + private boolean addWorkerByType(UnifiedJedis jedis, ShardWorker shardWorker, String json) { int type = shardWorker.getWorkerType(); if (type == 0) { return false; // no destination @@ -635,7 +658,7 @@ private boolean addWorkerByType(JedisCluster jedis, ShardWorker shardWorker, Str } private boolean removeWorkerAndPublish( - JedisCluster jedis, String name, String changeJson, boolean storage) { + UnifiedJedis jedis, String name, String changeJson, boolean storage) { boolean removedAny = state.executeWorkers.remove(jedis, name); if (storage && state.storageWorkers.remove(jedis, name)) { jedis.publish(configs.getBackplane().getWorkerChannel(), changeJson); @@ -776,7 +799,7 @@ public static List randomN(List list, int n) { } private void removeInvalidWorkers( - JedisCluster jedis, long testedAt, List workers, boolean storage) { + UnifiedJedis jedis, long testedAt, List workers, boolean storage) { if (!workers.isEmpty()) { for (ShardWorker worker : workers) { String name = worker.getEndpoint(); @@ -799,16 +822,16 @@ private void removeInvalidWorkers( } } - private Map fetchAndExpireStorageWorkers(JedisCluster jedis) { + private Map fetchAndExpireStorageWorkers(UnifiedJedis jedis) { return fetchAndExpireWorkers(jedis, state.storageWorkers.asMap(jedis), /* storage= */ true); } - private Map fetchAndExpireExecuteWorkers(JedisCluster jedis) { + private Map fetchAndExpireExecuteWorkers(UnifiedJedis jedis) { return fetchAndExpireWorkers(jedis, state.executeWorkers.asMap(jedis), /* storage= */ false); } private Map fetchAndExpireWorkers( - JedisCluster jedis, Map workers, boolean publish) { + UnifiedJedis jedis, Map workers, boolean publish) { long now = System.currentTimeMillis(); Map returnWorkers = Maps.newConcurrentMap(); ImmutableList.Builder invalidWorkers = ImmutableList.builder(); @@ -884,7 +907,7 @@ public void putActionResult(ActionKey actionKey, ActionResult actionResult) thro configs.getBackplane().getActionCacheExpire())); } - private void removeActionResult(JedisCluster jedis, ActionKey actionKey) { + private void removeActionResult(UnifiedJedis jedis, ActionKey actionKey) { state.actionCache.remove(jedis, asDigestStr(actionKey)); } @@ -984,7 +1007,7 @@ public Iterable> getOperations(Set operationId }); } - private String getOperation(JedisCluster jedis, String operationName) { + private String getOperation(UnifiedJedis jedis, String operationName) { return state.operations.get(jedis, operationName); } @@ -1038,7 +1061,7 @@ public boolean putOperation(Operation operation, ExecutionStage.Value stage) thr } private void queue( - JedisCluster jedis, + UnifiedJedis jedis, String operationName, List provisions, String queueEntryJson, @@ -1190,8 +1213,8 @@ public ImmutableList getDispatchedOperations() throws IOExc return builder.build(); } - private ExecuteEntry deprequeueOperation(JedisCluster jedis) throws InterruptedException { - String executeEntryJson = state.prequeue.dequeue(jedis); + private ExecuteEntry deprequeueOperation(UnifiedJedis jedis) throws InterruptedException { + String executeEntryJson = state.prequeue.dequeue(jedis, dequeueService); if (executeEntryJson == null) { return null; } @@ -1228,7 +1251,7 @@ public ExecuteEntry deprequeueOperation() throws IOException, InterruptedExcepti } private @Nullable QueueEntry dispatchOperation( - JedisCluster jedis, List provisions) throws InterruptedException { + UnifiedJedis jedis, List provisions) throws InterruptedException { String queueEntryJson = state.operationQueue.dequeue(jedis, provisions); if (queueEntryJson == null) { return null; @@ -1332,7 +1355,7 @@ public boolean pollOperation(QueueEntry queueEntry, ExecutionStage.Value stage, return client.call(jedis -> pollOperation(jedis, operationName, json)); } - boolean pollOperation(JedisCluster jedis, String operationName, String dispatchedOperationJson) { + boolean pollOperation(UnifiedJedis jedis, String operationName, String dispatchedOperationJson) { if (state.dispatchedOperations.exists(jedis, operationName)) { if (!state.dispatchedOperations.insert(jedis, operationName, dispatchedOperationJson)) { return true; @@ -1391,7 +1414,7 @@ public void requeueDispatchedOperation(QueueEntry queueEntry) throws IOException }); } - private void completeOperation(JedisCluster jedis, String operationName) { + private void completeOperation(UnifiedJedis jedis, String operationName) { state.dispatchedOperations.remove(jedis, operationName); } @@ -1449,7 +1472,7 @@ public boolean isBlacklisted(RequestMetadata requestMetadata) throws IOException return client.call(jedis -> isBlacklisted(jedis, requestMetadata)); } - private boolean isBlacklisted(JedisCluster jedis, RequestMetadata requestMetadata) { + private boolean isBlacklisted(UnifiedJedis jedis, RequestMetadata requestMetadata) { boolean isActionBlocked = (!requestMetadata.getActionId().isEmpty() && state.blockedActions.exists(jedis, requestMetadata.getActionId())); diff --git a/src/main/java/build/buildfarm/instance/shard/RedisShardSubscriber.java b/src/main/java/build/buildfarm/instance/shard/RedisShardSubscriber.java index 69f6aaebdd..edd2bfdfae 100644 --- a/src/main/java/build/buildfarm/instance/shard/RedisShardSubscriber.java +++ b/src/main/java/build/buildfarm/instance/shard/RedisShardSubscriber.java @@ -38,7 +38,7 @@ import java.util.logging.Level; import javax.annotation.Nullable; import lombok.extern.java.Log; -import redis.clients.jedis.Client; +import redis.clients.jedis.Connection; import redis.clients.jedis.JedisPubSub; @Log @@ -105,35 +105,6 @@ public List expiredWatchedOperationChannels(Instant now) { return builder.build(); } - // synchronizing on these because the client has been observed to - // cause protocol desynchronization for multiple concurrent calls - @Override - public synchronized void unsubscribe() { - if (isSubscribed()) { - super.unsubscribe(); - } - } - - @Override - public synchronized void unsubscribe(String... channels) { - super.unsubscribe(channels); - } - - @Override - public synchronized void subscribe(String... channels) { - super.subscribe(channels); - } - - @Override - public synchronized void psubscribe(String... patterns) { - super.psubscribe(patterns); - } - - @Override - public synchronized void punsubscribe(String... patterns) { - super.punsubscribe(patterns); - } - public ListenableFuture watch(String channel, TimedWatcher watcher) { TimedWatchFuture watchFuture = new TimedWatchFuture(watcher) { @@ -337,11 +308,10 @@ private String[] placeholderChannel() { return channels; } - @Override - public void proceed(Client client, String... channels) { + public void start(Connection client, String... channels) { if (channels.length == 0) { channels = placeholderChannel(); } - super.proceed(client, channels); + proceed(client, channels); } } diff --git a/src/main/java/build/buildfarm/instance/shard/RedisShardSubscription.java b/src/main/java/build/buildfarm/instance/shard/RedisShardSubscription.java index 39e62e141d..847d7920dc 100644 --- a/src/main/java/build/buildfarm/instance/shard/RedisShardSubscription.java +++ b/src/main/java/build/buildfarm/instance/shard/RedisShardSubscription.java @@ -24,14 +24,14 @@ import java.util.function.Supplier; import java.util.logging.Level; import lombok.extern.java.Log; -import redis.clients.jedis.JedisCluster; import redis.clients.jedis.JedisPubSub; +import redis.clients.jedis.UnifiedJedis; @Log class RedisShardSubscription implements Runnable { private final JedisPubSub subscriber; private final InterruptingRunnable onUnsubscribe; - private final Consumer onReset; + private final Consumer onReset; private final Supplier> subscriptions; private final RedisClient client; private final AtomicBoolean stopped = new AtomicBoolean(false); @@ -39,7 +39,7 @@ class RedisShardSubscription implements Runnable { RedisShardSubscription( JedisPubSub subscriber, InterruptingRunnable onUnsubscribe, - Consumer onReset, + Consumer onReset, Supplier> subscriptions, RedisClient client) { this.subscriber = subscriber; @@ -53,7 +53,7 @@ public JedisPubSub getSubscriber() { return subscriber; } - private void subscribe(JedisCluster jedis, boolean isReset) { + private void subscribe(UnifiedJedis jedis, boolean isReset) { if (isReset) { onReset.accept(jedis); } diff --git a/src/main/java/build/buildfarm/operations/finder/BUILD b/src/main/java/build/buildfarm/operations/finder/BUILD index 8b6a2cc557..fdbbe85199 100644 --- a/src/main/java/build/buildfarm/operations/finder/BUILD +++ b/src/main/java/build/buildfarm/operations/finder/BUILD @@ -10,7 +10,6 @@ java_library( "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/operations", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "//third_party/jedis", "@googleapis//:google_rpc_code_java_proto", "@googleapis//:google_rpc_error_details_java_proto", "@maven//:com_google_code_findbugs_jsr305", @@ -26,6 +25,7 @@ java_library( "@maven//:io_grpc_grpc_stub", "@maven//:org_apache_commons_commons_pool2", "@maven//:org_projectlombok_lombok", + "@maven//:redis_clients_jedis", "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/operations/finder/EnrichedOperationBuilder.java b/src/main/java/build/buildfarm/operations/finder/EnrichedOperationBuilder.java index f6cdfcbd2a..2dac505d1d 100644 --- a/src/main/java/build/buildfarm/operations/finder/EnrichedOperationBuilder.java +++ b/src/main/java/build/buildfarm/operations/finder/EnrichedOperationBuilder.java @@ -33,7 +33,7 @@ import com.google.rpc.PreconditionFailure; import java.util.logging.Level; import lombok.extern.java.Log; -import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.UnifiedJedis; /** * @class EnrichedOperationBuilder @@ -55,9 +55,9 @@ public class EnrichedOperationBuilder { * @note Suggested return identifier: operation. */ public static EnrichedOperation build( - JedisCluster cluster, Instance instance, String operationKey) { + UnifiedJedis jedis, Instance instance, String operationKey) { EnrichedOperation operationWithMetadata = new EnrichedOperation(); - operationWithMetadata.operation = operationKeyToOperation(cluster, operationKey); + operationWithMetadata.operation = operationKeyToOperation(jedis, operationKey); // the operation could not be fetched so there is nothing further to derive if (operationWithMetadata.operation == null) { return operationWithMetadata; @@ -83,8 +83,8 @@ public static EnrichedOperation build( * @return The looked up operation. * @note Suggested return identifier: operation. */ - public static Operation operationKeyToOperation(JedisCluster cluster, String operationKey) { - String json = cluster.get(operationKey); + public static Operation operationKeyToOperation(UnifiedJedis jedis, String operationKey) { + String json = jedis.get(operationKey); return jsonToOperation(json); } diff --git a/src/main/java/build/buildfarm/operations/finder/OperationsFinder.java b/src/main/java/build/buildfarm/operations/finder/OperationsFinder.java index 2bdb0c5648..912d16e811 100644 --- a/src/main/java/build/buildfarm/operations/finder/OperationsFinder.java +++ b/src/main/java/build/buildfarm/operations/finder/OperationsFinder.java @@ -34,10 +34,10 @@ import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; -import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisCluster; -import redis.clients.jedis.ScanParams; -import redis.clients.jedis.ScanResult; +import redis.clients.jedis.UnifiedJedis; +import redis.clients.jedis.params.ScanParams; +import redis.clients.jedis.resps.ScanResult; /** * @class OperationsFinder @@ -57,24 +57,29 @@ public class OperationsFinder { * @note Suggested return identifier: results. */ public static FindOperationsResults findEnrichedOperations( - JedisCluster cluster, Instance instance, FindOperationsSettings settings) { + UnifiedJedis jedis, Instance instance, FindOperationsSettings settings) { FindOperationsResults results = new FindOperationsResults(); results.operations = new HashMap<>(); adjustFilter(settings); - // JedisCluster only supports SCAN commands with MATCH patterns containing hash-tags. - // This prevents us from using the cluster's SCAN to traverse all of the CAS. - // That's why we choose to scan each of the jedisNode's individually. - cluster - .getClusterNodes() - .values() - .forEach( - pool -> { - try (Jedis node = pool.getResource()) { - findEnrichedOperationOnNode(cluster, node, instance, settings, results); - } - }); + if (jedis instanceof JedisCluster) { + JedisCluster cluster = (JedisCluster) jedis; + // JedisCluster only supports SCAN commands with MATCH patterns containing hash-tags. + // This prevents us from using the cluster's SCAN to traverse all of the CAS. + // That's why we choose to scan each of the jedisNode's individually. + cluster + .getClusterNodes() + .values() + .forEach( + pool -> { + try (UnifiedJedis node = new UnifiedJedis(pool.getResource())) { + findEnrichedOperationOnNode(cluster, node, instance, settings, results); + } + }); + } else { + findEnrichedOperationOnNode(jedis, jedis, instance, settings, results); + } return results; } @@ -89,23 +94,28 @@ public static FindOperationsResults findEnrichedOperations( * @note Suggested return identifier: results. */ public static List findOperations( - JedisCluster cluster, FindOperationsSettings settings) { + UnifiedJedis jedis, FindOperationsSettings settings) { List results = new ArrayList<>(); adjustFilter(settings); - // JedisCluster only supports SCAN commands with MATCH patterns containing hash-tags. - // This prevents us from using the cluster's SCAN to traverse all of the CAS. - // That's why we choose to scan each of the jedisNode's individually. - cluster - .getClusterNodes() - .values() - .forEach( - pool -> { - try (Jedis node = pool.getResource()) { - findOperationOnNode(cluster, node, settings, results); - } - }); + if (jedis instanceof JedisCluster) { + JedisCluster cluster = (JedisCluster) jedis; + // JedisCluster only supports SCAN commands with MATCH patterns containing hash-tags. + // This prevents us from using the cluster's SCAN to traverse all of the CAS. + // That's why we choose to scan each of the jedisNode's individually. + cluster + .getClusterNodes() + .values() + .forEach( + pool -> { + try (UnifiedJedis node = new UnifiedJedis(pool.getResource())) { + findOperationOnNode(cluster, node, settings, results); + } + }); + } else { + findOperationOnNode(jedis, jedis, settings, results); + } return results; } @@ -135,8 +145,8 @@ private static void adjustFilter(FindOperationsSettings settings) { */ @SuppressWarnings({"unchecked", "rawtypes"}) private static void findEnrichedOperationOnNode( - JedisCluster cluster, - Jedis node, + UnifiedJedis cluster, + UnifiedJedis node, Instance instance, FindOperationsSettings settings, FindOperationsResults results) { @@ -169,7 +179,10 @@ private static void findEnrichedOperationOnNode( * @param results Accumulating results from performing a search. */ private static void findOperationOnNode( - JedisCluster cluster, Jedis node, FindOperationsSettings settings, List results) { + UnifiedJedis cluster, + UnifiedJedis node, + FindOperationsSettings settings, + List results) { // iterate over all operation entries via scanning // construct query @@ -198,7 +211,7 @@ private static void findOperationOnNode( * @param results Accumulating results from finding operations. */ private static void collectOperations( - JedisCluster cluster, + UnifiedJedis cluster, Instance instance, List operationKeys, String filterPredicate, @@ -220,7 +233,7 @@ private static void collectOperations( * @param results Accumulating results from finding operations. */ private static void collectOperations( - JedisCluster cluster, + UnifiedJedis cluster, List operationKeys, String filterPredicate, List results) { diff --git a/src/main/java/build/buildfarm/tools/BUILD b/src/main/java/build/buildfarm/tools/BUILD index 44a4498ef9..120012ac2a 100644 --- a/src/main/java/build/buildfarm/tools/BUILD +++ b/src/main/java/build/buildfarm/tools/BUILD @@ -143,7 +143,6 @@ java_binary( "//src/main/java/build/buildfarm/instance/stub", "//src/main/java/build/buildfarm/worker/shard", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "//third_party/jedis", "@maven//:com_github_pcj_google_options", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", @@ -153,6 +152,7 @@ java_binary( "@maven//:io_grpc_grpc_core", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", + "@maven//:redis_clients_jedis", ], ) @@ -304,7 +304,6 @@ java_library( "//src/main/java/build/buildfarm/instance/stub", "//src/main/java/build/buildfarm/worker/shard", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "//third_party/jedis", "@maven//:com_github_pcj_google_options", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", @@ -314,5 +313,6 @@ java_library( "@maven//:io_grpc_grpc_core", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", + "@maven//:redis_clients_jedis", ], ) diff --git a/src/main/java/build/buildfarm/tools/WorkerProfile.java b/src/main/java/build/buildfarm/tools/WorkerProfile.java index c4f226a948..4a710cde32 100644 --- a/src/main/java/build/buildfarm/tools/WorkerProfile.java +++ b/src/main/java/build/buildfarm/tools/WorkerProfile.java @@ -40,7 +40,7 @@ import java.util.Map; import java.util.Set; import javax.naming.ConfigurationException; -import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.UnifiedJedis; class WorkerProfile { private static BuildfarmConfigs configs = BuildfarmConfigs.getInstance(); @@ -113,7 +113,7 @@ private static Set getWorkers(String[] args) throws ConfigurationExcepti return client.call(jedis -> fetchWorkers(jedis, System.currentTimeMillis())); } - private static Set fetchWorkers(JedisCluster jedis, long now) { + private static Set fetchWorkers(UnifiedJedis jedis, long now) { Set workers = Sets.newConcurrentHashSet(); for (Map.Entry entry : jedis.hgetAll(configs.getBackplane().getWorkersHashName() + "_storage").entrySet()) { diff --git a/src/test/java/build/buildfarm/common/BUILD b/src/test/java/build/buildfarm/common/BUILD index 70ff4abc94..971c0745d2 100644 --- a/src/test/java/build/buildfarm/common/BUILD +++ b/src/test/java/build/buildfarm/common/BUILD @@ -10,7 +10,6 @@ java_test( "//src/main/java/build/buildfarm/common", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "//third_party/jedis", "@googleapis//:google_bytestream_bytestream_java_proto", "@googleapis//:google_rpc_error_details_java_proto", "@maven//:com_google_guava_guava", @@ -23,5 +22,6 @@ java_test( "@maven//:io_grpc_grpc_stub", "@maven//:io_grpc_grpc_testing", "@maven//:org_mockito_mockito_core", + "@maven//:redis_clients_jedis", ], ) diff --git a/src/test/java/build/buildfarm/common/redis/BUILD b/src/test/java/build/buildfarm/common/redis/BUILD index f388e339e0..467f6fd335 100644 --- a/src/test/java/build/buildfarm/common/redis/BUILD +++ b/src/test/java/build/buildfarm/common/redis/BUILD @@ -5,11 +5,12 @@ COMMON_DEPS = [ "//src/main/java/build/buildfarm/common/redis", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "//third_party/jedis", + "@maven//:com_github_fppt_jedis_mock", "@maven//:com_google_guava_guava", "@maven//:com_google_truth_truth", "@maven//:io_grpc_grpc_api", "@maven//:org_mockito_mockito_core", + "@maven//:redis_clients_jedis", ] NATIVE_REDIS_TESTS = [ diff --git a/src/test/java/build/buildfarm/common/redis/BalancedRedisQueueMockTest.java b/src/test/java/build/buildfarm/common/redis/BalancedRedisQueueMockTest.java index 2869b2edc9..c93d0458db 100644 --- a/src/test/java/build/buildfarm/common/redis/BalancedRedisQueueMockTest.java +++ b/src/test/java/build/buildfarm/common/redis/BalancedRedisQueueMockTest.java @@ -16,22 +16,26 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; import build.buildfarm.common.StringVisitor; -import build.buildfarm.common.config.Queue; import com.google.common.collect.ImmutableList; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; +import java.util.concurrent.ExecutorService; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import redis.clients.jedis.Connection; +import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisCluster; /** @@ -46,28 +50,14 @@ @RunWith(JUnit4.class) public class BalancedRedisQueueMockTest { @Mock private JedisCluster redis; + @Mock private Connection connection; + @Mock QueueInterface subQueue; @Before public void setUp() { MockitoAnnotations.initMocks(this); - } - - // Function under test: removeFromDequeue - // Reason for testing: removing returns false because the queue is empty and there is nothing to - // remove - // Failure explanation: the queue was either not empty, or an error occured while removing from an - // empty queue - @Test - public void removeFromDequeueFalseOnEmpty() throws Exception { - // ARRANGE - when(redis.lrem(any(String.class), any(Long.class), any(String.class))).thenReturn(0L); - BalancedRedisQueue queue = new BalancedRedisQueue("test", ImmutableList.of()); - - // ACT - Boolean success = queue.removeFromDequeue(redis, "foo"); - - // ASSERT - assertThat(success).isFalse(); + when(redis.getConnectionFromSlot(any(Integer.class))).thenReturn(connection); + when(subQueue.getName()).thenReturn("test"); } // Function under test: removeFromDequeue @@ -78,8 +68,8 @@ public void removeFromDequeueFalseOnEmpty() throws Exception { @Test public void removeFromDequeueFalseWhenValueIsMissing() throws Exception { // ARRANGE - when(redis.lrem(any(String.class), any(Long.class), any(String.class))).thenReturn(0L); - BalancedRedisQueue queue = new BalancedRedisQueue("test", ImmutableList.of()); + when(subQueue.removeFromDequeue(any(Jedis.class), any(String.class))).thenReturn(false); + BalancedRedisQueue queue = new BalancedRedisQueue("test", -1, ImmutableList.of(subQueue)); // ACT Boolean success = queue.removeFromDequeue(redis, "baz"); @@ -95,8 +85,8 @@ public void removeFromDequeueFalseWhenValueIsMissing() throws Exception { @Test public void removeFromDequeueTrueWhenValueExists() throws Exception { // ARRANGE - when(redis.lrem(any(String.class), any(Long.class), any(String.class))).thenReturn(1L); - BalancedRedisQueue queue = new BalancedRedisQueue("test", ImmutableList.of()); + when(subQueue.removeFromDequeue(any(Jedis.class), any(String.class))).thenReturn(true); + BalancedRedisQueue queue = new BalancedRedisQueue("test", -1, ImmutableList.of(subQueue)); // ACT Boolean success = queue.removeFromDequeue(redis, "bar"); @@ -111,15 +101,17 @@ public void removeFromDequeueTrueWhenValueExists() throws Exception { @Test public void dequeueExponentialBackoffElementDequeuedOnNonBlock() throws Exception { // MOCK - when(redis.rpoplpush(any(String.class), any(String.class))).thenReturn("foo"); + when(subQueue.nonBlockingDequeue(any(Jedis.class))).thenReturn("foo"); + ExecutorService service = mock(ExecutorService.class); // ARRANGE - BalancedRedisQueue queue = new BalancedRedisQueue("test", ImmutableList.of()); + BalancedRedisQueue queue = new BalancedRedisQueue("test", -1, ImmutableList.of(subQueue)); // ACT - String val = queue.dequeue(redis); + String val = queue.dequeue(redis, service); // ASSERT + verifyNoInteractions(service); assertThat(val).isEqualTo("foo"); } @@ -129,16 +121,19 @@ public void dequeueExponentialBackoffElementDequeuedOnNonBlock() throws Exceptio @Test public void dequeueExponentialBackoffElementDequeuedOnBlock() throws Exception { // MOCK - when(redis.rpoplpush(any(String.class), any(String.class))).thenReturn(null); - when(redis.brpoplpush(any(String.class), any(String.class), any(int.class))).thenReturn("foo"); + when(subQueue.nonBlockingDequeue(any(Jedis.class))).thenReturn(null); + when(subQueue.dequeue(any(Jedis.class), any(Integer.class), any(ExecutorService.class))) + .thenReturn("foo"); // ARRANGE - BalancedRedisQueue queue = new BalancedRedisQueue("test", ImmutableList.of()); + BalancedRedisQueue queue = new BalancedRedisQueue("test", -1, ImmutableList.of(subQueue)); + ExecutorService service = mock(ExecutorService.class); // ACT - String val = queue.dequeue(redis); + String val = queue.dequeue(redis, service); // ASSERT + verifyNoInteractions(service); assertThat(val).isEqualTo("foo"); } @@ -214,10 +209,10 @@ public void getNameNameIsStored() throws Exception { @Test public void sizeInitialSizeIsZero() throws Exception { // MOCK - when(redis.llen(any(String.class))).thenReturn(0L); + when(subQueue.size(any(Jedis.class))).thenReturn(0L); // ARRANGE - BalancedRedisQueue queue = new BalancedRedisQueue("test", ImmutableList.of()); + BalancedRedisQueue queue = new BalancedRedisQueue("test", -1, ImmutableList.of(subQueue)); // ACT long size = queue.size(redis); @@ -232,28 +227,19 @@ public void sizeInitialSizeIsZero() throws Exception { @Test public void visitCheckVisitOfEachElement() throws Exception { // MOCK - when(redis.lrange(any(String.class), any(Long.class), any(Long.class))) - .thenReturn( - Arrays.asList( - "element 1", - "element 2", - "element 3", - "element 4", - "element 5", - "element 6", - "element 7", - "element 8")); + doAnswer( + invocation -> { + StringVisitor visitor = invocation.getArgument(1); + for (int i = 1; i <= 8; i++) { + visitor.visit("element " + i); + } + return null; + }) + .when(subQueue) + .visit(any(Jedis.class), any(StringVisitor.class)); // ARRANGE - BalancedRedisQueue queue = new BalancedRedisQueue("test", ImmutableList.of()); - queue.push(redis, "element 1"); - queue.push(redis, "element 2"); - queue.push(redis, "element 3"); - queue.push(redis, "element 4"); - queue.push(redis, "element 5"); - queue.push(redis, "element 6"); - queue.push(redis, "element 7"); - queue.push(redis, "element 8"); + BalancedRedisQueue queue = new BalancedRedisQueue("test", -1, ImmutableList.of(subQueue)); // ACT List visited = new ArrayList<>(); @@ -266,15 +252,16 @@ public void visit(String entry) { queue.visit(redis, visitor); // ASSERT - assertThat(visited.size()).isEqualTo(8); - assertThat(visited.contains("element 1")).isTrue(); - assertThat(visited.contains("element 2")).isTrue(); - assertThat(visited.contains("element 3")).isTrue(); - assertThat(visited.contains("element 4")).isTrue(); - assertThat(visited.contains("element 5")).isTrue(); - assertThat(visited.contains("element 6")).isTrue(); - assertThat(visited.contains("element 7")).isTrue(); - assertThat(visited.contains("element 8")).isTrue(); + assertThat(visited) + .containsExactly( + "element 1", + "element 2", + "element 3", + "element 4", + "element 5", + "element 6", + "element 7", + "element 8"); } // Function under test: visitDequeue @@ -283,20 +270,19 @@ public void visit(String entry) { @Test public void visitDequeueCheckVisitOfEachElement() throws Exception { // MOCK - when(redis.lrange(any(String.class), any(Long.class), any(Long.class))) - .thenReturn( - Arrays.asList( - "element 1", - "element 2", - "element 3", - "element 4", - "element 5", - "element 6", - "element 7", - "element 8")); + doAnswer( + invocation -> { + StringVisitor visitor = invocation.getArgument(1); + for (int i = 1; i <= 8; i++) { + visitor.visit("element " + i); + } + return null; + }) + .when(subQueue) + .visitDequeue(any(Jedis.class), any(StringVisitor.class)); // ARRANGE - BalancedRedisQueue queue = new BalancedRedisQueue("test", ImmutableList.of()); + BalancedRedisQueue queue = new BalancedRedisQueue("test", -1, ImmutableList.of(subQueue)); // ACT List visited = new ArrayList<>(); @@ -309,53 +295,34 @@ public void visit(String entry) { queue.visitDequeue(redis, visitor); // ASSERT - assertThat(visited.size()).isEqualTo(8); - assertThat(visited.contains("element 1")).isTrue(); - assertThat(visited.contains("element 2")).isTrue(); - assertThat(visited.contains("element 3")).isTrue(); - assertThat(visited.contains("element 4")).isTrue(); - assertThat(visited.contains("element 5")).isTrue(); - assertThat(visited.contains("element 6")).isTrue(); - assertThat(visited.contains("element 7")).isTrue(); - assertThat(visited.contains("element 8")).isTrue(); + assertThat(visited) + .containsExactly( + "element 1", + "element 2", + "element 3", + "element 4", + "element 5", + "element 6", + "element 7", + "element 8"); } // Function under test: isEvenlyDistributed // Reason for testing: an empty queue is always already evenly distributed // Failure explanation: evenly distributed is not working on the empty queue @Test - public void isEvenlyDistributedEmptyIsEvenlyDistributed() throws Exception { + public void emptyIsEvenlyDistributed() throws Exception { // MOCK - when(redis.llen(any(String.class))).thenReturn(0L); + when(subQueue.size(any(Jedis.class))).thenReturn(0L); // ARRANGE - BalancedRedisQueue queue = new BalancedRedisQueue("test", ImmutableList.of()); + BalancedRedisQueue queue = new BalancedRedisQueue("test", -1, ImmutableList.of(subQueue)); // ACT Boolean isEvenlyDistributed = queue.isEvenlyDistributed(redis); // ASSERT - verify(redis, times(2)).llen(any(String.class)); - assertThat(isEvenlyDistributed).isTrue(); - } - - // Function under test: isEvenlyDistributed for priority - // Reason for testing: an empty queue is always already evenly distributed - // Failure explanation: evenly distributed is not working on the empty queue - @Test - public void isEvenlyDistributedEmptyIsEvenlyDistributedPriority() throws Exception { - // MOCK - when(redis.zcard(any(String.class))).thenReturn(0L); - - // ARRANGE - BalancedRedisQueue queue = - new BalancedRedisQueue("test", ImmutableList.of(), Queue.QUEUE_TYPE.priority); - - // ACT - Boolean isEvenlyDistributed = queue.isEvenlyDistributed(redis); - - // ASSERT - verify(redis, times(2)).zcard(any(String.class)); + verify(subQueue, times(1)).size(any(Jedis.class)); assertThat(isEvenlyDistributed).isTrue(); } @@ -363,74 +330,34 @@ public void isEvenlyDistributedEmptyIsEvenlyDistributedPriority() throws Excepti // Reason for testing: infinite queues allow queuing // Failure explanation: the queue is not accepting queuing when it should @Test - public void canQueueIfiniteQueueAllowsQueuing() throws Exception { - // MOCK - when(redis.llen(any(String.class))).thenReturn(999L); - + public void canQueueInfiniteQueueAllowsQueuing() throws Exception { // ARRANGE - BalancedRedisQueue queue = new BalancedRedisQueue("test", ImmutableList.of(), -1); + BalancedRedisQueue queue = new BalancedRedisQueue("test", -1, ImmutableList.of(subQueue)); // ACT boolean canQueue = queue.canQueue(redis); // ASSERT + verifyNoInteractions(subQueue); assertThat(canQueue).isTrue(); } - // Function under test: canQueue - // Reason for testing: infinite queues allow queuing for priority - // Failure explanation: the queue is not accepting queuing when it should - @Test - public void canQueueIfinitePriorityQueueAllowsQueuing() throws Exception { - // MOCK - when(redis.zcard(any(String.class))).thenReturn(999L); - - // ARRANGE - BalancedRedisQueue queue = - new BalancedRedisQueue("test", ImmutableList.of(), -1, Queue.QUEUE_TYPE.priority); - - // ACT - boolean canQueue = queue.canQueue(redis); - - // ASSERT - assertThat(canQueue).isTrue(); - } - - // Function under test: canQueue for regular - // Reason for testing: Full queues do not allow queuing - // Failure explanation: the queue is still allowing queuing despite being full - @Test - public void canQueueFullQueueNotAllowsQueuing() throws Exception { - // MOCK - when(redis.llen(any(String.class))).thenReturn(123L); - - // ARRANGE - BalancedRedisQueue queue = new BalancedRedisQueue("test", ImmutableList.of(), 123); - - // ACT - boolean canQueue = queue.canQueue(redis); - - // ASSERT - assertThat(canQueue).isFalse(); - } - // Function under test: canQueue for priority // Reason for testing: Full queues do not allow queuing - // Failure explanation: the queue is still allowing queuing despite being full + // Failure explanation: the queue is still allows queueing despite being full @Test - public void canQueueFullPriorityQueueNotAllowsQueuing() throws Exception { + public void canQueueFullQueueNotAllowsQueueing() throws Exception { // MOCK - when(redis.zcard(any(String.class))).thenReturn(123L); + when(subQueue.size(any(Jedis.class))).thenReturn(123L); // ARRANGE - BalancedRedisQueue queue = - new BalancedRedisQueue("test", ImmutableList.of(), 123, Queue.QUEUE_TYPE.priority); + BalancedRedisQueue queue = new BalancedRedisQueue("test", 123, ImmutableList.of(subQueue)); // ACT boolean canQueue = queue.canQueue(redis); // ASSERT - verify(redis).zcard(any(String.class)); + verify(subQueue, times(1)).size(any(Jedis.class)); assertThat(canQueue).isFalse(); } } diff --git a/src/test/java/build/buildfarm/common/redis/BalancedRedisQueueTest.java b/src/test/java/build/buildfarm/common/redis/BalancedRedisQueueTest.java index 41fbece7c8..2ff3a9ca9c 100644 --- a/src/test/java/build/buildfarm/common/redis/BalancedRedisQueueTest.java +++ b/src/test/java/build/buildfarm/common/redis/BalancedRedisQueueTest.java @@ -15,6 +15,8 @@ package build.buildfarm.common.redis; import static com.google.common.truth.Truth.assertThat; +import static java.util.concurrent.Executors.newSingleThreadExecutor; +import static java.util.concurrent.TimeUnit.SECONDS; import build.buildfarm.common.StringVisitor; import build.buildfarm.common.config.BuildfarmConfigs; @@ -25,36 +27,37 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.concurrent.ExecutorService; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.UnifiedJedis; /** * @class BalancedRedisQueueTest - * @brief tests A balanced redis queue. - * @details A balanced redis queue is an implementation of a queue data structure which internally - * uses multiple redis nodes to distribute the data across the cluster. Its important to know + * @brief tests A balanced cluster queue. + * @details A balanced cluster queue is an implementation of a queue data structure which internally + * uses multiple cluster nodes to distribute the data across the cluster. Its important to know * that the lifetime of the queue persists before and after the queue data structure is created - * (since it exists in redis). Therefore, two redis queues with the same name, would in fact be - * the same underlying redis queues. + * (since it exists in jedis). Therefore, two cluster queues with the same name, would in fact + * be the same underlying cluster queues. */ @RunWith(JUnit4.class) public class BalancedRedisQueueTest { private BuildfarmConfigs configs = BuildfarmConfigs.getInstance(); - private JedisCluster redis; + private UnifiedJedis jedis; @Before public void setUp() throws Exception { - configs.getBackplane().setRedisUri("redis://localhost:6379"); - redis = JedisClusterFactory.createTest(); + configs.getBackplane().setRedisUri("cluster://localhost:6379"); + jedis = JedisClusterFactory.createTest(); } @After public void tearDown() { - redis.close(); + jedis.close(); } // Function under test: BalancedRedisQueue @@ -72,11 +75,11 @@ public void balancedRedisQueueCreateHashesConstructsWithoutError() throws Except @Test public void pushPushWithoutError() throws Exception { // ARRANGE - List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(redis); + List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags); // ACT - queue.push(redis, "foo"); + queue.push(jedis, "foo"); } // Function under test: push @@ -85,12 +88,12 @@ public void pushPushWithoutError() throws Exception { @Test public void pushPushDifferentWithoutError() throws Exception { // ARRANGE - List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(redis); + List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags); // ACT - queue.push(redis, "foo"); - queue.push(redis, "bar"); + queue.push(jedis, "foo"); + queue.push(jedis, "bar"); } // Function under test: push @@ -99,12 +102,12 @@ public void pushPushDifferentWithoutError() throws Exception { @Test public void pushPushSameWithoutError() throws Exception { // ARRANGE - List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(redis); + List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags); // ACT - queue.push(redis, "foo"); - queue.push(redis, "foo"); + queue.push(jedis, "foo"); + queue.push(jedis, "foo"); } // Function under test: push @@ -113,12 +116,12 @@ public void pushPushSameWithoutError() throws Exception { @Test public void pushPushMany() throws Exception { // ARRANGE - List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(redis); + List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags); // ACT for (int i = 0; i < 1000; ++i) { - queue.push(redis, "foo" + i); + queue.push(jedis, "foo" + i); } } @@ -128,31 +131,31 @@ public void pushPushMany() throws Exception { @Test public void pushPushIncreasesSize() throws Exception { // ARRANGE - List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(redis); + List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags); // ACT / ASSERT - assertThat(queue.size(redis)).isEqualTo(0); - queue.push(redis, "foo"); - assertThat(queue.size(redis)).isEqualTo(1); - queue.push(redis, "foo"); - assertThat(queue.size(redis)).isEqualTo(2); - queue.push(redis, "foo"); - assertThat(queue.size(redis)).isEqualTo(3); - queue.push(redis, "foo"); - assertThat(queue.size(redis)).isEqualTo(4); - queue.push(redis, "foo"); - assertThat(queue.size(redis)).isEqualTo(5); - queue.push(redis, "foo"); - assertThat(queue.size(redis)).isEqualTo(6); - queue.push(redis, "foo"); - assertThat(queue.size(redis)).isEqualTo(7); - queue.push(redis, "foo"); - assertThat(queue.size(redis)).isEqualTo(8); - queue.push(redis, "foo"); - assertThat(queue.size(redis)).isEqualTo(9); - queue.push(redis, "foo"); - assertThat(queue.size(redis)).isEqualTo(10); + assertThat(queue.size(jedis)).isEqualTo(0); + queue.push(jedis, "foo"); + assertThat(queue.size(jedis)).isEqualTo(1); + queue.push(jedis, "foo"); + assertThat(queue.size(jedis)).isEqualTo(2); + queue.push(jedis, "foo"); + assertThat(queue.size(jedis)).isEqualTo(3); + queue.push(jedis, "foo"); + assertThat(queue.size(jedis)).isEqualTo(4); + queue.push(jedis, "foo"); + assertThat(queue.size(jedis)).isEqualTo(5); + queue.push(jedis, "foo"); + assertThat(queue.size(jedis)).isEqualTo(6); + queue.push(jedis, "foo"); + assertThat(queue.size(jedis)).isEqualTo(7); + queue.push(jedis, "foo"); + assertThat(queue.size(jedis)).isEqualTo(8); + queue.push(jedis, "foo"); + assertThat(queue.size(jedis)).isEqualTo(9); + queue.push(jedis, "foo"); + assertThat(queue.size(jedis)).isEqualTo(10); } // Function under test: removeFromDequeue @@ -163,11 +166,11 @@ public void pushPushIncreasesSize() throws Exception { @Test public void removeFromDequeueFalseOnEmpty() throws Exception { // ARRANGE - List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(redis); + List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags); // ACT - Boolean success = queue.removeFromDequeue(redis, "foo"); + Boolean success = queue.removeFromDequeue(jedis, "foo"); // ASSERT assertThat(success).isFalse(); @@ -181,17 +184,20 @@ public void removeFromDequeueFalseOnEmpty() throws Exception { @Test public void removeFromDequeueFalseWhenValueIsMissing() throws Exception { // ARRANGE - List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(redis); + List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags); + ExecutorService service = newSingleThreadExecutor(); // ACT - queue.push(redis, "foo"); - queue.push(redis, "bar"); - queue.dequeue(redis); - queue.dequeue(redis); - Boolean success = queue.removeFromDequeue(redis, "baz"); + queue.push(jedis, "foo"); + queue.push(jedis, "bar"); + queue.dequeue(jedis, service); + queue.dequeue(jedis, service); + service.shutdown(); + Boolean success = queue.removeFromDequeue(jedis, "baz"); // ASSERT + assertThat(service.awaitTermination(0, SECONDS)).isTrue(); assertThat(success).isFalse(); } @@ -202,19 +208,22 @@ public void removeFromDequeueFalseWhenValueIsMissing() throws Exception { @Test public void removeFromDequeueTrueWhenValueExists() throws Exception { // ARRANGE - List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(redis); + List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags); + ExecutorService service = newSingleThreadExecutor(); // ACT - queue.push(redis, "foo"); - queue.push(redis, "bar"); - queue.push(redis, "baz"); - queue.dequeue(redis); - queue.dequeue(redis); - queue.dequeue(redis); - Boolean success = queue.removeFromDequeue(redis, "bar"); + queue.push(jedis, "foo"); + queue.push(jedis, "bar"); + queue.push(jedis, "baz"); + queue.dequeue(jedis, service); + queue.dequeue(jedis, service); + queue.dequeue(jedis, service); + service.shutdown(); + Boolean success = queue.removeFromDequeue(jedis, "bar"); // ASSERT + assertThat(service.awaitTermination(0, SECONDS)).isTrue(); assertThat(success).isTrue(); } @@ -224,7 +233,7 @@ public void removeFromDequeueTrueWhenValueExists() throws Exception { @Test public void getNameNameIsStored() throws Exception { // ARRANGE - List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(redis); + List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); BalancedRedisQueue queue = new BalancedRedisQueue("queue_name", hashtags); // ACT @@ -240,7 +249,7 @@ public void getNameNameIsStored() throws Exception { @Test public void getNameNameHasHashtagRemovedFront() throws Exception { // ARRANGE - List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(redis); + List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); BalancedRedisQueue queue = new BalancedRedisQueue("{hash}queue_name", hashtags); // ACT String name = queue.getName(); @@ -255,7 +264,7 @@ public void getNameNameHasHashtagRemovedFront() throws Exception { @Test public void getNameNameHasHashtagRemovedFrontPriority() throws Exception { // ARRANGE - List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(redis); + List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); BalancedRedisQueue queue = new BalancedRedisQueue("{hash}queue_name", hashtags, Queue.QUEUE_TYPE.priority); // ACT @@ -271,7 +280,7 @@ public void getNameNameHasHashtagRemovedFrontPriority() throws Exception { @Test public void getNameNameHasHashtagColonRemovedFront() throws Exception { // ARRANGE - List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(redis); + List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); // similar to what has been seen in configuration files BalancedRedisQueue queue = new BalancedRedisQueue("{Execution}:QueuedOperations", hashtags); // ACT @@ -287,7 +296,7 @@ public void getNameNameHasHashtagColonRemovedFront() throws Exception { @Test public void getNameNameHasHashtagColonRemovedFrontPriority() throws Exception { // ARRANGE - List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(redis); + List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); // similar to what has been seen in configuration files BalancedRedisQueue queue = new BalancedRedisQueue("{Execution}:QueuedOperations", hashtags, Queue.QUEUE_TYPE.priority); @@ -304,7 +313,7 @@ public void getNameNameHasHashtagColonRemovedFrontPriority() throws Exception { @Test public void getNameNameHasHashtagRemovedBack() throws Exception { // ARRANGE - List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(redis); + List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); BalancedRedisQueue queue = new BalancedRedisQueue("queue_name{hash}", hashtags); // ACT String name = queue.getName(); @@ -319,7 +328,7 @@ public void getNameNameHasHashtagRemovedBack() throws Exception { @Test public void getNameNameHasHashtagRemovedMiddle() throws Exception { // ARRANGE - List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(redis); + List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); BalancedRedisQueue queue = new BalancedRedisQueue("queue_{hash}name", hashtags); // ACT String name = queue.getName(); @@ -334,7 +343,7 @@ public void getNameNameHasHashtagRemovedMiddle() throws Exception { @Test public void getNameNameHasHashtagRemovedFrontBack() throws Exception { // ARRANGE - List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(redis); + List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); BalancedRedisQueue queue = new BalancedRedisQueue("{hash}queue_name{hash}", hashtags); // ACT String name = queue.getName(); @@ -349,35 +358,38 @@ public void getNameNameHasHashtagRemovedFrontBack() throws Exception { @Test public void sizeAdjustPushPop() throws Exception { // ARRANGE - List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(redis); + List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags); + ExecutorService service = newSingleThreadExecutor(); // ACT / ASSERT - assertThat(queue.size(redis)).isEqualTo(0); - queue.push(redis, "foo"); - assertThat(queue.size(redis)).isEqualTo(1); - queue.push(redis, "bar"); - assertThat(queue.size(redis)).isEqualTo(2); - queue.push(redis, "baz"); - assertThat(queue.size(redis)).isEqualTo(3); - queue.push(redis, "baz"); - assertThat(queue.size(redis)).isEqualTo(4); - queue.push(redis, "baz"); - assertThat(queue.size(redis)).isEqualTo(5); - queue.push(redis, "baz"); - assertThat(queue.size(redis)).isEqualTo(6); - queue.dequeue(redis); - assertThat(queue.size(redis)).isEqualTo(5); - queue.dequeue(redis); - assertThat(queue.size(redis)).isEqualTo(4); - queue.dequeue(redis); - assertThat(queue.size(redis)).isEqualTo(3); - queue.dequeue(redis); - assertThat(queue.size(redis)).isEqualTo(2); - queue.dequeue(redis); - assertThat(queue.size(redis)).isEqualTo(1); - queue.dequeue(redis); - assertThat(queue.size(redis)).isEqualTo(0); + assertThat(queue.size(jedis)).isEqualTo(0); + queue.push(jedis, "foo"); + assertThat(queue.size(jedis)).isEqualTo(1); + queue.push(jedis, "bar"); + assertThat(queue.size(jedis)).isEqualTo(2); + queue.push(jedis, "baz"); + assertThat(queue.size(jedis)).isEqualTo(3); + queue.push(jedis, "baz"); + assertThat(queue.size(jedis)).isEqualTo(4); + queue.push(jedis, "baz"); + assertThat(queue.size(jedis)).isEqualTo(5); + queue.push(jedis, "baz"); + assertThat(queue.size(jedis)).isEqualTo(6); + queue.dequeue(jedis, service); + assertThat(queue.size(jedis)).isEqualTo(5); + queue.dequeue(jedis, service); + assertThat(queue.size(jedis)).isEqualTo(4); + queue.dequeue(jedis, service); + assertThat(queue.size(jedis)).isEqualTo(3); + queue.dequeue(jedis, service); + assertThat(queue.size(jedis)).isEqualTo(2); + queue.dequeue(jedis, service); + assertThat(queue.size(jedis)).isEqualTo(1); + queue.dequeue(jedis, service); + assertThat(queue.size(jedis)).isEqualTo(0); + service.shutdown(); + assertThat(service.awaitTermination(0, SECONDS)).isTrue(); } // Function under test: size @@ -386,35 +398,38 @@ public void sizeAdjustPushPop() throws Exception { @Test public void sizeAdjustPushPopPriority() throws Exception { // ARRANGE - List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(redis); + List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags, Queue.QUEUE_TYPE.priority); + ExecutorService service = newSingleThreadExecutor(); // ACT / ASSERT - assertThat(queue.size(redis)).isEqualTo(0); - queue.push(redis, "foo"); - assertThat(queue.size(redis)).isEqualTo(1); - queue.push(redis, "bar"); - assertThat(queue.size(redis)).isEqualTo(2); - queue.push(redis, "baz"); - assertThat(queue.size(redis)).isEqualTo(3); - queue.push(redis, "baz"); - assertThat(queue.size(redis)).isEqualTo(4); - queue.push(redis, "baz"); - assertThat(queue.size(redis)).isEqualTo(5); - queue.push(redis, "baz"); - assertThat(queue.size(redis)).isEqualTo(6); - queue.dequeue(redis); - assertThat(queue.size(redis)).isEqualTo(5); - queue.dequeue(redis); - assertThat(queue.size(redis)).isEqualTo(4); - queue.dequeue(redis); - assertThat(queue.size(redis)).isEqualTo(3); - queue.dequeue(redis); - assertThat(queue.size(redis)).isEqualTo(2); - queue.dequeue(redis); - assertThat(queue.size(redis)).isEqualTo(1); - queue.dequeue(redis); - assertThat(queue.size(redis)).isEqualTo(0); + assertThat(queue.size(jedis)).isEqualTo(0); + queue.push(jedis, "foo"); + assertThat(queue.size(jedis)).isEqualTo(1); + queue.push(jedis, "bar"); + assertThat(queue.size(jedis)).isEqualTo(2); + queue.push(jedis, "baz"); + assertThat(queue.size(jedis)).isEqualTo(3); + queue.push(jedis, "baz"); + assertThat(queue.size(jedis)).isEqualTo(4); + queue.push(jedis, "baz"); + assertThat(queue.size(jedis)).isEqualTo(5); + queue.push(jedis, "baz"); + assertThat(queue.size(jedis)).isEqualTo(6); + queue.dequeue(jedis, service); + assertThat(queue.size(jedis)).isEqualTo(5); + queue.dequeue(jedis, service); + assertThat(queue.size(jedis)).isEqualTo(4); + queue.dequeue(jedis, service); + assertThat(queue.size(jedis)).isEqualTo(3); + queue.dequeue(jedis, service); + assertThat(queue.size(jedis)).isEqualTo(2); + queue.dequeue(jedis, service); + assertThat(queue.size(jedis)).isEqualTo(1); + queue.dequeue(jedis, service); + assertThat(queue.size(jedis)).isEqualTo(0); + service.shutdown(); + assertThat(service.awaitTermination(0, SECONDS)).isTrue(); } // Function under test: visit @@ -423,16 +438,16 @@ public void sizeAdjustPushPopPriority() throws Exception { @Test public void visitCheckVisitOfEachElement() throws Exception { // ARRANGE - List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(redis); + List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags); - queue.push(redis, "element 1"); - queue.push(redis, "element 2"); - queue.push(redis, "element 3"); - queue.push(redis, "element 4"); - queue.push(redis, "element 5"); - queue.push(redis, "element 6"); - queue.push(redis, "element 7"); - queue.push(redis, "element 8"); + queue.push(jedis, "element 1"); + queue.push(jedis, "element 2"); + queue.push(jedis, "element 3"); + queue.push(jedis, "element 4"); + queue.push(jedis, "element 5"); + queue.push(jedis, "element 6"); + queue.push(jedis, "element 7"); + queue.push(jedis, "element 8"); // ACT List visited = new ArrayList<>(); @@ -442,7 +457,7 @@ public void visit(String entry) { visited.add(entry); } }; - queue.visit(redis, visitor); + queue.visit(jedis, visitor); // ASSERT assertThat(visited.size()).isEqualTo(8); @@ -462,16 +477,16 @@ public void visit(String entry) { @Test public void visitCheckVisitOfEachElementPriority() throws Exception { // ARRANGE - List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(redis); + List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags, Queue.QUEUE_TYPE.priority); - queue.push(redis, "element 1"); - queue.push(redis, "element 2"); - queue.push(redis, "element 3"); - queue.push(redis, "element 4"); - queue.push(redis, "element 5"); - queue.push(redis, "element 6"); - queue.push(redis, "element 7"); - queue.push(redis, "element 8"); + queue.push(jedis, "element 1"); + queue.push(jedis, "element 2"); + queue.push(jedis, "element 3"); + queue.push(jedis, "element 4"); + queue.push(jedis, "element 5"); + queue.push(jedis, "element 6"); + queue.push(jedis, "element 7"); + queue.push(jedis, "element 8"); // ACT List visited = new ArrayList<>(); @@ -481,7 +496,7 @@ public void visit(String entry) { visited.add(entry); } }; - queue.visit(redis, visitor); + queue.visit(jedis, visitor); // ASSERT assertThat(visited.size()).isEqualTo(8); @@ -501,11 +516,11 @@ public void visit(String entry) { @Test public void isEvenlyDistributedEmptyIsEvenlyDistributed() throws Exception { // ARRANGE - List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(redis); + List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags); // ACT - Boolean isEvenlyDistributed = queue.isEvenlyDistributed(redis); + Boolean isEvenlyDistributed = queue.isEvenlyDistributed(jedis); // ASSERT assertThat(isEvenlyDistributed).isTrue(); @@ -517,11 +532,11 @@ public void isEvenlyDistributedEmptyIsEvenlyDistributed() throws Exception { @Test public void isEvenlyDistributedEmptyIsEvenlyDistributedPriority() throws Exception { // ARRANGE - List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(redis); + List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags, Queue.QUEUE_TYPE.priority); // ACT - Boolean isEvenlyDistributed = queue.isEvenlyDistributed(redis); + Boolean isEvenlyDistributed = queue.isEvenlyDistributed(jedis); // ASSERT assertThat(isEvenlyDistributed).isTrue(); @@ -539,9 +554,9 @@ public void isEvenlyDistributedFourNodesFourHundredPushesIsEven() throws Excepti // ACT for (int i = 0; i < 400; ++i) { - queue.push(redis, "foo"); + queue.push(jedis, "foo"); } - Boolean isEvenlyDistributed = queue.isEvenlyDistributed(redis); + Boolean isEvenlyDistributed = queue.isEvenlyDistributed(jedis); // ASSERT assertThat(isEvenlyDistributed).isTrue(); @@ -559,9 +574,9 @@ public void isEvenlyDistributedFourNodesFourHundredPushesIsEvenPriority() throws // ACT for (int i = 0; i < 400; ++i) { - queue.push(redis, "foo"); + queue.push(jedis, "foo"); } - Boolean isEvenlyDistributed = queue.isEvenlyDistributed(redis); + Boolean isEvenlyDistributed = queue.isEvenlyDistributed(jedis); // ASSERT assertThat(isEvenlyDistributed).isTrue(); @@ -579,9 +594,9 @@ public void isEvenlyDistributedFourNodesFourHundredOnePushesIsNotEven() throws E // ACT for (int i = 0; i < 401; ++i) { - queue.push(redis, "foo"); + queue.push(jedis, "foo"); } - Boolean isEvenlyDistributed = queue.isEvenlyDistributed(redis); + Boolean isEvenlyDistributed = queue.isEvenlyDistributed(jedis); // ASSERT assertThat(isEvenlyDistributed).isFalse(); @@ -599,9 +614,9 @@ public void isEvenlyDistributedFourNodesFourHundredOnePushesIsNotEvenPriority() // ACT for (int i = 0; i < 401; ++i) { - queue.push(redis, "foo"); + queue.push(jedis, "foo"); } - Boolean isEvenlyDistributed = queue.isEvenlyDistributed(redis); + Boolean isEvenlyDistributed = queue.isEvenlyDistributed(jedis); // ASSERT assertThat(isEvenlyDistributed).isFalse(); @@ -616,24 +631,27 @@ public void isEvenlyDistributedSingleNodeAlwaysEvenlyDistributes() throws Except // ARRANGE List hashtags = Collections.singletonList("single_node"); BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags); + ExecutorService service = newSingleThreadExecutor(); // ACT / ASSERT - queue.push(redis, "foo"); - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); - queue.push(redis, "foo"); - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); - queue.push(redis, "foo"); - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); - queue.push(redis, "foo"); - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); - queue.dequeue(redis); - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); - queue.dequeue(redis); - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); - queue.dequeue(redis); - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); - queue.dequeue(redis); - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); + queue.push(jedis, "foo"); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + queue.push(jedis, "foo"); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + queue.push(jedis, "foo"); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + queue.push(jedis, "foo"); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + queue.dequeue(jedis, service); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + queue.dequeue(jedis, service); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + queue.dequeue(jedis, service); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + queue.dequeue(jedis, service); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + service.shutdown(); + assertThat(service.awaitTermination(0, SECONDS)).isTrue(); } // Function under test: isEvenlyDistributed @@ -645,24 +663,27 @@ public void isEvenlyDistributedSingleNodeAlwaysEvenlyDistributesPriority() throw // ARRANGE List hashtags = Collections.singletonList("single_node"); BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags, Queue.QUEUE_TYPE.priority); + ExecutorService service = newSingleThreadExecutor(); // ACT / ASSERT - queue.push(redis, "foo"); - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); - queue.push(redis, "foo"); - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); - queue.push(redis, "foo"); - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); - queue.push(redis, "foo"); - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); - queue.dequeue(redis); - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); - queue.dequeue(redis); - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); - queue.dequeue(redis); - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); - queue.dequeue(redis); - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); + queue.push(jedis, "foo"); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + queue.push(jedis, "foo"); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + queue.push(jedis, "foo"); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + queue.push(jedis, "foo"); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + queue.dequeue(jedis, service); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + queue.dequeue(jedis, service); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + queue.dequeue(jedis, service); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + queue.dequeue(jedis, service); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + service.shutdown(); + assertThat(service.awaitTermination(0, SECONDS)).isTrue(); } // Function under test: isEvenlyDistributed @@ -673,37 +694,40 @@ public void isEvenlyDistributedTwoNodeExample() throws Exception { // ARRANGE List hashtags = Arrays.asList("node_1", "node_2"); BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags); + ExecutorService service = newSingleThreadExecutor(); // ACT / ASSERT - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); - queue.push(redis, "foo"); - assertThat(queue.isEvenlyDistributed(redis)).isFalse(); - queue.push(redis, "foo"); - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); - queue.push(redis, "foo"); - assertThat(queue.isEvenlyDistributed(redis)).isFalse(); - queue.push(redis, "foo"); - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); - queue.push(redis, "foo"); - assertThat(queue.isEvenlyDistributed(redis)).isFalse(); - queue.push(redis, "foo"); - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); - queue.push(redis, "foo"); - assertThat(queue.isEvenlyDistributed(redis)).isFalse(); - queue.dequeue(redis); - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); - queue.dequeue(redis); - assertThat(queue.isEvenlyDistributed(redis)).isFalse(); - queue.dequeue(redis); - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); - queue.dequeue(redis); - assertThat(queue.isEvenlyDistributed(redis)).isFalse(); - queue.dequeue(redis); - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); - queue.dequeue(redis); - assertThat(queue.isEvenlyDistributed(redis)).isFalse(); - queue.dequeue(redis); - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + queue.push(jedis, "foo"); + assertThat(queue.isEvenlyDistributed(jedis)).isFalse(); + queue.push(jedis, "foo"); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + queue.push(jedis, "foo"); + assertThat(queue.isEvenlyDistributed(jedis)).isFalse(); + queue.push(jedis, "foo"); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + queue.push(jedis, "foo"); + assertThat(queue.isEvenlyDistributed(jedis)).isFalse(); + queue.push(jedis, "foo"); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + queue.push(jedis, "foo"); + assertThat(queue.isEvenlyDistributed(jedis)).isFalse(); + queue.dequeue(jedis, service); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + queue.dequeue(jedis, service); + assertThat(queue.isEvenlyDistributed(jedis)).isFalse(); + queue.dequeue(jedis, service); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + queue.dequeue(jedis, service); + assertThat(queue.isEvenlyDistributed(jedis)).isFalse(); + queue.dequeue(jedis, service); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + queue.dequeue(jedis, service); + assertThat(queue.isEvenlyDistributed(jedis)).isFalse(); + queue.dequeue(jedis, service); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + service.shutdown(); + assertThat(service.awaitTermination(0, SECONDS)).isTrue(); } // Function under test: isEvenlyDistributed @@ -714,36 +738,39 @@ public void isEvenlyDistributedTwoNodeExamplePriority() throws Exception { // ARRANGE List hashtags = Arrays.asList("node_1", "node_2"); BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags, Queue.QUEUE_TYPE.priority); + ExecutorService service = newSingleThreadExecutor(); // ACT / ASSERT - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); - queue.push(redis, "foo"); - assertThat(queue.isEvenlyDistributed(redis)).isFalse(); - queue.push(redis, "foo1"); - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); - queue.push(redis, "foo2"); - assertThat(queue.isEvenlyDistributed(redis)).isFalse(); - queue.push(redis, "foo3"); - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); - queue.push(redis, "foo4"); - assertThat(queue.isEvenlyDistributed(redis)).isFalse(); - queue.push(redis, "foo5"); - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); - queue.push(redis, "foo6"); - assertThat(queue.isEvenlyDistributed(redis)).isFalse(); - queue.dequeue(redis); - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); - queue.dequeue(redis); - assertThat(queue.isEvenlyDistributed(redis)).isFalse(); - queue.dequeue(redis); - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); - queue.dequeue(redis); - assertThat(queue.isEvenlyDistributed(redis)).isFalse(); - queue.dequeue(redis); - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); - queue.dequeue(redis); - assertThat(queue.isEvenlyDistributed(redis)).isFalse(); - queue.dequeue(redis); - assertThat(queue.isEvenlyDistributed(redis)).isTrue(); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + queue.push(jedis, "foo"); + assertThat(queue.isEvenlyDistributed(jedis)).isFalse(); + queue.push(jedis, "foo1"); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + queue.push(jedis, "foo2"); + assertThat(queue.isEvenlyDistributed(jedis)).isFalse(); + queue.push(jedis, "foo3"); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + queue.push(jedis, "foo4"); + assertThat(queue.isEvenlyDistributed(jedis)).isFalse(); + queue.push(jedis, "foo5"); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + queue.push(jedis, "foo6"); + assertThat(queue.isEvenlyDistributed(jedis)).isFalse(); + queue.dequeue(jedis, service); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + queue.dequeue(jedis, service); + assertThat(queue.isEvenlyDistributed(jedis)).isFalse(); + queue.dequeue(jedis, service); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + queue.dequeue(jedis, service); + assertThat(queue.isEvenlyDistributed(jedis)).isFalse(); + queue.dequeue(jedis, service); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + queue.dequeue(jedis, service); + assertThat(queue.isEvenlyDistributed(jedis)).isFalse(); + queue.dequeue(jedis, service); + assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); + service.shutdown(); + assertThat(service.awaitTermination(0, SECONDS)).isTrue(); } } diff --git a/src/test/java/build/buildfarm/common/redis/RedisClientTest.java b/src/test/java/build/buildfarm/common/redis/RedisClientTest.java index f6855af23c..16e58c0627 100644 --- a/src/test/java/build/buildfarm/common/redis/RedisClientTest.java +++ b/src/test/java/build/buildfarm/common/redis/RedisClientTest.java @@ -26,7 +26,7 @@ import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import redis.clients.jedis.JedisCluster; -import redis.clients.jedis.exceptions.JedisClusterMaxAttemptsException; +import redis.clients.jedis.exceptions.JedisClusterOperationException; import redis.clients.jedis.exceptions.JedisConnectionException; @RunWith(JUnit4.class) @@ -82,8 +82,8 @@ public void runJedisClusterMaxAttemptsExceptionIsUnavailable() { RedisClient client = new RedisClient(mock(JedisCluster.class)); Status status = Status.UNKNOWN; try { - JedisClusterMaxAttemptsException jcoe = - new JedisClusterMaxAttemptsException("No more cluster attempts left."); + JedisClusterOperationException jcoe = + new JedisClusterOperationException("No more cluster attempts left."); jcoe.addSuppressed(new JedisConnectionException(new SocketException("Connection reset"))); client.run( jedis -> { diff --git a/src/test/java/build/buildfarm/common/redis/RedisHashMapTest.java b/src/test/java/build/buildfarm/common/redis/RedisHashMapTest.java index dc6d559b3e..d66f00baf4 100644 --- a/src/test/java/build/buildfarm/common/redis/RedisHashMapTest.java +++ b/src/test/java/build/buildfarm/common/redis/RedisHashMapTest.java @@ -29,7 +29,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.UnifiedJedis; /** * @class RedisHashMapTest @@ -42,7 +42,7 @@ @RunWith(JUnit4.class) public class RedisHashMapTest { private BuildfarmConfigs configs = BuildfarmConfigs.getInstance(); - private JedisCluster redis; + private UnifiedJedis redis; @Before public void setUp() throws Exception { diff --git a/src/test/java/build/buildfarm/common/redis/RedisNodeHashesMockTest.java b/src/test/java/build/buildfarm/common/redis/RedisNodeHashesMockTest.java index fe1e755f8b..e5a02f8e71 100644 --- a/src/test/java/build/buildfarm/common/redis/RedisNodeHashesMockTest.java +++ b/src/test/java/build/buildfarm/common/redis/RedisNodeHashesMockTest.java @@ -15,20 +15,28 @@ package build.buildfarm.common.redis; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; +import static redis.clients.jedis.Protocol.ClusterKeyword.SHARDS; +import static redis.clients.jedis.Protocol.Command.CLUSTER; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import redis.clients.jedis.Jedis; +import redis.clients.jedis.Connection; +import redis.clients.jedis.ConnectionPool; import redis.clients.jedis.JedisCluster; -import redis.clients.jedis.JedisPool; +import redis.clients.jedis.resps.ClusterShardInfo; import redis.clients.jedis.util.SafeEncoder; /** @@ -47,17 +55,23 @@ public class RedisNodeHashesMockTest { @Test public void getEvenlyDistributedHashesCanRetrieveDistributedHashes() throws Exception { // ARRANGE - Jedis node = mock(Jedis.class); - when(node.clusterSlots()) - .thenReturn( - Collections.singletonList( - Arrays.asList(0L, 100L, Arrays.asList(null, null, SafeEncoder.encode("nodeId"))))); + Connection connection = spy(Connection.class); + doNothing().when(connection).connect(); + doNothing().when(connection).sendCommand(CLUSTER, SHARDS); + doReturn( + Arrays.asList( + Arrays.asList( + SafeEncoder.encode(ClusterShardInfo.SLOTS), Arrays.asList(0L, 100L), + SafeEncoder.encode(ClusterShardInfo.NODES), Arrays.asList()))) + .when(connection) + .getObjectMultiBulkReply(); - JedisPool pool = mock(JedisPool.class); - when(pool.getResource()).thenReturn(node); + ConnectionPool pool = mock(ConnectionPool.class); + when(pool.getResource()).thenReturn(connection); + connection.setHandlingPool(pool); JedisCluster redis = mock(JedisCluster.class); - Map poolMap = new HashMap<>(); + Map poolMap = new HashMap<>(); poolMap.put("key1", pool); when(redis.getClusterNodes()).thenReturn(poolMap); @@ -66,6 +80,9 @@ public void getEvenlyDistributedHashesCanRetrieveDistributedHashes() throws Exce // ASSERT assertThat(hashtags.isEmpty()).isFalse(); + verify(pool, times(1)).getResource(); + verify(pool, times(1)).returnResource(connection); + verifyNoMoreInteractions(pool); } // Function under test: getEvenlyDistributedHashes @@ -99,19 +116,27 @@ public void getEvenlyDistributedHashesCanConstruct() throws Exception { @Test public void getEvenlyDistributedHashesWithPrefixExpectedPrefixHashes() throws Exception { // ARRANGE - Jedis node = mock(Jedis.class); - when(node.clusterSlots()) - .thenReturn( + Connection connection = spy(Connection.class); + doNothing().when(connection).connect(); + doNothing().when(connection).sendCommand(CLUSTER, SHARDS); + doReturn( Arrays.asList( - Arrays.asList(0L, 100L, Arrays.asList(null, null, SafeEncoder.encode("nodeId1"))), Arrays.asList( - 101L, 200L, Arrays.asList(null, null, SafeEncoder.encode("nodeId2"))))); + SafeEncoder.encode(ClusterShardInfo.SLOTS), Arrays.asList(0L, 100L), + SafeEncoder.encode(ClusterShardInfo.NODES), Arrays.asList()), + Arrays.asList( + SafeEncoder.encode(ClusterShardInfo.SLOTS), Arrays.asList(101L, 200L), + SafeEncoder.encode(ClusterShardInfo.NODES), Arrays.asList()))) + .when(connection) + .getObjectMultiBulkReply(); + doReturn(false).when(connection).isBroken(); - JedisPool pool = mock(JedisPool.class); - when(pool.getResource()).thenReturn(node); + ConnectionPool pool = mock(ConnectionPool.class); + when(pool.getResource()).thenReturn(connection); + connection.setHandlingPool(pool); JedisCluster redis = mock(JedisCluster.class); - Map poolMap = new HashMap<>(); + Map poolMap = new HashMap<>(); poolMap.put("key1", pool); when(redis.getClusterNodes()).thenReturn(poolMap); @@ -120,8 +145,17 @@ public void getEvenlyDistributedHashesWithPrefixExpectedPrefixHashes() throws Ex RedisNodeHashes.getEvenlyDistributedHashesWithPrefix(redis, "Execution"); // ASSERT + verify(connection, times(1)).sendCommand(CLUSTER, SHARDS); + verify(connection, times(1)).getObjectMultiBulkReply(); + verify(connection, times(1)).close(); + verify(connection, times(1)).isBroken(); + verify(connection, times(1)).setHandlingPool(pool); + verifyNoMoreInteractions(connection); assertThat(hashtags.size()).isEqualTo(2); assertThat(hashtags.get(0)).isEqualTo("Execution:97"); assertThat(hashtags.get(1)).isEqualTo("Execution:66"); + verify(pool, times(1)).getResource(); + verify(pool, times(1)).returnResource(connection); + verifyNoMoreInteractions(pool); } } diff --git a/src/test/java/build/buildfarm/common/redis/RedisPriorityQueueMockTest.java b/src/test/java/build/buildfarm/common/redis/RedisPriorityQueueMockTest.java index 300dec24a5..ecab18059b 100644 --- a/src/test/java/build/buildfarm/common/redis/RedisPriorityQueueMockTest.java +++ b/src/test/java/build/buildfarm/common/redis/RedisPriorityQueueMockTest.java @@ -16,14 +16,17 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.any; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; import build.buildfarm.common.StringVisitor; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.concurrent.ExecutorService; import java.util.stream.Collectors; import java.util.stream.Stream; import org.junit.Before; @@ -32,7 +35,7 @@ import org.junit.runners.JUnit4; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.Jedis; /** * @class RedisPriorityQueueMockTest @@ -45,7 +48,7 @@ */ @RunWith(JUnit4.class) public class RedisPriorityQueueMockTest { - @Mock private JedisCluster redis; + @Mock private Jedis redis; @Mock private Timestamp time; @Before @@ -199,12 +202,14 @@ public void dequeueElementCanBeDequeuedWithTimeout() throws Exception { // ARRANGE when(redis.eval(any(String.class), any(List.class), any(List.class))).thenReturn("foo"); RedisPriorityQueue queue = new RedisPriorityQueue("test"); + ExecutorService service = mock(ExecutorService.class); // ACT queue.push(redis, "foo"); - String val = queue.dequeue(redis, 1); + String val = queue.dequeue(redis, 1, service); // ASSERT + verifyNoInteractions(service); assertThat(val).isEqualTo("foo"); } @@ -216,12 +221,14 @@ public void dequeueElementIsNotDequeuedIfTimeRunsOut() throws Exception { // ARRANGE when(redis.eval(any(String.class), any(List.class), any(List.class))).thenReturn(null); RedisPriorityQueue queue = new RedisPriorityQueue("test"); + ExecutorService service = mock(ExecutorService.class); // ACT queue.push(redis, "foo"); - String val = queue.dequeue(redis, 5); + String val = queue.dequeue(redis, 5, service); // ASSERT + verifyNoInteractions(service); assertThat(val).isEqualTo(null); } @@ -233,6 +240,7 @@ public void dequeueInterrupt() throws Exception { // ARRANGE when(redis.eval(any(String.class), any(List.class), any(List.class))).thenReturn(null); RedisPriorityQueue queue = new RedisPriorityQueue("test"); + ExecutorService service = mock(ExecutorService.class); // ACT queue.push(redis, "foo"); @@ -240,12 +248,14 @@ public void dequeueInterrupt() throws Exception { new Thread( () -> { try { - queue.dequeue(redis, 100000); + queue.dequeue(redis, 100000, service); } catch (Exception e) { } }); call.start(); call.interrupt(); + call.join(); + verifyNoInteractions(service); } // Function under test: nonBlockingDequeue @@ -312,7 +322,7 @@ public void visitCheckVisitOfEachElement() throws Exception { "element 6", "element 7", "element 8") - .collect(Collectors.toSet())); + .collect(Collectors.toList())); // ARRANGE RedisPriorityQueue queue = new RedisPriorityQueue("test"); diff --git a/src/test/java/build/buildfarm/common/redis/RedisPriorityQueueTest.java b/src/test/java/build/buildfarm/common/redis/RedisPriorityQueueTest.java index 0f507c3fb6..4c88bdc11c 100644 --- a/src/test/java/build/buildfarm/common/redis/RedisPriorityQueueTest.java +++ b/src/test/java/build/buildfarm/common/redis/RedisPriorityQueueTest.java @@ -15,6 +15,8 @@ package build.buildfarm.common.redis; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verifyNoInteractions; import build.buildfarm.common.StringVisitor; import build.buildfarm.common.config.BuildfarmConfigs; @@ -23,12 +25,15 @@ import java.time.Instant; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.ExecutorService; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPooled; +import redis.clients.jedis.UnifiedJedis; /** * @class RedisPriorityQueueTest @@ -42,17 +47,22 @@ @RunWith(JUnit4.class) public class RedisPriorityQueueTest { private BuildfarmConfigs configs = BuildfarmConfigs.getInstance(); - private JedisCluster redis; + private JedisPooled pooled; + private Jedis redis; @Before public void setUp() throws Exception { configs.getBackplane().setRedisUri("redis://localhost:6379"); - redis = JedisClusterFactory.createTest(); + UnifiedJedis unified = JedisClusterFactory.createTest(); + assertThat(unified).isInstanceOf(JedisPooled.class); + pooled = (JedisPooled) unified; + redis = new Jedis(pooled.getPool().getResource()); } @After public void tearDown() { redis.close(); + pooled.close(); } // Function under test: RedisPriorityQueue @@ -185,6 +195,7 @@ public void getDequeueNameNameIsStored() throws Exception { public void sizeAdjustPushDequeue() throws Exception { // ARRANGE RedisPriorityQueue queue = new RedisPriorityQueue("test"); + ExecutorService service = mock(ExecutorService.class); // ACT / ASSERT assertThat(queue.size(redis)).isEqualTo(0); @@ -200,18 +211,19 @@ public void sizeAdjustPushDequeue() throws Exception { assertThat(queue.size(redis)).isEqualTo(5); queue.push(redis, "baz4"); assertThat(queue.size(redis)).isEqualTo(6); - queue.dequeue(redis, 1); + queue.dequeue(redis, 1, service); assertThat(queue.size(redis)).isEqualTo(5); - queue.dequeue(redis, 1); + queue.dequeue(redis, 1, service); assertThat(queue.size(redis)).isEqualTo(4); - queue.dequeue(redis, 1); + queue.dequeue(redis, 1, service); assertThat(queue.size(redis)).isEqualTo(3); - queue.dequeue(redis, 1); + queue.dequeue(redis, 1, service); assertThat(queue.size(redis)).isEqualTo(2); - queue.dequeue(redis, 1); + queue.dequeue(redis, 1, service); assertThat(queue.size(redis)).isEqualTo(1); - queue.dequeue(redis, 1); + queue.dequeue(redis, 1, service); assertThat(queue.size(redis)).isEqualTo(0); + verifyNoInteractions(service); } // Function under test: size @@ -221,6 +233,7 @@ public void sizeAdjustPushDequeue() throws Exception { public void checkPriorityOnDequeue() throws Exception { // ARRANGE RedisPriorityQueue queue = new RedisPriorityQueue("test"); + ExecutorService service = mock(ExecutorService.class); String val; // ACT / ASSERT assertThat(queue.size(redis)).isEqualTo(0); @@ -236,24 +249,25 @@ public void checkPriorityOnDequeue() throws Exception { assertThat(queue.size(redis)).isEqualTo(5); queue.push(redis, "baz4", 1); assertThat(queue.size(redis)).isEqualTo(6); - val = queue.dequeue(redis, 1); + val = queue.dequeue(redis, 1, service); assertThat(val).isEqualTo("bar"); assertThat(queue.size(redis)).isEqualTo(5); - val = queue.dequeue(redis, 1); + val = queue.dequeue(redis, 1, service); assertThat(val).isEqualTo("baz2"); assertThat(queue.size(redis)).isEqualTo(4); - val = queue.dequeue(redis, 1); + val = queue.dequeue(redis, 1, service); assertThat(val).isEqualTo("baz4"); assertThat(queue.size(redis)).isEqualTo(3); - val = queue.dequeue(redis, 1); + val = queue.dequeue(redis, 1, service); assertThat(val).isEqualTo("foo"); assertThat(queue.size(redis)).isEqualTo(2); - val = queue.dequeue(redis, 1); + val = queue.dequeue(redis, 1, service); assertThat(val).isEqualTo("baz3"); assertThat(queue.size(redis)).isEqualTo(1); - val = queue.dequeue(redis, 1); + val = queue.dequeue(redis, 1, service); assertThat(val).isEqualTo("baz"); assertThat(queue.size(redis)).isEqualTo(0); + verifyNoInteractions(service); } // Function under test: dequeue @@ -263,14 +277,16 @@ public void checkPriorityOnDequeue() throws Exception { public void checkDequeueTimeout() throws Exception { // ARRANGE RedisPriorityQueue queue = new RedisPriorityQueue("test"); + ExecutorService service = mock(ExecutorService.class); Instant start = Instant.now(); - String val = queue.dequeue(redis, 1); + String val = queue.dequeue(redis, 1, service); Instant finish = Instant.now(); long timeElapsed = Duration.between(start, finish).toMillis(); assertThat(timeElapsed).isGreaterThan(1000L); assertThat(val).isEqualTo(null); + verifyNoInteractions(service); } // Function under test: dequeue @@ -280,6 +296,7 @@ public void checkDequeueTimeout() throws Exception { public void checkNegativesInPriority() throws Exception { // ARRANGE RedisPriorityQueue queue = new RedisPriorityQueue("test"); + ExecutorService service = mock(ExecutorService.class); String val; // ACT / ASSERT @@ -292,22 +309,23 @@ public void checkNegativesInPriority() throws Exception { queue.push(redis, "baz-2", 2); queue.push(redis, "foo-4", 4); - val = queue.dequeue(redis, 1); + val = queue.dequeue(redis, 1, service); assertThat(val).isEqualTo("negative-50"); - val = queue.dequeue(redis, 1); + val = queue.dequeue(redis, 1, service); assertThat(val).isEqualTo("negative-1"); - val = queue.dequeue(redis, 1); + val = queue.dequeue(redis, 1, service); assertThat(val).isEqualTo("foo-1"); - val = queue.dequeue(redis, 1); + val = queue.dequeue(redis, 1, service); assertThat(val).isEqualTo("baz-2"); - val = queue.dequeue(redis, 1); + val = queue.dequeue(redis, 1, service); assertThat(val).isEqualTo("foo-3"); - val = queue.dequeue(redis, 1); + val = queue.dequeue(redis, 1, service); assertThat(val).isEqualTo("foo-4"); - val = queue.dequeue(redis, 1); + val = queue.dequeue(redis, 1, service); assertThat(val).isEqualTo("foo-5"); - val = queue.dequeue(redis, 1); + val = queue.dequeue(redis, 1, service); assertThat(val).isEqualTo("foo-6"); + verifyNoInteractions(service); } // Function under test: visit diff --git a/src/test/java/build/buildfarm/common/redis/RedisQueueMockTest.java b/src/test/java/build/buildfarm/common/redis/RedisQueueMockTest.java index c0cf68e61b..7a428c412b 100644 --- a/src/test/java/build/buildfarm/common/redis/RedisQueueMockTest.java +++ b/src/test/java/build/buildfarm/common/redis/RedisQueueMockTest.java @@ -15,22 +15,28 @@ package build.buildfarm.common.redis; import static com.google.common.truth.Truth.assertThat; +import static java.util.concurrent.Executors.newSingleThreadExecutor; +import static java.util.concurrent.TimeUnit.SECONDS; import static org.mockito.Mockito.any; +import static org.mockito.Mockito.eq; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static redis.clients.jedis.args.ListDirection.LEFT; +import static redis.clients.jedis.args.ListDirection.RIGHT; import build.buildfarm.common.StringVisitor; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.concurrent.ExecutorService; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.Jedis; /** * @class RedisQueueMockTest @@ -43,7 +49,7 @@ */ @RunWith(JUnit4.class) public class RedisQueueMockTest { - @Mock private JedisCluster redis; + @Mock private Jedis redis; @Before public void setUp() { @@ -174,15 +180,18 @@ public void removeFromDequeueRemoveADequeueValue() throws Exception { @Test public void dequeueElementCanBeDequeuedWithTimeout() throws Exception { // ARRANGE - when(redis.brpoplpush("test", "test_dequeue", 1)).thenReturn("foo"); + when(redis.blmove(eq("test"), eq("test_dequeue"), eq(RIGHT), eq(LEFT), any(double.class))) + .thenReturn("foo"); RedisQueue queue = new RedisQueue("test"); + ExecutorService service = newSingleThreadExecutor(); // ACT - queue.push(redis, "foo"); - String val = queue.dequeue(redis, 1); + String val = queue.dequeue(redis, 1, service); + service.shutdown(); // ASSERT assertThat(val).isEqualTo("foo"); + assertThat(service.awaitTermination(1, SECONDS)).isTrue(); } // Function under test: dequeue @@ -191,14 +200,18 @@ public void dequeueElementCanBeDequeuedWithTimeout() throws Exception { @Test public void dequeueElementIsNotDequeuedIfTimeRunsOut() throws Exception { // ARRANGE - when(redis.brpoplpush("test", "test_dequeue", 1)).thenReturn(null); + when(redis.blmove(eq("test"), eq("test_dequeue"), eq(RIGHT), eq(LEFT), any(double.class))) + .thenReturn(null); RedisQueue queue = new RedisQueue("test"); + ExecutorService service = newSingleThreadExecutor(); // ACT - queue.push(redis, "foo"); - String val = queue.dequeue(redis, 5); + String val = queue.dequeue(redis, 5, service); + service.shutdown(); // ASSERT + // future submission may still be completing after interrupt + assertThat(service.awaitTermination(1, SECONDS)).isTrue(); assertThat(val).isEqualTo(null); } @@ -208,21 +221,23 @@ public void dequeueElementIsNotDequeuedIfTimeRunsOut() throws Exception { @Test public void dequeueInterrupt() throws Exception { // ARRANGE - when(redis.brpoplpush("test", "test_dequeue", 1)).thenReturn(null); + when(redis.blmove(eq("test"), eq("test_dequeue"), eq(RIGHT), eq(LEFT), any(double.class))) + .thenReturn(null); RedisQueue queue = new RedisQueue("test"); + ExecutorService service = newSingleThreadExecutor(); // ACT - queue.push(redis, "foo"); Thread call = new Thread( () -> { try { - queue.dequeue(redis, 100000); + queue.dequeue(redis, 100000, service); } catch (Exception e) { } }); call.start(); call.interrupt(); + call.join(); } // Function under test: nonBlockingDequeue @@ -231,11 +246,10 @@ public void dequeueInterrupt() throws Exception { @Test public void nonBlockingDequeueElementCanBeDequeued() throws Exception { // ARRANGE - when(redis.rpoplpush("test", "test_dequeue")).thenReturn("foo"); + when(redis.lmove("test", "test_dequeue", RIGHT, LEFT)).thenReturn("foo"); RedisQueue queue = new RedisQueue("test"); // ACT - queue.push(redis, "foo"); String val = queue.nonBlockingDequeue(redis); // ASSERT @@ -292,14 +306,6 @@ public void visitCheckVisitOfEachElement() throws Exception { // ARRANGE RedisQueue queue = new RedisQueue("test"); - queue.push(redis, "element 1"); - queue.push(redis, "element 2"); - queue.push(redis, "element 3"); - queue.push(redis, "element 4"); - queue.push(redis, "element 5"); - queue.push(redis, "element 6"); - queue.push(redis, "element 7"); - queue.push(redis, "element 8"); // ACT List visited = new ArrayList<>(); diff --git a/src/test/java/build/buildfarm/common/redis/RedisQueueTest.java b/src/test/java/build/buildfarm/common/redis/RedisQueueTest.java index 23e46ca285..3f8b631148 100644 --- a/src/test/java/build/buildfarm/common/redis/RedisQueueTest.java +++ b/src/test/java/build/buildfarm/common/redis/RedisQueueTest.java @@ -15,18 +15,23 @@ package build.buildfarm.common.redis; import static com.google.common.truth.Truth.assertThat; +import static java.util.concurrent.Executors.newSingleThreadExecutor; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import build.buildfarm.common.StringVisitor; import build.buildfarm.common.config.BuildfarmConfigs; import build.buildfarm.instance.shard.JedisClusterFactory; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.ExecutorService; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPooled; +import redis.clients.jedis.UnifiedJedis; /** * @class RedisQueueTest @@ -40,17 +45,22 @@ @RunWith(JUnit4.class) public class RedisQueueTest { private BuildfarmConfigs configs = BuildfarmConfigs.getInstance(); - private JedisCluster redis; + private JedisPooled pooled; + private Jedis redis; @Before public void setUp() throws Exception { configs.getBackplane().setRedisUri("redis://localhost:6379"); - redis = JedisClusterFactory.createTest(); + UnifiedJedis unified = JedisClusterFactory.createTest(); + assertThat(unified).isInstanceOf(JedisPooled.class); + pooled = (JedisPooled) unified; + redis = new Jedis(pooled.getPool().getResource()); } @After public void tearDown() { redis.close(); + pooled.close(); } // Function under test: RedisQueue @@ -183,6 +193,7 @@ public void getDequeueNameNameIsStored() throws Exception { public void sizeAdjustPushDequeue() throws Exception { // ARRANGE RedisQueue queue = new RedisQueue("{hash}test"); + ExecutorService service = newSingleThreadExecutor(); // ACT / ASSERT assertThat(queue.size(redis)).isEqualTo(0); queue.push(redis, "foo"); @@ -197,18 +208,20 @@ public void sizeAdjustPushDequeue() throws Exception { assertThat(queue.size(redis)).isEqualTo(5); queue.push(redis, "baz"); assertThat(queue.size(redis)).isEqualTo(6); - queue.dequeue(redis, 1); + queue.dequeue(redis, 1, service); assertThat(queue.size(redis)).isEqualTo(5); - queue.dequeue(redis, 1); + queue.dequeue(redis, 1, service); assertThat(queue.size(redis)).isEqualTo(4); - queue.dequeue(redis, 1); + queue.dequeue(redis, 1, service); assertThat(queue.size(redis)).isEqualTo(3); - queue.dequeue(redis, 1); + queue.dequeue(redis, 1, service); assertThat(queue.size(redis)).isEqualTo(2); - queue.dequeue(redis, 1); + queue.dequeue(redis, 1, service); assertThat(queue.size(redis)).isEqualTo(1); - queue.dequeue(redis, 1); + queue.dequeue(redis, 1, service); assertThat(queue.size(redis)).isEqualTo(0); + service.shutdown(); + assertThat(service.awaitTermination(1, MILLISECONDS)).isTrue(); } // Function under test: visit diff --git a/src/test/java/build/buildfarm/common/redis/RedisSlotToHashTest.java b/src/test/java/build/buildfarm/common/redis/RedisSlotToHashTest.java index 4fd08de251..7cb7e59f43 100644 --- a/src/test/java/build/buildfarm/common/redis/RedisSlotToHashTest.java +++ b/src/test/java/build/buildfarm/common/redis/RedisSlotToHashTest.java @@ -15,8 +15,9 @@ package build.buildfarm.common.redis; import static com.google.common.truth.Truth.assertThat; -import static redis.clients.jedis.JedisCluster.HASHSLOTS; +import static redis.clients.jedis.Protocol.CLUSTER_HASHSLOTS; +import com.google.common.collect.ImmutableList; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -41,7 +42,7 @@ public class RedisSlotToHashTest { // slot numbers to strings is incorrect @Test public void correlateCorrectForEverySlot() throws Exception { - for (int i = 0; i < HASHSLOTS; ++i) { + for (int i = 0; i < CLUSTER_HASHSLOTS; ++i) { // convert to hashtag String hashtag = RedisSlotToHash.correlate(i); @@ -82,7 +83,9 @@ public void correlateRangeCorrectHashtagFoundForSlotRange() throws Exception { @Test public void correlateRangeWithPrefixCorrectHashtagFoundForSlotRange() throws Exception { // convert to hashtag - String hashtag = RedisSlotToHash.correlateRangeWithPrefix(100, 200, "Execution"); + String hashtag = + RedisSlotToHash.correlateRangesWithPrefix( + ImmutableList.of(ImmutableList.of(100l, 200l)), "Execution"); // convert hashtag back to slot int slotNumber = JedisClusterCRC16.getSlot(hashtag); diff --git a/src/test/java/build/buildfarm/common/resources/BUILD b/src/test/java/build/buildfarm/common/resources/BUILD index 3457160a4f..ab39387fc7 100644 --- a/src/test/java/build/buildfarm/common/resources/BUILD +++ b/src/test/java/build/buildfarm/common/resources/BUILD @@ -9,7 +9,6 @@ java_test( "//src/main/java/build/buildfarm/common/resources:resource_java_proto", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "//third_party/jedis", "@googleapis//:google_bytestream_bytestream_java_proto", "@googleapis//:google_rpc_error_details_java_proto", "@maven//:com_google_guava_guava", @@ -22,6 +21,7 @@ java_test( "@maven//:io_grpc_grpc_stub", "@maven//:io_grpc_grpc_testing", "@maven//:org_mockito_mockito_core", + "@maven//:redis_clients_jedis", "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) diff --git a/src/test/java/build/buildfarm/examples/BUILD b/src/test/java/build/buildfarm/examples/BUILD index a0204865e5..5bfd97b6e3 100644 --- a/src/test/java/build/buildfarm/examples/BUILD +++ b/src/test/java/build/buildfarm/examples/BUILD @@ -8,7 +8,6 @@ java_test( "//src/main/java/build/buildfarm/common/config", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "//third_party/jedis", "@googleapis//:google_bytestream_bytestream_java_proto", "@googleapis//:google_rpc_error_details_java_proto", "@maven//:com_google_guava_guava", @@ -21,5 +20,6 @@ java_test( "@maven//:io_grpc_grpc_stub", "@maven//:io_grpc_grpc_testing", "@maven//:org_mockito_mockito_core", + "@maven//:redis_clients_jedis", ], ) diff --git a/src/test/java/build/buildfarm/instance/shard/BUILD b/src/test/java/build/buildfarm/instance/shard/BUILD index 2f08b1003d..66a5b71f2d 100644 --- a/src/test/java/build/buildfarm/instance/shard/BUILD +++ b/src/test/java/build/buildfarm/instance/shard/BUILD @@ -17,7 +17,6 @@ java_test( "//src/main/java/build/buildfarm/instance/shard", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "//third_party/jedis", "@googleapis//:google_longrunning_operations_java_proto", "@googleapis//:google_rpc_code_java_proto", "@googleapis//:google_rpc_error_details_java_proto", @@ -31,6 +30,7 @@ java_test( "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", "@maven//:org_mockito_mockito_core", + "@maven//:redis_clients_jedis", "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) @@ -49,12 +49,12 @@ java_test( "//src/main/java/build/buildfarm/backplane", "//src/main/java/build/buildfarm/common", "//src/main/java/build/buildfarm/common/config", + "//src/main/java/build/buildfarm/common/redis", "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/instance/server", "//src/main/java/build/buildfarm/instance/shard", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "//third_party/jedis", "@googleapis//:google_longrunning_operations_java_proto", "@googleapis//:google_rpc_code_java_proto", "@googleapis//:google_rpc_error_details_java_proto", @@ -68,6 +68,7 @@ java_test( "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", "@maven//:org_mockito_mockito_core", + "@maven//:redis_clients_jedis", "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) @@ -91,7 +92,6 @@ java_test( "//src/main/java/build/buildfarm/instance/shard", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "//third_party/jedis", "@googleapis//:google_longrunning_operations_java_proto", "@googleapis//:google_rpc_code_java_proto", "@googleapis//:google_rpc_error_details_java_proto", @@ -105,6 +105,7 @@ java_test( "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", "@maven//:org_mockito_mockito_core", + "@maven//:redis_clients_jedis", "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) @@ -128,7 +129,6 @@ java_test( "//src/main/java/build/buildfarm/instance/shard", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "//third_party/jedis", "@googleapis//:google_longrunning_operations_java_proto", "@googleapis//:google_rpc_code_java_proto", "@googleapis//:google_rpc_error_details_java_proto", @@ -142,6 +142,7 @@ java_test( "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", "@maven//:org_mockito_mockito_core", + "@maven//:redis_clients_jedis", "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) @@ -165,7 +166,6 @@ java_test( "//src/main/java/build/buildfarm/instance/shard", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "//third_party/jedis", "@googleapis//:google_longrunning_operations_java_proto", "@googleapis//:google_rpc_code_java_proto", "@googleapis//:google_rpc_error_details_java_proto", @@ -179,6 +179,7 @@ java_test( "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", "@maven//:org_mockito_mockito_core", + "@maven//:redis_clients_jedis", "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) @@ -202,7 +203,6 @@ java_test( "//src/main/java/build/buildfarm/instance/shard", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "//third_party/jedis", "@googleapis//:google_longrunning_operations_java_proto", "@googleapis//:google_rpc_code_java_proto", "@googleapis//:google_rpc_error_details_java_proto", @@ -216,6 +216,7 @@ java_test( "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", "@maven//:org_mockito_mockito_core", + "@maven//:redis_clients_jedis", "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) @@ -233,8 +234,8 @@ java_test( "//src/main/java/build/buildfarm/instance/shard", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "//third_party/jedis", "@maven//:com_github_fppt_jedis_mock", "@maven//:com_google_truth_truth", + "@maven//:redis_clients_jedis", ], ) diff --git a/src/test/java/build/buildfarm/instance/shard/RedisShardBackplaneTest.java b/src/test/java/build/buildfarm/instance/shard/RedisShardBackplaneTest.java index f0dd36c4fb..d6812ed259 100644 --- a/src/test/java/build/buildfarm/instance/shard/RedisShardBackplaneTest.java +++ b/src/test/java/build/buildfarm/instance/shard/RedisShardBackplaneTest.java @@ -22,26 +22,30 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import build.bazel.remote.execution.v2.Digest; -import build.bazel.remote.execution.v2.Platform; import build.bazel.remote.execution.v2.RequestMetadata; import build.buildfarm.common.config.BuildfarmConfigs; import build.buildfarm.common.config.Queue; +import build.buildfarm.common.redis.BalancedRedisQueue; +import build.buildfarm.common.redis.RedisClient; +import build.buildfarm.common.redis.RedisHashMap; +import build.buildfarm.common.redis.RedisMap; import build.buildfarm.v1test.DispatchedOperation; import build.buildfarm.v1test.ExecuteEntry; import build.buildfarm.v1test.OperationChange; import build.buildfarm.v1test.QueueEntry; import build.buildfarm.v1test.ShardWorker; import build.buildfarm.v1test.WorkerChange; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.longrunning.Operation; import com.google.protobuf.util.JsonFormat; import java.io.IOException; import java.time.Instant; -import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; @@ -55,13 +59,13 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.UnifiedJedis; @RunWith(JUnit4.class) public class RedisShardBackplaneTest { private BuildfarmConfigs configs = BuildfarmConfigs.getInstance(); - @Mock Supplier mockJedisClusterFactory; + @Mock Supplier mockJedisClusterFactory; @Before public void setUp() throws IOException { @@ -82,20 +86,19 @@ public RedisShardBackplane createBackplane(String name) { @Test public void workersWithInvalidProtobufAreRemoved() throws IOException { - JedisCluster jedisCluster = mock(JedisCluster.class); - when(mockJedisClusterFactory.get()).thenReturn(jedisCluster); - when(jedisCluster.hgetAll(configs.getBackplane().getWorkersHashName() + "_storage")) + UnifiedJedis jedis = mock(UnifiedJedis.class); + when(mockJedisClusterFactory.get()).thenReturn(jedis); + when(jedis.hgetAll(configs.getBackplane().getWorkersHashName() + "_storage")) .thenReturn(ImmutableMap.of("foo", "foo")); - when(jedisCluster.hdel(configs.getBackplane().getWorkersHashName() + "_storage", "foo")) + when(jedis.hdel(configs.getBackplane().getWorkersHashName() + "_storage", "foo")) .thenReturn(1L); RedisShardBackplane backplane = createBackplane("invalid-protobuf-worker-removed-test"); backplane.start("startTime/test:0000"); assertThat(backplane.getStorageWorkers()).isEmpty(); - verify(jedisCluster, times(1)) - .hdel(configs.getBackplane().getWorkersHashName() + "_storage", "foo"); + verify(jedis, times(1)).hdel(configs.getBackplane().getWorkersHashName() + "_storage", "foo"); ArgumentCaptor changeCaptor = ArgumentCaptor.forClass(String.class); - verify(jedisCluster, times(1)) + verify(jedis, times(1)) .publish(eq(configs.getBackplane().getWorkerChannel()), changeCaptor.capture()); String json = changeCaptor.getValue(); WorkerChange.Builder builder = WorkerChange.newBuilder(); @@ -105,7 +108,7 @@ public void workersWithInvalidProtobufAreRemoved() throws IOException { assertThat(workerChange.getTypeCase()).isEqualTo(WorkerChange.TypeCase.REMOVE); } - OperationChange verifyChangePublished(String channel, JedisCluster jedis) throws IOException { + OperationChange verifyChangePublished(String channel, UnifiedJedis jedis) throws IOException { ArgumentCaptor changeCaptor = ArgumentCaptor.forClass(String.class); verify(jedis, times(1)).publish(eq(channel), changeCaptor.capture()); return parseOperationChange(changeCaptor.getValue()); @@ -117,36 +120,35 @@ String operationName(String name) { @Test public void prequeueUpdatesOperationPrequeuesAndPublishes() throws IOException { - JedisCluster jedisCluster = mock(JedisCluster.class); - when(mockJedisClusterFactory.get()).thenReturn(jedisCluster); + UnifiedJedis jedis = mock(UnifiedJedis.class); + RedisClient client = new RedisClient(jedis); + DistributedState state = new DistributedState(); + state.operations = mock(Operations.class); + state.prequeue = mock(BalancedRedisQueue.class); RedisShardBackplane backplane = createBackplane("prequeue-operation-test"); - backplane.start("startTime/test:0000"); + backplane.start(client, state, "startTime/test:0000"); final String opName = "op"; ExecuteEntry executeEntry = ExecuteEntry.newBuilder().setOperationName(opName).build(); Operation op = Operation.newBuilder().setName(opName).build(); backplane.prequeue(executeEntry, op); - verify(mockJedisClusterFactory, times(1)).get(); - verify(jedisCluster, times(1)) - .setex( - operationName(opName), - configs.getBackplane().getOperationExpire(), - RedisShardBackplane.operationPrinter.print(op)); - verify(jedisCluster, times(1)) - .lpush( - configs.getBackplane().getPreQueuedOperationsListName(), - JsonFormat.printer().print(executeEntry)); - OperationChange opChange = - verifyChangePublished(backplane.operationChannel(opName), jedisCluster); + verify(state.operations, times(1)) + .insert( + eq(jedis), + any(String.class), + eq(opName), + eq(RedisShardBackplane.operationPrinter.print(op))); + verifyNoMoreInteractions(state.operations); + OperationChange opChange = verifyChangePublished(backplane.operationChannel(opName), jedis); assertThat(opChange.hasReset()).isTrue(); assertThat(opChange.getReset().getOperation().getName()).isEqualTo(opName); } @Test public void queuingPublishes() throws IOException { - JedisCluster jedisCluster = mock(JedisCluster.class); - when(mockJedisClusterFactory.get()).thenReturn(jedisCluster); + UnifiedJedis jedis = mock(UnifiedJedis.class); + when(mockJedisClusterFactory.get()).thenReturn(jedis); RedisShardBackplane backplane = createBackplane("requeue-operation-test"); backplane.start("startTime/test:0000"); @@ -154,38 +156,38 @@ public void queuingPublishes() throws IOException { backplane.queueing(opName); verify(mockJedisClusterFactory, times(1)).get(); - OperationChange opChange = - verifyChangePublished(backplane.operationChannel(opName), jedisCluster); + OperationChange opChange = verifyChangePublished(backplane.operationChannel(opName), jedis); assertThat(opChange.hasReset()).isTrue(); assertThat(opChange.getReset().getOperation().getName()).isEqualTo(opName); } @Test public void requeueDispatchedOperationQueuesAndPublishes() throws IOException { - JedisCluster jedisCluster = mock(JedisCluster.class); - when(mockJedisClusterFactory.get()).thenReturn(jedisCluster); + UnifiedJedis jedis = mock(UnifiedJedis.class); + RedisClient client = new RedisClient(jedis); + DistributedState state = new DistributedState(); + state.dispatchedOperations = mock(RedisHashMap.class); + state.operationQueue = mock(OperationQueue.class); RedisShardBackplane backplane = createBackplane("requeue-operation-test"); - backplane.start("startTime/test:0000"); + backplane.start(client, state, "startTime/test:0000"); final String opName = "op"; - when(jedisCluster.hdel(configs.getBackplane().getDispatchedOperationsHashName(), opName)) - .thenReturn(1L); - QueueEntry queueEntry = QueueEntry.newBuilder() - .setExecuteEntry(ExecuteEntry.newBuilder().setOperationName("op").build()) + .setExecuteEntry(ExecuteEntry.newBuilder().setOperationName(opName).build()) .build(); backplane.requeueDispatchedOperation(queueEntry); - verify(mockJedisClusterFactory, times(1)).get(); - verify(jedisCluster, times(1)) - .hdel(configs.getBackplane().getDispatchedOperationsHashName(), opName); - verify(jedisCluster, times(1)) - .lpush( - configs.getBackplane().getQueuedOperationsListName(), - JsonFormat.printer().print(queueEntry)); - OperationChange opChange = - verifyChangePublished(backplane.operationChannel(opName), jedisCluster); + verify(state.dispatchedOperations, times(1)).remove(jedis, opName); + verifyNoMoreInteractions(state.dispatchedOperations); + verify(state.operationQueue, times(1)) + .push( + jedis, + queueEntry.getPlatform().getPropertiesList(), + JsonFormat.printer().print(queueEntry), + queueEntry.getExecuteEntry().getExecutionPolicy().getPriority()); + verifyNoMoreInteractions(state.operationQueue); + OperationChange opChange = verifyChangePublished(backplane.operationChannel(opName), jedis); assertThat(opChange.hasReset()).isTrue(); assertThat(opChange.getReset().getOperation().getName()).isEqualTo(opName); } @@ -199,25 +201,30 @@ public void dispatchedOperationsShowProperRequeueAmount0to1() int REQUEUE_AMOUNT_WHEN_READY_TO_REQUEUE = 1; // create a backplane - JedisCluster jedisCluster = mock(JedisCluster.class); - when(mockJedisClusterFactory.get()).thenReturn(jedisCluster); + UnifiedJedis jedis = mock(UnifiedJedis.class); + RedisClient client = new RedisClient(jedis); + DistributedState state = new DistributedState(); + state.dispatchedOperations = mock(RedisHashMap.class); + state.dispatchingOperations = mock(RedisMap.class); + state.operationQueue = mock(OperationQueue.class); RedisShardBackplane backplane = createBackplane("requeue-operation-test"); - backplane.start("startTime/test:0000"); + backplane.start(client, state, "startTime/test:0000"); // ARRANGE // Assume the operation queue is already populated with a first-time operation. // this means the operation's requeue amount will be 0. // The jedis cluser is also mocked to assume success on other operations. + final String opName = "op"; QueueEntry queueEntry = QueueEntry.newBuilder() - .setExecuteEntry(ExecuteEntry.newBuilder().setOperationName("op").build()) + .setExecuteEntry(ExecuteEntry.newBuilder().setOperationName(opName).build()) .setRequeueAttempts(STARTING_REQUEUE_AMOUNT) .build(); String queueEntryJson = JsonFormat.printer().print(queueEntry); - when(jedisCluster.rpoplpush(any(String.class), any(String.class))).thenReturn(queueEntryJson); - + when(state.operationQueue.dequeue(eq(jedis), any(List.class))).thenReturn(queueEntryJson); + when(state.operationQueue.removeFromDequeue(jedis, queueEntryJson)).thenReturn(true); // PRE-ASSERT - when(jedisCluster.hsetnx(any(String.class), any(String.class), any(String.class))) + when(state.dispatchedOperations.insertIfMissing(eq(jedis), eq(opName), any(String.class))) .thenAnswer( args -> { // Extract the operation that was dispatched @@ -230,17 +237,26 @@ public void dispatchedOperationsShowProperRequeueAmount0to1() assertThat(dispatchedOperation.getQueueEntry().getRequeueAttempts()) .isEqualTo(REQUEUE_AMOUNT_WHEN_DISPATCHED); - return 1L; + return true; }); // ACT // dispatch the operation and test properties of the QueueEntry and internal jedis calls. - List properties = new ArrayList<>(); - QueueEntry readyForRequeue = backplane.dispatchOperation(properties); + QueueEntry readyForRequeue = backplane.dispatchOperation(ImmutableList.of()); // ASSERT assertThat(readyForRequeue.getRequeueAttempts()) .isEqualTo(REQUEUE_AMOUNT_WHEN_READY_TO_REQUEUE); + verify(state.operationQueue, times(1)).dequeue(eq(jedis), any(List.class)); + verify(state.operationQueue, times(1)).removeFromDequeue(jedis, queueEntryJson); + verifyNoMoreInteractions(state.operationQueue); + verify(state.dispatchedOperations, times(1)) + .insertIfMissing( + eq(jedis), eq(queueEntry.getExecuteEntry().getOperationName()), any(String.class)); + verifyNoMoreInteractions(state.dispatchedOperations); + verify(state.dispatchingOperations, times(1)) + .remove(jedis, queueEntry.getExecuteEntry().getOperationName()); + verifyNoMoreInteractions(state.dispatchingOperations); } @Test @@ -252,24 +268,30 @@ public void dispatchedOperationsShowProperRequeueAmount1to2() int REQUEUE_AMOUNT_WHEN_READY_TO_REQUEUE = 2; // create a backplane - JedisCluster jedisCluster = mock(JedisCluster.class); - when(mockJedisClusterFactory.get()).thenReturn(jedisCluster); + UnifiedJedis jedis = mock(UnifiedJedis.class); + RedisClient client = new RedisClient(jedis); + DistributedState state = new DistributedState(); + state.dispatchedOperations = mock(RedisHashMap.class); + state.dispatchingOperations = mock(RedisMap.class); + state.operationQueue = mock(OperationQueue.class); RedisShardBackplane backplane = createBackplane("requeue-operation-test"); - backplane.start("startTime/test:0000"); + backplane.start(client, state, "startTime/test:0000"); + // ARRANGE // Assume the operation queue is already populated from a first re-queue. // this means the operation's requeue amount will be 1. // The jedis cluser is also mocked to assume success on other operations. + final String opName = "op"; QueueEntry queueEntry = QueueEntry.newBuilder() - .setExecuteEntry(ExecuteEntry.newBuilder().setOperationName("op").build()) + .setExecuteEntry(ExecuteEntry.newBuilder().setOperationName(opName).build()) .setRequeueAttempts(STARTING_REQUEUE_AMOUNT) .build(); String queueEntryJson = JsonFormat.printer().print(queueEntry); - when(jedisCluster.rpoplpush(any(String.class), any(String.class))).thenReturn(queueEntryJson); - + when(state.operationQueue.dequeue(eq(jedis), any(List.class))).thenReturn(queueEntryJson); + when(state.operationQueue.removeFromDequeue(jedis, queueEntryJson)).thenReturn(true); // PRE-ASSERT - when(jedisCluster.hsetnx(any(String.class), any(String.class), any(String.class))) + when(state.dispatchedOperations.insertIfMissing(eq(jedis), eq(opName), any(String.class))) .thenAnswer( args -> { // Extract the operation that was dispatched @@ -282,23 +304,32 @@ public void dispatchedOperationsShowProperRequeueAmount1to2() assertThat(dispatchedOperation.getQueueEntry().getRequeueAttempts()) .isEqualTo(REQUEUE_AMOUNT_WHEN_DISPATCHED); - return 1L; + return true; }); // ACT // dispatch the operation and test properties of the QueueEntry and internal jedis calls. - List properties = new ArrayList<>(); - QueueEntry readyForRequeue = backplane.dispatchOperation(properties); + QueueEntry readyForRequeue = backplane.dispatchOperation(ImmutableList.of()); // ASSERT assertThat(readyForRequeue.getRequeueAttempts()) .isEqualTo(REQUEUE_AMOUNT_WHEN_READY_TO_REQUEUE); + verify(state.operationQueue, times(1)).dequeue(eq(jedis), any(List.class)); + verify(state.operationQueue, times(1)).removeFromDequeue(jedis, queueEntryJson); + verifyNoMoreInteractions(state.operationQueue); + verify(state.dispatchedOperations, times(1)) + .insertIfMissing( + eq(jedis), eq(queueEntry.getExecuteEntry().getOperationName()), any(String.class)); + verifyNoMoreInteractions(state.dispatchedOperations); + verify(state.dispatchingOperations, times(1)) + .remove(jedis, queueEntry.getExecuteEntry().getOperationName()); + verifyNoMoreInteractions(state.dispatchingOperations); } @Test public void completeOperationUndispatches() throws IOException { - JedisCluster jedisCluster = mock(JedisCluster.class); - when(mockJedisClusterFactory.get()).thenReturn(jedisCluster); + UnifiedJedis jedis = mock(UnifiedJedis.class); + when(mockJedisClusterFactory.get()).thenReturn(jedis); RedisShardBackplane backplane = createBackplane("complete-operation-test"); backplane.start("startTime/test:0000"); @@ -307,15 +338,14 @@ public void completeOperationUndispatches() throws IOException { backplane.completeOperation(opName); verify(mockJedisClusterFactory, times(1)).get(); - verify(jedisCluster, times(1)) - .hdel(configs.getBackplane().getDispatchedOperationsHashName(), opName); + verify(jedis, times(1)).hdel(configs.getBackplane().getDispatchedOperationsHashName(), opName); } @Test @Ignore public void deleteOperationDeletesAndPublishes() throws IOException { - JedisCluster jedisCluster = mock(JedisCluster.class); - when(mockJedisClusterFactory.get()).thenReturn(jedisCluster); + UnifiedJedis jedis = mock(UnifiedJedis.class); + when(mockJedisClusterFactory.get()).thenReturn(jedis); RedisShardBackplane backplane = createBackplane("delete-operation-test"); backplane.start("startTime/test:0000"); @@ -324,11 +354,9 @@ public void deleteOperationDeletesAndPublishes() throws IOException { backplane.deleteOperation(opName); verify(mockJedisClusterFactory, times(1)).get(); - verify(jedisCluster, times(1)) - .hdel(configs.getBackplane().getDispatchedOperationsHashName(), opName); - verify(jedisCluster, times(1)).del(operationName(opName)); - OperationChange opChange = - verifyChangePublished(backplane.operationChannel(opName), jedisCluster); + verify(jedis, times(1)).hdel(configs.getBackplane().getDispatchedOperationsHashName(), opName); + verify(jedis, times(1)).del(operationName(opName)); + OperationChange opChange = verifyChangePublished(backplane.operationChannel(opName), jedis); assertThat(opChange.hasReset()).isTrue(); assertThat(opChange.getReset().getOperation().getName()).isEqualTo(opName); } @@ -336,11 +364,11 @@ public void deleteOperationDeletesAndPublishes() throws IOException { @Test public void invocationsCanBeBlacklisted() throws IOException { UUID toolInvocationId = UUID.randomUUID(); - JedisCluster jedisCluster = mock(JedisCluster.class); + UnifiedJedis jedis = mock(UnifiedJedis.class); String invocationBlacklistKey = configs.getBackplane().getInvocationBlacklistPrefix() + ":" + toolInvocationId; - when(jedisCluster.exists(invocationBlacklistKey)).thenReturn(true); - when(mockJedisClusterFactory.get()).thenReturn(jedisCluster); + when(jedis.exists(invocationBlacklistKey)).thenReturn(true); + when(mockJedisClusterFactory.get()).thenReturn(jedis); RedisShardBackplane backplane = createBackplane("invocation-blacklist-test"); backplane.start("startTime/test:0000"); @@ -352,13 +380,13 @@ public void invocationsCanBeBlacklisted() throws IOException { .isTrue(); verify(mockJedisClusterFactory, times(1)).get(); - verify(jedisCluster, times(1)).exists(invocationBlacklistKey); + verify(jedis, times(1)).exists(invocationBlacklistKey); } @Test public void testGetWorkersStartTime() throws IOException { - JedisCluster jedisCluster = mock(JedisCluster.class); - when(mockJedisClusterFactory.get()).thenReturn(jedisCluster); + UnifiedJedis jedis = mock(UnifiedJedis.class); + when(mockJedisClusterFactory.get()).thenReturn(jedis); RedisShardBackplane backplane = createBackplane("workers-starttime-test"); backplane.start("startTime/test:0000"); @@ -373,7 +401,7 @@ public void testGetWorkersStartTime() throws IOException { "worker2", "{\"endpoint\": \"worker2\", \"expireAt\": \"9999999999999\", \"workerType\": 3," + " \"firstRegisteredAt\": \"1685282624000\"}"); - when(jedisCluster.hgetAll(storageWorkerKey)).thenReturn(workersJson); + when(jedis.hgetAll(storageWorkerKey)).thenReturn(workersJson); Map workersStartTime = backplane.getWorkersStartTimeInEpochSecs(workerNames); assertThat(workersStartTime.size()).isEqualTo(2); assertThat(workersStartTime.get("worker1")).isEqualTo(1685292624L); @@ -383,13 +411,13 @@ public void testGetWorkersStartTime() throws IOException { @Test public void getDigestInsertTime() throws IOException { - JedisCluster jedisCluster = mock(JedisCluster.class); - when(mockJedisClusterFactory.get()).thenReturn(jedisCluster); + UnifiedJedis jedis = mock(UnifiedJedis.class); + when(mockJedisClusterFactory.get()).thenReturn(jedis); RedisShardBackplane backplane = createBackplane("digest-inserttime-test"); backplane.start("startTime/test:0000"); long ttl = 3600L; long expirationInSecs = configs.getBackplane().getCasExpire(); - when(jedisCluster.ttl("ContentAddressableStorage:abc/0")).thenReturn(ttl); + when(jedis.ttl("ContentAddressableStorage:abc/0")).thenReturn(ttl); Digest digest = Digest.newBuilder().setHash("abc").build(); @@ -406,22 +434,22 @@ public void getDigestInsertTime() throws IOException { public void testAddWorker() throws IOException { ShardWorker shardWorker = ShardWorker.newBuilder().setWorkerType(3).setFirstRegisteredAt(1703065913000L).build(); - JedisCluster jedisCluster = mock(JedisCluster.class); - when(mockJedisClusterFactory.get()).thenReturn(jedisCluster); - when(jedisCluster.hset(anyString(), anyString(), anyString())).thenReturn(1L); + UnifiedJedis jedis = mock(UnifiedJedis.class); + when(mockJedisClusterFactory.get()).thenReturn(jedis); + when(jedis.hset(anyString(), anyString(), anyString())).thenReturn(1L); RedisShardBackplane backplane = createBackplane("add-worker-test"); backplane.start("addWorker/test:0000"); backplane.addWorker(shardWorker); - verify(jedisCluster, times(1)) + verify(jedis, times(1)) .hset( configs.getBackplane().getWorkersHashName() + "_storage", "", JsonFormat.printer().print(shardWorker)); - verify(jedisCluster, times(1)) + verify(jedis, times(1)) .hset( configs.getBackplane().getWorkersHashName() + "_execute", "", JsonFormat.printer().print(shardWorker)); - verify(jedisCluster, times(1)).publish(anyString(), anyString()); + verify(jedis, times(1)).publish(anyString(), anyString()); } } diff --git a/src/test/java/build/buildfarm/instance/shard/RedisShardSubscriberTest.java b/src/test/java/build/buildfarm/instance/shard/RedisShardSubscriberTest.java index 9a1851170e..8169b01c69 100644 --- a/src/test/java/build/buildfarm/instance/shard/RedisShardSubscriberTest.java +++ b/src/test/java/build/buildfarm/instance/shard/RedisShardSubscriberTest.java @@ -24,8 +24,9 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static redis.clients.jedis.Protocol.Keyword.SUBSCRIBE; -import static redis.clients.jedis.Protocol.Keyword.UNSUBSCRIBE; +import static redis.clients.jedis.Protocol.Command.SUBSCRIBE; +import static redis.clients.jedis.Protocol.Command.UNSUBSCRIBE; +import static redis.clients.jedis.Protocol.ResponseKeyword; import build.buildfarm.instance.shard.RedisShardSubscriber.TimedWatchFuture; import build.buildfarm.v1test.OperationChange; @@ -35,9 +36,11 @@ import com.google.common.collect.MultimapBuilder; import com.google.common.collect.Multimaps; import com.google.common.collect.Sets; +import com.google.common.truth.Correspondence; import com.google.longrunning.Operation; import com.google.protobuf.InvalidProtocolBufferException; import java.time.Instant; +import java.util.Arrays; import java.util.List; import java.util.Set; import java.util.concurrent.BlockingQueue; @@ -47,7 +50,11 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import redis.clients.jedis.Client; +import redis.clients.jedis.CommandArguments; +import redis.clients.jedis.Connection; +import redis.clients.jedis.args.Rawable; +import redis.clients.jedis.args.RawableFactory; +import redis.clients.jedis.commands.ProtocolCommand; @RunWith(JUnit4.class) public class RedisShardSubscriberTest { @@ -63,17 +70,23 @@ public void unwatch() { } } - private static class TestClient extends Client { - private final Set subscriptions = Sets.newConcurrentHashSet(); - private final BlockingQueue> replyQueue = new LinkedBlockingQueue<>(); - private final BlockingQueue> pendingReplies = new LinkedBlockingQueue<>(); + private static class TestConnection extends Connection { + private final Set subscriptions = Sets.newConcurrentHashSet(); + private final BlockingQueue pendingRequests = new LinkedBlockingQueue<>(); + private final BlockingQueue replyQueue = new LinkedBlockingQueue<>(); + private final BlockingQueue pendingReplies = new LinkedBlockingQueue<>(); - Set getSubscriptions() { + Set getSubscriptions() { return subscriptions; } @Override public List getUnflushedObjectMultiBulkReply() { + throw new UnsupportedOperationException("getUnflushedObjectMultiBulkReply is deprecated"); + } + + @Override + public Object getUnflushedObject() { try { return replyQueue.take(); } catch (InterruptedException e) { @@ -83,40 +96,81 @@ public List getUnflushedObjectMultiBulkReply() { } @Override - public void subscribe(String... channels) { - for (String channel : channels) { - if (subscriptions.add(channel)) { - pendingReplies.add( - ImmutableList.of(SUBSCRIBE.raw, channel.getBytes(), (long) subscriptions.size())); + public void sendCommand(final CommandArguments cargs) { + ProtocolCommand command = cargs.getCommand(); + if (command == SUBSCRIBE) { + pendingRequests.add(() -> subscribe(cargs)); + } else if (command == UNSUBSCRIBE) { + if (cargs.size() == 1) { + // only includes command + pendingRequests.add(() -> unsubscribe()); } else { - throw new IllegalStateException("subscribe to already subscribed channel: " + channel); + pendingRequests.add(() -> unsubscribe(cargs)); } + } else { + throw new UnsupportedOperationException(cargs.toString()); } } @Override - public void unsubscribe() { + public void setTimeoutInfinite() { + // ignore + } + + private void subscribe(Iterable channels) { + boolean isCommand = true; + for (Rawable channel : channels) { + if (isCommand) { + isCommand = false; + } else { + if (subscriptions.add(channel)) { + pendingReplies.add( + ImmutableList.of( + ResponseKeyword.SUBSCRIBE.getRaw(), + channel.getRaw(), + (long) subscriptions.size())); + } else { + throw new IllegalStateException("subscribe to already subscribed channel: " + channel); + } + } + } + } + + private void unsubscribe() { long counter = subscriptions.size(); - for (String channel : subscriptions) { - pendingReplies.add(ImmutableList.of(UNSUBSCRIBE.raw, channel.getBytes(), --counter)); + for (Rawable channel : subscriptions) { + pendingReplies.add( + ImmutableList.of(ResponseKeyword.UNSUBSCRIBE.getRaw(), channel.getRaw(), --counter)); } subscriptions.clear(); } - @Override - public void unsubscribe(String... channels) { - for (String channel : channels) { - if (subscriptions.remove(channel)) { - pendingReplies.add( - ImmutableList.of(UNSUBSCRIBE.raw, channel.getBytes(), (long) subscriptions.size())); + private void unsubscribe(Iterable channels) { + boolean isCommand = true; + for (Rawable channel : channels) { + if (isCommand) { + isCommand = false; } else { - throw new IllegalStateException("unsubscribe from unknown channel: " + channel); + if (subscriptions.remove(channel)) { + pendingReplies.add( + ImmutableList.of( + ResponseKeyword.UNSUBSCRIBE.getRaw(), + channel.getRaw(), + (long) subscriptions.size())); + } else { + throw new IllegalStateException("unsubscribe from unknown channel: " + channel); + } } } } @Override public void flush() { + for (Runnable request = pendingRequests.poll(); + request != null; + request = pendingRequests.poll()) { + request.run(); + } pendingReplies.drainTo(replyQueue); } } @@ -130,6 +184,16 @@ RedisShardSubscriber createSubscriber(ListMultimap wat return createSubscriber(watchers, /* executor= */ null); } + private static final Correspondence rawableCorrespondence = + Correspondence.from( + new Correspondence.BinaryPredicate() { + @Override + public boolean apply(Rawable a, Rawable e) { + return Arrays.equals(a.getRaw(), e.getRaw()); + } + }, + "is rawably equivalent to"); + @Test public void novelChannelWatcherSubscribes() throws InterruptedException { ListMultimap watchers = @@ -137,8 +201,8 @@ public void novelChannelWatcherSubscribes() throws InterruptedException { MultimapBuilder.linkedHashKeys().arrayListValues().build()); RedisShardSubscriber operationSubscriber = createSubscriber(watchers, directExecutor()); - TestClient testClient = new TestClient(); - Thread proceedThread = new Thread(() -> operationSubscriber.proceed(testClient)); + TestConnection testConnection = new TestConnection(); + Thread proceedThread = new Thread(() -> operationSubscriber.start(testConnection)); proceedThread.start(); while (!operationSubscriber.isSubscribed()) { MICROSECONDS.sleep(10); @@ -151,7 +215,9 @@ public void novelChannelWatcherSubscribes() throws InterruptedException { .isEqualTo(novelWatcher); String[] channels = new String[1]; channels[0] = novelChannel; - assertThat(testClient.getSubscriptions()).contains(novelChannel); + assertThat(testConnection.getSubscriptions()) + .comparingElementsUsing(rawableCorrespondence) + .contains(RawableFactory.from(novelChannel)); operationSubscriber.unsubscribe(); proceedThread.join(); } @@ -228,8 +294,8 @@ public void doneResetOperationIsObservedAndUnsubscribed() MultimapBuilder.linkedHashKeys().arrayListValues().build()); RedisShardSubscriber operationSubscriber = createSubscriber(watchers, directExecutor()); - TestClient testClient = new TestClient(); - Thread proceedThread = new Thread(() -> operationSubscriber.proceed(testClient)); + TestConnection testConnection = new TestConnection(); + Thread proceedThread = new Thread(() -> operationSubscriber.start(testConnection)); proceedThread.start(); while (!operationSubscriber.isSubscribed()) { MICROSECONDS.sleep(10); @@ -257,7 +323,7 @@ public void observe(Operation operation) { .build()) .build())); assertThat(observed.get()).isTrue(); - assertThat(testClient.getSubscriptions()).doesNotContain(doneMessageChannel); + assertThat(testConnection.getSubscriptions()).doesNotContain(doneMessageChannel); operationSubscriber.unsubscribe(); proceedThread.join(); } diff --git a/third_party/jedis/BUILD b/third_party/jedis/BUILD deleted file mode 100644 index fa5987e544..0000000000 --- a/third_party/jedis/BUILD +++ /dev/null @@ -1,14 +0,0 @@ -licenses(["notice"]) - -java_library( - name = "jedis", - visibility = [ - "//visibility:public", - ], - exports = [ - "//external:jar/redis/clients/jedis", - ], - runtime_deps = [ - "@maven//:org_apache_commons_commons_pool2", - ], -) diff --git a/third_party/jedis/LICENSE b/third_party/jedis/LICENSE deleted file mode 100644 index 7b8b1cee63..0000000000 --- a/third_party/jedis/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2010 Jonathan Leibiusky - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file From 76a1e00dfcdb5c5597448157d0023ba800a2cdaf Mon Sep 17 00:00:00 2001 From: George Gensure Date: Mon, 8 Jan 2024 22:36:33 -0500 Subject: [PATCH 245/311] Calculate slot lookup table once per app instance The slot key index is invariant for all usage, calculate it once and avoid a costly lookup for successive calls to RedisSlotToHash.correlate. Evidenced in slow unit tests, but may improve production runtime as well. Provide an initial capacity to the slots ArrayList to boot. --- .../build/buildfarm/common/redis/RedisSlotToHash.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/build/buildfarm/common/redis/RedisSlotToHash.java b/src/main/java/build/buildfarm/common/redis/RedisSlotToHash.java index d4a66a0082..4feba7c30b 100644 --- a/src/main/java/build/buildfarm/common/redis/RedisSlotToHash.java +++ b/src/main/java/build/buildfarm/common/redis/RedisSlotToHash.java @@ -38,6 +38,8 @@ * return that slot number. */ public class RedisSlotToHash { + private static final List LOOKUP_TABLE = createLookupTable(); + /** * @brief Convert slot number into string that hashes to slot. * @details A short alphanumeric string will be given which when hashed by redis's crc16 algorithm @@ -123,8 +125,7 @@ private static String createHashtag(String prefix, long generated) { * @note Suggested return identifier: hashtag. */ private static String staticLookup(long slotNumber) { - List lookupTable = getLookupTable(); - return lookupTable.get((int) slotNumber); + return LOOKUP_TABLE.get((int) slotNumber); } /** @@ -135,8 +136,8 @@ private static String staticLookup(long slotNumber) { * @return The hashtags organized by slot index. * @note Suggested return identifier: lookupTable. */ - private static List getLookupTable() { - List lookupTable = new ArrayList<>(); + private static List createLookupTable() { + List lookupTable = new ArrayList<>(CLUSTER_HASHSLOTS); lookupTable.addAll(slots0To4999()); lookupTable.addAll(slots5000To9999()); lookupTable.addAll(slots10000To14999()); From 96a0c87f889c378d01d510b129af53d2c1d23fa1 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Mon, 8 Jan 2024 10:15:41 -0500 Subject: [PATCH 246/311] Switch jedis dequeue over to milli granularity Speeds up tests dramatically. --- .../common/redis/BalancedRedisQueue.java | 14 +++-- .../common/redis/QueueInterface.java | 5 +- .../common/redis/RedisPriorityQueue.java | 9 ++-- .../buildfarm/common/redis/RedisQueue.java | 11 ++-- .../redis/BalancedRedisQueueMockTest.java | 3 +- .../redis/RedisPriorityQueueMockTest.java | 12 ++--- .../common/redis/RedisPriorityQueueTest.java | 53 ++++++++++--------- .../common/redis/RedisQueueMockTest.java | 11 ++-- .../common/redis/RedisQueueTest.java | 15 +++--- 9 files changed, 75 insertions(+), 58 deletions(-) diff --git a/src/main/java/build/buildfarm/common/redis/BalancedRedisQueue.java b/src/main/java/build/buildfarm/common/redis/BalancedRedisQueue.java index 069e0915b1..c7c5e26f58 100644 --- a/src/main/java/build/buildfarm/common/redis/BalancedRedisQueue.java +++ b/src/main/java/build/buildfarm/common/redis/BalancedRedisQueue.java @@ -18,6 +18,7 @@ import build.buildfarm.common.config.Queue; import build.buildfarm.v1test.QueueStatus; import com.google.common.collect.ImmutableList; +import java.time.Duration; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -39,9 +40,9 @@ * the same underlying redis queues. */ public class BalancedRedisQueue { - private static final int START_TIMEOUT_SECONDS = 1; + private static final Duration START_TIMEOUT = Duration.ofSeconds(1); - private static final int MAX_TIMEOUT_SECONDS = 8; + private static final Duration MAX_TIMEOUT = Duration.ofSeconds(8); /** * @field name @@ -222,13 +223,13 @@ public String dequeue(UnifiedJedis unified, ExecutorService service) throws Inte // end this phase if we have done a full round-robin boolean blocking = false; // try each of the internal queues with exponential backoff - int currentTimeout_s = START_TIMEOUT_SECONDS; + Duration currentTimeout = START_TIMEOUT; while (true) { final String val; QueueInterface queue = queues.get(roundRobinPopIndex()); try (Jedis jedis = getJedisFromKey(unified, queue.getName())) { if (blocking) { - val = queue.dequeue(jedis, currentTimeout_s, service); + val = queue.dequeue(jedis, currentTimeout, service); } else { val = queue.nonBlockingDequeue(jedis); } @@ -246,7 +247,10 @@ public String dequeue(UnifiedJedis unified, ExecutorService service) throws Inte if (currentPopQueue == startQueue) { // advance timeout if blocking on queue and not at max each queue cycle if (blocking) { - currentTimeout_s = Math.min(currentTimeout_s * 2, MAX_TIMEOUT_SECONDS); + currentTimeout = currentTimeout.multipliedBy(2); + if (currentTimeout.compareTo(MAX_TIMEOUT) > 0) { + currentTimeout = MAX_TIMEOUT; + } } else { blocking = true; } diff --git a/src/main/java/build/buildfarm/common/redis/QueueInterface.java b/src/main/java/build/buildfarm/common/redis/QueueInterface.java index f87f195f1f..3915600d2d 100644 --- a/src/main/java/build/buildfarm/common/redis/QueueInterface.java +++ b/src/main/java/build/buildfarm/common/redis/QueueInterface.java @@ -15,6 +15,7 @@ package build.buildfarm.common.redis; import build.buildfarm.common.StringVisitor; +import java.time.Duration; import java.util.concurrent.ExecutorService; import redis.clients.jedis.Jedis; @@ -61,12 +62,12 @@ public abstract class QueueInterface { * dequeue. It will wait until the timeout has expired. Null is returned if the timeout has * expired. It is up to the caller to maintain the Jedis object and ensure it is valid for the * queue operations. - * @param timeout_s Timeout to wait if there is no item to dequeue. (units: seconds (s)) + * @param timeout Timeout to wait if there is no item to dequeue. * @return The value of the transfered element. null if the thread was interrupted. * @note Overloaded. * @note Suggested return identifier: val. */ - abstract String dequeue(Jedis jedis, int timeout_s, ExecutorService service) + abstract String dequeue(Jedis jedis, Duration timeout, ExecutorService service) throws InterruptedException; /** diff --git a/src/main/java/build/buildfarm/common/redis/RedisPriorityQueue.java b/src/main/java/build/buildfarm/common/redis/RedisPriorityQueue.java index 6346f87b98..5a4d906e09 100644 --- a/src/main/java/build/buildfarm/common/redis/RedisPriorityQueue.java +++ b/src/main/java/build/buildfarm/common/redis/RedisPriorityQueue.java @@ -15,6 +15,7 @@ package build.buildfarm.common.redis; import build.buildfarm.common.StringVisitor; +import java.time.Duration; import java.util.Arrays; import java.util.List; import java.util.concurrent.ExecutorService; @@ -142,15 +143,15 @@ public boolean removeAll(Jedis jedis, String val) { * @details This pops the element from one queue atomically into an internal list called the * dequeue. It will wait until the timeout has expired. Null is returned if the timeout has * expired. - * @param timeout_s Timeout to wait if there is no item to dequeue. (units: seconds (s)) + * @param timeout Timeout to wait if there is no item to dequeue. * @return The value of the transfered element. null if the thread was interrupted. * @note Overloaded. * @note Suggested return identifier: val. */ @Override - public String dequeue(Jedis jedis, int timeout_s, ExecutorService service) + public String dequeue(Jedis jedis, Duration timeout, ExecutorService service) throws InterruptedException { - int maxAttempts = (int) (timeout_s / (pollIntervalMillis / 1000.0)); + int maxAttempts = Math.max(1, (int) (timeout.toMillis() / pollIntervalMillis)); List args = Arrays.asList(name, getDequeueName(), "true"); String val; for (int i = 0; i < maxAttempts; ++i) { @@ -295,7 +296,7 @@ private String getLuaScript() { "local pped = redis.call('ZRANGE', zset, 0, 0)", "if next(pped) ~= nil then", " for _,item in ipairs(pped) do", - " val = item.sub('^%d*:', '')", + " val = string.gsub(item, '^%d*:', '')", " redis.call('ZREM', zset, item)", " redis.call('LPUSH', deqName, val)", " end", diff --git a/src/main/java/build/buildfarm/common/redis/RedisQueue.java b/src/main/java/build/buildfarm/common/redis/RedisQueue.java index c3871adb90..e6f539bd67 100644 --- a/src/main/java/build/buildfarm/common/redis/RedisQueue.java +++ b/src/main/java/build/buildfarm/common/redis/RedisQueue.java @@ -18,6 +18,7 @@ import static redis.clients.jedis.args.ListDirection.RIGHT; import build.buildfarm.common.StringVisitor; +import java.time.Duration; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; @@ -35,6 +36,10 @@ * queue. */ public class RedisQueue extends QueueInterface { + private static double toRedisTimeoutSeconds(Duration timeout) { + return timeout.getSeconds() + timeout.getNano() / 1e9; + } + /** * @field name * @brief The unique name of the queue. @@ -100,15 +105,15 @@ public boolean removeAll(Jedis jedis, String val) { * @details This pops the element from one queue atomically into an internal list called the * dequeue. It will wait until the timeout has expired. Null is returned if the timeout has * expired. - * @param timeout_s Timeout to wait if there is no item to dequeue. (units: seconds (s)) + * @param timeout Timeout to wait if there is no item to dequeue. * @return The value of the transfered element. null if the thread was interrupted. * @note Overloaded. * @note Suggested return identifier: val. */ - public String dequeue(Jedis jedis, int timeout_s, ExecutorService service) + public String dequeue(Jedis jedis, Duration timeout, ExecutorService service) throws InterruptedException { return interruptibleRequest( - () -> jedis.blmove(name, getDequeueName(), RIGHT, LEFT, timeout_s), + () -> jedis.blmove(name, getDequeueName(), RIGHT, LEFT, toRedisTimeoutSeconds(timeout)), jedis::disconnect, service); } diff --git a/src/test/java/build/buildfarm/common/redis/BalancedRedisQueueMockTest.java b/src/test/java/build/buildfarm/common/redis/BalancedRedisQueueMockTest.java index c93d0458db..8811d42103 100644 --- a/src/test/java/build/buildfarm/common/redis/BalancedRedisQueueMockTest.java +++ b/src/test/java/build/buildfarm/common/redis/BalancedRedisQueueMockTest.java @@ -25,6 +25,7 @@ import build.buildfarm.common.StringVisitor; import com.google.common.collect.ImmutableList; +import java.time.Duration; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; @@ -122,7 +123,7 @@ public void dequeueExponentialBackoffElementDequeuedOnNonBlock() throws Exceptio public void dequeueExponentialBackoffElementDequeuedOnBlock() throws Exception { // MOCK when(subQueue.nonBlockingDequeue(any(Jedis.class))).thenReturn(null); - when(subQueue.dequeue(any(Jedis.class), any(Integer.class), any(ExecutorService.class))) + when(subQueue.dequeue(any(Jedis.class), any(Duration.class), any(ExecutorService.class))) .thenReturn("foo"); // ARRANGE diff --git a/src/test/java/build/buildfarm/common/redis/RedisPriorityQueueMockTest.java b/src/test/java/build/buildfarm/common/redis/RedisPriorityQueueMockTest.java index ecab18059b..4081bf8fa8 100644 --- a/src/test/java/build/buildfarm/common/redis/RedisPriorityQueueMockTest.java +++ b/src/test/java/build/buildfarm/common/redis/RedisPriorityQueueMockTest.java @@ -16,6 +16,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.any; +import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -23,6 +24,7 @@ import static org.mockito.Mockito.when; import build.buildfarm.common.StringVisitor; +import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -150,9 +152,7 @@ public void pushPushMany() throws Exception { } // ASSERT - for (int i = 0; i < 1000; ++i) { - verify(redis, times(1)).zadd("test", 0, "123:foo" + i); - } + verify(redis, times(1000)).zadd(eq("test"), eq(0.0), any(String.class)); } // Function under test: push @@ -206,7 +206,7 @@ public void dequeueElementCanBeDequeuedWithTimeout() throws Exception { // ACT queue.push(redis, "foo"); - String val = queue.dequeue(redis, 1, service); + String val = queue.dequeue(redis, Duration.ofSeconds(1), service); // ASSERT verifyNoInteractions(service); @@ -225,7 +225,7 @@ public void dequeueElementIsNotDequeuedIfTimeRunsOut() throws Exception { // ACT queue.push(redis, "foo"); - String val = queue.dequeue(redis, 5, service); + String val = queue.dequeue(redis, Duration.ofMillis(100), service); // ASSERT verifyNoInteractions(service); @@ -248,7 +248,7 @@ public void dequeueInterrupt() throws Exception { new Thread( () -> { try { - queue.dequeue(redis, 100000, service); + queue.dequeue(redis, Duration.ofDays(1), service); } catch (Exception e) { } }); diff --git a/src/test/java/build/buildfarm/common/redis/RedisPriorityQueueTest.java b/src/test/java/build/buildfarm/common/redis/RedisPriorityQueueTest.java index 4c88bdc11c..28c8cc5129 100644 --- a/src/test/java/build/buildfarm/common/redis/RedisPriorityQueueTest.java +++ b/src/test/java/build/buildfarm/common/redis/RedisPriorityQueueTest.java @@ -15,14 +15,15 @@ package build.buildfarm.common.redis; import static com.google.common.truth.Truth.assertThat; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verifyNoInteractions; import build.buildfarm.common.StringVisitor; import build.buildfarm.common.config.BuildfarmConfigs; import build.buildfarm.instance.shard.JedisClusterFactory; +import com.google.common.base.Stopwatch; import java.time.Duration; -import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; @@ -196,6 +197,7 @@ public void sizeAdjustPushDequeue() throws Exception { // ARRANGE RedisPriorityQueue queue = new RedisPriorityQueue("test"); ExecutorService service = mock(ExecutorService.class); + Duration timeout = Duration.ofSeconds(1); // ACT / ASSERT assertThat(queue.size(redis)).isEqualTo(0); @@ -211,17 +213,17 @@ public void sizeAdjustPushDequeue() throws Exception { assertThat(queue.size(redis)).isEqualTo(5); queue.push(redis, "baz4"); assertThat(queue.size(redis)).isEqualTo(6); - queue.dequeue(redis, 1, service); + queue.dequeue(redis, timeout, service); assertThat(queue.size(redis)).isEqualTo(5); - queue.dequeue(redis, 1, service); + queue.dequeue(redis, timeout, service); assertThat(queue.size(redis)).isEqualTo(4); - queue.dequeue(redis, 1, service); + queue.dequeue(redis, timeout, service); assertThat(queue.size(redis)).isEqualTo(3); - queue.dequeue(redis, 1, service); + queue.dequeue(redis, timeout, service); assertThat(queue.size(redis)).isEqualTo(2); - queue.dequeue(redis, 1, service); + queue.dequeue(redis, timeout, service); assertThat(queue.size(redis)).isEqualTo(1); - queue.dequeue(redis, 1, service); + queue.dequeue(redis, timeout, service); assertThat(queue.size(redis)).isEqualTo(0); verifyNoInteractions(service); } @@ -234,6 +236,7 @@ public void checkPriorityOnDequeue() throws Exception { // ARRANGE RedisPriorityQueue queue = new RedisPriorityQueue("test"); ExecutorService service = mock(ExecutorService.class); + Duration timeout = Duration.ofSeconds(1); String val; // ACT / ASSERT assertThat(queue.size(redis)).isEqualTo(0); @@ -249,22 +252,22 @@ public void checkPriorityOnDequeue() throws Exception { assertThat(queue.size(redis)).isEqualTo(5); queue.push(redis, "baz4", 1); assertThat(queue.size(redis)).isEqualTo(6); - val = queue.dequeue(redis, 1, service); + val = queue.dequeue(redis, timeout, service); assertThat(val).isEqualTo("bar"); assertThat(queue.size(redis)).isEqualTo(5); - val = queue.dequeue(redis, 1, service); + val = queue.dequeue(redis, timeout, service); assertThat(val).isEqualTo("baz2"); assertThat(queue.size(redis)).isEqualTo(4); - val = queue.dequeue(redis, 1, service); + val = queue.dequeue(redis, timeout, service); assertThat(val).isEqualTo("baz4"); assertThat(queue.size(redis)).isEqualTo(3); - val = queue.dequeue(redis, 1, service); + val = queue.dequeue(redis, timeout, service); assertThat(val).isEqualTo("foo"); assertThat(queue.size(redis)).isEqualTo(2); - val = queue.dequeue(redis, 1, service); + val = queue.dequeue(redis, timeout, service); assertThat(val).isEqualTo("baz3"); assertThat(queue.size(redis)).isEqualTo(1); - val = queue.dequeue(redis, 1, service); + val = queue.dequeue(redis, timeout, service); assertThat(val).isEqualTo("baz"); assertThat(queue.size(redis)).isEqualTo(0); verifyNoInteractions(service); @@ -279,11 +282,10 @@ public void checkDequeueTimeout() throws Exception { RedisPriorityQueue queue = new RedisPriorityQueue("test"); ExecutorService service = mock(ExecutorService.class); - Instant start = Instant.now(); - String val = queue.dequeue(redis, 1, service); - Instant finish = Instant.now(); + Stopwatch stopwatch = Stopwatch.createStarted(); + String val = queue.dequeue(redis, Duration.ofSeconds(1), service); + long timeElapsed = stopwatch.elapsed(MILLISECONDS); - long timeElapsed = Duration.between(start, finish).toMillis(); assertThat(timeElapsed).isGreaterThan(1000L); assertThat(val).isEqualTo(null); verifyNoInteractions(service); @@ -297,6 +299,7 @@ public void checkNegativesInPriority() throws Exception { // ARRANGE RedisPriorityQueue queue = new RedisPriorityQueue("test"); ExecutorService service = mock(ExecutorService.class); + Duration timeout = Duration.ofSeconds(1); String val; // ACT / ASSERT @@ -309,21 +312,21 @@ public void checkNegativesInPriority() throws Exception { queue.push(redis, "baz-2", 2); queue.push(redis, "foo-4", 4); - val = queue.dequeue(redis, 1, service); + val = queue.dequeue(redis, timeout, service); assertThat(val).isEqualTo("negative-50"); - val = queue.dequeue(redis, 1, service); + val = queue.dequeue(redis, timeout, service); assertThat(val).isEqualTo("negative-1"); - val = queue.dequeue(redis, 1, service); + val = queue.dequeue(redis, timeout, service); assertThat(val).isEqualTo("foo-1"); - val = queue.dequeue(redis, 1, service); + val = queue.dequeue(redis, timeout, service); assertThat(val).isEqualTo("baz-2"); - val = queue.dequeue(redis, 1, service); + val = queue.dequeue(redis, timeout, service); assertThat(val).isEqualTo("foo-3"); - val = queue.dequeue(redis, 1, service); + val = queue.dequeue(redis, timeout, service); assertThat(val).isEqualTo("foo-4"); - val = queue.dequeue(redis, 1, service); + val = queue.dequeue(redis, timeout, service); assertThat(val).isEqualTo("foo-5"); - val = queue.dequeue(redis, 1, service); + val = queue.dequeue(redis, timeout, service); assertThat(val).isEqualTo("foo-6"); verifyNoInteractions(service); } diff --git a/src/test/java/build/buildfarm/common/redis/RedisQueueMockTest.java b/src/test/java/build/buildfarm/common/redis/RedisQueueMockTest.java index 7a428c412b..4b75098630 100644 --- a/src/test/java/build/buildfarm/common/redis/RedisQueueMockTest.java +++ b/src/test/java/build/buildfarm/common/redis/RedisQueueMockTest.java @@ -26,6 +26,7 @@ import static redis.clients.jedis.args.ListDirection.RIGHT; import build.buildfarm.common.StringVisitor; +import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -127,9 +128,7 @@ public void pushPushMany() throws Exception { } // ASSERT - for (int i = 0; i < 1000; ++i) { - verify(redis, times(1)).lpush("test", "foo" + i); - } + verify(redis, times(1000)).lpush(eq("test"), any(String.class)); } // Function under test: push @@ -186,7 +185,7 @@ public void dequeueElementCanBeDequeuedWithTimeout() throws Exception { ExecutorService service = newSingleThreadExecutor(); // ACT - String val = queue.dequeue(redis, 1, service); + String val = queue.dequeue(redis, Duration.ofSeconds(1), service); service.shutdown(); // ASSERT @@ -206,7 +205,7 @@ public void dequeueElementIsNotDequeuedIfTimeRunsOut() throws Exception { ExecutorService service = newSingleThreadExecutor(); // ACT - String val = queue.dequeue(redis, 5, service); + String val = queue.dequeue(redis, Duration.ofMillis(100), service); service.shutdown(); // ASSERT @@ -231,7 +230,7 @@ public void dequeueInterrupt() throws Exception { new Thread( () -> { try { - queue.dequeue(redis, 100000, service); + queue.dequeue(redis, Duration.ofDays(1), service); } catch (Exception e) { } }); diff --git a/src/test/java/build/buildfarm/common/redis/RedisQueueTest.java b/src/test/java/build/buildfarm/common/redis/RedisQueueTest.java index 3f8b631148..d08081b4e9 100644 --- a/src/test/java/build/buildfarm/common/redis/RedisQueueTest.java +++ b/src/test/java/build/buildfarm/common/redis/RedisQueueTest.java @@ -21,6 +21,7 @@ import build.buildfarm.common.StringVisitor; import build.buildfarm.common.config.BuildfarmConfigs; import build.buildfarm.instance.shard.JedisClusterFactory; +import java.time.Duration; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; @@ -194,6 +195,8 @@ public void sizeAdjustPushDequeue() throws Exception { // ARRANGE RedisQueue queue = new RedisQueue("{hash}test"); ExecutorService service = newSingleThreadExecutor(); + Duration timeout = Duration.ofSeconds(1); + // ACT / ASSERT assertThat(queue.size(redis)).isEqualTo(0); queue.push(redis, "foo"); @@ -208,17 +211,17 @@ public void sizeAdjustPushDequeue() throws Exception { assertThat(queue.size(redis)).isEqualTo(5); queue.push(redis, "baz"); assertThat(queue.size(redis)).isEqualTo(6); - queue.dequeue(redis, 1, service); + queue.dequeue(redis, timeout, service); assertThat(queue.size(redis)).isEqualTo(5); - queue.dequeue(redis, 1, service); + queue.dequeue(redis, timeout, service); assertThat(queue.size(redis)).isEqualTo(4); - queue.dequeue(redis, 1, service); + queue.dequeue(redis, timeout, service); assertThat(queue.size(redis)).isEqualTo(3); - queue.dequeue(redis, 1, service); + queue.dequeue(redis, timeout, service); assertThat(queue.size(redis)).isEqualTo(2); - queue.dequeue(redis, 1, service); + queue.dequeue(redis, timeout, service); assertThat(queue.size(redis)).isEqualTo(1); - queue.dequeue(redis, 1, service); + queue.dequeue(redis, timeout, service); assertThat(queue.size(redis)).isEqualTo(0); service.shutdown(); assertThat(service.awaitTermination(1, MILLISECONDS)).isTrue(); From 7e3db2ec491bbbae4077fb2db1e4474d2736d620 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Thu, 21 Mar 2024 11:18:55 -0700 Subject: [PATCH 247/311] ci: bump buildifier to 6.4.0 --- .bazelci/presubmit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index 675beb237c..fdc0fa986d 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -1,5 +1,5 @@ --- -buildifier: 4.2.5 +buildifier: 6.4.0 tasks: # Linting jobs From 2db583ae8156d7f59aaba8f83b0b3b770da54235 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Tue, 20 Feb 2024 22:41:37 -0500 Subject: [PATCH 248/311] Prevent NPE on shutdown with null pipeline --- src/main/java/build/buildfarm/worker/shard/Worker.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/build/buildfarm/worker/shard/Worker.java b/src/main/java/build/buildfarm/worker/shard/Worker.java index 844f1f1e72..60f8cf34d4 100644 --- a/src/main/java/build/buildfarm/worker/shard/Worker.java +++ b/src/main/java/build/buildfarm/worker/shard/Worker.java @@ -650,7 +650,9 @@ private void awaitTermination() throws InterruptedException { } public void initiateShutdown() { - pipeline.stopMatchingOperations(); + if (pipeline != null) { + pipeline.stopMatchingOperations(); + } if (server != null) { server.shutdown(); } From 97d009338d33de21a3a887c8ea00b36d98a94cc5 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Fri, 22 Mar 2024 14:54:32 -0400 Subject: [PATCH 249/311] Update to latest jedis release 5.1.2 --- defs.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/defs.bzl b/defs.bzl index ff380e378f..020edac27e 100644 --- a/defs.bzl +++ b/defs.bzl @@ -109,7 +109,7 @@ def buildfarm_init(name = "buildfarm"): "org.yaml:snakeyaml:2.2", "org.projectlombok:lombok:1.18.30", "org.slf4j:slf4j-simple:2.0.9", - "redis.clients:jedis:5.1.0", + "redis.clients:jedis:5.1.2", ], generate_compat_repositories = True, override_targets = IO_GRPC_GRPC_JAVA_OVERRIDE_TARGETS, From 788f7ea4956def2b47a464a1ff77997e20f00f12 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Fri, 22 Mar 2024 21:44:19 -0400 Subject: [PATCH 250/311] Update remaining references to redis 5.0.9 --- README.md | 2 +- examples/bf-run | 2 +- run_server | 4 ++-- run_worker | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 079f453ac3..f02a8bbb6f 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ All commandline options override corresponding config settings. Run via ```shell -$ docker run -d --rm --name buildfarm-redis -p 6379:6379 redis:5.0.9 +$ docker run -d --rm --name buildfarm-redis -p 6379:6379 redis:7.2.4 redis-cli config set stop-writes-on-bgsave-error no ``` diff --git a/examples/bf-run b/examples/bf-run index b74b020f6f..ffea9faf42 100755 --- a/examples/bf-run +++ b/examples/bf-run @@ -3,7 +3,7 @@ set -e REDIS_NAME="buildfarm-redis" -REDIS_IMAGE="redis:5.0.9" +REDIS_IMAGE="redis:7.2.4" SERVER_NAME="buildfarm-server" SERVER_IMAGE="bazelbuild/buildfarm-server:latest" diff --git a/run_server b/run_server index 7698063fef..759b31743d 100755 --- a/run_server +++ b/run_server @@ -3,7 +3,7 @@ set -e set -o pipefail # Run Redis docker container -docker start buildfarm-redis || docker run -d --rm --name buildfarm-redis -p 6379:6379 redis:5.0.9 +docker start buildfarm-redis || docker run -d --rm --name buildfarm-redis -p 6379:6379 redis:7.2.4 redis-cli config set stop-writes-on-bgsave-error no # Determine which configuration file to use - default or user provided @@ -15,4 +15,4 @@ else fi # Run Server -bazelisk run //src/main/java/build/buildfarm:buildfarm-server -- --jvm_flag=-Dlogging.config=file:$PWD/examples/logging.properties $config \ No newline at end of file +bazelisk run //src/main/java/build/buildfarm:buildfarm-server -- --jvm_flag=-Dlogging.config=file:$PWD/examples/logging.properties $config diff --git a/run_worker b/run_worker index f3b84fdccf..f1da296906 100755 --- a/run_worker +++ b/run_worker @@ -3,7 +3,7 @@ set -e set -o pipefail # Run Redis docker container -docker start buildfarm-redis || docker run -d --rm --name buildfarm-redis -p 6379:6379 redis:5.0.9 +docker start buildfarm-redis || docker run -d --rm --name buildfarm-redis -p 6379:6379 redis:7.2.4 redis-cli config set stop-writes-on-bgsave-error no # Determine which configuration file to use - default or user provided @@ -15,4 +15,4 @@ else fi # Run Server -bazelisk run //src/main/java/build/buildfarm:buildfarm-shard-worker -- --jvm_flag=-Dlogging.config=file:$PWD/examples/logging.properties $config \ No newline at end of file +bazelisk run //src/main/java/build/buildfarm:buildfarm-shard-worker -- --jvm_flag=-Dlogging.config=file:$PWD/examples/logging.properties $config From 1501dd449781275750d7497b70fc60c14e9ade07 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Tue, 26 Mar 2024 07:53:11 -0700 Subject: [PATCH 251/311] build(bzlmod): update rules_pkg (#1646) * build(rules_pkg): switch to bzlmod dependency * build: add more toolchains for rpms * build: satisfy buildkite * refactor: swap genrule for rules_pkg * tests: container tests - update single-quotes to double quotes for consistency - add file permissions for skip_sleep_preload.so --- BUILD | 96 +++++++++---------- MODULE.bazel | 17 ++++ container/test/example_config.yaml | 6 +- container/test/server.yaml | 9 +- container/test/telemetry_tools.yaml | 2 +- container/test/worker.yaml | 12 +-- container/test/worker_wrappers.yaml | 37 +++---- deps.bzl | 10 -- .../java/build/buildfarm/rpms/server/BUILD | 2 +- .../java/build/buildfarm/rpms/worker/BUILD | 2 +- 10 files changed, 99 insertions(+), 94 deletions(-) diff --git a/BUILD b/BUILD index d37e4925f1..a1f6749aaa 100644 --- a/BUILD +++ b/BUILD @@ -1,6 +1,7 @@ load("@buildifier_prebuilt//:rules.bzl", "buildifier") load("@rules_oci//oci:defs.bzl", "oci_image", "oci_image_index", "oci_push", "oci_tarball") load("@rules_pkg//:pkg.bzl", "pkg_tar") +load("@rules_pkg//pkg:mappings.bzl", "pkg_attributes", "pkg_files") load("//:jvm_flags.bzl", "server_jvm_flags", "worker_jvm_flags") load("//container:defs.bzl", "oci_image_env") @@ -46,13 +47,8 @@ DEFAULT_PACKAGE_DIR = "app/build_buildfarm" pkg_tar( name = "execution_wrappers", srcs = [ - ":as-nobody", - ":delay", - ":linux-sandbox.binary", - ":macos-wrapper", - ":process-wrapper.binary", - ":skip_sleep.binary", - ":skip_sleep.preload", + ":exec-wrapper-files", + ":exec-wrapper-helpers", ], package_dir = DEFAULT_PACKAGE_DIR, tags = ["container"], @@ -67,32 +63,28 @@ pkg_tar( tags = ["container"], ) -genrule( - name = "process-wrapper.binary", - srcs = ["@bazel//src/main/tools:process-wrapper"], - outs = ["process-wrapper"], - cmd = "cp $< $@;", -) - -genrule( - name = "linux-sandbox.binary", - srcs = ["@bazel//src/main/tools:linux-sandbox"], - outs = ["linux-sandbox"], - cmd = "cp $< $@;", -) - -genrule( +pkg_files( name = "tini.binary", srcs = ["@tini//file"], - outs = ["tini"], - cmd = "cp $< $@ && chmod +x $@", + attributes = pkg_attributes( + mode = "0555", + ), + renames = { + "@tini//file": "tini", + }, + tags = ["container"], ) -genrule( +pkg_files( name = "opentelemetry-javaagent", srcs = ["@opentelemetry//jar"], - outs = ["opentelemetry-javaagent.jar"], - cmd = "cp $< $@;", + attributes = pkg_attributes( + mode = "0444", + ), + renames = { + "@opentelemetry//jar": "opentelemetry-javaagent.jar", + }, + tags = ["container"], ) cc_binary( @@ -101,38 +93,42 @@ cc_binary( "//config:windows": ["as-nobody-windows.c"], "//conditions:default": ["as-nobody.c"], }), + tags = ["container"], ) -genrule( - name = "skip_sleep.binary", - srcs = ["@skip_sleep"], - outs = ["skip_sleep"], - cmd = "cp $< $@;", +pkg_files( + name = "exec-wrapper-files", + srcs = [ + ":as-nobody", + "@bazel//src/main/tools:linux-sandbox", + "@bazel//src/main/tools:process-wrapper", + "@skip_sleep", + # The delay wrapper is only intended to be used with the "skip_sleep" wrapper. + "delay.sh", + "macos-wrapper.sh", + ], + attributes = pkg_attributes( + mode = "0555", + ), + tags = ["container"], ) -genrule( - name = "skip_sleep.preload", +pkg_files( + name = "exec-wrapper-helpers", srcs = ["@skip_sleep//:skip_sleep_preload"], - outs = ["skip_sleep_preload.so"], - cmd = "cp $< $@;", -) - -# The delay wrapper is only intended to be used with the "skip_sleep" wrapper. -sh_binary( - name = "delay", - srcs = ["delay.sh"], -) - -sh_binary( - name = "macos-wrapper", - srcs = ["macos-wrapper.sh"], + attributes = pkg_attributes( + mode = "0444", + ), + prefix = DEFAULT_PACKAGE_DIR, + renames = { + "@skip_sleep//:skip_sleep_preload": "skip_sleep_preload.so", + }, + tags = ["container"], ) pkg_tar( name = "layer_tini_amd64", - srcs = ["@tini//file"], - mode = "0555", - remap_paths = {"/downloaded": "/tini"}, + srcs = [":tini.binary"], tags = ["container"], ) diff --git a/MODULE.bazel b/MODULE.bazel index 1624d4adc9..5f7f6ac1ae 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -13,6 +13,7 @@ bazel_dep(name = "rules_go", version = "0.44.2", repo_name = "io_bazel_rules_go" bazel_dep(name = "rules_jvm_external", version = "5.3") bazel_dep(name = "rules_license", version = "0.0.7") bazel_dep(name = "rules_oci", version = "1.7.4") +bazel_dep(name = "rules_pkg", version = "0.10.1") # Test dependencies bazel_dep( @@ -51,3 +52,19 @@ use_repo( "amazon_corretto_java_image_base", "ubuntu_mantic", ) + +# https://github.com/bazelbuild/rules_python/pull/713#issuecomment-1885628496 +# Satisfy running tests in Docker as root. +bazel_dep(name = "rules_python", version = "0.24.0") + +python = use_extension("@rules_python//python/extensions:python.bzl", "python") +python.toolchain( + configure_coverage_tool = False, + ignore_root_user_error = True, + python_version = "3.11", +) + +find_rpm = use_extension("@rules_pkg//toolchains/rpm:rpmbuild_configure.bzl", "find_system_rpmbuild_bzlmod") +use_repo(find_rpm, "rules_pkg_rpmbuild") + +register_toolchains("@rules_pkg_rpmbuild//:all") diff --git a/container/test/example_config.yaml b/container/test/example_config.yaml index 100d20289f..eb875ae66a 100644 --- a/container/test/example_config.yaml +++ b/container/test/example_config.yaml @@ -3,10 +3,10 @@ schemaVersion: "2.0.0" fileExistenceTests: - name: "config.minimal.yaml" - path: '/app/build_buildfarm/config.minimal.yml' + path: "/app/build_buildfarm/config.minimal.yml" shouldExist: true - - name: 'logging.properties' - path: '/app/build_buildfarm/src/main/java/build/buildfarm/logging.properties' + - name: "logging.properties" + path: "/app/build_buildfarm/src/main/java/build/buildfarm/logging.properties" shouldExist: true metadataTest: diff --git a/container/test/server.yaml b/container/test/server.yaml index 780d00b101..40f64ed354 100644 --- a/container/test/server.yaml +++ b/container/test/server.yaml @@ -2,16 +2,15 @@ schemaVersion: "2.0.0" fileExistenceTests: - - name: "JAR" - path: '/app/build_buildfarm/buildfarm-server_deploy.jar' + path: "/app/build_buildfarm/buildfarm-server_deploy.jar" shouldExist: true metadataTest: envVars: - key: JAVA_TOOL_OPTIONS - value: 'UseContainerSupport' + value: "UseContainerSupport" isRegex: true labels: - - key: 'org.opencontainers.image.source' - value: 'https://github.com/bazelbuild/bazel-buildfarm' + - key: "org.opencontainers.image.source" + value: "https://github.com/bazelbuild/bazel-buildfarm" diff --git a/container/test/telemetry_tools.yaml b/container/test/telemetry_tools.yaml index 233faafaeb..828067f571 100644 --- a/container/test/telemetry_tools.yaml +++ b/container/test/telemetry_tools.yaml @@ -3,5 +3,5 @@ schemaVersion: "2.0.0" fileExistenceTests: - name: "opentelemetry-javaagent" - path: '/app/build_buildfarm/opentelemetry-javaagent.jar' + path: "/app/build_buildfarm/opentelemetry-javaagent.jar" shouldExist: true diff --git a/container/test/worker.yaml b/container/test/worker.yaml index c670f4a682..60caad9900 100644 --- a/container/test/worker.yaml +++ b/container/test/worker.yaml @@ -3,19 +3,19 @@ schemaVersion: "2.0.0" fileExistenceTests: - name: "JAR" - path: '/app/build_buildfarm/buildfarm-shard-worker_deploy.jar' + path: "/app/build_buildfarm/buildfarm-shard-worker_deploy.jar" shouldExist: true - name: "tini" - path: '/tini' + path: "/tini" shouldExist: true - permissions: '-r-xr-xr-x' + permissions: "-r-xr-xr-x" metadataTest: envVars: - key: JAVA_TOOL_OPTIONS - value: 'UseContainerSupport' + value: "UseContainerSupport" isRegex: true labels: - - key: 'org.opencontainers.image.source' - value: 'https://github.com/bazelbuild/bazel-buildfarm' \ No newline at end of file + - key: "org.opencontainers.image.source" + value: "https://github.com/bazelbuild/bazel-buildfarm" diff --git a/container/test/worker_wrappers.yaml b/container/test/worker_wrappers.yaml index 4df0da7afe..36eac05a84 100644 --- a/container/test/worker_wrappers.yaml +++ b/container/test/worker_wrappers.yaml @@ -3,45 +3,48 @@ schemaVersion: "2.0.0" # These align with the default paths in //src/main/java/build/buildfarm/common/config/ExecutionWrappers.java fileExistenceTests: - name: "cgroups cexec" + # This is installed by the OS package manager. path: "/usr/bin/cgexec" shouldExist: true - permissions: '-rwxr-xr-x' + permissions: "-rwxr-xr-x" - name: "unshare" + # This is installed by the OS package manager. path: "/usr/bin/unshare" shouldExist: true - permissions: '-rwxr-xr-x' + permissions: "-rwxr-xr-x" - name: "as-nobody wrapper" - path: '/app/build_buildfarm/as-nobody' + path: "/app/build_buildfarm/as-nobody" shouldExist: true - permissions: '-r-xr-xr-x' + permissions: "-r-xr-xr-x" - name: "process-wrapper" - path: '/app/build_buildfarm/process-wrapper' + path: "/app/build_buildfarm/process-wrapper" shouldExist: true - permissions: '-r-xr-xr-x' + permissions: "-r-xr-xr-x" - name: "skip-sleep" - path: '/app/build_buildfarm/skip_sleep' + path: "/app/build_buildfarm/skip_sleep" shouldExist: true - permissions: '-r-xr-xr-x' + permissions: "-r-xr-xr-x" - name: "skip-sleep-preload" - path: '/app/build_buildfarm/skip_sleep_preload.so' + path: "/app/build_buildfarm/skip_sleep_preload.so" shouldExist: true + permissions: "-r--r--r--" - name: "delay.sh" - path: '/app/build_buildfarm/delay.sh' + path: "/app/build_buildfarm/delay.sh" shouldExist: true - permissions: '-r-xr-xr-x' -#----- -# These are documented in //:execution_wrappers + permissions: "-r-xr-xr-x" + #----- + # These are documented in //:execution_wrappers - name: "linux-sandbox" - path: '/app/build_buildfarm/linux-sandbox' + path: "/app/build_buildfarm/linux-sandbox" shouldExist: true - permissions: '-r-xr-xr-x' + permissions: "-r-xr-xr-x" - name: "macos-wrapper" - path: '/app/build_buildfarm/macos-wrapper.sh' + path: "/app/build_buildfarm/macos-wrapper.sh" shouldExist: true - permissions: '-r-xr-xr-x' + permissions: "-r-xr-xr-x" diff --git a/deps.bzl b/deps.bzl index df8d20db86..6607f5a2c1 100644 --- a/deps.bzl +++ b/deps.bzl @@ -15,16 +15,6 @@ def archive_dependencies(third_party): "urls": ["https://github.com/grpc/grpc-java/archive/v1.62.2.zip"], # Bzlmod: Waiting for https://github.com/bazelbuild/bazel-central-registry/issues/353 }, - { - "name": "rules_pkg", - "sha256": "335632735e625d408870ec3e361e192e99ef7462315caa887417f4d88c4c8fb8", - "urls": [ - "https://mirror.bazel.build/github.com/bazelbuild/rules_pkg/releases/download/0.9.0/rules_pkg-0.9.0.tar.gz", - "https://github.com/bazelbuild/rules_pkg/releases/download/0.9.0/rules_pkg-0.9.0.tar.gz", - ], - # Bzlmod : Waiting for >0.9.1 for https://github.com/bazelbuild/rules_pkg/pull/766 to be released - }, - # The APIs that we implement. { "name": "googleapis", diff --git a/src/main/java/build/buildfarm/rpms/server/BUILD b/src/main/java/build/buildfarm/rpms/server/BUILD index 31942644e8..d407be4589 100644 --- a/src/main/java/build/buildfarm/rpms/server/BUILD +++ b/src/main/java/build/buildfarm/rpms/server/BUILD @@ -1,4 +1,4 @@ -load("@rules_pkg//:rpm.bzl", "pkg_rpm") +load("@rules_pkg//pkg:rpm.bzl", "pkg_rpm") pkg_rpm( name = "buildfarm-server-rpm", diff --git a/src/main/java/build/buildfarm/rpms/worker/BUILD b/src/main/java/build/buildfarm/rpms/worker/BUILD index 1a06f01c90..98e76fb81e 100644 --- a/src/main/java/build/buildfarm/rpms/worker/BUILD +++ b/src/main/java/build/buildfarm/rpms/worker/BUILD @@ -1,4 +1,4 @@ -load("@rules_pkg//:rpm.bzl", "pkg_rpm") +load("@rules_pkg//pkg:rpm.bzl", "pkg_rpm") pkg_rpm( name = "buildfarm-worker-rpm", From e1ad3ad22875a2462d19db36727b498d9e738f81 Mon Sep 17 00:00:00 2001 From: Andrew Rothstein Date: Tue, 26 Mar 2024 17:52:17 -0400 Subject: [PATCH 252/311] publish Helm chart as OCI artifact to ghcr.io (#1683) in lieu of publishing a tgz as a GitHub release artifact, this change publishes (on tag helm/${semver}) the Helm chart bundled as an OCI artifact to the GitHub container registry, i.e. ghcr.io. I also updated the installation instructions which are now less gory. This change requires granting public read access to the corresponding buildfarm "package" within the bazel-buildfarm project. It defaults to private. --- .../buildfarm-helm-chart-publish.yml | 26 +++++++++++++++---- README.md | 7 +++-- kubernetes/helm-charts/buildfarm/Chart.yaml | 2 +- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/.github/workflows/buildfarm-helm-chart-publish.yml b/.github/workflows/buildfarm-helm-chart-publish.yml index 0c43525e8c..322634368f 100644 --- a/.github/workflows/buildfarm-helm-chart-publish.yml +++ b/.github/workflows/buildfarm-helm-chart-publish.yml @@ -7,8 +7,9 @@ on: - 'helm/*' env: - GH_TOKEN: ${{ github.token }} - CHART_ROOT: kubernetes/helm-charts/buildfarm + CHART_NAME: buildfarm + CHART_ROOT: ${{ github.workspace }}/kubernetes/helm-charts/buildfarm + GHCR_REPO: ghcr.io/${{ github.repository_owner }} jobs: build: @@ -32,11 +33,26 @@ jobs: yq -i \ '.version |= "${{ steps.get-chart-ver.outputs.chart_ver }}"' \ ${CHART_ROOT}/Chart.yaml - - id: helm-lint-package-release - name: Helm Chart Lint, Package, and Release + - id: helm-lint + name: Helm Chart Lint run: |- set -ex helm dep up "${CHART_ROOT}" helm lint "${CHART_ROOT}" + - id: helm-bundle-push + name: Helm Chart Bundle and Push + run: |- + set -e + echo ${{ secrets.GITHUB_TOKEN }} | \ + helm registry \ + login "${GHCR_REPO}" \ + --username "${{ github.repository_owner }}" \ + --password-stdin + set -ex + helm dep up "${CHART_ROOT}" helm package "${CHART_ROOT}" - gh release create "${{ github.ref_name }}" *.tgz + export CHART_BUNDLE="${CHART_NAME}-${{ steps.get-chart-ver.outputs.chart_ver }}.tgz" + ls -l "${CHART_BUNDLE}" + helm push \ + "${CHART_BUNDLE}" \ + "oci://${GHCR_REPO}" diff --git a/README.md b/README.md index f02a8bbb6f..6813ab4545 100644 --- a/README.md +++ b/README.md @@ -140,14 +140,13 @@ buildfarm_images() ### Helm Chart -To install with helm: +To install OCI bundled Helm chart: ```bash -# https://github.com/bazelbuild/bazel-buildfarm/releases/download/helm%2F0.3.0/buildfarm-0.3.0.tgz -CHART_VER="0.3.0" helm install \ -n bazel-buildfarm \ --create-namespace \ bazel-buildfarm \ - "https://github.com/bazelbuild/bazel-buildfarm/releases/download/helm%2F${CHART_VER}/buildfarm-${CHART_VER}.tgz" + oci://ghcr.io/bazelbuild/buildfarm \ + --version "0.2.4" ``` diff --git a/kubernetes/helm-charts/buildfarm/Chart.yaml b/kubernetes/helm-charts/buildfarm/Chart.yaml index 8e105c726e..66c2560526 100644 --- a/kubernetes/helm-charts/buildfarm/Chart.yaml +++ b/kubernetes/helm-charts/buildfarm/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.3.0 +version: 0.2.4 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to From 66ce90dd4c0f7d463858750af2116dece2fb873c Mon Sep 17 00:00:00 2001 From: George Gensure Date: Thu, 28 Mar 2024 22:25:37 -0400 Subject: [PATCH 253/311] Create codeql.yml (#1689) --- .github/workflows/codeql.yml | 50 ++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000000..e2c75ddef5 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,50 @@ +name: CodeQL + +# Declare default permissions as read only. +permissions: read-all + +on: + pull_request: + branches: [main] + push: + branches: + - main + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + + permissions: + security-events: write + + strategy: + matrix: + language: ["java-kotlin"] + + steps: + - uses: bazel-contrib/setup-bazel@0.8.1 + with: + # Avoid downloading Bazel every time. + bazelisk-cache: true + + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + build-mode: manual + + - name: Build java + # Note: Bazel requires specific args to do the build with a little caching as possible. Kind of the anthesis of Bazel's philosophy, + # But codeql wants to observe all the compilation. + # See also: https://docs.github.com/en/enterprise-cloud@latest/code-security/codeql-cli/getting-started-with-the-codeql-cli/preparing-your-code-for-codeql-analysis#specifying-build-commands + run: | + bazel build --spawn_strategy=local --nouse_action_cache --noremote_accept_cached --noremote_upload_local_results //src/main/java/build/buildfarm:buildfarm-server //src/main/java/build/buildfarm:buildfarm-shard-worker + bazel shutdown + + - uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{ matrix.language }}" From 2a8afb333e411b1b962ed71af9257a8f8ddf9aa9 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Sun, 31 Mar 2024 19:40:12 -0700 Subject: [PATCH 254/311] fix: remove redis hashtags from prometheus metrics (#1693) Strip the redis hashtags from the `queue_size` metric Fixes: #1687 --- .../java/build/buildfarm/instance/shard/ServerInstance.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/build/buildfarm/instance/shard/ServerInstance.java b/src/main/java/build/buildfarm/instance/shard/ServerInstance.java index aa8d442f5f..1d526f5ab8 100644 --- a/src/main/java/build/buildfarm/instance/shard/ServerInstance.java +++ b/src/main/java/build/buildfarm/instance/shard/ServerInstance.java @@ -79,6 +79,7 @@ import build.buildfarm.common.Write; import build.buildfarm.common.config.BuildfarmConfigs; import build.buildfarm.common.grpc.UniformDelegateServerCallStreamObserver; +import build.buildfarm.common.redis.RedisHashtags; import build.buildfarm.instance.Instance; import build.buildfarm.instance.MatchListener; import build.buildfarm.instance.server.NodeInstance; @@ -541,7 +542,9 @@ public void run() { private void updateQueueSizes(List queues) { if (queueSize != null) { for (QueueStatus queueStatus : queues) { - queueSize.labels(queueStatus.getName()).set(queueStatus.getSize()); + queueSize + .labels(RedisHashtags.unhashedName(queueStatus.getName())) + .set(queueStatus.getSize()); } } } From c61e8247b4daa44aafc926864c078e90d9eb4954 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Tue, 2 Apr 2024 23:24:51 -0400 Subject: [PATCH 255/311] Rework Queue object pattern hierarchy (#1695) --- .../java/build/buildfarm/common/Queue.java | 26 ++ .../java/build/buildfarm/common/redis/BUILD | 1 + .../common/redis/BalancedRedisQueue.java | 209 +++++----- .../common/redis/ProvisionedRedisQueue.java | 13 +- .../common/redis/QueueDecorator.java | 8 + .../common/redis/QueueInterface.java | 121 ------ .../common/redis/RedisPriorityQueue.java | 81 ++-- .../buildfarm/common/redis/RedisQueue.java | 120 +++--- .../buildfarm/common/redis/RedisQueues.java | 38 -- .../buildfarm/common/redis/Timestamp.java | 11 - .../shard/DistributedStateCreator.java | 15 +- .../instance/shard/OperationQueue.java | 14 +- .../instance/shard/RedisShardBackplane.java | 4 +- .../redis/BalancedRedisQueueMockTest.java | 112 +++--- .../common/redis/BalancedRedisQueueTest.java | 320 ++++++++-------- .../redis/RedisPriorityQueueMockTest.java | 212 +++++------ .../common/redis/RedisPriorityQueueTest.java | 300 +++++++-------- .../common/redis/RedisQueueMockTest.java | 356 ++++-------------- .../common/redis/RedisQueueTest.java | 284 +++++--------- 19 files changed, 882 insertions(+), 1363 deletions(-) create mode 100644 src/main/java/build/buildfarm/common/Queue.java create mode 100644 src/main/java/build/buildfarm/common/redis/QueueDecorator.java delete mode 100644 src/main/java/build/buildfarm/common/redis/QueueInterface.java delete mode 100644 src/main/java/build/buildfarm/common/redis/RedisQueues.java delete mode 100644 src/main/java/build/buildfarm/common/redis/Timestamp.java diff --git a/src/main/java/build/buildfarm/common/Queue.java b/src/main/java/build/buildfarm/common/Queue.java new file mode 100644 index 0000000000..0fc9573e90 --- /dev/null +++ b/src/main/java/build/buildfarm/common/Queue.java @@ -0,0 +1,26 @@ +package build.buildfarm.common; + +import java.time.Duration; + +public interface Queue { + // java.util.BlockingQueue-ish + E take(Duration timeout) throws InterruptedException; + + // java.util.Queue + E poll(); + + boolean offer(E e); + + // our special variety + boolean offer(E e, double priority); + + // java.util.Collection + long size(); + + // maybe switch to iterator? + void visit(StringVisitor visitor); + + void visitDequeue(StringVisitor visitor); + + boolean removeFromDequeue(E e); +} diff --git a/src/main/java/build/buildfarm/common/redis/BUILD b/src/main/java/build/buildfarm/common/redis/BUILD index 19b5c77456..3f3ca09dd3 100644 --- a/src/main/java/build/buildfarm/common/redis/BUILD +++ b/src/main/java/build/buildfarm/common/redis/BUILD @@ -6,6 +6,7 @@ java_library( "//src/main/java/build/buildfarm/common", "//src/main/java/build/buildfarm/common/config", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", + "@maven//:com_google_code_findbugs_jsr305", "@maven//:com_google_guava_guava", "@maven//:io_grpc_grpc_api", "@maven//:org_redisson_redisson", diff --git a/src/main/java/build/buildfarm/common/redis/BalancedRedisQueue.java b/src/main/java/build/buildfarm/common/redis/BalancedRedisQueue.java index c7c5e26f58..8ed911d6c0 100644 --- a/src/main/java/build/buildfarm/common/redis/BalancedRedisQueue.java +++ b/src/main/java/build/buildfarm/common/redis/BalancedRedisQueue.java @@ -14,15 +14,21 @@ package build.buildfarm.common.redis; +import static com.google.common.collect.Iterables.transform; + +import build.buildfarm.common.Queue; import build.buildfarm.common.StringVisitor; -import build.buildfarm.common.config.Queue; import build.buildfarm.v1test.QueueStatus; import com.google.common.collect.ImmutableList; import java.time.Duration; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import javax.annotation.Nullable; import redis.clients.jedis.Connection; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisCluster; @@ -77,7 +83,9 @@ public class BalancedRedisQueue { * @details Although these are multiple queues, the balanced redis queue treats them as one in its * interface. */ - private final List queues; + private final List queues; + + private final QueueDecorator queueDecorator; /** * @field currentPushQueue @@ -102,32 +110,8 @@ public class BalancedRedisQueue { * @param hashtags Hashtags to distribute queue data. * @note Overloaded. */ - public BalancedRedisQueue(String name, List hashtags) { - this(name, hashtags, -1, Queue.QUEUE_TYPE.standard); - } - - /** - * @brief Constructor. - * @details Construct a named redis queue with an established redis cluster. - * @param name The global name of the queue. - * @param hashtags Hashtags to distribute queue data. - * @param queueType Type of the queue in use - * @note Overloaded. - */ - public BalancedRedisQueue(String name, List hashtags, Queue.QUEUE_TYPE queueType) { - this(name, hashtags, -1, queueType); - } - - /** - * @brief Constructor. - * @details Construct a named redis queue with an established redis cluster. - * @param name The global name of the queue. - * @param hashtags Hashtags to distribute queue data. - * @param maxQueueSize The maximum amount of elements that should be added to the queue. - * @note Overloaded. - */ - public BalancedRedisQueue(String name, List hashtags, int maxQueueSize) { - this(name, hashtags, maxQueueSize, Queue.QUEUE_TYPE.standard); + public BalancedRedisQueue(String name, List hashtags, QueueDecorator queueDecorator) { + this(name, hashtags, -1, queueDecorator); } /** @@ -136,19 +120,20 @@ public BalancedRedisQueue(String name, List hashtags, int maxQueueSize) * @param name The global name of the queue. * @param hashtags Hashtags to distribute queue data. * @param maxQueueSize The maximum amount of elements that should be added to the queue. - * @param queueType Type of the queue in use * @note Overloaded. */ public BalancedRedisQueue( - String name, List hashtags, int maxQueueSize, Queue.QUEUE_TYPE queueType) { - this(name, maxQueueSize, createHashedQueues(name, hashtags, queueType)); + String name, List hashtags, int maxQueueSize, QueueDecorator queueDecorator) { + this(name, maxQueueSize, createHashedQueues(name, hashtags), queueDecorator); } - public BalancedRedisQueue(String name, int maxQueueSize, List queues) { + public BalancedRedisQueue( + String name, int maxQueueSize, List queues, QueueDecorator queueDecorator) { this.originalHashtag = RedisHashtags.existingHash(name); this.name = RedisHashtags.unhashedName(name); this.maxQueueSize = maxQueueSize; this.queues = queues; + this.queueDecorator = queueDecorator; } /** @@ -156,10 +141,10 @@ public BalancedRedisQueue(String name, int maxQueueSize, List qu * @details Adds the value into one of the internal backend redis queues. * @param val The value to push onto the queue. */ - public void push(UnifiedJedis unified, String val) { - QueueInterface queue = queues.get(roundRobinPushIndex()); - try (Jedis jedis = getJedisFromKey(unified, queue.getName())) { - queue.push(jedis, val); + public boolean offer(UnifiedJedis unified, String val) { + String queue = queues.get(roundRobinPushIndex()); + try (Jedis jedis = getJedisFromKey(unified, queue)) { + return queueDecorator.decorate(jedis, queue).offer(val); } } @@ -168,10 +153,10 @@ public void push(UnifiedJedis unified, String val) { * @details Adds the value into one of the internal backend redis queues. * @param val The value to push onto the queue. */ - public void push(UnifiedJedis unified, String val, double priority) { - QueueInterface queue = queues.get(roundRobinPushIndex()); - try (Jedis jedis = getJedisFromKey(unified, queue.getName())) { - queue.push(jedis, val, priority); + public boolean offer(UnifiedJedis unified, String val, double priority) { + String queue = queues.get(roundRobinPushIndex()); + try (Jedis jedis = getJedisFromKey(unified, queue)) { + return queueDecorator.decorate(jedis, queue).offer(val, priority); } } @@ -183,9 +168,9 @@ public void push(UnifiedJedis unified, String val, double priority) { * @note Suggested return identifier: wasRemoved. */ public boolean removeFromDequeue(UnifiedJedis unified, String val) { - for (QueueInterface queue : partialIterationQueueOrder()) { - try (Jedis jedis = getJedisFromKey(unified, queue.getName())) { - if (queue.removeFromDequeue(jedis, val)) { + for (String queue : partialIterationQueueOrder()) { + try (Jedis jedis = getJedisFromKey(unified, queue)) { + if (queueDecorator.decorate(jedis, queue).removeFromDequeue(val)) { return true; } } @@ -193,6 +178,41 @@ public boolean removeFromDequeue(UnifiedJedis unified, String val) { return false; } + private String take(Jedis jedis, Queue queue, Duration timeout, ExecutorService service) + throws InterruptedException { + return interruptibleRequest(() -> queue.take(timeout), jedis::disconnect, service); + } + + private T interruptibleRequest( + Callable command, Runnable onInterrupted, ExecutorService service) + throws InterruptedException { + Future reply = service.submit(command); + return getBlockingReply(reply, onInterrupted); + } + + private T getBlockingReply(Future reply, Runnable onInterrupted) + throws InterruptedException { + InterruptedException interruption = null; + for (; ; ) { + try { + return reply.get(); + } catch (ExecutionException e) { + Throwable cause = e.getCause(); + if (interruption != null) { + interruption.addSuppressed(cause); + Thread.currentThread().interrupt(); + throw interruption; + } + throw new RuntimeException(cause); + } catch (InterruptedException e) { + interruption = e; + Thread.interrupted(); + reply.cancel(true); + onInterrupted.run(); + } + } + } + /** * @brief Pop element into internal dequeue and return value. * @details This pops the element from one queue atomically into an internal list called the @@ -201,7 +221,7 @@ public boolean removeFromDequeue(UnifiedJedis unified, String val) { * @return The value of the transfered element. null if the thread was interrupted. * @note Suggested return identifier: val. */ - public String dequeue(UnifiedJedis unified, ExecutorService service) throws InterruptedException { + public String take(UnifiedJedis unified, ExecutorService service) throws InterruptedException { // The conditions of this algorithm are as followed: // - from a client's perspective we want to block indefinitely. // (so this function should not return null under any normal circumstances.) @@ -226,12 +246,13 @@ public String dequeue(UnifiedJedis unified, ExecutorService service) throws Inte Duration currentTimeout = START_TIMEOUT; while (true) { final String val; - QueueInterface queue = queues.get(roundRobinPopIndex()); - try (Jedis jedis = getJedisFromKey(unified, queue.getName())) { + String queueName = queues.get(roundRobinPopIndex()); + try (Jedis jedis = getJedisFromKey(unified, queueName)) { + Queue queue = queueDecorator.decorate(jedis, queueName); if (blocking) { - val = queue.dequeue(jedis, currentTimeout, service); + val = take(jedis, queue, currentTimeout, service); } else { - val = queue.nonBlockingDequeue(jedis); + val = queue.poll(); } } // return if found @@ -279,10 +300,10 @@ private static Jedis getJedisFromKey(UnifiedJedis jedis, String name) { * @return The value of the transfered element. null if queue is empty or thread was interrupted. * @note Suggested return identifier: val. */ - public String nonBlockingDequeue(UnifiedJedis unified) throws InterruptedException { - QueueInterface queue = queues.get(roundRobinPopIndex()); - try (Jedis jedis = getJedisFromKey(unified, queue.getName())) { - return queue.nonBlockingDequeue(jedis); + public @Nullable String poll(UnifiedJedis unified) { + String queue = queues.get(roundRobinPopIndex()); + try (Jedis jedis = getJedisFromKey(unified, queue)) { + return queueDecorator.decorate(jedis, queue).poll(); } } @@ -292,7 +313,7 @@ public String nonBlockingDequeue(UnifiedJedis unified) throws InterruptedExcepti * @return The queue that the balanced queue intends to pop from next. * @note Suggested return identifier: currentPopQueue. */ - public QueueInterface getCurrentPopQueue() { + public String getCurrentPopQueue() { return queues.get(currentPopQueue); } @@ -313,7 +334,7 @@ public int getCurrentPopQueueIndex() { * @return The internal queue found at that index. * @note Suggested return identifier: internalQueue. */ - public QueueInterface getInternalQueue(int index) { + public String getInternalQueue(int index) { return queues.get(index); } @@ -339,6 +360,15 @@ public String getName() { return name; } + // annoying that there's no inject/accumulate + private static long size(Iterable sizes) { + long size = 0; + for (long s : sizes) { + size += s; + } + return size; + } + /** * @brief Get size. * @details Checks the current length of the queue. @@ -347,13 +377,18 @@ public String getName() { */ public long size(UnifiedJedis unified) { // the accumulated size of all of the queues - long size = 0; - for (QueueInterface queue : queues) { - try (Jedis jedis = getJedisFromKey(unified, queue.getName())) { - size += queue.size(jedis); - } + return size(sizes(unified)); + } + + private long size(UnifiedJedis unified, String queue) { + try (Jedis jedis = getJedisFromKey(unified, queue)) { + return queueDecorator.decorate(jedis, queue).size(); } - return size; + } + + private Iterable sizes(UnifiedJedis unified) { + // this could be done in parallel + return transform(queues, queue -> size(unified, queue)); } /** @@ -364,21 +399,13 @@ public long size(UnifiedJedis unified) { */ public QueueStatus status(UnifiedJedis unified) { // get properties - long size = 0; - ImmutableList.Builder sizes = ImmutableList.builder(); - for (QueueInterface queue : queues) { - try (Jedis jedis = getJedisFromKey(unified, queue.getName())) { - long queueSize = queue.size(jedis); - sizes.add(queueSize); - size += queueSize; - } - } + Iterable sizes = sizes(unified); // build proto return QueueStatus.newBuilder() .setName(RedisHashtags.hashedName(name, originalHashtag)) - .setSize(size) - .addAllInternalSizes(sizes.build()) + .setSize(size(sizes)) + .addAllInternalSizes(sizes) .build(); } @@ -388,9 +415,9 @@ public QueueStatus status(UnifiedJedis unified) { * @param visitor A visitor for each visited element in the queue. */ public void visit(UnifiedJedis unified, StringVisitor visitor) { - for (QueueInterface queue : fullIterationQueueOrder()) { - try (Jedis jedis = getJedisFromKey(unified, queue.getName())) { - queue.visit(jedis, visitor); + for (String queue : fullIterationQueueOrder()) { + try (Jedis jedis = getJedisFromKey(unified, queue)) { + queueDecorator.decorate(jedis, queue).visit(visitor); } } } @@ -401,9 +428,9 @@ public void visit(UnifiedJedis unified, StringVisitor visitor) { * @param visitor A visitor for each visited element in the queue. */ public void visitDequeue(UnifiedJedis unified, StringVisitor visitor) { - for (QueueInterface queue : fullIterationQueueOrder()) { - try (Jedis jedis = getJedisFromKey(unified, queue.getName())) { - queue.visitDequeue(jedis, visitor); + for (String queue : fullIterationQueueOrder()) { + try (Jedis jedis = getJedisFromKey(unified, queue)) { + queueDecorator.decorate(jedis, queue).visitDequeue(visitor); } } } @@ -418,14 +445,11 @@ public void visitDequeue(UnifiedJedis unified, StringVisitor visitor) { */ public boolean isEvenlyDistributed(UnifiedJedis unified) { long size = -1; - for (QueueInterface queue : partialIterationQueueOrder()) { - try (Jedis jedis = getJedisFromKey(unified, queue.getName())) { - long queueSize = queue.size(jedis); - if (size != -1 && queueSize != size) { - return false; - } - size = queueSize; + for (long queueSize : sizes(unified)) { + if (size != -1 && queueSize != size) { + return false; } + size = queueSize; } return true; } @@ -448,10 +472,9 @@ public boolean canQueue(UnifiedJedis jedis) { * @param name The global name of the queue. * @param hashtags Hashtags to distribute queue data. */ - private static List createHashedQueues( - String name, List hashtags, Queue.QUEUE_TYPE queueType) { + private static List createHashedQueues(String name, List hashtags) { String unhashedName = RedisHashtags.unhashedName(name); - ImmutableList.Builder queues = ImmutableList.builder(); + ImmutableList.Builder queues = ImmutableList.builder(); // if there were no hashtags, we'll create a single internal queue // so that the balanced redis queue can still function. // we'll use the basename provided to create the single internal queue and use the original @@ -465,7 +488,7 @@ private static List createHashedQueues( } // create an internal queue for each of the provided hashtags for (String hashtag : hashtags) { - queues.add(RedisQueues.create(queueType, RedisHashtags.hashedName(unhashedName, hashtag))); + queues.add(RedisHashtags.hashedName(unhashedName, hashtag)); } return queues.build(); } @@ -476,7 +499,7 @@ private static List createHashedQueues( * @return The current round-robin index. * @note Suggested return identifier: queueIndex. */ - private int roundRobinPushIndex() { + private synchronized int roundRobinPushIndex() { int currentIndex = currentPushQueue; currentPushQueue = nextQueueInRoundRobin(currentPushQueue); return currentIndex; @@ -488,7 +511,7 @@ private int roundRobinPushIndex() { * @return The current round-robin index. * @note Suggested return identifier: queueIndex. */ - private int roundRobinPopIndex() { + private synchronized int roundRobinPopIndex() { int currentIndex = currentPopQueue; currentPopQueue = nextQueueInRoundRobin(currentPopQueue); return currentIndex; @@ -516,7 +539,7 @@ private int nextQueueInRoundRobin(int index) { * @return An ordered list of queues. * @note Suggested return identifier: queues. */ - private List fullIterationQueueOrder() { + private List fullIterationQueueOrder() { // if we are going to iterate over all of the queues // there will be no noticeable side effects from the order return queues; @@ -532,11 +555,11 @@ private List fullIterationQueueOrder() { * @return An ordered list of queues. * @note Suggested return identifier: queues. */ - private List partialIterationQueueOrder() { + private List partialIterationQueueOrder() { // to improve cpu utilization, we can try randomizing // the order we traverse the internal queues for operations // that may return early - List randomQueues = new ArrayList<>(queues); + List randomQueues = new ArrayList<>(queues); Collections.shuffle(randomQueues); return randomQueues; } diff --git a/src/main/java/build/buildfarm/common/redis/ProvisionedRedisQueue.java b/src/main/java/build/buildfarm/common/redis/ProvisionedRedisQueue.java index 75d3d2cc0c..2c65ad3922 100644 --- a/src/main/java/build/buildfarm/common/redis/ProvisionedRedisQueue.java +++ b/src/main/java/build/buildfarm/common/redis/ProvisionedRedisQueue.java @@ -16,7 +16,6 @@ import build.buildfarm.common.ExecutionProperties; import build.buildfarm.common.MapUtils; -import build.buildfarm.common.config.Queue; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSetMultimap; import com.google.common.collect.SetMultimap; @@ -91,7 +90,7 @@ public class ProvisionedRedisQueue { */ public ProvisionedRedisQueue( String name, List hashtags, SetMultimap filterProvisions) { - this(name, Queue.QUEUE_TYPE.standard, hashtags, filterProvisions, false); + this(name, RedisQueue::decorate, hashtags, filterProvisions, false); } /** @@ -109,7 +108,7 @@ public ProvisionedRedisQueue( List hashtags, SetMultimap filterProvisions, boolean allowUserUnmatched) { - this(name, Queue.QUEUE_TYPE.standard, hashtags, filterProvisions, allowUserUnmatched); + this(name, RedisQueue::decorate, hashtags, filterProvisions, allowUserUnmatched); } /** @@ -123,10 +122,10 @@ public ProvisionedRedisQueue( */ public ProvisionedRedisQueue( String name, - Queue.QUEUE_TYPE type, + QueueDecorator queueDecorator, List hashtags, SetMultimap filterProvisions) { - this(name, type, hashtags, filterProvisions, false); + this(name, queueDecorator, hashtags, filterProvisions, false); } /** @@ -142,11 +141,11 @@ public ProvisionedRedisQueue( */ public ProvisionedRedisQueue( String name, - Queue.QUEUE_TYPE type, + QueueDecorator queueDecorator, List hashtags, SetMultimap filterProvisions, boolean allowUserUnmatched) { - this.queue = new BalancedRedisQueue(name, hashtags, type); + this.queue = new BalancedRedisQueue(name, hashtags, queueDecorator); isFullyWildcard = filterProvisions.containsKey(WILDCARD_VALUE); provisions = filterProvisionsByWildcard(filterProvisions, isFullyWildcard); this.allowUserUnmatched = allowUserUnmatched; diff --git a/src/main/java/build/buildfarm/common/redis/QueueDecorator.java b/src/main/java/build/buildfarm/common/redis/QueueDecorator.java new file mode 100644 index 0000000000..3f8e34fc93 --- /dev/null +++ b/src/main/java/build/buildfarm/common/redis/QueueDecorator.java @@ -0,0 +1,8 @@ +package build.buildfarm.common.redis; + +import build.buildfarm.common.Queue; +import redis.clients.jedis.Jedis; + +public interface QueueDecorator { + Queue decorate(Jedis jedis, String name); +} diff --git a/src/main/java/build/buildfarm/common/redis/QueueInterface.java b/src/main/java/build/buildfarm/common/redis/QueueInterface.java deleted file mode 100644 index 3915600d2d..0000000000 --- a/src/main/java/build/buildfarm/common/redis/QueueInterface.java +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2020-2022 The Bazel Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package build.buildfarm.common.redis; - -import build.buildfarm.common.StringVisitor; -import java.time.Duration; -import java.util.concurrent.ExecutorService; -import redis.clients.jedis.Jedis; - -/** - * @class QueueInterface - * @brief A redis queue interface. - */ -public abstract class QueueInterface { - /** - * @brief Push a value onto the queue with default priority of 1. - * @details Adds the value into the backend rdered set. - * @param val The value to push onto the priority queue. - */ - abstract void push(Jedis jedis, String val); - - /** - * @brief Push a value onto the queue with defined priority. - * @details Adds the value into the backend rdered set. - * @param val The value to push onto the priority queue. - */ - abstract void push(Jedis jedis, String val, double priority); - - /** - * @brief Remove element from dequeue. - * @details Removes an element from the dequeue and specifies whether it was removed. - * @param val The value to remove. - * @return Whether or not the value was removed. - * @note Suggested return identifier: wasRemoved. - */ - abstract boolean removeFromDequeue(Jedis jedis, String val); - - /** - * @brief Remove all elements that match from queue. - * @details Removes all matching elements from the queue and specifies whether it was removed. - * @param val The value to remove. - * @return Whether or not the value was removed. - * @note Suggested return identifier: wasRemoved. - */ - abstract boolean removeAll(Jedis jedis, String val); - - /** - * @brief Pop element into internal dequeue and return value. - * @details This pops the element from one queue atomically into an internal list called the - * dequeue. It will wait until the timeout has expired. Null is returned if the timeout has - * expired. It is up to the caller to maintain the Jedis object and ensure it is valid for the - * queue operations. - * @param timeout Timeout to wait if there is no item to dequeue. - * @return The value of the transfered element. null if the thread was interrupted. - * @note Overloaded. - * @note Suggested return identifier: val. - */ - abstract String dequeue(Jedis jedis, Duration timeout, ExecutorService service) - throws InterruptedException; - - /** - * @brief Pop element into internal dequeue and return value. - * @details This pops the element from one queue atomically into an internal list called the - * dequeue. It does not block and null is returned if there is nothing to dequeue. - * @return The value of the transfered element. null if nothing was dequeued. - * @note Suggested return identifier: val. - */ - abstract String nonBlockingDequeue(Jedis jedis) throws InterruptedException; - - /** - * @brief Get name. - * @details Get the name of the queue. this is the redis key used for the list. - * @return The name of the queue. - * @note Suggested return identifier: name. - */ - abstract String getName(); - - /** - * @brief Get dequeue name. - * @details Get the name of the internal dequeue used by the queue. this is the redis key used for - * the list. - * @return The name of the queue. - * @note Suggested return identifier: name. - */ - abstract String getDequeueName(); - - /** - * @brief Get size. - * @details Checks the current length of the queue. - * @return The current length of the queue. - * @note Suggested return identifier: length. - */ - abstract long size(Jedis jedis); - - /** - * @brief Visit each element in the queue. - * @details Enacts a visitor over each element in the queue. - * @param visitor A visitor for each visited element in the queue. - * @note Overloaded. - */ - abstract void visit(Jedis jedis, StringVisitor visitor); - - /** - * @brief Visit each element in the dequeue. - * @details Enacts a visitor over each element in the dequeue. - * @param visitor A visitor for each visited element in the queue. - */ - abstract void visitDequeue(Jedis jedis, StringVisitor visitor); -} diff --git a/src/main/java/build/buildfarm/common/redis/RedisPriorityQueue.java b/src/main/java/build/buildfarm/common/redis/RedisPriorityQueue.java index 5a4d906e09..c2473992a8 100644 --- a/src/main/java/build/buildfarm/common/redis/RedisPriorityQueue.java +++ b/src/main/java/build/buildfarm/common/redis/RedisPriorityQueue.java @@ -14,11 +14,12 @@ package build.buildfarm.common.redis; +import build.buildfarm.common.Queue; import build.buildfarm.common.StringVisitor; +import com.google.common.collect.ImmutableList; +import java.time.Clock; import java.time.Duration; -import java.util.Arrays; import java.util.List; -import java.util.concurrent.ExecutorService; import redis.clients.jedis.Jedis; /** @@ -30,7 +31,16 @@ * Therefore, two redis queues with the same name, would in fact be the same underlying redis * queue. */ -public class RedisPriorityQueue extends QueueInterface { +public class RedisPriorityQueue implements Queue { + private static final Clock defaultClock = Clock.systemUTC(); + private static final long defaultPollIntervalMillis = 100; + + public static Queue decorate(Jedis jedis, String name) { + return new RedisPriorityQueue(jedis, name); + } + + private final Jedis jedis; + /** * @field name * @brief The unique name of the queue. @@ -40,18 +50,16 @@ public class RedisPriorityQueue extends QueueInterface { private final String name; private final String script; - private Timestamp time; - private final List keys; + private final Clock clock; private final long pollIntervalMillis; - private static long defaultPollIntervalMillis = 100; /** * @brief Constructor. * @details Construct a named redis queue with an established redis cluster. * @param name The global name of the queue. */ - public RedisPriorityQueue(String name) { - this(name, new Timestamp(), defaultPollIntervalMillis); + public RedisPriorityQueue(Jedis jedis, String name) { + this(jedis, name, defaultPollIntervalMillis); } /** @@ -59,10 +67,9 @@ public RedisPriorityQueue(String name) { * @details Construct a named redis queue with an established redis cluster. Used to ease the * testing of the order of the queued actions * @param name The global name of the queue. - * @param time Timestamp of the operation. */ - public RedisPriorityQueue(String name, Timestamp time) { - this(name, time, defaultPollIntervalMillis); + public RedisPriorityQueue(Jedis jedis, String name, Clock clock) { + this(jedis, name, clock, defaultPollIntervalMillis); } /** @@ -72,8 +79,8 @@ public RedisPriorityQueue(String name, Timestamp time) { * @param name The global name of the queue. * @param pollIntervalMillis pollInterval to use when dqueuing from redis. */ - public RedisPriorityQueue(String name, long pollIntervalMillis) { - this(name, new Timestamp(), pollIntervalMillis); + public RedisPriorityQueue(Jedis jedis, String name, long pollIntervalMillis) { + this(jedis, name, defaultClock, pollIntervalMillis); } /** @@ -84,10 +91,10 @@ public RedisPriorityQueue(String name, long pollIntervalMillis) { * @param time Timestamp of the operation. * @param pollIntervalMillis pollInterval to use when dqueuing from redis. */ - public RedisPriorityQueue(String name, Timestamp time, long pollIntervalMillis) { + public RedisPriorityQueue(Jedis jedis, String name, Clock clock, long pollIntervalMillis) { + this.jedis = jedis; this.name = name; - this.time = time; - this.keys = Arrays.asList(name); + this.clock = clock; this.script = getLuaScript(); this.pollIntervalMillis = pollIntervalMillis; } @@ -98,8 +105,8 @@ public RedisPriorityQueue(String name, Timestamp time, long pollIntervalMillis) * @param val The value to push onto the priority queue. */ @Override - public void push(Jedis jedis, String val) { - push(jedis, val, 0); + public boolean offer(String val) { + return offer(val, 0); } /** @@ -110,8 +117,9 @@ public void push(Jedis jedis, String val) { * @param priority The priority of action 0 means highest */ @Override - public void push(Jedis jedis, String val, double priority) { - jedis.zadd(name, priority, time.getNanos() + ":" + val); + public boolean offer(String val, double priority) { + jedis.zadd(name, priority, clock.millis() + ":" + val); + return true; } /** @@ -122,7 +130,7 @@ public void push(Jedis jedis, String val, double priority) { * @note Suggested return identifier: wasRemoved. */ @Override - public boolean removeFromDequeue(Jedis jedis, String val) { + public boolean removeFromDequeue(String val) { return jedis.lrem(getDequeueName(), -1, val) != 0; } @@ -133,8 +141,7 @@ public boolean removeFromDequeue(Jedis jedis, String val) { * @return Whether or not the value was removed. * @note Suggested return identifier: wasRemoved. */ - @Override - public boolean removeAll(Jedis jedis, String val) { + public boolean removeAll(String val) { return jedis.zrem(name, val) != 0; } @@ -149,13 +156,12 @@ public boolean removeAll(Jedis jedis, String val) { * @note Suggested return identifier: val. */ @Override - public String dequeue(Jedis jedis, Duration timeout, ExecutorService service) - throws InterruptedException { + public String take(Duration timeout) throws InterruptedException { int maxAttempts = Math.max(1, (int) (timeout.toMillis() / pollIntervalMillis)); - List args = Arrays.asList(name, getDequeueName(), "true"); + List args = ImmutableList.of(name, getDequeueName(), "true"); String val; for (int i = 0; i < maxAttempts; ++i) { - Object obj_val = jedis.eval(script, keys, args); + Object obj_val = jedis.eval(script, ImmutableList.of(name), args); val = String.valueOf(obj_val); if (!isEmpty(val)) { return val; @@ -173,16 +179,13 @@ public String dequeue(Jedis jedis, Duration timeout, ExecutorService service) * @note Suggested return identifier: val. */ @Override - public String nonBlockingDequeue(Jedis jedis) throws InterruptedException { - List args = Arrays.asList(name, getDequeueName()); - Object obj_val = jedis.eval(script, keys, args); + public String poll() { + List args = ImmutableList.of(name, getDequeueName()); + Object obj_val = jedis.eval(script, ImmutableList.of(name), args); String val = String.valueOf(obj_val); if (!isEmpty(val)) { return val; } - if (Thread.currentThread().isInterrupted()) { - throw new InterruptedException(); - } return null; } @@ -192,7 +195,6 @@ public String nonBlockingDequeue(Jedis jedis) throws InterruptedException { * @return The name of the queue. * @note Suggested return identifier: name. */ - @Override public String getName() { return name; } @@ -214,8 +216,7 @@ public String getDequeueName() { * @return The current length of the queue. * @note Suggested return identifier: length. */ - @Override - public long size(Jedis jedis) { + public long size() { return jedis.zcard(name); } @@ -226,8 +227,8 @@ public long size(Jedis jedis) { * @note Overloaded. */ @Override - public void visit(Jedis jedis, StringVisitor visitor) { - visit(jedis, name, visitor); + public void visit(StringVisitor visitor) { + visit(name, visitor); } /** @@ -236,7 +237,7 @@ public void visit(Jedis jedis, StringVisitor visitor) { * @param visitor A visitor for each visited element in the queue. */ @Override - public void visitDequeue(Jedis jedis, StringVisitor visitor) { + public void visitDequeue(StringVisitor visitor) { int listPageSize = 10000; int index = 0; int nextIndex = listPageSize; @@ -259,7 +260,7 @@ public void visitDequeue(Jedis jedis, StringVisitor visitor) { * @param visitor A visitor for each visited element in the queue. * @note Overloaded. */ - private void visit(Jedis jedis, String queueName, StringVisitor visitor) { + private void visit(String queueName, StringVisitor visitor) { int listPageSize = 10000; int index = 0; int nextIndex = listPageSize; diff --git a/src/main/java/build/buildfarm/common/redis/RedisQueue.java b/src/main/java/build/buildfarm/common/redis/RedisQueue.java index e6f539bd67..d6c11e7ec4 100644 --- a/src/main/java/build/buildfarm/common/redis/RedisQueue.java +++ b/src/main/java/build/buildfarm/common/redis/RedisQueue.java @@ -17,13 +17,10 @@ import static redis.clients.jedis.args.ListDirection.LEFT; import static redis.clients.jedis.args.ListDirection.RIGHT; +import build.buildfarm.common.Queue; import build.buildfarm.common.StringVisitor; import java.time.Duration; import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Future; import redis.clients.jedis.Jedis; /** @@ -32,14 +29,22 @@ * @details A redis queue is an implementation of a queue data structure which internally uses redis * to store and distribute the data. It's important to know that the lifetime of the queue * persists before and after the queue data structure is created (since it exists in redis). - * Therefore, two redis queues with the same name, would in fact be the same underlying redis - * queue. + * Therefore, two redis queues with the same name and redis service, would in fact be the same + * underlying redis queue. */ -public class RedisQueue extends QueueInterface { +public class RedisQueue implements Queue { + private static final int defaultListPageSize = 10000; + + public static Queue decorate(Jedis jedis, String name) { + return new RedisQueue(jedis, name, defaultListPageSize); + } + private static double toRedisTimeoutSeconds(Duration timeout) { return timeout.getSeconds() + timeout.getNano() / 1e9; } + private final Jedis jedis; + /** * @field name * @brief The unique name of the queue. @@ -48,16 +53,21 @@ private static double toRedisTimeoutSeconds(Duration timeout) { */ private final String name; + private final int listPageSize; + /** * @brief Constructor. * @details Construct a named redis queue with an established redis cluster. * @param name The global name of the queue. */ - public RedisQueue(String name) { - // In order for dequeue properly, the queue needs to have a hashtag. Otherwise it will error - // with: "No way to dispatch this command to Redis Cluster because keys have different slots." - // when trying to blmove. If no hashtag was given we provide a default. + public RedisQueue(Jedis jedis, String name) { + this(jedis, name, defaultListPageSize); + } + + public RedisQueue(Jedis jedis, String name, int listPageSize) { + this.jedis = jedis; this.name = name; + this.listPageSize = listPageSize; } /** @@ -65,8 +75,9 @@ public RedisQueue(String name) { * @details Adds the value into the backend redis queue. * @param val The value to push onto the queue. */ - public void push(Jedis jedis, String val) { - push(jedis, val, 1); + @Override + public boolean offer(String val) { + return offer(val, 1); } /** @@ -74,8 +85,10 @@ public void push(Jedis jedis, String val) { * @details Adds the value into the backend redis queue. * @param val The value to push onto the queue. */ - public void push(Jedis jedis, String val, double priority) { + @Override + public boolean offer(String val, double priority) { jedis.lpush(name, val); + return true; } /** @@ -85,7 +98,8 @@ public void push(Jedis jedis, String val, double priority) { * @return Whether the value was removed. * @note Suggested return identifier: wasRemoved. */ - public boolean removeFromDequeue(Jedis jedis, String val) { + @Override + public boolean removeFromDequeue(String val) { return jedis.lrem(getDequeueName(), -1, val) != 0; } @@ -96,7 +110,7 @@ public boolean removeFromDequeue(Jedis jedis, String val) { * @return Whether the value was removed. * @note Suggested return identifier: wasRemoved. */ - public boolean removeAll(Jedis jedis, String val) { + public boolean removeAll(String val) { return jedis.lrem(name, 0, val) != 0; } @@ -110,41 +124,9 @@ public boolean removeAll(Jedis jedis, String val) { * @note Overloaded. * @note Suggested return identifier: val. */ - public String dequeue(Jedis jedis, Duration timeout, ExecutorService service) - throws InterruptedException { - return interruptibleRequest( - () -> jedis.blmove(name, getDequeueName(), RIGHT, LEFT, toRedisTimeoutSeconds(timeout)), - jedis::disconnect, - service); - } - - private T interruptibleRequest( - Callable command, Runnable onInterrupted, ExecutorService service) - throws InterruptedException { - Future reply = service.submit(command); - return getBlockingReply(reply, onInterrupted); - } - - private T getBlockingReply(Future reply, Runnable onInterrupted) - throws InterruptedException { - InterruptedException interruption = null; - for (; ; ) { - try { - return reply.get(); - } catch (ExecutionException e) { - Throwable cause = e.getCause(); - if (interruption != null) { - interruption.addSuppressed(cause); - Thread.currentThread().interrupt(); - throw interruption; - } - throw new RuntimeException(cause); - } catch (InterruptedException e) { - interruption = e; - Thread.interrupted(); - onInterrupted.run(); - } - } + @Override + public String take(Duration timeout) { + return jedis.blmove(name, getDequeueName(), RIGHT, LEFT, toRedisTimeoutSeconds(timeout)); } /** @@ -154,25 +136,9 @@ private T getBlockingReply(Future reply, Runnable onInterrupted) * @return The value of the transfered element. null if nothing was dequeued. * @note Suggested return identifier: val. */ - public String nonBlockingDequeue(Jedis jedis) throws InterruptedException { - String val = jedis.lmove(name, getDequeueName(), RIGHT, LEFT); - if (val != null) { - return val; - } - if (Thread.currentThread().isInterrupted()) { - throw new InterruptedException(); - } - return null; - } - - /** - * @brief Get name. - * @details Get the name of the queue. this is the redis key used for the list. - * @return The name of the queue. - * @note Suggested return identifier: name. - */ - public String getName() { - return name; + @Override + public String poll() { + return jedis.lmove(name, getDequeueName(), RIGHT, LEFT); } /** @@ -192,7 +158,7 @@ public String getDequeueName() { * @return The current length of the queue. * @note Suggested return identifier: length. */ - public long size(Jedis jedis) { + public long size() { return jedis.llen(name); } @@ -202,8 +168,8 @@ public long size(Jedis jedis) { * @param visitor A visitor for each visited element in the queue. * @note Overloaded. */ - public void visit(Jedis jedis, StringVisitor visitor) { - visit(jedis, name, visitor); + public void visit(StringVisitor visitor) { + visit(name, visitor); } /** @@ -211,8 +177,8 @@ public void visit(Jedis jedis, StringVisitor visitor) { * @details Enacts a visitor over each element in the dequeue. * @param visitor A visitor for each visited element in the queue. */ - public void visitDequeue(Jedis jedis, StringVisitor visitor) { - visit(jedis, getDequeueName(), visitor); + public void visitDequeue(StringVisitor visitor) { + visit(getDequeueName(), visitor); } /** @@ -222,9 +188,7 @@ public void visitDequeue(Jedis jedis, StringVisitor visitor) { * @param visitor A visitor for each visited element in the queue. * @note Overloaded. */ - private void visit(Jedis jedis, String queueName, StringVisitor visitor) { - int listPageSize = 10000; - + private void visit(String queueName, StringVisitor visitor) { int index = 0; int nextIndex = listPageSize; List entries; diff --git a/src/main/java/build/buildfarm/common/redis/RedisQueues.java b/src/main/java/build/buildfarm/common/redis/RedisQueues.java deleted file mode 100644 index 52679f523e..0000000000 --- a/src/main/java/build/buildfarm/common/redis/RedisQueues.java +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2020-2022 The Bazel Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package build.buildfarm.common.redis; - -import build.buildfarm.common.config.BuildfarmConfigs; -import build.buildfarm.common.config.Queue.QUEUE_TYPE; - -/** - * @class RedisQueues - * @brief Managed redis queue creation. - */ -public final class RedisQueues { - private static BuildfarmConfigs configs = BuildfarmConfigs.getInstance(); - - private RedisQueues() {} - - public static QueueInterface create(QUEUE_TYPE queueType, String name) { - if (queueType == QUEUE_TYPE.standard) { - return new RedisQueue(name); - } - if (queueType == QUEUE_TYPE.priority) { - return new RedisPriorityQueue(name, configs.getBackplane().getPriorityPollIntervalMillis()); - } - throw new IllegalArgumentException("Unknown queueType " + queueType); - } -} diff --git a/src/main/java/build/buildfarm/common/redis/Timestamp.java b/src/main/java/build/buildfarm/common/redis/Timestamp.java deleted file mode 100644 index cdf810eccf..0000000000 --- a/src/main/java/build/buildfarm/common/redis/Timestamp.java +++ /dev/null @@ -1,11 +0,0 @@ -package build.buildfarm.common.redis; - -public class Timestamp { - public Long getMillis() { - return System.currentTimeMillis(); - } - - public Long getNanos() { - return System.nanoTime(); - } -} diff --git a/src/main/java/build/buildfarm/instance/shard/DistributedStateCreator.java b/src/main/java/build/buildfarm/instance/shard/DistributedStateCreator.java index b5fdcebbea..5ed7255734 100644 --- a/src/main/java/build/buildfarm/instance/shard/DistributedStateCreator.java +++ b/src/main/java/build/buildfarm/instance/shard/DistributedStateCreator.java @@ -19,11 +19,14 @@ import build.buildfarm.common.config.Queue; import build.buildfarm.common.redis.BalancedRedisQueue; import build.buildfarm.common.redis.ProvisionedRedisQueue; +import build.buildfarm.common.redis.QueueDecorator; import build.buildfarm.common.redis.RedisClient; import build.buildfarm.common.redis.RedisHashMap; import build.buildfarm.common.redis.RedisHashtags; import build.buildfarm.common.redis.RedisMap; import build.buildfarm.common.redis.RedisNodeHashes; +import build.buildfarm.common.redis.RedisPriorityQueue; +import build.buildfarm.common.redis.RedisQueue; import com.google.common.collect.ImmutableList; import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.SetMultimap; @@ -90,7 +93,7 @@ private static BalancedRedisQueue createPrequeue(RedisClient client) throws IOEx getPreQueuedOperationsListName(), getQueueHashes(client, getPreQueuedOperationsListName()), configs.getBackplane().getMaxPreQueueDepth(), - getQueueType()); + getQueueDecorator()); } private static OperationQueue createOperationQueue(RedisClient client) throws IOException { @@ -104,7 +107,7 @@ private static OperationQueue createOperationQueue(RedisClient client) throws IO ProvisionedRedisQueue provisionedQueue = new ProvisionedRedisQueue( getQueueName(queueConfig), - getQueueType(), + getQueueDecorator(), getQueueHashes(client, getQueueName(queueConfig)), toMultimap(queueConfig.getPlatform().getPropertiesList()), queueConfig.isAllowUnmatched()); @@ -124,7 +127,7 @@ private static OperationQueue createOperationQueue(RedisClient client) throws IO ProvisionedRedisQueue defaultQueue = new ProvisionedRedisQueue( getQueuedOperationsListName(), - getQueueType(), + getQueueDecorator(), getQueueHashes(client, getQueuedOperationsListName()), defaultProvisions); provisionedQueues.add(defaultQueue); @@ -148,6 +151,12 @@ private static SetMultimap toMultimap(List pr return set; } + private static QueueDecorator getQueueDecorator() { + return configs.getBackplane().isPriorityQueue() + ? RedisPriorityQueue::decorate + : RedisQueue::decorate; + } + private static Queue.QUEUE_TYPE getQueueType() { return configs.getBackplane().isPriorityQueue() ? Queue.QUEUE_TYPE.priority diff --git a/src/main/java/build/buildfarm/instance/shard/OperationQueue.java b/src/main/java/build/buildfarm/instance/shard/OperationQueue.java index 4cd31cf2e7..43e7384e5c 100644 --- a/src/main/java/build/buildfarm/instance/shard/OperationQueue.java +++ b/src/main/java/build/buildfarm/instance/shard/OperationQueue.java @@ -180,7 +180,7 @@ public String getName(List provisions) { public void push( UnifiedJedis jedis, List provisions, String val, int priority) { BalancedRedisQueue queue = chooseEligibleQueue(provisions); - queue.push(jedis, val, (double) priority); + queue.offer(jedis, val, (double) priority); } /** @@ -197,16 +197,14 @@ public String dequeue(UnifiedJedis jedis, List provisions) throws InterruptedException { // Select all matched queues, and attempt dequeuing via round-robin. List queues = chooseEligibleQueues(provisions); - int index = roundRobinPopIndex(queues); - String value = queues.get(index).nonBlockingDequeue(jedis); - // Keep iterating over matched queues until we find one that is non-empty and provides a // dequeued value. - while (value == null) { - index = roundRobinPopIndex(queues); - value = queues.get(index).nonBlockingDequeue(jedis); + for (int index = roundRobinPopIndex(queues); ; index = roundRobinPopIndex(queues)) { + String value = queues.get(index).poll(jedis); + if (value != null) { + return value; + } } - return value; } /** diff --git a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java index 08686054b1..6ade389b93 100644 --- a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java +++ b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java @@ -1214,7 +1214,7 @@ public ImmutableList getDispatchedOperations() throws IOExc } private ExecuteEntry deprequeueOperation(UnifiedJedis jedis) throws InterruptedException { - String executeEntryJson = state.prequeue.dequeue(jedis, dequeueService); + String executeEntryJson = state.prequeue.take(jedis, dequeueService); if (executeEntryJson == null) { return null; } @@ -1378,7 +1378,7 @@ public void prequeue(ExecuteEntry executeEntry, Operation operation) throws IOEx client.run( jedis -> { state.operations.insert(jedis, invocationId, operationName, operationJson); - state.prequeue.push(jedis, executeEntryJson, priority); + state.prequeue.offer(jedis, executeEntryJson, priority); publishReset(jedis, publishOperation); }); } diff --git a/src/test/java/build/buildfarm/common/redis/BalancedRedisQueueMockTest.java b/src/test/java/build/buildfarm/common/redis/BalancedRedisQueueMockTest.java index 8811d42103..61453672e6 100644 --- a/src/test/java/build/buildfarm/common/redis/BalancedRedisQueueMockTest.java +++ b/src/test/java/build/buildfarm/common/redis/BalancedRedisQueueMockTest.java @@ -15,14 +15,16 @@ package build.buildfarm.common.redis; import static com.google.common.truth.Truth.assertThat; +import static java.util.concurrent.Executors.newSingleThreadExecutor; +import static java.util.concurrent.TimeUnit.SECONDS; import static org.mockito.Mockito.any; import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; +import build.buildfarm.common.Queue; import build.buildfarm.common.StringVisitor; import com.google.common.collect.ImmutableList; import java.time.Duration; @@ -52,13 +54,17 @@ public class BalancedRedisQueueMockTest { @Mock private JedisCluster redis; @Mock private Connection connection; - @Mock QueueInterface subQueue; + @Mock private Queue subQueue; + + @SuppressWarnings("unused") // parameters are ignored + private Queue subQueueDecorate(Jedis jedis, String name) { + return subQueue; + } @Before public void setUp() { MockitoAnnotations.initMocks(this); when(redis.getConnectionFromSlot(any(Integer.class))).thenReturn(connection); - when(subQueue.getName()).thenReturn("test"); } // Function under test: removeFromDequeue @@ -69,8 +75,9 @@ public void setUp() { @Test public void removeFromDequeueFalseWhenValueIsMissing() throws Exception { // ARRANGE - when(subQueue.removeFromDequeue(any(Jedis.class), any(String.class))).thenReturn(false); - BalancedRedisQueue queue = new BalancedRedisQueue("test", -1, ImmutableList.of(subQueue)); + when(subQueue.removeFromDequeue(any(String.class))).thenReturn(false); + BalancedRedisQueue queue = + new BalancedRedisQueue("test", ImmutableList.of("test"), this::subQueueDecorate); // ACT Boolean success = queue.removeFromDequeue(redis, "baz"); @@ -86,8 +93,9 @@ public void removeFromDequeueFalseWhenValueIsMissing() throws Exception { @Test public void removeFromDequeueTrueWhenValueExists() throws Exception { // ARRANGE - when(subQueue.removeFromDequeue(any(Jedis.class), any(String.class))).thenReturn(true); - BalancedRedisQueue queue = new BalancedRedisQueue("test", -1, ImmutableList.of(subQueue)); + when(subQueue.removeFromDequeue(any(String.class))).thenReturn(true); + BalancedRedisQueue queue = + new BalancedRedisQueue("test", ImmutableList.of("test"), this::subQueueDecorate); // ACT Boolean success = queue.removeFromDequeue(redis, "bar"); @@ -96,46 +104,49 @@ public void removeFromDequeueTrueWhenValueExists() throws Exception { assertThat(success).isTrue(); } - // Function under test: dequeue - // Reason for testing: the element is dequeued via nonblocking + // Function under test: take + // Reason for testing: the element is taken via nonblocking // Failure explanation: the element failed to dequeue @Test - public void dequeueExponentialBackoffElementDequeuedOnNonBlock() throws Exception { + public void takeElementDequeuedOnNonBlock() throws Exception { // MOCK - when(subQueue.nonBlockingDequeue(any(Jedis.class))).thenReturn("foo"); - ExecutorService service = mock(ExecutorService.class); + when(subQueue.poll()).thenReturn("foo"); + ExecutorService service = newSingleThreadExecutor(); // ARRANGE - BalancedRedisQueue queue = new BalancedRedisQueue("test", -1, ImmutableList.of(subQueue)); + BalancedRedisQueue queue = + new BalancedRedisQueue("test", ImmutableList.of("test"), this::subQueueDecorate); // ACT - String val = queue.dequeue(redis, service); + String val = queue.take(redis, service); // ASSERT - verifyNoInteractions(service); assertThat(val).isEqualTo("foo"); + service.shutdown(); + assertThat(service.awaitTermination(1, SECONDS)).isTrue(); } - // Function under test: dequeue - // Reason for testing: the element is dequeued via nonblocking + // Function under test: take + // Reason for testing: the element is taken via nonblocking // Failure explanation: the element failed to dequeue @Test - public void dequeueExponentialBackoffElementDequeuedOnBlock() throws Exception { + public void dequeueElementDequeuedOnBlock() throws Exception { // MOCK - when(subQueue.nonBlockingDequeue(any(Jedis.class))).thenReturn(null); - when(subQueue.dequeue(any(Jedis.class), any(Duration.class), any(ExecutorService.class))) - .thenReturn("foo"); + when(subQueue.poll()).thenReturn(null); + when(subQueue.take(any(Duration.class))).thenReturn("foo"); // ARRANGE - BalancedRedisQueue queue = new BalancedRedisQueue("test", -1, ImmutableList.of(subQueue)); - ExecutorService service = mock(ExecutorService.class); + BalancedRedisQueue queue = + new BalancedRedisQueue("test", ImmutableList.of("test"), this::subQueueDecorate); + ExecutorService service = newSingleThreadExecutor(); // ACT - String val = queue.dequeue(redis, service); + String val = queue.take(redis, service); // ASSERT - verifyNoInteractions(service); assertThat(val).isEqualTo("foo"); + service.shutdown(); + assertThat(service.awaitTermination(1, SECONDS)).isTrue(); } // Function under test: getCurrentPopQueue @@ -144,7 +155,8 @@ public void dequeueExponentialBackoffElementDequeuedOnBlock() throws Exception { @Test public void getCurrentPopQueueCanGet() throws Exception { // ARRANGE - BalancedRedisQueue queue = new BalancedRedisQueue("queue_name", ImmutableList.of()); + BalancedRedisQueue queue = + new BalancedRedisQueue("queue_name", ImmutableList.of(), this::subQueueDecorate); // ACT queue.getCurrentPopQueue(); @@ -156,7 +168,8 @@ public void getCurrentPopQueueCanGet() throws Exception { @Test public void getCurrentPopQueueIndexCanGet() throws Exception { // ARRANGE - BalancedRedisQueue queue = new BalancedRedisQueue("queue_name", ImmutableList.of()); + BalancedRedisQueue queue = + new BalancedRedisQueue("queue_name", ImmutableList.of(), this::subQueueDecorate); // ACT queue.getCurrentPopQueueIndex(); @@ -168,7 +181,8 @@ public void getCurrentPopQueueIndexCanGet() throws Exception { @Test public void getInternalQueueCanGet() throws Exception { // ARRANGE - BalancedRedisQueue queue = new BalancedRedisQueue("queue_name", ImmutableList.of()); + BalancedRedisQueue queue = + new BalancedRedisQueue("queue_name", ImmutableList.of(), this::subQueueDecorate); // ACT queue.getInternalQueue(0); @@ -180,7 +194,8 @@ public void getInternalQueueCanGet() throws Exception { @Test public void getDequeueNameCanGet() throws Exception { // ARRANGE - BalancedRedisQueue queue = new BalancedRedisQueue("queue_name", ImmutableList.of()); + BalancedRedisQueue queue = + new BalancedRedisQueue("queue_name", ImmutableList.of(), this::subQueueDecorate); // ACT String name = queue.getDequeueName(); @@ -195,7 +210,8 @@ public void getDequeueNameCanGet() throws Exception { @Test public void getNameNameIsStored() throws Exception { // ARRANGE - BalancedRedisQueue queue = new BalancedRedisQueue("queue_name", ImmutableList.of()); + BalancedRedisQueue queue = + new BalancedRedisQueue("queue_name", ImmutableList.of(), this::subQueueDecorate); // ACT String name = queue.getName(); @@ -210,10 +226,11 @@ public void getNameNameIsStored() throws Exception { @Test public void sizeInitialSizeIsZero() throws Exception { // MOCK - when(subQueue.size(any(Jedis.class))).thenReturn(0L); + when(subQueue.size()).thenReturn(0L); // ARRANGE - BalancedRedisQueue queue = new BalancedRedisQueue("test", -1, ImmutableList.of(subQueue)); + BalancedRedisQueue queue = + new BalancedRedisQueue("test", ImmutableList.of("test"), this::subQueueDecorate); // ACT long size = queue.size(redis); @@ -230,17 +247,18 @@ public void visitCheckVisitOfEachElement() throws Exception { // MOCK doAnswer( invocation -> { - StringVisitor visitor = invocation.getArgument(1); + StringVisitor visitor = invocation.getArgument(0); for (int i = 1; i <= 8; i++) { visitor.visit("element " + i); } return null; }) .when(subQueue) - .visit(any(Jedis.class), any(StringVisitor.class)); + .visit(any(StringVisitor.class)); // ARRANGE - BalancedRedisQueue queue = new BalancedRedisQueue("test", -1, ImmutableList.of(subQueue)); + BalancedRedisQueue queue = + new BalancedRedisQueue("test", ImmutableList.of("test"), this::subQueueDecorate); // ACT List visited = new ArrayList<>(); @@ -273,17 +291,18 @@ public void visitDequeueCheckVisitOfEachElement() throws Exception { // MOCK doAnswer( invocation -> { - StringVisitor visitor = invocation.getArgument(1); + StringVisitor visitor = invocation.getArgument(0); for (int i = 1; i <= 8; i++) { visitor.visit("element " + i); } return null; }) .when(subQueue) - .visitDequeue(any(Jedis.class), any(StringVisitor.class)); + .visitDequeue(any(StringVisitor.class)); // ARRANGE - BalancedRedisQueue queue = new BalancedRedisQueue("test", -1, ImmutableList.of(subQueue)); + BalancedRedisQueue queue = + new BalancedRedisQueue("test", ImmutableList.of("test"), this::subQueueDecorate); // ACT List visited = new ArrayList<>(); @@ -314,16 +333,17 @@ public void visit(String entry) { @Test public void emptyIsEvenlyDistributed() throws Exception { // MOCK - when(subQueue.size(any(Jedis.class))).thenReturn(0L); + when(subQueue.size()).thenReturn(0L); // ARRANGE - BalancedRedisQueue queue = new BalancedRedisQueue("test", -1, ImmutableList.of(subQueue)); + BalancedRedisQueue queue = + new BalancedRedisQueue("test", ImmutableList.of("test"), this::subQueueDecorate); // ACT Boolean isEvenlyDistributed = queue.isEvenlyDistributed(redis); // ASSERT - verify(subQueue, times(1)).size(any(Jedis.class)); + verify(subQueue, times(1)).size(); assertThat(isEvenlyDistributed).isTrue(); } @@ -333,7 +353,8 @@ public void emptyIsEvenlyDistributed() throws Exception { @Test public void canQueueInfiniteQueueAllowsQueuing() throws Exception { // ARRANGE - BalancedRedisQueue queue = new BalancedRedisQueue("test", -1, ImmutableList.of(subQueue)); + BalancedRedisQueue queue = + new BalancedRedisQueue("test", ImmutableList.of("test"), this::subQueueDecorate); // ACT boolean canQueue = queue.canQueue(redis); @@ -349,16 +370,17 @@ public void canQueueInfiniteQueueAllowsQueuing() throws Exception { @Test public void canQueueFullQueueNotAllowsQueueing() throws Exception { // MOCK - when(subQueue.size(any(Jedis.class))).thenReturn(123L); + when(subQueue.size()).thenReturn(123L); // ARRANGE - BalancedRedisQueue queue = new BalancedRedisQueue("test", 123, ImmutableList.of(subQueue)); + BalancedRedisQueue queue = + new BalancedRedisQueue("test", ImmutableList.of("test"), 123, this::subQueueDecorate); // ACT boolean canQueue = queue.canQueue(redis); // ASSERT - verify(subQueue, times(1)).size(any(Jedis.class)); + verify(subQueue, times(1)).size(); assertThat(canQueue).isFalse(); } } diff --git a/src/test/java/build/buildfarm/common/redis/BalancedRedisQueueTest.java b/src/test/java/build/buildfarm/common/redis/BalancedRedisQueueTest.java index 2ff3a9ca9c..1aacd5605e 100644 --- a/src/test/java/build/buildfarm/common/redis/BalancedRedisQueueTest.java +++ b/src/test/java/build/buildfarm/common/redis/BalancedRedisQueueTest.java @@ -20,7 +20,6 @@ import build.buildfarm.common.StringVisitor; import build.buildfarm.common.config.BuildfarmConfigs; -import build.buildfarm.common.config.Queue; import build.buildfarm.instance.shard.JedisClusterFactory; import com.google.common.collect.ImmutableList; import java.util.ArrayList; @@ -66,95 +65,95 @@ public void tearDown() { @Test public void balancedRedisQueueCreateHashesConstructsWithoutError() throws Exception { // ACT - new BalancedRedisQueue("test", ImmutableList.of()); + new BalancedRedisQueue("test", ImmutableList.of(), RedisQueue::decorate); } - // Function under test: push + // Function under test: offer // Reason for testing: the queue can have a value pushed onto it - // Failure explanation: the queue is throwing an exception upon push + // Failure explanation: the queue is throwing an exception upon offer @Test public void pushPushWithoutError() throws Exception { // ARRANGE List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); - BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags); + BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags, RedisQueue::decorate); // ACT - queue.push(jedis, "foo"); + queue.offer(jedis, "foo"); } - // Function under test: push + // Function under test: offer // Reason for testing: the queue can have the different values pushed onto it // Failure explanation: the queue is throwing an exception upon pushing different values @Test public void pushPushDifferentWithoutError() throws Exception { // ARRANGE List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); - BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags); + BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags, RedisQueue::decorate); // ACT - queue.push(jedis, "foo"); - queue.push(jedis, "bar"); + queue.offer(jedis, "foo"); + queue.offer(jedis, "bar"); } - // Function under test: push + // Function under test: offer // Reason for testing: the queue can have the same values pushed onto it // Failure explanation: the queue is throwing an exception upon pushing the same values @Test public void pushPushSameWithoutError() throws Exception { // ARRANGE List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); - BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags); + BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags, RedisQueue::decorate); // ACT - queue.push(jedis, "foo"); - queue.push(jedis, "foo"); + queue.offer(jedis, "foo"); + queue.offer(jedis, "foo"); } - // Function under test: push + // Function under test: offer // Reason for testing: the queue can have many values pushed into it // Failure explanation: the queue is throwing an exception upon pushing many values @Test public void pushPushMany() throws Exception { // ARRANGE List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); - BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags); + BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags, RedisQueue::decorate); // ACT for (int i = 0; i < 1000; ++i) { - queue.push(jedis, "foo" + i); + queue.offer(jedis, "foo" + i); } } - // Function under test: push + // Function under test: offer // Reason for testing: the queue size increases as elements are pushed // Failure explanation: the queue size is not accurately reflecting the pushes @Test public void pushPushIncreasesSize() throws Exception { // ARRANGE List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); - BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags); + BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags, RedisQueue::decorate); // ACT / ASSERT assertThat(queue.size(jedis)).isEqualTo(0); - queue.push(jedis, "foo"); + queue.offer(jedis, "foo"); assertThat(queue.size(jedis)).isEqualTo(1); - queue.push(jedis, "foo"); + queue.offer(jedis, "foo"); assertThat(queue.size(jedis)).isEqualTo(2); - queue.push(jedis, "foo"); + queue.offer(jedis, "foo"); assertThat(queue.size(jedis)).isEqualTo(3); - queue.push(jedis, "foo"); + queue.offer(jedis, "foo"); assertThat(queue.size(jedis)).isEqualTo(4); - queue.push(jedis, "foo"); + queue.offer(jedis, "foo"); assertThat(queue.size(jedis)).isEqualTo(5); - queue.push(jedis, "foo"); + queue.offer(jedis, "foo"); assertThat(queue.size(jedis)).isEqualTo(6); - queue.push(jedis, "foo"); + queue.offer(jedis, "foo"); assertThat(queue.size(jedis)).isEqualTo(7); - queue.push(jedis, "foo"); + queue.offer(jedis, "foo"); assertThat(queue.size(jedis)).isEqualTo(8); - queue.push(jedis, "foo"); + queue.offer(jedis, "foo"); assertThat(queue.size(jedis)).isEqualTo(9); - queue.push(jedis, "foo"); + queue.offer(jedis, "foo"); assertThat(queue.size(jedis)).isEqualTo(10); } @@ -167,7 +166,7 @@ public void pushPushIncreasesSize() throws Exception { public void removeFromDequeueFalseOnEmpty() throws Exception { // ARRANGE List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); - BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags); + BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags, RedisQueue::decorate); // ACT Boolean success = queue.removeFromDequeue(jedis, "foo"); @@ -185,14 +184,14 @@ public void removeFromDequeueFalseOnEmpty() throws Exception { public void removeFromDequeueFalseWhenValueIsMissing() throws Exception { // ARRANGE List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); - BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags); + BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags, RedisQueue::decorate); ExecutorService service = newSingleThreadExecutor(); // ACT - queue.push(jedis, "foo"); - queue.push(jedis, "bar"); - queue.dequeue(jedis, service); - queue.dequeue(jedis, service); + queue.offer(jedis, "foo"); + queue.offer(jedis, "bar"); + queue.take(jedis, service); + queue.take(jedis, service); service.shutdown(); Boolean success = queue.removeFromDequeue(jedis, "baz"); @@ -209,16 +208,16 @@ public void removeFromDequeueFalseWhenValueIsMissing() throws Exception { public void removeFromDequeueTrueWhenValueExists() throws Exception { // ARRANGE List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); - BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags); + BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags, RedisQueue::decorate); ExecutorService service = newSingleThreadExecutor(); // ACT - queue.push(jedis, "foo"); - queue.push(jedis, "bar"); - queue.push(jedis, "baz"); - queue.dequeue(jedis, service); - queue.dequeue(jedis, service); - queue.dequeue(jedis, service); + queue.offer(jedis, "foo"); + queue.offer(jedis, "bar"); + queue.offer(jedis, "baz"); + queue.take(jedis, service); + queue.take(jedis, service); + queue.take(jedis, service); service.shutdown(); Boolean success = queue.removeFromDequeue(jedis, "bar"); @@ -234,7 +233,7 @@ public void removeFromDequeueTrueWhenValueExists() throws Exception { public void getNameNameIsStored() throws Exception { // ARRANGE List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); - BalancedRedisQueue queue = new BalancedRedisQueue("queue_name", hashtags); + BalancedRedisQueue queue = new BalancedRedisQueue("queue_name", hashtags, RedisQueue::decorate); // ACT String name = queue.getName(); @@ -250,7 +249,8 @@ public void getNameNameIsStored() throws Exception { public void getNameNameHasHashtagRemovedFront() throws Exception { // ARRANGE List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); - BalancedRedisQueue queue = new BalancedRedisQueue("{hash}queue_name", hashtags); + BalancedRedisQueue queue = + new BalancedRedisQueue("{hash}queue_name", hashtags, RedisQueue::decorate); // ACT String name = queue.getName(); @@ -266,7 +266,7 @@ public void getNameNameHasHashtagRemovedFrontPriority() throws Exception { // ARRANGE List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); BalancedRedisQueue queue = - new BalancedRedisQueue("{hash}queue_name", hashtags, Queue.QUEUE_TYPE.priority); + new BalancedRedisQueue("{hash}queue_name", hashtags, RedisPriorityQueue::decorate); // ACT String name = queue.getName(); @@ -282,7 +282,8 @@ public void getNameNameHasHashtagColonRemovedFront() throws Exception { // ARRANGE List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); // similar to what has been seen in configuration files - BalancedRedisQueue queue = new BalancedRedisQueue("{Execution}:QueuedOperations", hashtags); + BalancedRedisQueue queue = + new BalancedRedisQueue("{Execution}:QueuedOperations", hashtags, RedisQueue::decorate); // ACT String name = queue.getName(); @@ -299,7 +300,8 @@ public void getNameNameHasHashtagColonRemovedFrontPriority() throws Exception { List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); // similar to what has been seen in configuration files BalancedRedisQueue queue = - new BalancedRedisQueue("{Execution}:QueuedOperations", hashtags, Queue.QUEUE_TYPE.priority); + new BalancedRedisQueue( + "{Execution}:QueuedOperations", hashtags, RedisPriorityQueue::decorate); // ACT String name = queue.getName(); @@ -314,7 +316,8 @@ public void getNameNameHasHashtagColonRemovedFrontPriority() throws Exception { public void getNameNameHasHashtagRemovedBack() throws Exception { // ARRANGE List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); - BalancedRedisQueue queue = new BalancedRedisQueue("queue_name{hash}", hashtags); + BalancedRedisQueue queue = + new BalancedRedisQueue("queue_name{hash}", hashtags, RedisQueue::decorate); // ACT String name = queue.getName(); @@ -329,7 +332,8 @@ public void getNameNameHasHashtagRemovedBack() throws Exception { public void getNameNameHasHashtagRemovedMiddle() throws Exception { // ARRANGE List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); - BalancedRedisQueue queue = new BalancedRedisQueue("queue_{hash}name", hashtags); + BalancedRedisQueue queue = + new BalancedRedisQueue("queue_{hash}name", hashtags, RedisQueue::decorate); // ACT String name = queue.getName(); @@ -344,7 +348,8 @@ public void getNameNameHasHashtagRemovedMiddle() throws Exception { public void getNameNameHasHashtagRemovedFrontBack() throws Exception { // ARRANGE List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); - BalancedRedisQueue queue = new BalancedRedisQueue("{hash}queue_name{hash}", hashtags); + BalancedRedisQueue queue = + new BalancedRedisQueue("{hash}queue_name{hash}", hashtags, RedisQueue::decorate); // ACT String name = queue.getName(); @@ -353,80 +358,81 @@ public void getNameNameHasHashtagRemovedFrontBack() throws Exception { } // Function under test: size - // Reason for testing: size adjusts with push and dequeue + // Reason for testing: size adjusts with offer and take // Failure explanation: size is incorrectly reporting the expected queue size @Test public void sizeAdjustPushPop() throws Exception { // ARRANGE List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); - BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags); + BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags, RedisQueue::decorate); ExecutorService service = newSingleThreadExecutor(); // ACT / ASSERT assertThat(queue.size(jedis)).isEqualTo(0); - queue.push(jedis, "foo"); + queue.offer(jedis, "foo"); assertThat(queue.size(jedis)).isEqualTo(1); - queue.push(jedis, "bar"); + queue.offer(jedis, "bar"); assertThat(queue.size(jedis)).isEqualTo(2); - queue.push(jedis, "baz"); + queue.offer(jedis, "baz"); assertThat(queue.size(jedis)).isEqualTo(3); - queue.push(jedis, "baz"); + queue.offer(jedis, "baz"); assertThat(queue.size(jedis)).isEqualTo(4); - queue.push(jedis, "baz"); + queue.offer(jedis, "baz"); assertThat(queue.size(jedis)).isEqualTo(5); - queue.push(jedis, "baz"); + queue.offer(jedis, "baz"); assertThat(queue.size(jedis)).isEqualTo(6); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.size(jedis)).isEqualTo(5); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.size(jedis)).isEqualTo(4); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.size(jedis)).isEqualTo(3); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.size(jedis)).isEqualTo(2); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.size(jedis)).isEqualTo(1); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.size(jedis)).isEqualTo(0); service.shutdown(); assertThat(service.awaitTermination(0, SECONDS)).isTrue(); } // Function under test: size - // Reason for testing: size adjusts with push and dequeue + // Reason for testing: size adjusts with offer and take // Failure explanation: size is incorrectly reporting the expected queue size @Test public void sizeAdjustPushPopPriority() throws Exception { // ARRANGE List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); - BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags, Queue.QUEUE_TYPE.priority); + BalancedRedisQueue queue = + new BalancedRedisQueue("test", hashtags, RedisPriorityQueue::decorate); ExecutorService service = newSingleThreadExecutor(); // ACT / ASSERT assertThat(queue.size(jedis)).isEqualTo(0); - queue.push(jedis, "foo"); + queue.offer(jedis, "foo1"); assertThat(queue.size(jedis)).isEqualTo(1); - queue.push(jedis, "bar"); + queue.offer(jedis, "foo2"); assertThat(queue.size(jedis)).isEqualTo(2); - queue.push(jedis, "baz"); + queue.offer(jedis, "foo3"); assertThat(queue.size(jedis)).isEqualTo(3); - queue.push(jedis, "baz"); + queue.offer(jedis, "foo4"); assertThat(queue.size(jedis)).isEqualTo(4); - queue.push(jedis, "baz"); + queue.offer(jedis, "foo5"); assertThat(queue.size(jedis)).isEqualTo(5); - queue.push(jedis, "baz"); + queue.offer(jedis, "foo6"); assertThat(queue.size(jedis)).isEqualTo(6); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.size(jedis)).isEqualTo(5); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.size(jedis)).isEqualTo(4); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.size(jedis)).isEqualTo(3); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.size(jedis)).isEqualTo(2); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.size(jedis)).isEqualTo(1); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.size(jedis)).isEqualTo(0); service.shutdown(); assertThat(service.awaitTermination(0, SECONDS)).isTrue(); @@ -439,15 +445,15 @@ public void sizeAdjustPushPopPriority() throws Exception { public void visitCheckVisitOfEachElement() throws Exception { // ARRANGE List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); - BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags); - queue.push(jedis, "element 1"); - queue.push(jedis, "element 2"); - queue.push(jedis, "element 3"); - queue.push(jedis, "element 4"); - queue.push(jedis, "element 5"); - queue.push(jedis, "element 6"); - queue.push(jedis, "element 7"); - queue.push(jedis, "element 8"); + BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags, RedisQueue::decorate); + queue.offer(jedis, "element 1"); + queue.offer(jedis, "element 2"); + queue.offer(jedis, "element 3"); + queue.offer(jedis, "element 4"); + queue.offer(jedis, "element 5"); + queue.offer(jedis, "element 6"); + queue.offer(jedis, "element 7"); + queue.offer(jedis, "element 8"); // ACT List visited = new ArrayList<>(); @@ -478,15 +484,16 @@ public void visit(String entry) { public void visitCheckVisitOfEachElementPriority() throws Exception { // ARRANGE List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); - BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags, Queue.QUEUE_TYPE.priority); - queue.push(jedis, "element 1"); - queue.push(jedis, "element 2"); - queue.push(jedis, "element 3"); - queue.push(jedis, "element 4"); - queue.push(jedis, "element 5"); - queue.push(jedis, "element 6"); - queue.push(jedis, "element 7"); - queue.push(jedis, "element 8"); + BalancedRedisQueue queue = + new BalancedRedisQueue("test", hashtags, RedisPriorityQueue::decorate); + queue.offer(jedis, "element 1"); + queue.offer(jedis, "element 2"); + queue.offer(jedis, "element 3"); + queue.offer(jedis, "element 4"); + queue.offer(jedis, "element 5"); + queue.offer(jedis, "element 6"); + queue.offer(jedis, "element 7"); + queue.offer(jedis, "element 8"); // ACT List visited = new ArrayList<>(); @@ -517,7 +524,7 @@ public void visit(String entry) { public void isEvenlyDistributedEmptyIsEvenlyDistributed() throws Exception { // ARRANGE List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); - BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags); + BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags, RedisQueue::decorate); // ACT Boolean isEvenlyDistributed = queue.isEvenlyDistributed(jedis); @@ -533,7 +540,8 @@ public void isEvenlyDistributedEmptyIsEvenlyDistributed() throws Exception { public void isEvenlyDistributedEmptyIsEvenlyDistributedPriority() throws Exception { // ARRANGE List hashtags = RedisNodeHashes.getEvenlyDistributedHashes(jedis); - BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags, Queue.QUEUE_TYPE.priority); + BalancedRedisQueue queue = + new BalancedRedisQueue("test", hashtags, RedisPriorityQueue::decorate); // ACT Boolean isEvenlyDistributed = queue.isEvenlyDistributed(jedis); @@ -550,11 +558,11 @@ public void isEvenlyDistributedEmptyIsEvenlyDistributedPriority() throws Excepti public void isEvenlyDistributedFourNodesFourHundredPushesIsEven() throws Exception { // ARRANGE List hashtags = Arrays.asList("node1", "node2", "node3", "node4"); - BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags); + BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags, RedisQueue::decorate); // ACT for (int i = 0; i < 400; ++i) { - queue.push(jedis, "foo"); + queue.offer(jedis, "foo"); } Boolean isEvenlyDistributed = queue.isEvenlyDistributed(jedis); @@ -570,11 +578,12 @@ public void isEvenlyDistributedFourNodesFourHundredPushesIsEven() throws Excepti public void isEvenlyDistributedFourNodesFourHundredPushesIsEvenPriority() throws Exception { // ARRANGE List hashtags = Arrays.asList("node1", "node2", "node3", "node4"); - BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags, Queue.QUEUE_TYPE.priority); + BalancedRedisQueue queue = + new BalancedRedisQueue("test", hashtags, RedisPriorityQueue::decorate); // ACT for (int i = 0; i < 400; ++i) { - queue.push(jedis, "foo"); + queue.offer(jedis, "foo"); } Boolean isEvenlyDistributed = queue.isEvenlyDistributed(jedis); @@ -590,11 +599,11 @@ public void isEvenlyDistributedFourNodesFourHundredPushesIsEvenPriority() throws public void isEvenlyDistributedFourNodesFourHundredOnePushesIsNotEven() throws Exception { // ARRANGE List hashtags = Arrays.asList("node1", "node2", "node3", "node4"); - BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags); + BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags, RedisQueue::decorate); // ACT for (int i = 0; i < 401; ++i) { - queue.push(jedis, "foo"); + queue.offer(jedis, "foo" + i); } Boolean isEvenlyDistributed = queue.isEvenlyDistributed(jedis); @@ -610,11 +619,12 @@ public void isEvenlyDistributedFourNodesFourHundredOnePushesIsNotEven() throws E public void isEvenlyDistributedFourNodesFourHundredOnePushesIsNotEvenPriority() throws Exception { // ARRANGE List hashtags = Arrays.asList("node1", "node2", "node3", "node4"); - BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags, Queue.QUEUE_TYPE.priority); + BalancedRedisQueue queue = + new BalancedRedisQueue("test", hashtags, RedisPriorityQueue::decorate); // ACT for (int i = 0; i < 401; ++i) { - queue.push(jedis, "foo"); + queue.offer(jedis, "foo" + i); } Boolean isEvenlyDistributed = queue.isEvenlyDistributed(jedis); @@ -630,25 +640,25 @@ public void isEvenlyDistributedFourNodesFourHundredOnePushesIsNotEvenPriority() public void isEvenlyDistributedSingleNodeAlwaysEvenlyDistributes() throws Exception { // ARRANGE List hashtags = Collections.singletonList("single_node"); - BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags); + BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags, RedisQueue::decorate); ExecutorService service = newSingleThreadExecutor(); // ACT / ASSERT - queue.push(jedis, "foo"); + queue.offer(jedis, "foo"); assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); - queue.push(jedis, "foo"); + queue.offer(jedis, "foo"); assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); - queue.push(jedis, "foo"); + queue.offer(jedis, "foo"); assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); - queue.push(jedis, "foo"); + queue.offer(jedis, "foo"); assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); service.shutdown(); assertThat(service.awaitTermination(0, SECONDS)).isTrue(); @@ -662,25 +672,26 @@ public void isEvenlyDistributedSingleNodeAlwaysEvenlyDistributes() throws Except public void isEvenlyDistributedSingleNodeAlwaysEvenlyDistributesPriority() throws Exception { // ARRANGE List hashtags = Collections.singletonList("single_node"); - BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags, Queue.QUEUE_TYPE.priority); + BalancedRedisQueue queue = + new BalancedRedisQueue("test", hashtags, RedisPriorityQueue::decorate); ExecutorService service = newSingleThreadExecutor(); // ACT / ASSERT - queue.push(jedis, "foo"); + queue.offer(jedis, "foo"); assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); - queue.push(jedis, "foo"); + queue.offer(jedis, "bar"); assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); - queue.push(jedis, "foo"); + queue.offer(jedis, "baz"); assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); - queue.push(jedis, "foo"); + queue.offer(jedis, "quux"); assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); service.shutdown(); assertThat(service.awaitTermination(0, SECONDS)).isTrue(); @@ -693,38 +704,38 @@ public void isEvenlyDistributedSingleNodeAlwaysEvenlyDistributesPriority() throw public void isEvenlyDistributedTwoNodeExample() throws Exception { // ARRANGE List hashtags = Arrays.asList("node_1", "node_2"); - BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags); + BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags, RedisQueue::decorate); ExecutorService service = newSingleThreadExecutor(); // ACT / ASSERT assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); - queue.push(jedis, "foo"); + queue.offer(jedis, "foo1"); assertThat(queue.isEvenlyDistributed(jedis)).isFalse(); - queue.push(jedis, "foo"); + queue.offer(jedis, "foo2"); assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); - queue.push(jedis, "foo"); + queue.offer(jedis, "foo3"); assertThat(queue.isEvenlyDistributed(jedis)).isFalse(); - queue.push(jedis, "foo"); + queue.offer(jedis, "foo4"); assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); - queue.push(jedis, "foo"); + queue.offer(jedis, "foo5"); assertThat(queue.isEvenlyDistributed(jedis)).isFalse(); - queue.push(jedis, "foo"); + queue.offer(jedis, "foo6"); assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); - queue.push(jedis, "foo"); + queue.offer(jedis, "foo7"); assertThat(queue.isEvenlyDistributed(jedis)).isFalse(); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.isEvenlyDistributed(jedis)).isFalse(); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.isEvenlyDistributed(jedis)).isFalse(); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.isEvenlyDistributed(jedis)).isFalse(); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); service.shutdown(); assertThat(service.awaitTermination(0, SECONDS)).isTrue(); @@ -737,38 +748,39 @@ public void isEvenlyDistributedTwoNodeExample() throws Exception { public void isEvenlyDistributedTwoNodeExamplePriority() throws Exception { // ARRANGE List hashtags = Arrays.asList("node_1", "node_2"); - BalancedRedisQueue queue = new BalancedRedisQueue("test", hashtags, Queue.QUEUE_TYPE.priority); + BalancedRedisQueue queue = + new BalancedRedisQueue("test", hashtags, RedisPriorityQueue::decorate); ExecutorService service = newSingleThreadExecutor(); // ACT / ASSERT assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); - queue.push(jedis, "foo"); + queue.offer(jedis, "foo"); assertThat(queue.isEvenlyDistributed(jedis)).isFalse(); - queue.push(jedis, "foo1"); + queue.offer(jedis, "foo1"); assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); - queue.push(jedis, "foo2"); + queue.offer(jedis, "foo2"); assertThat(queue.isEvenlyDistributed(jedis)).isFalse(); - queue.push(jedis, "foo3"); + queue.offer(jedis, "foo3"); assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); - queue.push(jedis, "foo4"); + queue.offer(jedis, "foo4"); assertThat(queue.isEvenlyDistributed(jedis)).isFalse(); - queue.push(jedis, "foo5"); + queue.offer(jedis, "foo5"); assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); - queue.push(jedis, "foo6"); + queue.offer(jedis, "foo6"); assertThat(queue.isEvenlyDistributed(jedis)).isFalse(); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.isEvenlyDistributed(jedis)).isFalse(); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.isEvenlyDistributed(jedis)).isFalse(); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.isEvenlyDistributed(jedis)).isFalse(); - queue.dequeue(jedis, service); + queue.take(jedis, service); assertThat(queue.isEvenlyDistributed(jedis)).isTrue(); service.shutdown(); assertThat(service.awaitTermination(0, SECONDS)).isTrue(); diff --git a/src/test/java/build/buildfarm/common/redis/RedisPriorityQueueMockTest.java b/src/test/java/build/buildfarm/common/redis/RedisPriorityQueueMockTest.java index 4081bf8fa8..b2a9981e55 100644 --- a/src/test/java/build/buildfarm/common/redis/RedisPriorityQueueMockTest.java +++ b/src/test/java/build/buildfarm/common/redis/RedisPriorityQueueMockTest.java @@ -17,18 +17,16 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.any; import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; import build.buildfarm.common.StringVisitor; +import java.time.Clock; import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.concurrent.ExecutorService; import java.util.stream.Collectors; import java.util.stream.Stream; import org.junit.Before; @@ -51,7 +49,7 @@ @RunWith(JUnit4.class) public class RedisPriorityQueueMockTest { @Mock private Jedis redis; - @Mock private Timestamp time; + @Mock private Clock clock; @Before public void setUp() { @@ -64,113 +62,113 @@ public void setUp() { @Test public void redisPriorityQueueConstructsWithoutError() throws Exception { // ACT - new RedisPriorityQueue("test"); + new RedisPriorityQueue(redis, "test"); } - // Function under test: push - // Reason for testing: the queue can have a value pushed onto it - // Failure explanation: the queue is throwing an exception upon push + // Function under test: offer + // Reason for testing: the queue can have a value offered to it + // Failure explanation: the queue is throwing an exception upon offer @Test - public void pushPushWithoutError() throws Exception { + public void offerOfferWithoutError() throws Exception { // ARRANGE - when(time.getNanos()).thenReturn(123L); - RedisPriorityQueue queue = new RedisPriorityQueue("test", time); + when(clock.millis()).thenReturn(123L); + RedisPriorityQueue queue = new RedisPriorityQueue(redis, "test", clock); // ACT - queue.push(redis, "foo"); + queue.offer("foo"); // ASSERT verify(redis, times(1)).zadd("test", 0, "123:foo"); } - // Function under test: push - // Reason for testing: the queue can have the different values pushed onto it - // Failure explanation: the queue is throwing an exception upon pushing different values + // Function under test: offer + // Reason for testing: the queue can have the different values offered onto it + // Failure explanation: the queue is throwing an exception upon offering different values @Test - public void pushPushDifferentWithoutError() throws Exception { + public void offerOfferDifferentWithoutError() throws Exception { // ARRANGE - when(time.getNanos()).thenReturn(123L, 124L); - RedisPriorityQueue queue = new RedisPriorityQueue("test", time); + when(clock.millis()).thenReturn(123L, 124L); + RedisPriorityQueue queue = new RedisPriorityQueue(redis, "test", clock); // ACT - queue.push(redis, "foo"); - queue.push(redis, "bar"); + queue.offer("foo"); + queue.offer("bar"); // ASSERT verify(redis, times(1)).zadd("test", 0, "123:foo"); verify(redis, times(1)).zadd("test", 0, "124:bar"); } - // Function under test: push - // Reason for testing: the queue can have the same values pushed onto it - // Failure explanation: the queue is throwing an exception upon pushing the same values + // Function under test: offer + // Reason for testing: the queue can have the same values offered to it + // Failure explanation: the queue is throwing an exception upon offering the same values @Test - public void pushPushSameWithoutError() throws Exception { + public void offerOfferSameWithoutError() throws Exception { // ARRANGE - when(time.getNanos()).thenReturn(123L, 124L); - RedisPriorityQueue queue = new RedisPriorityQueue("test", time); + when(clock.millis()).thenReturn(123L, 124L); + RedisPriorityQueue queue = new RedisPriorityQueue(redis, "test", clock); // ACT - queue.push(redis, "foo"); - queue.push(redis, "foo"); + queue.offer("foo"); + queue.offer("foo"); // ASSERT verify(redis, times(1)).zadd("test", 0, "123:foo"); verify(redis, times(1)).zadd("test", 0, "124:foo"); } - // Function under test: push - // Reason for testing: the queue can have the same values pushed onto it - // Failure explanation: the queue is throwing an exception upon pushing the same values + // Function under test: offer + // Reason for testing: the queue can have the same values offered to it + // Failure explanation: the queue throws an exception when offered the same values @Test - public void pushPushPriorityWithoutError() throws Exception { + public void offerOfferPriorityWithoutError() throws Exception { // ARRANGE - when(time.getNanos()).thenReturn(123L, 124L); - RedisPriorityQueue queue = new RedisPriorityQueue("test", time); + when(clock.millis()).thenReturn(123L, 124L); + RedisPriorityQueue queue = new RedisPriorityQueue(redis, "test", clock); // ACT - queue.push(redis, "foo", 1); - queue.push(redis, "foo2", 2); + queue.offer("foo", 1); + queue.offer("foo2", 2); // ASSERT verify(redis, times(1)).zadd("test", 1, "123:foo"); verify(redis, times(1)).zadd("test", 2, "124:foo2"); } - // Function under test: push - // Reason for testing: the queue can have many values pushed into it - // Failure explanation: the queue is throwing an exception upon pushing many values + // Function under test: offer + // Reason for testing: the queue can have many values offered to it + // Failure explanation: the queue throws an exception when offered many values @Test - public void pushPushMany() throws Exception { + public void offerMany() throws Exception { // ARRANGE - when(time.getNanos()).thenReturn(123L); - RedisPriorityQueue queue = new RedisPriorityQueue("test", time); + when(clock.millis()).thenReturn(123L); + RedisPriorityQueue queue = new RedisPriorityQueue(redis, "test", clock); // ACT for (int i = 0; i < 1000; ++i) { - queue.push(redis, "foo" + i); + queue.offer("foo" + i); } // ASSERT verify(redis, times(1000)).zadd(eq("test"), eq(0.0), any(String.class)); } - // Function under test: push - // Reason for testing: the queue size increases as elements are pushed - // Failure explanation: the queue size is not accurately reflecting the pushes + // Function under test: offer + // Reason for testing: the queue size increases as elements are offered + // Failure explanation: the queue size does not reflect the offerings @Test - public void pushCallsLPush() throws Exception { + public void offerCallsZAdd() throws Exception { // ARRANGE - when(time.getNanos()).thenReturn(123L, 124L, 125L); - RedisPriorityQueue queue = new RedisPriorityQueue("test", time); + when(clock.millis()).thenReturn(123L, 124L, 125L); + RedisPriorityQueue queue = new RedisPriorityQueue(redis, "test", clock); // ACT - queue.push(redis, "foo", 0); - queue.push(redis, "foo1", 2); - queue.push(redis, "foo2", 2); + queue.offer("foo", 0); + queue.offer("foo1", 2); + queue.offer("foo2", 2); // ASSERT - verify(time, times(3)).getNanos(); + verify(clock, times(3)).millis(); verify(redis, times(1)).zadd("test", 0, "123:foo"); verify(redis, times(1)).zadd("test", 2, "124:foo1"); verify(redis, times(1)).zadd("test", 2, "125:foo2"); @@ -184,127 +182,87 @@ public void pushCallsLPush() throws Exception { public void removeFromDequeueRemoveADequeueValue() throws Exception { // ARRANGE when(redis.lrem("test_dequeue", -1, "foo")).thenReturn(1L); - RedisPriorityQueue queue = new RedisPriorityQueue("test"); + RedisPriorityQueue queue = new RedisPriorityQueue(redis, "test"); // ACT - boolean wasRemoved = queue.removeFromDequeue(redis, "foo"); + boolean wasRemoved = queue.removeFromDequeue("foo"); // ASSERT assertThat(wasRemoved).isTrue(); verify(redis, times(1)).lrem("test_dequeue", -1, "foo"); } - // Function under test: dequeue - // Reason for testing: the element is able to be dequeued - // Failure explanation: something prevented the element from being dequeued + // Function under test: take + // Reason for testing: the element is able to be taken + // Failure explanation: something prevented the element from being taken @Test public void dequeueElementCanBeDequeuedWithTimeout() throws Exception { // ARRANGE when(redis.eval(any(String.class), any(List.class), any(List.class))).thenReturn("foo"); - RedisPriorityQueue queue = new RedisPriorityQueue("test"); - ExecutorService service = mock(ExecutorService.class); + RedisPriorityQueue queue = new RedisPriorityQueue(redis, "test"); // ACT - queue.push(redis, "foo"); - String val = queue.dequeue(redis, Duration.ofSeconds(1), service); + String val = queue.take(Duration.ofSeconds(1)); // ASSERT - verifyNoInteractions(service); assertThat(val).isEqualTo("foo"); } - // Function under test: dequeue - // Reason for testing: element is not dequeued - // Failure explanation: element was dequeued + // Function under test: take + // Reason for testing: element is not taken + // Failure explanation: element was taken @Test public void dequeueElementIsNotDequeuedIfTimeRunsOut() throws Exception { // ARRANGE when(redis.eval(any(String.class), any(List.class), any(List.class))).thenReturn(null); - RedisPriorityQueue queue = new RedisPriorityQueue("test"); - ExecutorService service = mock(ExecutorService.class); + RedisPriorityQueue queue = new RedisPriorityQueue(redis, "test"); // ACT - queue.push(redis, "foo"); - String val = queue.dequeue(redis, Duration.ofMillis(100), service); + String val = queue.take(Duration.ofMillis(100)); // ASSERT - verifyNoInteractions(service); assertThat(val).isEqualTo(null); } - // Function under test: dequeue - // Reason for testing: the dequeue is interrupted - // Failure explanation: the dequeue was not interrupted as expected + // Function under test: take + // Reason for testing: the take is interrupted + // Failure explanation: the take was not interrupted as expected @Test public void dequeueInterrupt() throws Exception { // ARRANGE when(redis.eval(any(String.class), any(List.class), any(List.class))).thenReturn(null); - RedisPriorityQueue queue = new RedisPriorityQueue("test"); - ExecutorService service = mock(ExecutorService.class); + RedisPriorityQueue queue = new RedisPriorityQueue(redis, "test"); // ACT - queue.push(redis, "foo"); Thread call = new Thread( () -> { try { - queue.dequeue(redis, Duration.ofDays(1), service); + queue.take(Duration.ofDays(1)); } catch (Exception e) { } }); call.start(); call.interrupt(); call.join(); - verifyNoInteractions(service); } - // Function under test: nonBlockingDequeue - // Reason for testing: the element is able to be dequeued - // Failure explanation: something prevented the element from being dequeued + // Function under test: poll + // Reason for testing: the element is able to be polled + // Failure explanation: something prevented the element from being polled @Test public void nonBlockingDequeueElementCanBeDequeued() throws Exception { // ARRANGE when(redis.eval(any(String.class), any(List.class), any(List.class))).thenReturn("foo"); - RedisPriorityQueue queue = new RedisPriorityQueue("test"); + RedisPriorityQueue queue = new RedisPriorityQueue(redis, "test"); // ACT - queue.push(redis, "foo"); - String val = queue.nonBlockingDequeue(redis); + String val = queue.poll(); // ASSERT assertThat(val).isEqualTo("foo"); } - // Function under test: getName - // Reason for testing: the name can be received - // Failure explanation: name does not match what it should - @Test - public void getNameNameIsStored() throws Exception { - // ARRANGE - RedisPriorityQueue queue = new RedisPriorityQueue("queue_name"); - - // ACT - String name = queue.getName(); - - // ASSERT - assertThat(name).isEqualTo("queue_name"); - } - - // Function under test: getDequeueName - // Reason for testing: the name can be received - // Failure explanation: name does not match what it should - @Test - public void getDequeueNameNameIsStored() throws Exception { - // ARRANGE - RedisPriorityQueue queue = new RedisPriorityQueue("queue_name"); - - // ACT - String name = queue.getDequeueName(); - - // ASSERT - assertThat(name).isEqualTo("queue_name_dequeue"); - } - // Function under test: visit // Reason for testing: each element in the queue can be visited // Failure explanation: we are unable to visit each element in the queue @@ -325,15 +283,15 @@ public void visitCheckVisitOfEachElement() throws Exception { .collect(Collectors.toList())); // ARRANGE - RedisPriorityQueue queue = new RedisPriorityQueue("test"); - queue.push(redis, "element 1"); - queue.push(redis, "element 2"); - queue.push(redis, "element 3"); - queue.push(redis, "element 4"); - queue.push(redis, "element 5"); - queue.push(redis, "element 6"); - queue.push(redis, "element 7"); - queue.push(redis, "element 8"); + RedisPriorityQueue queue = new RedisPriorityQueue(redis, "test"); + queue.offer("element 1"); + queue.offer("element 2"); + queue.offer("element 3"); + queue.offer("element 4"); + queue.offer("element 5"); + queue.offer("element 6"); + queue.offer("element 7"); + queue.offer("element 8"); // ACT List visited = new ArrayList<>(); @@ -343,7 +301,7 @@ public void visit(String entry) { visited.add(entry); } }; - queue.visit(redis, visitor); + queue.visit(visitor); // ASSERT assertThat(visited.size()).isEqualTo(8); @@ -376,7 +334,7 @@ public void visitDequeueCheckVisitOfEachElement() throws Exception { "element 8")); // ARRANGE - RedisPriorityQueue queue = new RedisPriorityQueue("test"); + RedisPriorityQueue queue = new RedisPriorityQueue(redis, "test"); // ACT List visited = new ArrayList<>(); @@ -386,7 +344,7 @@ public void visit(String entry) { visited.add(entry); } }; - queue.visitDequeue(redis, visitor); + queue.visitDequeue(visitor); // ASSERT assertThat(visited.size()).isEqualTo(8); diff --git a/src/test/java/build/buildfarm/common/redis/RedisPriorityQueueTest.java b/src/test/java/build/buildfarm/common/redis/RedisPriorityQueueTest.java index 28c8cc5129..2845eaa554 100644 --- a/src/test/java/build/buildfarm/common/redis/RedisPriorityQueueTest.java +++ b/src/test/java/build/buildfarm/common/redis/RedisPriorityQueueTest.java @@ -23,6 +23,7 @@ import build.buildfarm.common.config.BuildfarmConfigs; import build.buildfarm.instance.shard.JedisClusterFactory; import com.google.common.base.Stopwatch; +import com.google.common.collect.ImmutableList; import java.time.Duration; import java.util.ArrayList; import java.util.List; @@ -68,110 +69,95 @@ public void tearDown() { // Function under test: RedisPriorityQueue // Reason for testing: the queue can be constructed with a valid cluster instance and name - // Failure explanation: the queue is throwing an exception upon construction + // Failure explanation: the queue throws an exception upon construction @Test public void redisPriorityQueueConstructsWithoutError() throws Exception { // ACT - new RedisPriorityQueue("test"); + new RedisPriorityQueue(redis, "test"); } - // Function under test: push - // Reason for testing: the queue can have a value pushed onto it - // Failure explanation: the queue is throwing an exception upon push + // Function under test: offer + // Reason for testing: the queue can have a value offered to it + // Failure explanation: the queue throws an exception upon offer @Test - public void pushPushWithoutError() throws Exception { + public void offerWithoutError() throws Exception { // ARRANGE - RedisPriorityQueue queue = new RedisPriorityQueue("test"); + RedisPriorityQueue queue = new RedisPriorityQueue(redis, "test"); // ACT - queue.push(redis, "foo"); + queue.offer("foo"); } - // Function under test: push - // Reason for testing: the queue can have the different values pushed onto it - // Failure explanation: the queue is throwing an exception upon pushing different values + // Function under test: offer + // Reason for testing: the queue can have the different values offered to it + // Failure explanation: the queue throws an exception upon offering different values @Test - public void pushPushDifferentWithoutError() throws Exception { + public void offerDifferentWithoutError() throws Exception { // ARRANGE - RedisPriorityQueue queue = new RedisPriorityQueue("test"); + RedisPriorityQueue queue = new RedisPriorityQueue(redis, "test"); // ACT - queue.push(redis, "foo"); - queue.push(redis, "bar"); + queue.offer("foo"); + queue.offer("bar"); } - // Function under test: push - // Reason for testing: the queue can have the same values pushed onto it - // Failure explanation: the queue is throwing an exception upon pushing the same values + // Function under test: offer + // Reason for testing: the queue can have the same values offered to it + // Failure explanation: the queue throws an exception upon offering the same values @Test public void pushPushSameWithoutError() throws Exception { // ARRANGE - RedisPriorityQueue queue = new RedisPriorityQueue("test"); + RedisPriorityQueue queue = new RedisPriorityQueue(redis, "test"); // ACT - queue.push(redis, "foo"); - queue.push(redis, "foo"); + queue.offer("foo"); + queue.offer("foo"); } - // Function under test: push - // Reason for testing: the queue can have many values pushed into it - // Failure explanation: the queue is throwing an exception upon pushing many values + // Function under test: offer + // Reason for testing: the queue can have many values offered to it + // Failure explanation: the queue throws an exception upon offering many values @Test public void pushPushMany() throws Exception { // ARRANGE - RedisPriorityQueue queue = new RedisPriorityQueue("test"); + RedisPriorityQueue queue = new RedisPriorityQueue(redis, "test"); // ACT for (int i = 0; i < 1000; ++i) { - queue.push(redis, "foo" + i); + queue.offer("foo" + i); } } - // Function under test: push - // Reason for testing: the queue size increases as elements are pushed - // Failure explanation: the queue size is not accurately reflecting the pushes + // Function under test: offer + // Reason for testing: the queue size increases as elements are offered + // Failure explanation: the queue size does not reflect offers @Test public void pushPushIncreasesSize() throws Exception { // ARRANGE - RedisPriorityQueue queue = new RedisPriorityQueue("test"); + RedisPriorityQueue queue = new RedisPriorityQueue(redis, "test"); // ACT / ASSERT - assertThat(queue.size(redis)).isEqualTo(0); - queue.push(redis, "foo"); - assertThat(queue.size(redis)).isEqualTo(1); - queue.push(redis, "foo1"); - assertThat(queue.size(redis)).isEqualTo(2); - queue.push(redis, "foo2"); - assertThat(queue.size(redis)).isEqualTo(3); - queue.push(redis, "foo3"); - assertThat(queue.size(redis)).isEqualTo(4); - queue.push(redis, "foo4"); - assertThat(queue.size(redis)).isEqualTo(5); - queue.push(redis, "foo5"); - assertThat(queue.size(redis)).isEqualTo(6); - queue.push(redis, "foo6"); - assertThat(queue.size(redis)).isEqualTo(7); - queue.push(redis, "foo7"); - assertThat(queue.size(redis)).isEqualTo(8); - queue.push(redis, "foo8"); - assertThat(queue.size(redis)).isEqualTo(9); - queue.push(redis, "foo9"); - assertThat(queue.size(redis)).isEqualTo(10); - } - - // Function under test: getName - // Reason for testing: the name can be received - // Failure explanation: name does not match what it should - @Test - public void getNameNameIsStored() throws Exception { - // ARRANGE - RedisPriorityQueue queue = new RedisPriorityQueue("queue_name"); - - // ACT - String name = queue.getName(); - - // ASSERT - assertThat(name).isEqualTo("queue_name"); + assertThat(queue.size()).isEqualTo(0); + queue.offer("foo"); + assertThat(queue.size()).isEqualTo(1); + queue.offer("foo1"); + assertThat(queue.size()).isEqualTo(2); + queue.offer("foo2"); + assertThat(queue.size()).isEqualTo(3); + queue.offer("foo3"); + assertThat(queue.size()).isEqualTo(4); + queue.offer("foo4"); + assertThat(queue.size()).isEqualTo(5); + queue.offer("foo5"); + assertThat(queue.size()).isEqualTo(6); + queue.offer("foo6"); + assertThat(queue.size()).isEqualTo(7); + queue.offer("foo7"); + assertThat(queue.size()).isEqualTo(8); + queue.offer("foo8"); + assertThat(queue.size()).isEqualTo(9); + queue.offer("foo9"); + assertThat(queue.size()).isEqualTo(10); } // Function under test: getDequeueName @@ -180,7 +166,7 @@ public void getNameNameIsStored() throws Exception { @Test public void getDequeueNameNameIsStored() throws Exception { // ARRANGE - RedisPriorityQueue queue = new RedisPriorityQueue("queue_name"); + RedisPriorityQueue queue = new RedisPriorityQueue(redis, "queue_name"); // ACT String name = queue.getDequeueName(); @@ -190,86 +176,78 @@ public void getDequeueNameNameIsStored() throws Exception { } // Function under test: size - // Reason for testing: size adjusts with push and dequeue + // Reason for testing: size adjusts with offer(and dequeue // Failure explanation: size is incorrectly reporting the expected queue size @Test public void sizeAdjustPushDequeue() throws Exception { // ARRANGE - RedisPriorityQueue queue = new RedisPriorityQueue("test"); + RedisPriorityQueue queue = new RedisPriorityQueue(redis, "test"); ExecutorService service = mock(ExecutorService.class); Duration timeout = Duration.ofSeconds(1); // ACT / ASSERT - assertThat(queue.size(redis)).isEqualTo(0); - queue.push(redis, "foo"); - assertThat(queue.size(redis)).isEqualTo(1); - queue.push(redis, "bar"); - assertThat(queue.size(redis)).isEqualTo(2); - queue.push(redis, "baz"); - assertThat(queue.size(redis)).isEqualTo(3); - queue.push(redis, "baz2"); - assertThat(queue.size(redis)).isEqualTo(4); - queue.push(redis, "baz3"); - assertThat(queue.size(redis)).isEqualTo(5); - queue.push(redis, "baz4"); - assertThat(queue.size(redis)).isEqualTo(6); - queue.dequeue(redis, timeout, service); - assertThat(queue.size(redis)).isEqualTo(5); - queue.dequeue(redis, timeout, service); - assertThat(queue.size(redis)).isEqualTo(4); - queue.dequeue(redis, timeout, service); - assertThat(queue.size(redis)).isEqualTo(3); - queue.dequeue(redis, timeout, service); - assertThat(queue.size(redis)).isEqualTo(2); - queue.dequeue(redis, timeout, service); - assertThat(queue.size(redis)).isEqualTo(1); - queue.dequeue(redis, timeout, service); - assertThat(queue.size(redis)).isEqualTo(0); + assertThat(queue.size()).isEqualTo(0); + queue.offer("foo"); + assertThat(queue.size()).isEqualTo(1); + queue.offer("bar"); + assertThat(queue.size()).isEqualTo(2); + queue.offer("baz"); + assertThat(queue.size()).isEqualTo(3); + queue.offer("baz2"); + assertThat(queue.size()).isEqualTo(4); + queue.offer("baz3"); + assertThat(queue.size()).isEqualTo(5); + queue.offer("baz4"); + assertThat(queue.size()).isEqualTo(6); + queue.take(timeout); + assertThat(queue.size()).isEqualTo(5); + queue.take(timeout); + assertThat(queue.size()).isEqualTo(4); + queue.take(timeout); + assertThat(queue.size()).isEqualTo(3); + queue.take(timeout); + assertThat(queue.size()).isEqualTo(2); + queue.take(timeout); + assertThat(queue.size()).isEqualTo(1); + queue.take(timeout); + assertThat(queue.size()).isEqualTo(0); verifyNoInteractions(service); } // Function under test: size - // Reason for testing: size adjusts with push and dequeue + // Reason for testing: size adjusts with offer(and take(timeout); // Failure explanation: size is incorrectly reporting the expected queue size @Test public void checkPriorityOnDequeue() throws Exception { // ARRANGE - RedisPriorityQueue queue = new RedisPriorityQueue("test"); + RedisPriorityQueue queue = new RedisPriorityQueue(redis, "test"); ExecutorService service = mock(ExecutorService.class); Duration timeout = Duration.ofSeconds(1); - String val; // ACT / ASSERT - assertThat(queue.size(redis)).isEqualTo(0); - queue.push(redis, "foo", 2); - assertThat(queue.size(redis)).isEqualTo(1); - queue.push(redis, "bar", 1); - assertThat(queue.size(redis)).isEqualTo(2); - queue.push(redis, "baz", 3); - assertThat(queue.size(redis)).isEqualTo(3); - queue.push(redis, "baz2", 1); - assertThat(queue.size(redis)).isEqualTo(4); - queue.push(redis, "baz3", 2); - assertThat(queue.size(redis)).isEqualTo(5); - queue.push(redis, "baz4", 1); - assertThat(queue.size(redis)).isEqualTo(6); - val = queue.dequeue(redis, timeout, service); - assertThat(val).isEqualTo("bar"); - assertThat(queue.size(redis)).isEqualTo(5); - val = queue.dequeue(redis, timeout, service); - assertThat(val).isEqualTo("baz2"); - assertThat(queue.size(redis)).isEqualTo(4); - val = queue.dequeue(redis, timeout, service); - assertThat(val).isEqualTo("baz4"); - assertThat(queue.size(redis)).isEqualTo(3); - val = queue.dequeue(redis, timeout, service); - assertThat(val).isEqualTo("foo"); - assertThat(queue.size(redis)).isEqualTo(2); - val = queue.dequeue(redis, timeout, service); - assertThat(val).isEqualTo("baz3"); - assertThat(queue.size(redis)).isEqualTo(1); - val = queue.dequeue(redis, timeout, service); - assertThat(val).isEqualTo("baz"); - assertThat(queue.size(redis)).isEqualTo(0); + assertThat(queue.size()).isEqualTo(0); + queue.offer("prio_2_1", 2); + assertThat(queue.size()).isEqualTo(1); + queue.offer("prio_1_1", 1); + assertThat(queue.size()).isEqualTo(2); + queue.offer("prio_3_1", 3); + assertThat(queue.size()).isEqualTo(3); + queue.offer("prio_1_2", 1); + assertThat(queue.size()).isEqualTo(4); + queue.offer("prio_2_2", 2); + assertThat(queue.size()).isEqualTo(5); + queue.offer("prio_1_3", 1); + assertThat(queue.size()).isEqualTo(6); + // priority 1 + assertThat(ImmutableList.of(queue.take(timeout), queue.take(timeout), queue.take(timeout))) + .containsExactly("prio_1_1", "prio_1_2", "prio_1_3"); + assertThat(queue.size()).isEqualTo(3); + // priority 2 + assertThat(ImmutableList.of(queue.take(timeout), queue.take(timeout))) + .containsExactly("prio_2_1", "prio_2_2"); + assertThat(queue.size()).isEqualTo(1); + // priority 3 + assertThat(ImmutableList.of(queue.take(timeout))).containsExactly("prio_3_1"); + assertThat(queue.size()).isEqualTo(0); verifyNoInteractions(service); } @@ -279,11 +257,11 @@ public void checkPriorityOnDequeue() throws Exception { @Test public void checkDequeueTimeout() throws Exception { // ARRANGE - RedisPriorityQueue queue = new RedisPriorityQueue("test"); + RedisPriorityQueue queue = new RedisPriorityQueue(redis, "test"); ExecutorService service = mock(ExecutorService.class); Stopwatch stopwatch = Stopwatch.createStarted(); - String val = queue.dequeue(redis, Duration.ofSeconds(1), service); + String val = queue.take(Duration.ofSeconds(1)); long timeElapsed = stopwatch.elapsed(MILLISECONDS); assertThat(timeElapsed).isGreaterThan(1000L); @@ -297,36 +275,36 @@ public void checkDequeueTimeout() throws Exception { @Test public void checkNegativesInPriority() throws Exception { // ARRANGE - RedisPriorityQueue queue = new RedisPriorityQueue("test"); + RedisPriorityQueue queue = new RedisPriorityQueue(redis, "test"); ExecutorService service = mock(ExecutorService.class); Duration timeout = Duration.ofSeconds(1); String val; // ACT / ASSERT - queue.push(redis, "foo-6", 6); - queue.push(redis, "foo-5", 5); - queue.push(redis, "foo-3", 3); - queue.push(redis, "negative-50", -50); - queue.push(redis, "negative-1", -1); - queue.push(redis, "foo-1", 1); - queue.push(redis, "baz-2", 2); - queue.push(redis, "foo-4", 4); - - val = queue.dequeue(redis, timeout, service); + queue.offer("foo-6", 6); + queue.offer("foo-5", 5); + queue.offer("foo-3", 3); + queue.offer("negative-50", -50); + queue.offer("negative-1", -1); + queue.offer("foo-1", 1); + queue.offer("baz-2", 2); + queue.offer("foo-4", 4); + + val = queue.take(timeout); assertThat(val).isEqualTo("negative-50"); - val = queue.dequeue(redis, timeout, service); + val = queue.take(timeout); assertThat(val).isEqualTo("negative-1"); - val = queue.dequeue(redis, timeout, service); + val = queue.take(timeout); assertThat(val).isEqualTo("foo-1"); - val = queue.dequeue(redis, timeout, service); + val = queue.take(timeout); assertThat(val).isEqualTo("baz-2"); - val = queue.dequeue(redis, timeout, service); + val = queue.take(timeout); assertThat(val).isEqualTo("foo-3"); - val = queue.dequeue(redis, timeout, service); + val = queue.take(timeout); assertThat(val).isEqualTo("foo-4"); - val = queue.dequeue(redis, timeout, service); + val = queue.take(timeout); assertThat(val).isEqualTo("foo-5"); - val = queue.dequeue(redis, timeout, service); + val = queue.take(timeout); assertThat(val).isEqualTo("foo-6"); verifyNoInteractions(service); } @@ -337,15 +315,15 @@ public void checkNegativesInPriority() throws Exception { @Test public void visitCheckVisitOfEachElement() throws Exception { // ARRANGE - RedisPriorityQueue queue = new RedisPriorityQueue("test"); - queue.push(redis, "element 1"); - queue.push(redis, "element 2"); - queue.push(redis, "element 3"); - queue.push(redis, "element 4"); - queue.push(redis, "element 5"); - queue.push(redis, "element 6"); - queue.push(redis, "element 7"); - queue.push(redis, "element 8"); + RedisPriorityQueue queue = new RedisPriorityQueue(redis, "test"); + queue.offer("element 1"); + queue.offer("element 2"); + queue.offer("element 3"); + queue.offer("element 4"); + queue.offer("element 5"); + queue.offer("element 6"); + queue.offer("element 7"); + queue.offer("element 8"); // ACT List visited = new ArrayList<>(); @@ -355,7 +333,7 @@ public void visit(String entry) { visited.add(entry); } }; - queue.visit(redis, visitor); + queue.visit(visitor); // ASSERT assertThat(visited.size()).isEqualTo(8); @@ -375,9 +353,9 @@ public void visit(String entry) { @Test public void visitVisitManyOverPageSize() throws Exception { // ARRANGE - RedisPriorityQueue queue = new RedisPriorityQueue("test"); + RedisPriorityQueue queue = new RedisPriorityQueue(redis, "test"); for (int i = 0; i < 2500; ++i) { - queue.push(redis, "foo" + i); + queue.offer("foo" + i); } // ACT @@ -388,7 +366,7 @@ public void visit(String entry) { visited.add(entry); } }; - queue.visit(redis, visitor); + queue.visit(visitor); // ASSERT assertThat(visited.size()).isEqualTo(2500); diff --git a/src/test/java/build/buildfarm/common/redis/RedisQueueMockTest.java b/src/test/java/build/buildfarm/common/redis/RedisQueueMockTest.java index 4b75098630..947b5cef1a 100644 --- a/src/test/java/build/buildfarm/common/redis/RedisQueueMockTest.java +++ b/src/test/java/build/buildfarm/common/redis/RedisQueueMockTest.java @@ -14,11 +14,9 @@ package build.buildfarm.common.redis; -import static com.google.common.truth.Truth.assertThat; -import static java.util.concurrent.Executors.newSingleThreadExecutor; -import static java.util.concurrent.TimeUnit.SECONDS; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.eq; +import static com.google.common.collect.Iterables.partition; +import static com.google.common.collect.Lists.newArrayList; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -26,11 +24,8 @@ import static redis.clients.jedis.args.ListDirection.RIGHT; import build.buildfarm.common.StringVisitor; +import com.google.common.collect.ImmutableList; import java.time.Duration; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.ExecutorService; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -39,15 +34,6 @@ import org.mockito.MockitoAnnotations; import redis.clients.jedis.Jedis; -/** - * @class RedisQueueMockTest - * @brief tests A redis queue. - * @details A redis queue is an implementation of a queue data structure which internally uses redis - * to store and distribute the data. Its important to know that the lifetime of the queue - * persists before and after the queue data structure is created (since it exists in redis). - * Therefore, two redis queues with the same name, would in fact be the same underlying redis - * queue. - */ @RunWith(JUnit4.class) public class RedisQueueMockTest { @Mock private Jedis redis; @@ -57,317 +43,117 @@ public void setUp() { MockitoAnnotations.initMocks(this); } - // Function under test: redisQueue - // Reason for testing: the queue can be constructed with a valid cluster instance and name - // Failure explanation: the queue is throwing an exception upon construction @Test - public void redisQueueConstructsWithoutError() throws Exception { - // ACT - new RedisQueue("test"); + public void decorateSucceeds() { + RedisQueue.decorate(redis, "test"); } - // Function under test: push - // Reason for testing: the queue can have a value pushed onto it - // Failure explanation: the queue is throwing an exception upon push @Test - public void pushPushWithoutError() throws Exception { - // ARRANGE - RedisQueue queue = new RedisQueue("test"); + public void offerShouldLPush() { + RedisQueue queue = new RedisQueue(redis, "test"); - // ACT - queue.push(redis, "foo"); + queue.offer("foo"); - // ASSERT verify(redis, times(1)).lpush("test", "foo"); } - // Function under test: push - // Reason for testing: the queue can have the different values pushed onto it - // Failure explanation: the queue is throwing an exception upon pushing different values @Test - public void pushPushDifferentWithoutError() throws Exception { - // ARRANGE - RedisQueue queue = new RedisQueue("test"); + public void removeFromDequeueShouldLRemTail() { + RedisQueue queue = new RedisQueue(redis, "test"); - // ACT - queue.push(redis, "foo"); - queue.push(redis, "bar"); + queue.removeFromDequeue("foo"); - // ASSERT - verify(redis, times(1)).lpush("test", "foo"); - verify(redis, times(1)).lpush("test", "bar"); + verify(redis, times(1)).lrem(queue.getDequeueName(), -1, "foo"); } - // Function under test: push - // Reason for testing: the queue can have the same values pushed onto it - // Failure explanation: the queue is throwing an exception upon pushing the same values @Test - public void pushPushSameWithoutError() throws Exception { - // ARRANGE - RedisQueue queue = new RedisQueue("test"); + public void removeAllShouldLRemAll() { + RedisQueue queue = new RedisQueue(redis, "test"); - // ACT - queue.push(redis, "foo"); - queue.push(redis, "foo"); + queue.removeAll("foo"); - // ASSERT - verify(redis, times(2)).lpush("test", "foo"); + verify(redis, times(1)).lrem("test", 0, "foo"); } - // Function under test: push - // Reason for testing: the queue can have many values pushed into it - // Failure explanation: the queue is throwing an exception upon pushing many values @Test - public void pushPushMany() throws Exception { - // ARRANGE - RedisQueue queue = new RedisQueue("test"); - - // ACT - for (int i = 0; i < 1000; ++i) { - queue.push(redis, "foo" + i); - } + public void takeShouldBLMove() { + RedisQueue queue = new RedisQueue(redis, "test"); - // ASSERT - verify(redis, times(1000)).lpush(eq("test"), any(String.class)); - } + queue.take(Duration.ofMillis(1470)); - // Function under test: push - // Reason for testing: the queue size increases as elements are pushed - // Failure explanation: the queue size is not accurately reflecting the pushes - @Test - public void pushCallsLPush() throws Exception { - // ARRANGE - RedisQueue queue = new RedisQueue("test"); - - // ACT - queue.push(redis, "foo"); - queue.push(redis, "foo"); - queue.push(redis, "foo"); - queue.push(redis, "foo"); - queue.push(redis, "foo"); - queue.push(redis, "foo"); - queue.push(redis, "foo"); - queue.push(redis, "foo"); - queue.push(redis, "foo"); - queue.push(redis, "foo"); - - // ASSERT - verify(redis, times(10)).lpush("test", "foo"); + verify(redis, times(1)).blmove("test", queue.getDequeueName(), RIGHT, LEFT, 1.47); } - // Function under test: removeFromDequeue - // Reason for testing: we can remove an element from the dequeue - // Failure explanation: we are either unable to get an element into the dequeue or unable to - // remove it @Test - public void removeFromDequeueRemoveADequeueValue() throws Exception { - // ARRANGE - when(redis.lrem("test_dequeue", -1, "foo")).thenReturn(1L); - RedisQueue queue = new RedisQueue("test"); + public void pollShouldLMove() { + RedisQueue queue = new RedisQueue(redis, "test"); - // ACT - boolean wasRemoved = queue.removeFromDequeue(redis, "foo"); + queue.poll(); - // ASSERT - assertThat(wasRemoved).isTrue(); - verify(redis, times(1)).lrem("test_dequeue", -1, "foo"); + verify(redis, times(1)).lmove("test", queue.getDequeueName(), RIGHT, LEFT); } - // Function under test: dequeue - // Reason for testing: the element is able to be dequeued - // Failure explanation: something prevented the element from being dequeued @Test - public void dequeueElementCanBeDequeuedWithTimeout() throws Exception { - // ARRANGE - when(redis.blmove(eq("test"), eq("test_dequeue"), eq(RIGHT), eq(LEFT), any(double.class))) - .thenReturn("foo"); - RedisQueue queue = new RedisQueue("test"); - ExecutorService service = newSingleThreadExecutor(); - - // ACT - String val = queue.dequeue(redis, Duration.ofSeconds(1), service); - service.shutdown(); - - // ASSERT - assertThat(val).isEqualTo("foo"); - assertThat(service.awaitTermination(1, SECONDS)).isTrue(); - } + public void sizeShouldLLen() { + RedisQueue queue = new RedisQueue(redis, "test"); - // Function under test: dequeue - // Reason for testing: element is not dequeued - // Failure explanation: element was dequeued - @Test - public void dequeueElementIsNotDequeuedIfTimeRunsOut() throws Exception { - // ARRANGE - when(redis.blmove(eq("test"), eq("test_dequeue"), eq(RIGHT), eq(LEFT), any(double.class))) - .thenReturn(null); - RedisQueue queue = new RedisQueue("test"); - ExecutorService service = newSingleThreadExecutor(); - - // ACT - String val = queue.dequeue(redis, Duration.ofMillis(100), service); - service.shutdown(); - - // ASSERT - // future submission may still be completing after interrupt - assertThat(service.awaitTermination(1, SECONDS)).isTrue(); - assertThat(val).isEqualTo(null); - } + queue.size(); - // Function under test: dequeue - // Reason for testing: the dequeue is interrupted - // Failure explanation: the dequeue was not interrupted as expected - @Test - public void dequeueInterrupt() throws Exception { - // ARRANGE - when(redis.blmove(eq("test"), eq("test_dequeue"), eq(RIGHT), eq(LEFT), any(double.class))) - .thenReturn(null); - RedisQueue queue = new RedisQueue("test"); - ExecutorService service = newSingleThreadExecutor(); - - // ACT - Thread call = - new Thread( - () -> { - try { - queue.dequeue(redis, Duration.ofDays(1), service); - } catch (Exception e) { - } - }); - call.start(); - call.interrupt(); - call.join(); + verify(redis, times(1)).llen("test"); } - // Function under test: nonBlockingDequeue - // Reason for testing: the element is able to be dequeued - // Failure explanation: something prevented the element from being dequeued - @Test - public void nonBlockingDequeueElementCanBeDequeued() throws Exception { - // ARRANGE - when(redis.lmove("test", "test_dequeue", RIGHT, LEFT)).thenReturn("foo"); - RedisQueue queue = new RedisQueue("test"); - - // ACT - String val = queue.nonBlockingDequeue(redis); - - // ASSERT - assertThat(val).isEqualTo("foo"); + private void arrangeVisitLRange(String name, int listPageSize, Iterable entries) { + int index = 0; + int nextIndex = listPageSize; + for (Iterable page : partition(entries, listPageSize)) { + when(redis.lrange(name, index, nextIndex - 1)).thenReturn(newArrayList(page)); + index = nextIndex; + nextIndex += listPageSize; + } } - // Function under test: getName - // Reason for testing: the name can be received - // Failure explanation: name does not match what it should - @Test - public void getNameNameIsStored() throws Exception { - // ARRANGE - RedisQueue queue = new RedisQueue("queue_name"); - - // ACT - String name = queue.getName(); - - // ASSERT - assertThat(name).isEqualTo("queue_name"); + private void verifyVisitLRange( + String name, StringVisitor visitor, int listPageSize, Iterable entries) { + int pageCount = listPageSize; + int index = 0; + int nextIndex = listPageSize; + for (String entry : entries) { + verify(visitor, times(1)).visit(entry); + if (--pageCount == 0) { + verify(redis, times(1)).lrange(name, index, nextIndex - 1); + index = nextIndex; + nextIndex += listPageSize; + pageCount = listPageSize; + } + } + if (pageCount != 0) { + verify(redis, times(1)).lrange(name, index, nextIndex - 1); + } } - // Function under test: getDequeueName - // Reason for testing: the name can be received - // Failure explanation: name does not match what it should + private final Iterable VISIT_ENTRIES = ImmutableList.of("one", "two", "three", "four"); + @Test - public void getDequeueNameNameIsStored() throws Exception { - // ARRANGE - RedisQueue queue = new RedisQueue("queue_name"); + public void visitShouldLRange() { + int listPageSize = 3; + RedisQueue queue = new RedisQueue(redis, "test", listPageSize); + arrangeVisitLRange("test", listPageSize, VISIT_ENTRIES); + StringVisitor visitor = mock(StringVisitor.class); - // ACT - String name = queue.getDequeueName(); + queue.visit(visitor); - // ASSERT - assertThat(name).isEqualTo("queue_name_dequeue"); + verifyVisitLRange("test", visitor, listPageSize, VISIT_ENTRIES); } - // Function under test: visit - // Reason for testing: each element in the queue can be visited - // Failure explanation: we are unable to visit each element in the queue @Test - public void visitCheckVisitOfEachElement() throws Exception { - // MOCK - when(redis.lrange(any(String.class), any(Long.class), any(Long.class))) - .thenReturn( - Arrays.asList( - "element 1", - "element 2", - "element 3", - "element 4", - "element 5", - "element 6", - "element 7", - "element 8")); - - // ARRANGE - RedisQueue queue = new RedisQueue("test"); - - // ACT - List visited = new ArrayList<>(); - StringVisitor visitor = - new StringVisitor() { - public void visit(String entry) { - visited.add(entry); - } - }; - queue.visit(redis, visitor); - - // ASSERT - assertThat(visited.size()).isEqualTo(8); - assertThat(visited.contains("element 1")).isTrue(); - assertThat(visited.contains("element 2")).isTrue(); - assertThat(visited.contains("element 3")).isTrue(); - assertThat(visited.contains("element 4")).isTrue(); - assertThat(visited.contains("element 5")).isTrue(); - assertThat(visited.contains("element 6")).isTrue(); - assertThat(visited.contains("element 7")).isTrue(); - assertThat(visited.contains("element 8")).isTrue(); - } + public void visitDequeueShouldLRange() { + int listPageSize = 3; + RedisQueue queue = new RedisQueue(redis, "test", listPageSize); + arrangeVisitLRange(queue.getDequeueName(), listPageSize, VISIT_ENTRIES); + StringVisitor visitor = mock(StringVisitor.class); - // Function under test: visitDequeue - // Reason for testing: each element in the queue can be visited - // Failure explanation: we are unable to visit each element in the queue - @Test - public void visitDequeueCheckVisitOfEachElement() throws Exception { - // MOCK - when(redis.lrange(any(String.class), any(Long.class), any(Long.class))) - .thenReturn( - Arrays.asList( - "element 1", - "element 2", - "element 3", - "element 4", - "element 5", - "element 6", - "element 7", - "element 8")); - - // ARRANGE - RedisQueue queue = new RedisQueue("test"); - - // ACT - List visited = new ArrayList<>(); - StringVisitor visitor = - new StringVisitor() { - public void visit(String entry) { - visited.add(entry); - } - }; - queue.visitDequeue(redis, visitor); - - // ASSERT - assertThat(visited.size()).isEqualTo(8); - assertThat(visited.contains("element 1")).isTrue(); - assertThat(visited.contains("element 2")).isTrue(); - assertThat(visited.contains("element 3")).isTrue(); - assertThat(visited.contains("element 4")).isTrue(); - assertThat(visited.contains("element 5")).isTrue(); - assertThat(visited.contains("element 6")).isTrue(); - assertThat(visited.contains("element 7")).isTrue(); - assertThat(visited.contains("element 8")).isTrue(); + queue.visitDequeue(visitor); + + verifyVisitLRange(queue.getDequeueName(), visitor, listPageSize, VISIT_ENTRIES); } } diff --git a/src/test/java/build/buildfarm/common/redis/RedisQueueTest.java b/src/test/java/build/buildfarm/common/redis/RedisQueueTest.java index d08081b4e9..c220684b9f 100644 --- a/src/test/java/build/buildfarm/common/redis/RedisQueueTest.java +++ b/src/test/java/build/buildfarm/common/redis/RedisQueueTest.java @@ -15,16 +15,15 @@ package build.buildfarm.common.redis; import static com.google.common.truth.Truth.assertThat; -import static java.util.concurrent.Executors.newSingleThreadExecutor; -import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import build.buildfarm.common.StringVisitor; import build.buildfarm.common.config.BuildfarmConfigs; import build.buildfarm.instance.shard.JedisClusterFactory; +import com.google.common.collect.ImmutableList; import java.time.Duration; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ExecutorService; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -56,240 +55,145 @@ public void setUp() throws Exception { assertThat(unified).isInstanceOf(JedisPooled.class); pooled = (JedisPooled) unified; redis = new Jedis(pooled.getPool().getResource()); + redis.flushDB(); } @After public void tearDown() { + redis.flushDB(); redis.close(); pooled.close(); } - // Function under test: RedisQueue - // Reason for testing: the queue can be constructed with a valid cluster instance and name - // Failure explanation: the queue is throwing an exception upon construction @Test - public void redisQueueConstructsWithoutError() throws Exception { - // ACT - new RedisQueue("test"); + public void decorateSucceeds() { + RedisQueue.decorate(redis, "test"); } - // Function under test: push - // Reason for testing: the queue can have a value pushed onto it - // Failure explanation: the queue is throwing an exception upon push @Test - public void pushPushWithoutError() throws Exception { - // ARRANGE - RedisQueue queue = new RedisQueue("test"); + public void offerShouldContain() { + RedisQueue queue = new RedisQueue(redis, "test"); - // ACT - queue.push(redis, "foo"); + queue.offer("foo"); + + assertThat(redis.lrange("test", 0, -1)).containsExactly("foo"); } - // Function under test: push - // Reason for testing: the queue can have the different values pushed onto it - // Failure explanation: the queue is throwing an exception upon pushing different values @Test - public void pushPushDifferentWithoutError() throws Exception { - // ARRANGE - RedisQueue queue = new RedisQueue("test"); + public void removeFromDequeueShouldExclude() { + RedisQueue queue = new RedisQueue(redis, "test"); + redis.lpush(queue.getDequeueName(), "foo", "bar", "foo"); + + queue.removeFromDequeue("foo"); - // ACT - queue.push(redis, "foo"); - queue.push(redis, "bar"); + assertThat(redis.lrange(queue.getDequeueName(), 0, -1)).containsExactly("foo", "bar").inOrder(); } - // Function under test: push - // Reason for testing: the queue can have the same values pushed onto it - // Failure explanation: the queue is throwing an exception upon pushing the same values @Test - public void pushPushSameWithoutError() throws Exception { - // ARRANGE - RedisQueue queue = new RedisQueue("test"); + public void removeAllShouldExclude() { + RedisQueue queue = new RedisQueue(redis, "test"); + redis.lpush("test", "foo", "bar", "foo"); - // ACT - queue.push(redis, "foo"); - queue.push(redis, "foo"); + queue.removeAll("foo"); + + assertThat(redis.lrange("test", 0, -1)).containsExactly("bar"); } - // Function under test: push - // Reason for testing: the queue can have many values pushed into it - // Failure explanation: the queue is throwing an exception upon pushing many values @Test - public void pushPushMany() throws Exception { - // ARRANGE - RedisQueue queue = new RedisQueue("test"); + public void takeShouldPrependToDequeue() { + RedisQueue queue = new RedisQueue(redis, "test"); + redis.lpush("test", "foo", "bar", "foo"); + redis.lpush(queue.getDequeueName(), "baz"); - // ACT - for (int i = 0; i < 1000; ++i) { - queue.push(redis, "foo" + i); - } + String value = queue.take(Duration.ofMillis(1)); + + assertThat(value).isEqualTo("foo"); + assertThat(redis.lrange("test", 0, -1)).containsExactly("foo", "bar").inOrder(); + assertThat(redis.lrange(queue.getDequeueName(), 0, -1)).containsExactly("foo", "baz").inOrder(); } - // Function under test: push - // Reason for testing: the queue size increases as elements are pushed - // Failure explanation: the queue size is not accurately reflecting the pushes @Test - public void pushPushIncreasesSize() throws Exception { - // ARRANGE - RedisQueue queue = new RedisQueue("test"); - - // ACT / ASSERT - assertThat(queue.size(redis)).isEqualTo(0); - queue.push(redis, "foo"); - assertThat(queue.size(redis)).isEqualTo(1); - queue.push(redis, "foo"); - assertThat(queue.size(redis)).isEqualTo(2); - queue.push(redis, "foo"); - assertThat(queue.size(redis)).isEqualTo(3); - queue.push(redis, "foo"); - assertThat(queue.size(redis)).isEqualTo(4); - queue.push(redis, "foo"); - assertThat(queue.size(redis)).isEqualTo(5); - queue.push(redis, "foo"); - assertThat(queue.size(redis)).isEqualTo(6); - queue.push(redis, "foo"); - assertThat(queue.size(redis)).isEqualTo(7); - queue.push(redis, "foo"); - assertThat(queue.size(redis)).isEqualTo(8); - queue.push(redis, "foo"); - assertThat(queue.size(redis)).isEqualTo(9); - queue.push(redis, "foo"); - assertThat(queue.size(redis)).isEqualTo(10); + public void takeEmptyShouldReturnNullAfterTimeoutAndIgnoreDequeue() { + RedisQueue queue = new RedisQueue(redis, "test"); + redis.lpush(queue.getDequeueName(), "foo"); + + String value = queue.take(Duration.ofMillis(1)); + + assertThat(value).isNull(); + assertThat(redis.lrange("test", 0, -1)).isEmpty(); + assertThat(redis.lrange(queue.getDequeueName(), 0, -1)).containsExactly("foo"); } - // Function under test: getName - // Reason for testing: the name can be received - // Failure explanation: name does not match what it should @Test - public void getNameNameIsStored() throws Exception { - // ARRANGE - RedisQueue queue = new RedisQueue("queue_name"); + public void pollShouldPrependToDequeue() { + RedisQueue queue = new RedisQueue(redis, "test"); + redis.lpush("test", "foo", "bar", "foo"); + redis.lpush(queue.getDequeueName(), "baz"); - // ACT - String name = queue.getName(); + String value = queue.poll(); - // ASSERT - assertThat(name).isEqualTo("queue_name"); + assertThat(value).isEqualTo("foo"); + assertThat(redis.lrange("test", 0, -1)).containsExactly("foo", "bar").inOrder(); + assertThat(redis.lrange(queue.getDequeueName(), 0, -1)).containsExactly("foo", "baz").inOrder(); } - // Function under test: getDequeueName - // Reason for testing: the name can be received - // Failure explanation: name does not match what it should @Test - public void getDequeueNameNameIsStored() throws Exception { - // ARRANGE - RedisQueue queue = new RedisQueue("queue_name"); + public void pollEmptyShouldReturnNullAndIgnoreDequeue() { + RedisQueue queue = new RedisQueue(redis, "test"); + redis.lpush(queue.getDequeueName(), "foo"); - // ACT - String name = queue.getDequeueName(); + String value = queue.poll(); - // ASSERT - assertThat(name).isEqualTo("queue_name_dequeue"); + assertThat(value).isNull(); + assertThat(redis.lrange("test", 0, -1)).isEmpty(); + assertThat(redis.lrange(queue.getDequeueName(), 0, -1)).containsExactly("foo"); } - // Function under test: size - // Reason for testing: size adjusts with push and dequeue - // Failure explanation: size is incorrectly reporting the expected queue size @Test - public void sizeAdjustPushDequeue() throws Exception { - // ARRANGE - RedisQueue queue = new RedisQueue("{hash}test"); - ExecutorService service = newSingleThreadExecutor(); - Duration timeout = Duration.ofSeconds(1); - - // ACT / ASSERT - assertThat(queue.size(redis)).isEqualTo(0); - queue.push(redis, "foo"); - assertThat(queue.size(redis)).isEqualTo(1); - queue.push(redis, "bar"); - assertThat(queue.size(redis)).isEqualTo(2); - queue.push(redis, "baz"); - assertThat(queue.size(redis)).isEqualTo(3); - queue.push(redis, "baz"); - assertThat(queue.size(redis)).isEqualTo(4); - queue.push(redis, "baz"); - assertThat(queue.size(redis)).isEqualTo(5); - queue.push(redis, "baz"); - assertThat(queue.size(redis)).isEqualTo(6); - queue.dequeue(redis, timeout, service); - assertThat(queue.size(redis)).isEqualTo(5); - queue.dequeue(redis, timeout, service); - assertThat(queue.size(redis)).isEqualTo(4); - queue.dequeue(redis, timeout, service); - assertThat(queue.size(redis)).isEqualTo(3); - queue.dequeue(redis, timeout, service); - assertThat(queue.size(redis)).isEqualTo(2); - queue.dequeue(redis, timeout, service); - assertThat(queue.size(redis)).isEqualTo(1); - queue.dequeue(redis, timeout, service); - assertThat(queue.size(redis)).isEqualTo(0); - service.shutdown(); - assertThat(service.awaitTermination(1, MILLISECONDS)).isTrue(); + public void sizeYieldsLengthAndIgnoresDequeue() { + RedisQueue queue = new RedisQueue(redis, "test"); + + redis.lpush(queue.getDequeueName(), "foo"); + assertThat(queue.size()).isEqualTo(0); + redis.lpush("test", "bar"); + assertThat(queue.size()).isEqualTo(1); + redis.lpush("test", "baz"); + assertThat(queue.size()).isEqualTo(2); } - // Function under test: visit - // Reason for testing: each element in the queue can be visited - // Failure explanation: we are unable to visit each element in the queue + private final Iterable VISIT_ENTRIES = ImmutableList.of("one", "two", "three", "four"); + @Test - public void visitCheckVisitOfEachElement() throws Exception { - // ARRANGE - RedisQueue queue = new RedisQueue("test"); - queue.push(redis, "element 1"); - queue.push(redis, "element 2"); - queue.push(redis, "element 3"); - queue.push(redis, "element 4"); - queue.push(redis, "element 5"); - queue.push(redis, "element 6"); - queue.push(redis, "element 7"); - queue.push(redis, "element 8"); - - // ACT - List visited = new ArrayList<>(); - StringVisitor visitor = - new StringVisitor() { - public void visit(String entry) { - visited.add(entry); - } - }; - queue.visit(redis, visitor); - - // ASSERT - assertThat(visited.size()).isEqualTo(8); - assertThat(visited.contains("element 1")).isTrue(); - assertThat(visited.contains("element 2")).isTrue(); - assertThat(visited.contains("element 3")).isTrue(); - assertThat(visited.contains("element 4")).isTrue(); - assertThat(visited.contains("element 5")).isTrue(); - assertThat(visited.contains("element 6")).isTrue(); - assertThat(visited.contains("element 7")).isTrue(); - assertThat(visited.contains("element 8")).isTrue(); + public void visitShouldEnumerateAndIgnoreDequeue() { + int listPageSize = 3; + RedisQueue queue = new RedisQueue(redis, "test", listPageSize); + redis.lpush(queue.getDequeueName(), "processing"); + for (String entry : VISIT_ENTRIES) { + redis.lpush("test", entry); + } + StringVisitor visitor = mock(StringVisitor.class); + + queue.visit(visitor); + + for (String entry : VISIT_ENTRIES) { + verify(visitor, times(1)).visit(entry); + } } - // Function under test: visit - // Reason for testing: add and visit many elements - // Failure explanation: we are unable to visit all the elements when there are many of them @Test - public void visitVisitManyOverPageSize() throws Exception { - // ARRANGE - RedisQueue queue = new RedisQueue("test"); - for (int i = 0; i < 2500; ++i) { - queue.push(redis, "foo" + i); + public void visitDequeueShouldEnumerateAndIgnoreQueue() { + int listPageSize = 3; + RedisQueue queue = new RedisQueue(redis, "test", listPageSize); + redis.lpush("test", "processing"); + for (String entry : VISIT_ENTRIES) { + redis.lpush(queue.getDequeueName(), entry); } + StringVisitor visitor = mock(StringVisitor.class); + + queue.visitDequeue(visitor); - // ACT - List visited = new ArrayList<>(); - StringVisitor visitor = - new StringVisitor() { - public void visit(String entry) { - visited.add(entry); - } - }; - queue.visit(redis, visitor); - - // ASSERT - assertThat(visited.size()).isEqualTo(2500); - for (int i = 0; i < 2500; ++i) { - assertThat(visited.contains("foo" + i)).isTrue(); + for (String entry : VISIT_ENTRIES) { + verify(visitor, times(1)).visit(entry); } } } From 89a97d13f8d1df4bbbaa5b17af7c89840c062b2a Mon Sep 17 00:00:00 2001 From: George Gensure Date: Wed, 3 Apr 2024 02:09:42 -0400 Subject: [PATCH 256/311] Support for BLAKE3 digest function (#1697) Incorporate support for BLAKE3 digest exclusively on a server instance Compressor + Digest + DigestFunction.Value coupling should mean that BlobInformation could cut down on params. Still much to do to support the new DigestFunction.Value fields in many messages, and no migration support for this (or any other) function. First foray into JniLoader native behavior, adapted from bazel implementation of blake3 support. --- MODULE.bazel | 1 + deps.bzl | 8 +- src/main/java/build/buildfarm/common/BUILD | 1 + .../build/buildfarm/common/DigestUtil.java | 12 +- .../java/build/buildfarm/common/blake3/BUILD | 23 +++ .../common/blake3/Blake3HashFunction.java | 87 +++++++++++ .../buildfarm/common/blake3/Blake3Hasher.java | 145 ++++++++++++++++++ .../common/blake3/Blake3MessageDigest.java | 113 ++++++++++++++ .../buildfarm/common/blake3/JniLoader.java | 139 +++++++++++++++++ .../common/resources/ResourceParser.java | 56 +++++-- .../buildfarm/common/resources/resource.proto | 2 + .../common/services/ByteStreamService.java | 22 +-- .../common/services/WriteStreamObserver.java | 11 +- .../build/buildfarm/instance/Instance.java | 7 +- .../java/build/buildfarm/instance/Utils.java | 8 +- .../instance/server/NodeInstance.java | 16 +- .../instance/shard/ServerInstance.java | 19 ++- .../buildfarm/instance/shard/Writes.java | 11 +- .../buildfarm/instance/stub/StubInstance.java | 15 +- .../buildfarm/worker/shard/CasWriter.java | 7 +- .../worker/shard/LocalCasWriter.java | 8 +- .../worker/shard/RemoteCasWriter.java | 29 ++-- .../worker/shard/ShardWorkerContext.java | 20 +-- src/main/native/BUILD | 65 ++++++++ src/main/native/blake3_jni.cc | 73 +++++++++ .../buildfarm/common/DigestUtilTest.java | 1 - .../common/config/BackplaneTest.java | 1 - .../services/ByteStreamServiceTest.java | 13 +- .../services/WriteStreamObserverTest.java | 5 + .../instance/server/NodeInstanceTest.java | 2 +- .../instance/shard/ServerInstanceTest.java | 3 + third_party/remote-apis/BUILD | 0 third_party/remote-apis/remote-apis.patch | 22 --- 33 files changed, 847 insertions(+), 98 deletions(-) create mode 100644 src/main/java/build/buildfarm/common/blake3/BUILD create mode 100644 src/main/java/build/buildfarm/common/blake3/Blake3HashFunction.java create mode 100644 src/main/java/build/buildfarm/common/blake3/Blake3Hasher.java create mode 100644 src/main/java/build/buildfarm/common/blake3/Blake3MessageDigest.java create mode 100644 src/main/java/build/buildfarm/common/blake3/JniLoader.java create mode 100644 src/main/native/BUILD create mode 100644 src/main/native/blake3_jni.cc delete mode 100644 third_party/remote-apis/BUILD delete mode 100644 third_party/remote-apis/remote-apis.patch diff --git a/MODULE.bazel b/MODULE.bazel index 5f7f6ac1ae..bd656d1c49 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -5,6 +5,7 @@ module( repo_name = "build_buildfarm", ) +bazel_dep(name = "blake3", version = "1.3.3.bcr.1") bazel_dep(name = "gazelle", version = "0.35.0", repo_name = "bazel_gazelle") bazel_dep(name = "platforms", version = "0.0.8") bazel_dep(name = "protobuf", version = "23.1", repo_name = "com_google_protobuf") diff --git a/deps.bzl b/deps.bzl index 6607f5a2c1..8cff71c2a2 100644 --- a/deps.bzl +++ b/deps.bzl @@ -28,11 +28,9 @@ def archive_dependencies(third_party): { "name": "remote_apis", "build_file": "%s:BUILD.remote_apis" % third_party, - "patch_args": ["-p1"], - "patches": ["%s/remote-apis:remote-apis.patch" % third_party], - "sha256": "743d2d5b5504029f3f825beb869ce0ec2330b647b3ee465a4f39ca82df83f8bf", - "strip_prefix": "remote-apis-636121a32fa7b9114311374e4786597d8e7a69f3", - "url": "https://github.com/bazelbuild/remote-apis/archive/636121a32fa7b9114311374e4786597d8e7a69f3.zip", + "sha256": "e9a69cf51df14e20b7d3623ac9580bc8fb9275dda46305788e88eb768926b9c3", + "strip_prefix": "remote-apis-8f539af4b407a4f649707f9632fc2b715c9aa065", + "url": "https://github.com/bazelbuild/remote-apis/archive/8f539af4b407a4f649707f9632fc2b715c9aa065.zip", }, # Used to format proto files diff --git a/src/main/java/build/buildfarm/common/BUILD b/src/main/java/build/buildfarm/common/BUILD index 1b0b73f372..a4af6fcb4c 100644 --- a/src/main/java/build/buildfarm/common/BUILD +++ b/src/main/java/build/buildfarm/common/BUILD @@ -12,6 +12,7 @@ java_library( plugins = [":lombok"], visibility = ["//visibility:public"], deps = [ + "//src/main/java/build/buildfarm/common/blake3", "//src/main/java/build/buildfarm/common/resources", "//src/main/java/build/buildfarm/common/resources:resource_java_proto", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", diff --git a/src/main/java/build/buildfarm/common/DigestUtil.java b/src/main/java/build/buildfarm/common/DigestUtil.java index ae804d5653..4d68c9b290 100644 --- a/src/main/java/build/buildfarm/common/DigestUtil.java +++ b/src/main/java/build/buildfarm/common/DigestUtil.java @@ -17,6 +17,7 @@ import build.bazel.remote.execution.v2.Action; import build.bazel.remote.execution.v2.Digest; import build.bazel.remote.execution.v2.DigestFunction; +import build.buildfarm.common.blake3.Blake3HashFunction; import com.google.common.hash.Funnels; import com.google.common.hash.HashCode; import com.google.common.hash.Hasher; @@ -42,7 +43,8 @@ public enum HashFunction { MD5(Hashing.md5()), @SuppressWarnings("deprecation") SHA1(Hashing.sha1()), - SHA256(Hashing.sha256()); + SHA256(Hashing.sha256()), + BLAKE3(new Blake3HashFunction()); private final com.google.common.hash.HashFunction hash; final HashCode empty; @@ -53,6 +55,9 @@ public enum HashFunction { } public DigestFunction.Value getDigestFunction() { + if (this == BLAKE3) { + return DigestFunction.Value.BLAKE3; + } if (this == SHA256) { return DigestFunction.Value.SHA256; } @@ -69,6 +74,9 @@ public static HashFunction forHash(String hexDigest) { if (SHA256.isValidHexDigest(hexDigest)) { return SHA256; } + if (BLAKE3.isValidHexDigest(hexDigest)) { + return BLAKE3; + } if (SHA1.isValidHexDigest(hexDigest)) { return SHA1; } @@ -84,6 +92,8 @@ public static HashFunction get(DigestFunction.Value digestFunction) { case UNRECOGNIZED: case UNKNOWN: throw new IllegalArgumentException(digestFunction.toString()); + case BLAKE3: + return BLAKE3; case SHA256: return SHA256; case SHA1: diff --git a/src/main/java/build/buildfarm/common/blake3/BUILD b/src/main/java/build/buildfarm/common/blake3/BUILD new file mode 100644 index 0000000000..b0056a4de6 --- /dev/null +++ b/src/main/java/build/buildfarm/common/blake3/BUILD @@ -0,0 +1,23 @@ +java_library( + name = "blake3", + srcs = glob(["*.java"]), + plugins = ["//src/main/java/build/buildfarm/common:lombok"], + resources = select({ + "@bazel//src/conditions:darwin": [ + "//src/main/native:libblake3_jni.dylib", + ], + "@bazel//src/conditions:windows": [ + "//src/main/native:blake3_jni.dll", + ], + "//conditions:default": [ + "//src/main/native:libblake3_jni.so", + ], + }), + visibility = ["//src/main/java/build/buildfarm/common:__pkg__"], + deps = [ + "@maven//:com_google_code_findbugs_jsr305", + "@maven//:com_google_errorprone_error_prone_annotations", + "@maven//:com_google_guava_guava", + "@maven//:org_projectlombok_lombok", + ], +) diff --git a/src/main/java/build/buildfarm/common/blake3/Blake3HashFunction.java b/src/main/java/build/buildfarm/common/blake3/Blake3HashFunction.java new file mode 100644 index 0000000000..b311a6fee1 --- /dev/null +++ b/src/main/java/build/buildfarm/common/blake3/Blake3HashFunction.java @@ -0,0 +1,87 @@ +// Copyright 2023 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package build.buildfarm.common.blake3; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkPositionIndexes; + +import com.google.common.hash.Funnel; +import com.google.common.hash.HashCode; +import com.google.common.hash.HashFunction; +import com.google.common.hash.Hasher; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; + +/** A {@link HashFunction} for BLAKE3. */ +public final class Blake3HashFunction implements HashFunction { + @Override + public int bits() { + return 256; + } + + @Override + public Hasher newHasher() { + return new Blake3Hasher(new Blake3MessageDigest()); + } + + @Override + public Hasher newHasher(int expectedInputSize) { + checkArgument( + expectedInputSize >= 0, "expectedInputSize must be >= 0 but was %s", expectedInputSize); + return newHasher(); + } + + /* The following methods implement the {HashFunction} interface. */ + @Override + public HashCode hashObject(T instance, Funnel funnel) { + return newHasher().putObject(instance, funnel).hash(); + } + + @Override + public HashCode hashUnencodedChars(CharSequence input) { + int len = input.length(); + return newHasher(len * 2).putUnencodedChars(input).hash(); + } + + @Override + public HashCode hashString(CharSequence input, Charset charset) { + return newHasher().putString(input, charset).hash(); + } + + @Override + public HashCode hashInt(int input) { + return newHasher(4).putInt(input).hash(); + } + + @Override + public HashCode hashLong(long input) { + return newHasher(8).putLong(input).hash(); + } + + @Override + public HashCode hashBytes(byte[] input) { + return hashBytes(input, 0, input.length); + } + + @Override + public HashCode hashBytes(byte[] input, int off, int len) { + checkPositionIndexes(off, off + len, input.length); + return newHasher(len).putBytes(input, off, len).hash(); + } + + @Override + public HashCode hashBytes(ByteBuffer input) { + return newHasher(input.remaining()).putBytes(input).hash(); + } +} diff --git a/src/main/java/build/buildfarm/common/blake3/Blake3Hasher.java b/src/main/java/build/buildfarm/common/blake3/Blake3Hasher.java new file mode 100644 index 0000000000..311e25fb54 --- /dev/null +++ b/src/main/java/build/buildfarm/common/blake3/Blake3Hasher.java @@ -0,0 +1,145 @@ +// Copyright 2023 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package build.buildfarm.common.blake3; + +import static com.google.common.base.Preconditions.checkState; + +import com.google.common.hash.Funnel; +import com.google.common.hash.HashCode; +import com.google.common.hash.Hasher; +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; + +/** A {@link Hasher} for BLAKE3. */ +public final class Blake3Hasher implements Hasher { + private final Blake3MessageDigest messageDigest; + private boolean isDone = false; + + public Blake3Hasher(Blake3MessageDigest blake3MessageDigest) { + messageDigest = blake3MessageDigest; + } + + /* The following methods implement the {Hasher} interface. */ + @Override + @CanIgnoreReturnValue + public Hasher putBytes(ByteBuffer b) { + messageDigest.engineUpdate(b); + return this; + } + + @Override + @CanIgnoreReturnValue + public Hasher putBytes(byte[] bytes, int off, int len) { + messageDigest.engineUpdate(bytes, off, len); + return this; + } + + @Override + @CanIgnoreReturnValue + public Hasher putBytes(byte[] bytes) { + messageDigest.engineUpdate(bytes, 0, bytes.length); + return this; + } + + @Override + @CanIgnoreReturnValue + public Hasher putByte(byte b) { + messageDigest.engineUpdate(b); + return this; + } + + @Override + public HashCode hash() { + checkState(!isDone); + isDone = true; + + return HashCode.fromBytes(messageDigest.engineDigest()); + } + + @Override + @CanIgnoreReturnValue + public Hasher putBoolean(boolean b) { + return putByte(b ? (byte) 1 : (byte) 0); + } + + @Override + @CanIgnoreReturnValue + public Hasher putDouble(double d) { + return putLong(Double.doubleToRawLongBits(d)); + } + + @Override + @CanIgnoreReturnValue + public Hasher putFloat(float f) { + return putInt(Float.floatToRawIntBits(f)); + } + + @Override + @CanIgnoreReturnValue + public Hasher putUnencodedChars(CharSequence charSequence) { + for (int i = 0, len = charSequence.length(); i < len; i++) { + putChar(charSequence.charAt(i)); + } + return this; + } + + @Override + @CanIgnoreReturnValue + public Hasher putString(CharSequence charSequence, Charset charset) { + return putBytes(charSequence.toString().getBytes(charset)); + } + + @Override + @CanIgnoreReturnValue + public Hasher putShort(short s) { + putByte((byte) s); + putByte((byte) (s >>> 8)); + return this; + } + + @Override + @CanIgnoreReturnValue + public Hasher putInt(int i) { + putByte((byte) i); + putByte((byte) (i >>> 8)); + putByte((byte) (i >>> 16)); + putByte((byte) (i >>> 24)); + return this; + } + + @Override + @CanIgnoreReturnValue + public Hasher putLong(long l) { + for (int i = 0; i < 64; i += 8) { + putByte((byte) (l >>> i)); + } + return this; + } + + @Override + @CanIgnoreReturnValue + public Hasher putChar(char c) { + putByte((byte) c); + putByte((byte) (c >>> 8)); + return this; + } + + @Override + @CanIgnoreReturnValue + public Hasher putObject(T instance, Funnel funnel) { + funnel.funnel(instance, this); + return this; + } +} diff --git a/src/main/java/build/buildfarm/common/blake3/Blake3MessageDigest.java b/src/main/java/build/buildfarm/common/blake3/Blake3MessageDigest.java new file mode 100644 index 0000000000..fbec3019a0 --- /dev/null +++ b/src/main/java/build/buildfarm/common/blake3/Blake3MessageDigest.java @@ -0,0 +1,113 @@ +// Copyright 2023 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package build.buildfarm.common.blake3; + +import java.nio.ByteBuffer; +import java.security.DigestException; +import java.security.MessageDigest; + +/** A {@link MessageDigest} for BLAKE3. */ +public final class Blake3MessageDigest extends MessageDigest { + // These constants match the native definitions in: + // https://github.com/BLAKE3-team/BLAKE3/blob/master/c/blake3.h + public static final int KEY_LEN = 32; + public static final int OUT_LEN = 32; + + static { + JniLoader.loadJni(); + } + + private static final int STATE_SIZE = hasher_size(); + private static final byte[] INITIAL_STATE = new byte[STATE_SIZE]; + + static { + initialize_hasher(INITIAL_STATE); + } + + private final byte[] hasher = new byte[STATE_SIZE]; + private final byte[] oneByteArray = new byte[1]; + + public Blake3MessageDigest() { + super("BLAKE3"); + System.arraycopy(INITIAL_STATE, 0, hasher, 0, STATE_SIZE); + } + + @Override + public void engineUpdate(byte[] data, int offset, int length) { + blake3_hasher_update(hasher, data, offset, length); + } + + @Override + public void engineUpdate(byte b) { + oneByteArray[0] = b; + engineUpdate(oneByteArray, 0, 1); + } + + @SuppressWarnings("UselessOverridingMethod") + @Override + public void engineUpdate(ByteBuffer input) { + super.engineUpdate(input); + } + + private byte[] getOutput(int outputLength) { + byte[] retByteArray = new byte[outputLength]; + blake3_hasher_finalize(hasher, retByteArray, outputLength); + + engineReset(); + return retByteArray; + } + + @Override + public Object clone() throws CloneNotSupportedException { + throw new CloneNotSupportedException(); + } + + @Override + public void engineReset() { + System.arraycopy(INITIAL_STATE, 0, hasher, 0, STATE_SIZE); + } + + @Override + public int engineGetDigestLength() { + return OUT_LEN; + } + + @Override + public byte[] engineDigest() { + return getOutput(OUT_LEN); + } + + @Override + public int engineDigest(byte[] buf, int off, int len) throws DigestException { + if (len < OUT_LEN) { + throw new DigestException("partial digests not returned"); + } + if (buf.length - off < OUT_LEN) { + throw new DigestException("insufficient space in the output buffer to store the digest"); + } + + byte[] digestBytes = getOutput(OUT_LEN); + System.arraycopy(digestBytes, 0, buf, off, digestBytes.length); + return digestBytes.length; + } + + public static native int hasher_size(); + + public static native void initialize_hasher(byte[] hasher); + + public static native void blake3_hasher_update( + byte[] hasher, byte[] input, int offset, int inputLen); + + public static native void blake3_hasher_finalize(byte[] hasher, byte[] out, int outLen); +} diff --git a/src/main/java/build/buildfarm/common/blake3/JniLoader.java b/src/main/java/build/buildfarm/common/blake3/JniLoader.java new file mode 100644 index 0000000000..ca92224da3 --- /dev/null +++ b/src/main/java/build/buildfarm/common/blake3/JniLoader.java @@ -0,0 +1,139 @@ +// Copyright 2019 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package build.buildfarm.common.blake3; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.io.ByteStreams; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.logging.Level; +import javax.annotation.Nullable; +import lombok.extern.java.Log; + +/** Generic code to interact with the platform-specific JNI code bundle. */ +@Log +public final class JniLoader { + @Nullable private static final Throwable JNI_LOAD_ERROR; + + private static boolean isDarwin() { + return System.getProperty("os.name").equals("Mac OS X"); + } + + private static boolean isWindows() { + return System.getProperty("os.name").startsWith("Windows"); + } + + static { + Throwable jniLoadError; + try { + if (isDarwin()) { + loadLibrary("main/native/libblake3_jni.dylib"); + } else if (isWindows()) { + loadLibrary("main/native/blake3_jni.dll"); + } else { // presumed soloader capable + loadLibrary("main/native/libblake3_jni.so"); + } + jniLoadError = null; + } catch (IOException | UnsatisfiedLinkError e) { + log.log(Level.WARNING, "Failed to load JNI library", e); + jniLoadError = e; + } + JNI_LOAD_ERROR = jniLoadError; + } + + /** + * Loads a resource as a shared library. + * + * @param resourceName the name of the shared library to load, specified as a slash-separated + * relative path within the JAR with at least two components + * @throws IOException if the resource cannot be extracted or loading the library fails for any + * other reason + */ + private static void loadLibrary(String resourceName) throws IOException { + Path dir = null; + Path tempFile = null; + try { + dir = Files.createTempDirectory("buildfarm-jni."); + int slash = resourceName.lastIndexOf('/'); + checkArgument(slash != -1, "resourceName must contain two path components"); + tempFile = dir.resolve(resourceName.substring(slash + 1)); + + ClassLoader loader = JniLoader.class.getClassLoader(); + try (InputStream resource = loader.getResourceAsStream(resourceName)) { + if (resource == null) { + throw new UnsatisfiedLinkError("Resource " + resourceName + " not in JAR"); + } + try (OutputStream diskFile = new FileOutputStream(tempFile.toString())) { + ByteStreams.copy(resource, diskFile); + } + } + + System.load(tempFile.toString()); + + // Remove the temporary file now that we have loaded it. If we keep it short-lived, we can + // avoid the file system from persisting it to disk, avoiding an unnecessary cost. + // + // Unfortunately, we cannot do this on Windows because the DLL remains open and we don't have + // a way to specify FILE_SHARE_DELETE in the System.load() call. + if (!isWindows()) { + Files.delete(tempFile); + tempFile = null; + Files.delete(dir); + } + } catch (IOException e) { + try { + if (tempFile != null) { + Files.deleteIfExists(tempFile); + } + if (dir != null) { + Files.delete(dir); + } + } catch (IOException e2) { + // Nothing else we can do. Rely on "delete on exit" to try clean things up later on. + } + throw e; + } + } + + private JniLoader() {} + + /** + * Triggers the load of the JNI bundle in a platform-independent basis. + * + *

This does not fail if the JNI bundle cannot be loaded because there are scenarios in + * which we want to run Bazel without JNI (e.g. during bootstrapping) or are able to fall back to + * an alternative implementation (e.g. in some filesystem implementations). + * + *

Callers can check if the JNI bundle was successfully loaded via {@link #isJniAvailable()} + * and obtain the load error via {@link #getJniLoadError()}. + */ + public static void loadJni() {} + + /** Returns whether the JNI bundle was successfully loaded. */ + public static boolean isJniAvailable() { + return JNI_LOAD_ERROR == null; + } + + /** Returns the exception thrown while loading the JNI bundle, if it failed. */ + @Nullable + public static Throwable getJniLoadError() { + return JNI_LOAD_ERROR; + } +} diff --git a/src/main/java/build/buildfarm/common/resources/ResourceParser.java b/src/main/java/build/buildfarm/common/resources/ResourceParser.java index 6e581cdb97..339dbd1724 100644 --- a/src/main/java/build/buildfarm/common/resources/ResourceParser.java +++ b/src/main/java/build/buildfarm/common/resources/ResourceParser.java @@ -16,10 +16,12 @@ import build.bazel.remote.execution.v2.Compressor; import build.bazel.remote.execution.v2.Digest; +import build.bazel.remote.execution.v2.DigestFunction; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import java.util.Arrays; -import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.stream.IntStream; import java.util.stream.Stream; import org.apache.commons.lang3.mutable.MutableInt; @@ -58,7 +60,14 @@ public class ResourceParser { * @brief A list of keywords to their corresponding types. * @details This lookup table is used for parsing resource_names. */ - private static final HashMap KEYWORDS = keywordResourceMap(); + private static final Map KEYWORDS = keywordResourceMap(); + + /** + * @field DIGEST_FUNCTIONS + * @brief A map of uppercase digest function names to DigestFunction.Value. + * @details This lookup table is used to parse digest_function in resource_names. + */ + private static final Map DIGEST_FUNCTIONS = digestFunctionMap(); /** * @brief Categorize the resource type by analyzing a resource name URI. @@ -103,7 +112,7 @@ public static UploadBlobRequest parseUploadBlobRequest(String resourceName) { MutableInt index = startIndex(segments, Resource.TypeCase.UPLOAD_BLOB_REQUEST); // Extract each of the following segments: - // `{instance_name}/uploads/{uuid}/blobs/{hash}/{size}{/optional_metadata}` or + // `{instance_name}/uploads/{uuid}/blobs/{digest_function/}{hash}/{size}{/optional_metadata}` or // `{instance_name}/uploads/{uuid}/compressed-blobs/{compressor}/{uncompressed_hash}/{uncompressed_size}{/optional_metadata}` UploadBlobRequest.Builder builder = UploadBlobRequest.newBuilder(); builder.setInstanceName(asResourcePath(previousSegments(segments, index))); @@ -145,6 +154,9 @@ private static void addDigestResource(ImmutableList.Builder resource, Di private static void addBlobResource( ImmutableList.Builder resource, BlobInformation blob) { addCompressorName(resource, blob.getCompressor()); + if (blob.getDigestFunction() != DigestFunction.Value.UNKNOWN) { + resource.add(blob.getDigestFunction().toString().toLowerCase()); + } addDigestResource(resource, blob.getDigest()); } @@ -210,13 +222,30 @@ public static DownloadBlobRequest parseDownloadBlobRequest(String resourceName) * @return A lookup table for keyword to resource type. * @note Suggested return identifier: keywordMap. */ - private static HashMap keywordResourceMap() { - HashMap keywords = new HashMap<>(); - keywords.put("blobs", Resource.TypeCase.DOWNLOAD_BLOB_REQUEST); - keywords.put(COMPRESSED_BLOBS_KEYWORD, Resource.TypeCase.DOWNLOAD_BLOB_REQUEST); - keywords.put("uploads", Resource.TypeCase.UPLOAD_BLOB_REQUEST); - keywords.put("operations", Resource.TypeCase.STREAM_OPERATION_REQUEST); - return keywords; + private static Map keywordResourceMap() { + return ImmutableMap.of( + "blobs", + Resource.TypeCase.DOWNLOAD_BLOB_REQUEST, + COMPRESSED_BLOBS_KEYWORD, + Resource.TypeCase.DOWNLOAD_BLOB_REQUEST, + "uploads", + Resource.TypeCase.UPLOAD_BLOB_REQUEST, + "operations", + Resource.TypeCase.STREAM_OPERATION_REQUEST); + } + + /** + * @brief A mapping of DigestFunction.Value values to their respective enum types. + * @details This lookup table can be used for parsing. + * @return A lookup table for digest_function to DigestFunction.Value. + * @note Suggested return identifier: digestFunctionMap. + */ + private static Map digestFunctionMap() { + ImmutableMap.Builder builder = ImmutableMap.builder(); + for (DigestFunction.Value digestFunction : DigestFunction.Value.values()) { + builder.put(digestFunction.toString().toUpperCase(), digestFunction); + } + return builder.build(); } /** @@ -254,7 +283,7 @@ private static MutableInt startIndex(String[] segments, Resource.TypeCase type) * @note Suggested return identifier: keywordIndex. */ private static int findKeywordIndex( - String[] segments, HashMap keywords, Resource.TypeCase type) { + String[] segments, Map keywords, Resource.TypeCase type) { return IntStream.range(0, segments.length) .filter(i -> keywords.get(segments[i]) == type) .findFirst() @@ -278,6 +307,11 @@ private static BlobInformation parseBlobInformation(String[] segments, MutableIn } else { builder.setCompressor(Compressor.Value.IDENTITY); } + String maybeDigestFunction = segments[index.getValue()].toUpperCase(); + if (DIGEST_FUNCTIONS.containsKey(maybeDigestFunction)) { + builder.setDigestFunction(DIGEST_FUNCTIONS.get(maybeDigestFunction)); + index.getAndIncrement(); + } String hash = segments[index.getAndIncrement()]; String size = segments[index.getAndIncrement()]; builder.setDigest(parseDigest(hash, size)); diff --git a/src/main/java/build/buildfarm/common/resources/resource.proto b/src/main/java/build/buildfarm/common/resources/resource.proto index f629366f73..83368d775b 100644 --- a/src/main/java/build/buildfarm/common/resources/resource.proto +++ b/src/main/java/build/buildfarm/common/resources/resource.proto @@ -52,6 +52,8 @@ message BlobInformation { build.bazel.remote.execution.v2.Compressor.Value compressor = 1; build.bazel.remote.execution.v2.Digest digest = 2; + + build.bazel.remote.execution.v2.DigestFunction.Value digest_function = 3; } message Resource { diff --git a/src/main/java/build/buildfarm/common/services/ByteStreamService.java b/src/main/java/build/buildfarm/common/services/ByteStreamService.java index 4bb944abff..d2003c32e3 100644 --- a/src/main/java/build/buildfarm/common/services/ByteStreamService.java +++ b/src/main/java/build/buildfarm/common/services/ByteStreamService.java @@ -16,9 +16,7 @@ import static build.buildfarm.common.UrlPath.detectResourceOperation; import static build.buildfarm.common.UrlPath.parseBlobDigest; -import static build.buildfarm.common.UrlPath.parseUploadBlobCompressor; -import static build.buildfarm.common.UrlPath.parseUploadBlobDigest; -import static build.buildfarm.common.UrlPath.parseUploadBlobUUID; +import static build.buildfarm.common.resources.ResourceParser.parseUploadBlobRequest; import static com.google.common.util.concurrent.Futures.immediateFailedFuture; import static io.grpc.Status.INVALID_ARGUMENT; import static io.grpc.Status.NOT_FOUND; @@ -39,6 +37,7 @@ import build.buildfarm.common.io.FeedbackOutputStream; import build.buildfarm.common.resources.DownloadBlobRequest; import build.buildfarm.common.resources.ResourceParser; +import build.buildfarm.common.resources.UploadBlobRequest; import build.buildfarm.instance.Instance; import com.google.bytestream.ByteStreamGrpc.ByteStreamImplBase; import com.google.bytestream.ByteStreamProto.QueryWriteStatusRequest; @@ -425,14 +424,19 @@ public ListenableFuture getFuture() { }; } - static Write getUploadBlobWrite( - Instance instance, Compressor.Value compressor, Digest digest, UUID uuid) + static Write getUploadBlobWrite(Instance instance, String resourceName) throws EntryLimitException { + UploadBlobRequest request = parseUploadBlobRequest(resourceName); + Digest digest = request.getBlob().getDigest(); if (digest.getSizeBytes() == 0) { return new CompleteWrite(0); } return instance.getBlobWrite( - compressor, digest, uuid, TracingMetadataUtils.fromCurrentContext()); + request.getBlob().getCompressor(), + digest, + request.getBlob().getDigestFunction(), + UUID.fromString(request.getUuid()), + TracingMetadataUtils.fromCurrentContext()); } static Write getOperationStreamWrite(Instance instance, String resourceName) { @@ -444,11 +448,7 @@ Write getWrite(String resourceName) throws EntryLimitException, InvalidResourceN case DOWNLOAD_BLOB_REQUEST: return getBlobWrite(instance, parseBlobDigest(resourceName)); case UPLOAD_BLOB_REQUEST: - return getUploadBlobWrite( - instance, - parseUploadBlobCompressor(resourceName), - parseUploadBlobDigest(resourceName), - parseUploadBlobUUID(resourceName)); + return getUploadBlobWrite(instance, resourceName); case STREAM_OPERATION_REQUEST: return getOperationStreamWrite(instance, resourceName); default: diff --git a/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java b/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java index 2eba90eba5..7ee68dcce9 100644 --- a/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java +++ b/src/main/java/build/buildfarm/common/services/WriteStreamObserver.java @@ -17,7 +17,6 @@ import static build.buildfarm.common.UrlPath.detectResourceOperation; import static build.buildfarm.common.UrlPath.parseUploadBlobCompressor; import static build.buildfarm.common.UrlPath.parseUploadBlobDigest; -import static build.buildfarm.common.UrlPath.parseUploadBlobUUID; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static io.grpc.Status.ABORTED; @@ -26,7 +25,6 @@ import static java.lang.String.format; import build.bazel.remote.execution.v2.Compressor; -import build.bazel.remote.execution.v2.Digest; import build.bazel.remote.execution.v2.RequestMetadata; import build.buildfarm.cas.DigestMismatchException; import build.buildfarm.common.EntryLimitException; @@ -134,13 +132,8 @@ private Write getWrite(String resourceName) throws EntryLimitException, InvalidResourceNameException { switch (detectResourceOperation(resourceName)) { case UPLOAD_BLOB_REQUEST: - Digest uploadBlobDigest = parseUploadBlobDigest(resourceName); - expectedCommittedSize = uploadBlobDigest.getSizeBytes(); - return ByteStreamService.getUploadBlobWrite( - instance, - parseUploadBlobCompressor(resourceName), - uploadBlobDigest, - parseUploadBlobUUID(resourceName)); + expectedCommittedSize = parseUploadBlobDigest(resourceName).getSizeBytes(); + return ByteStreamService.getUploadBlobWrite(instance, resourceName); case STREAM_OPERATION_REQUEST: return ByteStreamService.getOperationStreamWrite(instance, resourceName); case DOWNLOAD_BLOB_REQUEST: diff --git a/src/main/java/build/buildfarm/instance/Instance.java b/src/main/java/build/buildfarm/instance/Instance.java index 5ae73f24ce..7844575801 100644 --- a/src/main/java/build/buildfarm/instance/Instance.java +++ b/src/main/java/build/buildfarm/instance/Instance.java @@ -19,6 +19,7 @@ import build.bazel.remote.execution.v2.BatchUpdateBlobsResponse; import build.bazel.remote.execution.v2.Compressor; import build.bazel.remote.execution.v2.Digest; +import build.bazel.remote.execution.v2.DigestFunction; import build.bazel.remote.execution.v2.ExecutionPolicy; import build.bazel.remote.execution.v2.ExecutionStage; import build.bazel.remote.execution.v2.Platform; @@ -95,7 +96,11 @@ InputStream newBlobInput( String getTree(Digest rootDigest, int pageSize, String pageToken, Tree.Builder tree); Write getBlobWrite( - Compressor.Value compressor, Digest digest, UUID uuid, RequestMetadata requestMetadata) + Compressor.Value compressor, + Digest digest, + DigestFunction.Value digestFunction, + UUID uuid, + RequestMetadata requestMetadata) throws EntryLimitException; Iterable putAllBlobs(Iterable blobs, RequestMetadata requestMetadata) diff --git a/src/main/java/build/buildfarm/instance/Utils.java b/src/main/java/build/buildfarm/instance/Utils.java index 0efc86b855..c25e07368c 100644 --- a/src/main/java/build/buildfarm/instance/Utils.java +++ b/src/main/java/build/buildfarm/instance/Utils.java @@ -91,7 +91,13 @@ public static ListenableFuture putBlobFuture( } SettableFuture future = SettableFuture.create(); try { - Write write = instance.getBlobWrite(compressor, digest, UUID.randomUUID(), requestMetadata); + Write write = + instance.getBlobWrite( + compressor, + digest, + instance.getDigestUtil().getDigestFunction(), + UUID.randomUUID(), + requestMetadata); // indicate that we know this write is novel write.reset(); Futures.addCallback( diff --git a/src/main/java/build/buildfarm/instance/server/NodeInstance.java b/src/main/java/build/buildfarm/instance/server/NodeInstance.java index 37741aa1b1..6863598c99 100644 --- a/src/main/java/build/buildfarm/instance/server/NodeInstance.java +++ b/src/main/java/build/buildfarm/instance/server/NodeInstance.java @@ -43,6 +43,7 @@ import build.bazel.remote.execution.v2.Command; import build.bazel.remote.execution.v2.Compressor; import build.bazel.remote.execution.v2.Digest; +import build.bazel.remote.execution.v2.DigestFunction; import build.bazel.remote.execution.v2.Directory; import build.bazel.remote.execution.v2.DirectoryNode; import build.bazel.remote.execution.v2.ExecuteOperationMetadata; @@ -406,8 +407,15 @@ public InputStream newBlobInput( @Override public Write getBlobWrite( - Compressor.Value compressor, Digest digest, UUID uuid, RequestMetadata requestMetadata) + Compressor.Value compressor, + Digest digest, + DigestFunction.Value digestFunction, + UUID uuid, + RequestMetadata requestMetadata) throws EntryLimitException { + Preconditions.checkState( + digestFunction == DigestFunction.Value.UNKNOWN + || digestFunction == digestUtil.getDigestFunction()); return contentAddressableStorage.getWrite(compressor, digest, uuid, requestMetadata); } @@ -673,7 +681,11 @@ ListenableFuture fetchBlobUrls( throw new DigestMismatchException(actualDigest, expectedDigest); } return getBlobWrite( - Compressor.Value.IDENTITY, actualDigest, UUID.randomUUID(), requestMetadata) + Compressor.Value.IDENTITY, + actualDigest, + digestUtil.getDigestFunction(), + UUID.randomUUID(), + requestMetadata) .getOutput(1, DAYS, () -> {}); }); return immediateFuture(actualDigestBuilder.build()); diff --git a/src/main/java/build/buildfarm/instance/shard/ServerInstance.java b/src/main/java/build/buildfarm/instance/shard/ServerInstance.java index 1d526f5ab8..5b473165c2 100644 --- a/src/main/java/build/buildfarm/instance/shard/ServerInstance.java +++ b/src/main/java/build/buildfarm/instance/shard/ServerInstance.java @@ -51,6 +51,7 @@ import build.bazel.remote.execution.v2.Command; import build.bazel.remote.execution.v2.Compressor; import build.bazel.remote.execution.v2.Digest; +import build.bazel.remote.execution.v2.DigestFunction; import build.bazel.remote.execution.v2.Directory; import build.bazel.remote.execution.v2.DirectoryNode; import build.bazel.remote.execution.v2.ExecuteOperationMetadata; @@ -1295,8 +1296,15 @@ public InputStream newBlobInput( @Override public Write getBlobWrite( - Compressor.Value compressor, Digest digest, UUID uuid, RequestMetadata requestMetadata) + Compressor.Value compressor, + Digest digest, + DigestFunction.Value digestFunction, + UUID uuid, + RequestMetadata requestMetadata) throws EntryLimitException { + checkState( + digestFunction == DigestFunction.Value.UNKNOWN + || digestFunction == digestUtil.getDigestFunction()); try { if (inDenyList(requestMetadata)) { throw Status.UNAVAILABLE.withDescription(BLOCK_LIST_ERROR).asRuntimeException(); @@ -1308,7 +1316,7 @@ public Write getBlobWrite( throw new EntryLimitException(digest.getSizeBytes(), maxEntrySizeBytes); } // FIXME small blob write to proto cache - return writes.get(compressor, digest, uuid, requestMetadata); + return writes.get(compressor, digest, digestFunction, uuid, requestMetadata); } protected int getTreeDefaultPageSize() { @@ -1656,7 +1664,12 @@ private ListenableFuture writeBlobFuture( checkState(digest.getSizeBytes() == content.size()); SettableFuture writtenFuture = SettableFuture.create(); Write write = - getBlobWrite(Compressor.Value.IDENTITY, digest, UUID.randomUUID(), requestMetadata); + getBlobWrite( + Compressor.Value.IDENTITY, + digest, + digestUtil.getDigestFunction(), + UUID.randomUUID(), + requestMetadata); addCallback( write.getFuture(), new FutureCallback() { diff --git a/src/main/java/build/buildfarm/instance/shard/Writes.java b/src/main/java/build/buildfarm/instance/shard/Writes.java index 95e6166dca..d085107c08 100644 --- a/src/main/java/build/buildfarm/instance/shard/Writes.java +++ b/src/main/java/build/buildfarm/instance/shard/Writes.java @@ -22,6 +22,7 @@ import build.bazel.remote.execution.v2.Compressor; import build.bazel.remote.execution.v2.Digest; +import build.bazel.remote.execution.v2.DigestFunction; import build.bazel.remote.execution.v2.RequestMetadata; import build.buildfarm.common.EntryLimitException; import build.buildfarm.common.Write; @@ -135,7 +136,11 @@ public Instance load(BlobWriteKey key) { } public Write get( - Compressor.Value compressor, Digest digest, UUID uuid, RequestMetadata requestMetadata) + Compressor.Value compressor, + Digest digest, + DigestFunction.Value digestFunction, + UUID uuid, + RequestMetadata requestMetadata) throws EntryLimitException { if (digest.getSizeBytes() == 0) { return new CompleteWrite(0); @@ -148,7 +153,9 @@ public Write get( .build(); try { return new InvalidatingWrite( - blobWriteInstances.get(key).getBlobWrite(compressor, digest, uuid, requestMetadata), + blobWriteInstances + .get(key) + .getBlobWrite(compressor, digest, digestFunction, uuid, requestMetadata), () -> blobWriteInstances.invalidate(key)); } catch (ExecutionException e) { Throwable cause = e.getCause(); diff --git a/src/main/java/build/buildfarm/instance/stub/StubInstance.java b/src/main/java/build/buildfarm/instance/stub/StubInstance.java index bc744682cd..cfcca8384f 100644 --- a/src/main/java/build/buildfarm/instance/stub/StubInstance.java +++ b/src/main/java/build/buildfarm/instance/stub/StubInstance.java @@ -42,6 +42,7 @@ import build.bazel.remote.execution.v2.ContentAddressableStorageGrpc.ContentAddressableStorageBlockingStub; import build.bazel.remote.execution.v2.ContentAddressableStorageGrpc.ContentAddressableStorageFutureStub; import build.bazel.remote.execution.v2.Digest; +import build.bazel.remote.execution.v2.DigestFunction; import build.bazel.remote.execution.v2.Directory; import build.bazel.remote.execution.v2.ExecutionGrpc; import build.bazel.remote.execution.v2.ExecutionGrpc.ExecutionStub; @@ -698,12 +699,22 @@ Write getWrite( */ @Override public Write getBlobWrite( - Compressor.Value compressor, Digest digest, UUID uuid, RequestMetadata requestMetadata) { + Compressor.Value compressor, + Digest digest, + DigestFunction.Value digestFunction, + UUID uuid, + RequestMetadata requestMetadata) { + BlobInformation blob = + BlobInformation.newBuilder() + .setCompressor(compressor) + .setDigest(digest) + .setDigestFunction(digestFunction) + .build(); String resourceName = ResourceParser.uploadResourceName( UploadBlobRequest.newBuilder() .setInstanceName(getName()) - .setBlob(BlobInformation.newBuilder().setCompressor(compressor).setDigest(digest)) + .setBlob(blob) .setUuid(uuid.toString()) .build()); return getWrite( diff --git a/src/main/java/build/buildfarm/worker/shard/CasWriter.java b/src/main/java/build/buildfarm/worker/shard/CasWriter.java index f433d63b31..eecc088b83 100644 --- a/src/main/java/build/buildfarm/worker/shard/CasWriter.java +++ b/src/main/java/build/buildfarm/worker/shard/CasWriter.java @@ -15,12 +15,15 @@ package build.buildfarm.worker.shard; import build.bazel.remote.execution.v2.Digest; +import build.bazel.remote.execution.v2.DigestFunction; import com.google.protobuf.ByteString; import java.io.IOException; import java.nio.file.Path; public interface CasWriter { - void write(Digest digest, Path file) throws IOException, InterruptedException; + void write(Digest digest, DigestFunction.Value digestFunction, Path file) + throws IOException, InterruptedException; - void insertBlob(Digest digest, ByteString content) throws IOException, InterruptedException; + void insertBlob(Digest digest, DigestFunction.Value digestFunction, ByteString content) + throws IOException, InterruptedException; } diff --git a/src/main/java/build/buildfarm/worker/shard/LocalCasWriter.java b/src/main/java/build/buildfarm/worker/shard/LocalCasWriter.java index f5285a2cfd..01881eea72 100644 --- a/src/main/java/build/buildfarm/worker/shard/LocalCasWriter.java +++ b/src/main/java/build/buildfarm/worker/shard/LocalCasWriter.java @@ -18,6 +18,7 @@ import build.bazel.remote.execution.v2.Compressor; import build.bazel.remote.execution.v2.Digest; +import build.bazel.remote.execution.v2.DigestFunction; import build.bazel.remote.execution.v2.RequestMetadata; import build.buildfarm.common.Write; import build.buildfarm.common.function.IOSupplier; @@ -38,11 +39,14 @@ public LocalCasWriter(ExecFileSystem execFileSystem) { this.execFileSystem = execFileSystem; } - public void write(Digest digest, Path file) throws IOException, InterruptedException { + @Override + public void write(Digest digest, DigestFunction.Value digestFunction, Path file) + throws IOException, InterruptedException { insertStream(digest, () -> Files.newInputStream(file)); } - public void insertBlob(Digest digest, ByteString content) + @Override + public void insertBlob(Digest digest, DigestFunction.Value digestFunction, ByteString content) throws IOException, InterruptedException { insertStream(digest, content::newInput); } diff --git a/src/main/java/build/buildfarm/worker/shard/RemoteCasWriter.java b/src/main/java/build/buildfarm/worker/shard/RemoteCasWriter.java index e16c2888c7..0ba8db48b5 100644 --- a/src/main/java/build/buildfarm/worker/shard/RemoteCasWriter.java +++ b/src/main/java/build/buildfarm/worker/shard/RemoteCasWriter.java @@ -20,6 +20,7 @@ import build.bazel.remote.execution.v2.Compressor; import build.bazel.remote.execution.v2.Digest; +import build.bazel.remote.execution.v2.DigestFunction; import build.bazel.remote.execution.v2.RequestMetadata; import build.buildfarm.backplane.Backplane; import build.buildfarm.common.Size; @@ -60,16 +61,18 @@ public RemoteCasWriter( this.retrier = retrier; } - public void write(Digest digest, Path file) throws IOException, InterruptedException { + @Override + public void write(Digest digest, DigestFunction.Value digestFunction, Path file) + throws IOException, InterruptedException { if (digest.getSizeBytes() > 0) { - insertFileToCasMember(digest, file); + insertFileToCasMember(digest, digestFunction, file); } } - private void insertFileToCasMember(Digest digest, Path file) + private void insertFileToCasMember(Digest digest, DigestFunction.Value digestFunction, Path file) throws IOException, InterruptedException { try (InputStream in = Files.newInputStream(file)) { - retrier.execute(() -> writeToCasMember(digest, in)); + retrier.execute(() -> writeToCasMember(digest, digestFunction, in)); } catch (RetryException e) { Throwable cause = e.getCause(); Throwables.throwIfInstanceOf(cause, IOException.class); @@ -78,11 +81,11 @@ private void insertFileToCasMember(Digest digest, Path file) } } - private long writeToCasMember(Digest digest, InputStream in) + private long writeToCasMember(Digest digest, DigestFunction.Value digestFunction, InputStream in) throws IOException, InterruptedException { // create a write for inserting into another CAS member. String workerName = getRandomWorker(); - Write write = getCasMemberWrite(digest, workerName); + Write write = getCasMemberWrite(digest, digestFunction, workerName); write.reset(); try { @@ -96,17 +99,23 @@ private long writeToCasMember(Digest digest, InputStream in) } } - private Write getCasMemberWrite(Digest digest, String workerName) throws IOException { + private Write getCasMemberWrite( + Digest digest, DigestFunction.Value digestFunction, String workerName) throws IOException { Instance casMember = workerStub(workerName); return casMember.getBlobWrite( - Compressor.Value.IDENTITY, digest, UUID.randomUUID(), RequestMetadata.getDefaultInstance()); + Compressor.Value.IDENTITY, + digest, + digestFunction, + UUID.randomUUID(), + RequestMetadata.getDefaultInstance()); } - public void insertBlob(Digest digest, ByteString content) + @Override + public void insertBlob(Digest digest, DigestFunction.Value digestFunction, ByteString content) throws IOException, InterruptedException { try (InputStream in = content.newInput()) { - retrier.execute(() -> writeToCasMember(digest, in)); + retrier.execute(() -> writeToCasMember(digest, digestFunction, in)); } catch (RetryException e) { Throwable cause = e.getCause(); Throwables.throwIfInstanceOf(cause, IOException.class); diff --git a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java index 006db931fa..398e76fc1c 100644 --- a/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java +++ b/src/main/java/build/buildfarm/worker/shard/ShardWorkerContext.java @@ -27,6 +27,7 @@ import build.bazel.remote.execution.v2.Command; import build.bazel.remote.execution.v2.Compressor; import build.bazel.remote.execution.v2.Digest; +import build.bazel.remote.execution.v2.DigestFunction; import build.bazel.remote.execution.v2.Directory; import build.bazel.remote.execution.v2.DirectoryNode; import build.bazel.remote.execution.v2.ExecutionStage; @@ -465,15 +466,16 @@ public Duration getMaximumActionTimeout() { return maximumActionTimeout; } - private void insertBlob(Digest digest, ByteString content) + private void insertBlob(Digest digest, DigestFunction.Value digestFunction, ByteString content) throws IOException, InterruptedException { if (digest.getSizeBytes() > 0) { - writer.insertBlob(digest, content); + writer.insertBlob(digest, digestFunction, content); } } - private void insertFile(Digest digest, Path file) throws IOException, InterruptedException { - writer.write(digest, file); + private void insertFile(Digest digest, DigestFunction.Value digestFunction, Path file) + throws IOException, InterruptedException { + writer.write(digest, digestFunction, file); } private void updateActionResultStdOutputs(ActionResult.Builder resultBuilder) @@ -483,7 +485,7 @@ private void updateActionResultStdOutputs(ActionResult.Builder resultBuilder) // reset to allow policy to determine inlining resultBuilder.setStdoutRaw(ByteString.EMPTY); Digest stdoutDigest = getDigestUtil().compute(stdoutRaw); - insertBlob(stdoutDigest, stdoutRaw); + insertBlob(stdoutDigest, getDigestUtil().getDigestFunction(), stdoutRaw); resultBuilder.setStdoutDigest(stdoutDigest); } @@ -492,7 +494,7 @@ private void updateActionResultStdOutputs(ActionResult.Builder resultBuilder) // reset to allow policy to determine inlining resultBuilder.setStderrRaw(ByteString.EMPTY); Digest stderrDigest = getDigestUtil().compute(stderrRaw); - insertBlob(stderrDigest, stderrRaw); + insertBlob(stderrDigest, getDigestUtil().getDigestFunction(), stderrRaw); resultBuilder.setStderrDigest(stderrDigest); } } @@ -567,7 +569,7 @@ private void uploadOutputFile( .setIsExecutable(Files.isExecutable(outputPath)); try { - insertFile(digest, outputPath); + insertFile(digest, getDigestUtil().getDigestFunction(), outputPath); } catch (EntryLimitException e) { preconditionFailure .addViolationsBuilder() @@ -688,7 +690,7 @@ private void visitRegularFile(Path file, BasicFileAttributes attrs) throws IOExc .setIsExecutable(Files.isExecutable(file)) .build()); try { - insertFile(digest, file); + insertFile(digest, getDigestUtil().getDigestFunction(), file); } catch (InterruptedException e) { throw new IOException(e); } catch (EntryLimitException e) { @@ -734,7 +736,7 @@ public FileVisitResult postVisitDirectory(Path dir, IOException exc) { Tree tree = treeBuilder.build(); ByteString treeBlob = tree.toByteString(); Digest treeDigest = getDigestUtil().compute(treeBlob); - insertBlob(treeDigest, treeBlob); + insertBlob(treeDigest, getDigestUtil().getDigestFunction(), treeBlob); resultBuilder.addOutputDirectoriesBuilder().setPath(outputDir).setTreeDigest(treeDigest); } diff --git a/src/main/native/BUILD b/src/main/native/BUILD new file mode 100644 index 0000000000..b352a822cc --- /dev/null +++ b/src/main/native/BUILD @@ -0,0 +1,65 @@ +genrule( + name = "copy_link_jni_md_header", + srcs = select({ + "@bazel//src/conditions:darwin": ["@bazel_tools//tools/jdk:jni_md_header-darwin"], + "@bazel//src/conditions:freebsd": ["@bazel_tools//tools/jdk:jni_md_header-freebsd"], + "@bazel//src/conditions:openbsd": ["@bazel_tools//tools/jdk:jni_md_header-openbsd"], + "@bazel//src/conditions:windows": ["@bazel_tools//tools/jdk:jni_md_header-windows"], + "//conditions:default": ["@bazel_tools//tools/jdk:jni_md_header-linux"], + }), + outs = ["jni_md.h"], + cmd = "cp -f $< $@", + visibility = ["//src/main/native:__subpackages__"], +) + +genrule( + name = "copy_link_jni_header", + srcs = ["@bazel_tools//tools/jdk:jni_header"], + outs = ["jni.h"], + cmd = "cp -f $< $@", + visibility = ["//src/main/native:__subpackages__"], +) + +cc_library( + name = "blake3", + srcs = [ + "blake3_jni.cc", + ":jni.h", + ":jni_md.h", + ], + includes = ["."], # For jni headers. + visibility = ["//src/main/native:__subpackages__"], + deps = [ + "@blake3", + ], + alwayslink = 1, +) + +cc_binary( + name = "libblake3_jni.so", + linkshared = 1, + visibility = ["//src/main/java/build/buildfarm/common/blake3:__pkg__"], + deps = [ + ":blake3", + ], +) + +genrule( + name = "mac-compat", + srcs = ["libblake3_jni.so"], + outs = ["libblake3_jni.dylib"], + cmd = "cp $< $@", + output_to_bindir = 1, + visibility = ["//src/main/java/build/buildfarm/common/blake3:__pkg__"], +) + +cc_binary( + name = "blake3_jni.dll", + linkshared = 1, + visibility = [ + "//src/main/java/build/buildfarm/common/blake3:__pkg__", + ], + deps = [ + ":blake3", + ], +) diff --git a/src/main/native/blake3_jni.cc b/src/main/native/blake3_jni.cc new file mode 100644 index 0000000000..7bbb2ed088 --- /dev/null +++ b/src/main/native/blake3_jni.cc @@ -0,0 +1,73 @@ +// Copyright 2023 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include "c/blake3.h" + +namespace blaze_jni { + +jbyte *get_byte_array(JNIEnv *env, jbyteArray java_array) { + return (jbyte *)env->GetPrimitiveArrayCritical(java_array, nullptr); +} + +void release_byte_array(JNIEnv *env, jbyteArray array, jbyte *addr) { + env->ReleasePrimitiveArrayCritical(array, addr, 0); +} + +extern "C" JNIEXPORT int JNICALL +Java_build_buildfarm_common_blake3_Blake3MessageDigest_hasher_1size( + JNIEnv *env, jobject obj) { + return (int)sizeof(blake3_hasher); +} + +extern "C" JNIEXPORT void JNICALL +Java_build_buildfarm_common_blake3_Blake3MessageDigest_initialize_1hasher( + JNIEnv *env, jobject obj, jbyteArray jhasher) { + blake3_hasher *hasher = (blake3_hasher *)get_byte_array(env, jhasher); + if (hasher) { + blake3_hasher_init(hasher); + release_byte_array(env, jhasher, (jbyte *)hasher); + } +} + +extern "C" JNIEXPORT void JNICALL +Java_build_buildfarm_common_blake3_Blake3MessageDigest_blake3_1hasher_1update( + JNIEnv *env, jobject obj, jbyteArray jhasher, jbyteArray input, jint offset, + jint input_len) { + blake3_hasher *hasher = (blake3_hasher *)get_byte_array(env, jhasher); + if (hasher) { + jbyte *input_addr = get_byte_array(env, input); + blake3_hasher_update(hasher, input_addr + offset, input_len); + release_byte_array(env, input, input_addr); + release_byte_array(env, jhasher, (jbyte *)hasher); + } +} + +extern "C" JNIEXPORT void JNICALL +Java_build_buildfarm_common_blake3_Blake3MessageDigest_blake3_1hasher_1finalize( + JNIEnv *env, jobject obj, jbyteArray jhasher, jbyteArray out, + jint out_len) { + blake3_hasher *hasher = (blake3_hasher *)get_byte_array(env, jhasher); + if (hasher) { + jbyte *out_addr = get_byte_array(env, out); + blake3_hasher_finalize(hasher, (uint8_t *)out_addr, out_len); + release_byte_array(env, out, out_addr); + release_byte_array(env, jhasher, (jbyte *)hasher); + } +} + +} // namespace blaze_jni diff --git a/src/test/java/build/buildfarm/common/DigestUtilTest.java b/src/test/java/build/buildfarm/common/DigestUtilTest.java index 45df23990e..9427c36c68 100644 --- a/src/test/java/build/buildfarm/common/DigestUtilTest.java +++ b/src/test/java/build/buildfarm/common/DigestUtilTest.java @@ -28,7 +28,6 @@ @RunWith(JUnit4.class) public class DigestUtilTest { - @Test public void buildThrowsOnInvalidHashCode() { DigestUtil digestUtil = new DigestUtil(HashFunction.MD5); diff --git a/src/test/java/build/buildfarm/common/config/BackplaneTest.java b/src/test/java/build/buildfarm/common/config/BackplaneTest.java index 9cf61eadc5..703f967e6c 100644 --- a/src/test/java/build/buildfarm/common/config/BackplaneTest.java +++ b/src/test/java/build/buildfarm/common/config/BackplaneTest.java @@ -27,7 +27,6 @@ */ @RunWith(JUnit4.class) public class BackplaneTest { - @Before public void assertNoEnvVariable() { // If a REDIS_PASSWORD env variable is set, it wins. We're not mocking env vars. diff --git a/src/test/java/build/buildfarm/common/services/ByteStreamServiceTest.java b/src/test/java/build/buildfarm/common/services/ByteStreamServiceTest.java index 0ad0714a0b..72f3c46bbe 100644 --- a/src/test/java/build/buildfarm/common/services/ByteStreamServiceTest.java +++ b/src/test/java/build/buildfarm/common/services/ByteStreamServiceTest.java @@ -29,6 +29,7 @@ import build.bazel.remote.execution.v2.Compressor; import build.bazel.remote.execution.v2.Digest; +import build.bazel.remote.execution.v2.DigestFunction; import build.bazel.remote.execution.v2.RequestMetadata; import build.buildfarm.common.DigestUtil; import build.buildfarm.common.Write; @@ -153,7 +154,11 @@ public boolean isReady() { when(write.getFuture()).thenReturn(writtenFuture); when(instance.getBlobWrite( - Compressor.Value.IDENTITY, digest, uuid, RequestMetadata.getDefaultInstance())) + Compressor.Value.IDENTITY, + digest, + DigestFunction.Value.UNKNOWN, + uuid, + RequestMetadata.getDefaultInstance())) .thenReturn(write); HashCode hash = HashCode.fromString(digest.getHash()); @@ -226,7 +231,11 @@ public boolean isReady() { when(write.getFuture()).thenReturn(writtenFuture); when(instance.getBlobWrite( - Compressor.Value.IDENTITY, digest, uuid, RequestMetadata.getDefaultInstance())) + Compressor.Value.IDENTITY, + digest, + DigestFunction.Value.UNKNOWN, + uuid, + RequestMetadata.getDefaultInstance())) .thenReturn(write); HashCode hash = HashCode.fromString(digest.getHash()); diff --git a/src/test/java/build/buildfarm/common/services/WriteStreamObserverTest.java b/src/test/java/build/buildfarm/common/services/WriteStreamObserverTest.java index 165232ab05..4a3c864b24 100644 --- a/src/test/java/build/buildfarm/common/services/WriteStreamObserverTest.java +++ b/src/test/java/build/buildfarm/common/services/WriteStreamObserverTest.java @@ -13,6 +13,7 @@ import build.bazel.remote.execution.v2.Compressor; import build.bazel.remote.execution.v2.Digest; +import build.bazel.remote.execution.v2.DigestFunction; import build.bazel.remote.execution.v2.RequestMetadata; import build.buildfarm.common.DigestUtil; import build.buildfarm.common.DigestUtil.HashFunction; @@ -68,6 +69,7 @@ public void cancelledBeforeGetOutputIsSilent() throws Exception { when(instance.getBlobWrite( eq(Compressor.Value.IDENTITY), eq(cancelledDigest), + eq(DigestFunction.Value.UNKNOWN), eq(uuid), any(RequestMetadata.class))) .thenReturn(write); @@ -85,6 +87,7 @@ public void cancelledBeforeGetOutputIsSilent() throws Exception { .getBlobWrite( eq(Compressor.Value.IDENTITY), eq(cancelledDigest), + eq(DigestFunction.Value.UNKNOWN), eq(uuid), any(RequestMetadata.class)); verify(write, times(1)).getOutput(any(Long.class), any(TimeUnit.class), any(Runnable.class)); @@ -112,6 +115,7 @@ public void noErrorWhenContextCancelled() throws Exception { when(instance.getBlobWrite( eq(Compressor.Value.IDENTITY), eq(cancelledDigest), + eq(DigestFunction.Value.UNKNOWN), eq(uuid), any(RequestMetadata.class))) .thenReturn(write); @@ -134,6 +138,7 @@ public void noErrorWhenContextCancelled() throws Exception { .getBlobWrite( eq(Compressor.Value.IDENTITY), eq(cancelledDigest), + eq(DigestFunction.Value.UNKNOWN), eq(uuid), any(RequestMetadata.class)); verifyNoInteractions(responseObserver); diff --git a/src/test/java/build/buildfarm/instance/server/NodeInstanceTest.java b/src/test/java/build/buildfarm/instance/server/NodeInstanceTest.java index 9ebade96e5..87ae91c4c9 100644 --- a/src/test/java/build/buildfarm/instance/server/NodeInstanceTest.java +++ b/src/test/java/build/buildfarm/instance/server/NodeInstanceTest.java @@ -107,7 +107,7 @@ static class DummyServerInstance extends NodeInstance { ContentAddressableStorage contentAddressableStorage, ActionCache actionCache) { super( /* name= */ null, - /* digestUtil= */ null, + /* digestUtil= */ DIGEST_UTIL, contentAddressableStorage, actionCache, /* outstandingOperations= */ null, diff --git a/src/test/java/build/buildfarm/instance/shard/ServerInstanceTest.java b/src/test/java/build/buildfarm/instance/shard/ServerInstanceTest.java index f97cc750dc..5ef0db01ec 100644 --- a/src/test/java/build/buildfarm/instance/shard/ServerInstanceTest.java +++ b/src/test/java/build/buildfarm/instance/shard/ServerInstanceTest.java @@ -52,6 +52,7 @@ import build.bazel.remote.execution.v2.Command; import build.bazel.remote.execution.v2.Compressor; import build.bazel.remote.execution.v2.Digest; +import build.bazel.remote.execution.v2.DigestFunction; import build.bazel.remote.execution.v2.Directory; import build.bazel.remote.execution.v2.DirectoryNode; import build.bazel.remote.execution.v2.ExecuteOperationMetadata; @@ -540,6 +541,7 @@ public void queueOperationPutFailureCancelsOperation() throws Exception { .getBlobWrite( any(Compressor.Value.class), any(Digest.class), + any(DigestFunction.Value.class), any(UUID.class), any(RequestMetadata.class)); @@ -636,6 +638,7 @@ public void queueWithFailedCacheCheckContinues() throws Exception { .getBlobWrite( any(Compressor.Value.class), any(Digest.class), + any(DigestFunction.Value.class), any(UUID.class), any(RequestMetadata.class)); diff --git a/third_party/remote-apis/BUILD b/third_party/remote-apis/BUILD deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/third_party/remote-apis/remote-apis.patch b/third_party/remote-apis/remote-apis.patch deleted file mode 100644 index f761945057..0000000000 --- a/third_party/remote-apis/remote-apis.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff --git a/repository_rules.bzl b/repository_rules.bzl -index 2b36886..6ffc75b 100644 ---- a/repository_rules.bzl -+++ b/repository_rules.bzl -@@ -6,8 +6,6 @@ This is adapted from - https://github.com/googleapis/googleapis/blob/master/repository_rules.bzl - """ - --load("//:remote_apis_deps.bzl", "remote_apis_go_deps") -- - def _switched_rules_impl(ctx): - disabled_rule_script = """ - def {rule_name}(**kwargs): -@@ -118,8 +116,6 @@ def switched_rules_by_language( - name = name, - rules = rules, - ) -- if go: -- remote_apis_go_deps() - - def _switch(enabled, enabled_value): - return enabled_value if enabled else "" From 4cbcd4ae3a7d1f748d29ac2938424e17239a16d8 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Wed, 3 Apr 2024 09:42:17 -0700 Subject: [PATCH 257/311] chore(deps): bump bazel to 7.1.1 (#1694) --- .bazelversion | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bazelversion b/.bazelversion index a8907c025d..21c8c7b46b 100644 --- a/.bazelversion +++ b/.bazelversion @@ -1 +1 @@ -7.0.2 +7.1.1 From 0bc8a59718545aab7e99aaeec937c3927712d5a4 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Wed, 3 Apr 2024 12:11:13 -0700 Subject: [PATCH 258/311] chore: remove bazel binary This is a platform-specific (linux x68_64) binary of unknown origin. To build buildfarm, use Bazelisk. See README for more info. --- bazel | Bin 5148672 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100755 bazel diff --git a/bazel b/bazel deleted file mode 100755 index d3aef1931265626d8487cbcc3c412c785544ff23..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5148672 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

L>`y124b(}FJWIhe!HTi@hg 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 rvHXZvdUX5=pcX9F})z`ksXx3B~yM; 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�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 _Rid6$E-(lr#X<1_2qJf9Ms?W2L`^Sr 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 z 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 z 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

N7at&f-?;HskU2$)4?F;3@ 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ɀQE209Cn>LAm#YoTL)=)noAPDszbe1f=DN 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%0D89_2GRw&mUP=wVQQCYyS$l;egC0W(dsd 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�EKW0qNP>1%ra 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 z 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≫rZldb0y&_Ie88JME~Gq{!l-W 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 q3@<=Oj_Kb!lvM|;!TWS`t8{-u4v5!^o? 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 z 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 z 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

;Hm_bMC(Gxc5t#K2a&k_f{>1(o>&f3bgDZ< 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�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ɵ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 z zV?Iv?_i0;{g&;p4&qSe_pcqY38f2ichsQAEz`!xaVPTVvBO_-S$HX`qr>2_VIWon) zj~ogvZf@($X}#j^ z?qTl1K5Kfqg&-rtN|2dLk0~oiOBX#4NlCKckmk|P#_EDF4(Dni2nR#kqb&q6c&3Fy zPLKeeGc&DtW{ZktaBf{?+yn&YO894973UTb$_c_KGm)HN+jcOBIw3xu6C@^~K1j9@ zq@;kyR1U|-`DD|&Ak0AuBkK`u3RCOgDZ=#(3E}HW;nuBZZMH|>vdPL)Lw>DIV9-+= z`h5NJ|5wv#9qQrn*~Zh82z`Ay+s&J4{it9Y5I}@GcdFa&O4PQcbysPrJkEEMtuQ{- zHeqL#ZCa)bK68*vY8w6QZ~Mf=P;Dj1hKn)1KJ;4Cbs>Mv%~6ka5~Qbh#x?AKYhWp$ z^Z!Vb0z7vG1M>?C2A1&U3kC-7q}vfe7WhP6gXfIUI#z&l7Jz$P3xemB@b?)!(|aaB zeJ(&<&)@fKT$4OJuk_fI8>(|~PV|}a_Ljx*MK*nYh5Wf%2-5lbO%`<(Eia9FkZM`} zdElRyoL}nN!Xng9I9K|N2?VkNu)>$6^|KrywK$(jK{Tnw^{9+3B(-3uvY5XHq|$8* zsYTsW8Jf`4Z?C9^m$}u3I!Z9%Lk)!DT5W%iQ!tMtV zM8^{M9qfMNd~r<)zCVfk9xzUyfl}N@Y5EK$SqPHB4Si;0kiR(q`@l0m-xCV(8E9ES zfJo<~Zox?Afji;~2JYNhFfcKxU|<@ylSQ7pPr*RH;DUi+kp%;{#}Ita(rrZFc~s*X zW8F$nP-2eqw0^P@1P5E;U4%p3B6_CjeNRlZ5P%83?5<>yrn6enZM=P~1ipS2cqXj` z0Rh+t|G7lZUPZ+>9o$#c??WB7Zzsa&=&=rXPEbEicSuhc)r)f2KkB`x!BzISh~d1=`ZbNW3=k44Mk{Ry9uMA369 zDn4gkQgR*T#H>s6ywI}rJ6rV5Bn#$6+ZPv0^WR;#fBbRs^J~qEiev?Jx-NSDbl;RY z(LE5=^K_lQUr~+cg8zK(?)dKU66K-Z#Q!+{^YEPWEK2du7tN>d2`c0s-WQ(Xy~4mr zDD2=AAK%j{A>k*dojb=m?b>CAdX*C-r*=f0WG2YkgYOSKPl~vYZg|J@+H4{4!+lK4 z{LpvrUe2ksbhcAjnFpdUu5c37Z=p`$9p`}WL{HIoiyN+|?>5xi@m7MJc!x{k>qjfp z)wG<2AcTL9!29E7(S4-PF0FU|UjDbQzy#bM5QOpnGW03Oq=u7Gqr)i=&w~<~LZ1V^~bU zXbJ44{6va0>JOc^Yc-4HvyQAM8wfvh7Qxh61n?10;zhiP5Ah|N8=RwG1N+w|UP7^; z>cxVWIet!TY6p`L5=z4Gt7{9{O4tNiB$8~yyC`Pv!S!g2_)OY}ztj}*mYR_$ep;;< zjHlEivHTQ+Ef8}_NaE?v_(h+zA_?M^-_<+GE|f`ZP!82KK~+ssAgO$Q8c8Px#1MUz z86=amAx7}($RZ{zHc~spL^8v8N(<6~Sn}onvyyD|590L&^Cx1)V1E8Y%%Dgxg(4Bn zC`RWL!>ceUg_L3L!3wgE>?fF23{x2Xz4ljLiNmY0pXow z11|%9en4VRdJ_k}(^lCwGZMUfyjkKR?BxsHin5E{-E5C5DEjrP_vN zWkrVN<&tg0(tJB$SXd~@$_9T+rTt_aiAe$5x=8~c!CA`mhIc(eJ=Mc3$ z(;+%~C4PfNImE^`;)KE|5+9#T5_Znx@ca1hHsinBjA{GGe{GwwG%+#G&HZ(|u{5zo z{x5CE(uB4hTcAz23)*t&?^rcy+II1;w<9Y%iQ191o&Npp$Xe298^don^8aajvJ`%2 zI+Bcxb0jmfFUiUpfce$$qy8I8a!V$Y($W{CtZXVNFP}+h+XeL!bMxyZ6B@e5Au_TB z*|lqB)5OGS&66-%Av-$~&xf*UUfvGlf`TTdg@vw7OH17x%FAgz-Bs7e$4b}NcUjZT zo1@#JuY{m&1@-L~vU_)1l2@#QI(nYW-n}+BrY5E|j>Yk$P?s7Ix6L}l&u^ZLzrPI$ z2+$;fK^`O|#GizQ#*whF-DJxa8E)&=P!b*7j2?A?myEuE{|XE z-UhTy`G9KrnC(Rn1%6)Va@aMEOjyaJ@Q2D=u-H_Tw1yi_lxF<+SH|pyG(YrxUEgpu8uJ~ zs&R3&OegK!Tts~&+ncz#?`h)UalDDA*R>|zo1ZuF3y{(d3{=t%3ewUJ4r!?!y2V0! z>(;K?;o&m)9>g=?_8V>US(fOBEs!ZF@KY!%kwZCc>D{}VN$=S+9PRZjrStN}pv~S; zy0Fk#x~Qm~baC+vzWtuIjf&gfrHPhQOiUB0*x2ve;o*y*os*-2BVQ&(=qLL3waY7@ z9jAwOOso;NV~3M=T-+oMeU><`EZ>)k_RdK9z4*?NMT{ml&&kBwdp7Y4@gQO8_@3kUH=nq9c@Xb7M|50x zkP_rcqwUdcizC^Z=|QsiGRefv$C3EPdys^^j--??^Am9k_aG73jwGi-8sANOIXAay zG6F$4=e~WCOmy^dE+(dmi;caCy5lPs7xx^$4W4lE@hiE6J^oy7ZYq~oG7aBxmW-6DJH%%r#znm-J zx4Xf)1x=C(4nEF>gj8{%p;x)Eu&>;fEzj{i_=F1&U&%!z`E$w1sa#6dG}Qm)96euE zxG}l;PLkQY`8en2SH=1JU*!Slqgq^6d0X?UJ# zU*@0dpP=s))A7AMQrFMVN7vs!K{p^EMK>_8vUyNYo^EjPM%}bDfo^)br!MVRr7;pi zLQL^}vDg$oC#C{HPg8gIVWu9Q<4wK1`n4>l-6H(Z@_oJ-^+i( z72wbxK>4Bl7;-eG2Kqh(toOqmtRv6?yq7%qeggWd-POT|1C>3q*Y7HTls7EdD?G54_JMCjI zK?}So{@OwglZO2amFQ{ch+rQv2nBQuX$(2er!nLNYuBZDf8_5ZIfZhkA!o>0r038g zY>GBv+OjHYRTZ_TirP|XOYu##rQRmhe2eiNw4i?9YApHb|GU@G<^K0ygDY^af&Jqv zLtE6v|Gm%mBRpU|3ACO2F?m8nZO1RjuUm`7+x~p2;1oG}EtEKAP6Yws)i`xd z1OL_Jv=An>G5gxbeh*Gvp>#mRv`!6KBPB=DKiQ@xN}IH8&Bx@U(Pyt_Nqs+45WW z=9?vm#>n45s} zo5)S#CUaAM^Gv65(~vJD)43Vk%zt?QCHMX7^;v&#``O%_-#iz39-_aw+`I<+n*W2+ z-+%T$vL+-8xP|{MJ=!lrI$mm;J2dQFVyQrmiU(E{xj(9YeNq z;Xfbe`?LOKO??0VoQ`Plto*qx|EkiF>3KX%KDfVI@WYyk8&bXM9ao((m_GGW z+`Lh8CmhaSerSL0sPQ7YrK~_aVb=r^W7*A0nH#e{+26|UGBo#xrKZ_Me3 zoph+2G*)p^8GwMXYPZg*-t&tkytb7P~X z)szieW4+RPP}J<{S<$1WUTC7WN_hU!p@@pIH?6MC^PV;|ry}yYllHX`gSFwEn%ep- zasDafnr;tgn_i|~M_woT-m_Zu@T_iz@{#hTFPndKoohtAQ-;28?04?Npk){GR)1Qw zD=68dIxwWXmv#f3Iz23vTlARuu>~?9A8#7?>oKG?#Lfg4M&Knmtc2;pc zHf~G(l`f~QjBJvY*L2%0;WeunUpKxP>{7i)HuF*FySBYPURQoHTjzDu@DX84+Y~(+ zG-+I9-}@!)586y3+@dlFp3l zaqdpyh5LJBq@xS1;uODh8K>ge#&Gr3GtDmcEwvt^(`(4Bk#QY9j!=7%>!b8p_0HT# z$8}GyDn8b99(3}^!5zac-fMJ7J*uDb-SMZ-Y^;{ID>u|FEINBWaq5xvNA(}K?0fUl zs}Hv(IUkjMq(_1-FRCk<^R`b{rIVM>w(Vnaz2kw#RXw+cY(J%U_uPSC(|2?G&&m(h z9x`R|;hXP2@6JiD8P?mRIQjI$ei2V^O)cNh)FFALt=j4V_JOP18r3W~;M8YHn6m2w z-F@Tx&D2?VWlD?H3To9$-d%j8t{yjfk*`(7v_<{y=M5QNud*Z{G0J*JqRYcJ+naif z_Fo@2vN4g8iy5J?ZT84vd!CQ|Qq(vp%G19-_>JN4o;@D4PkLwFe^7f5cYo(wA3MxB z5~uM_#qRKgSDAWM#$)E&E6Oh2|2d*mWB3yCsBTMD*Dl{=<>p;FhrJk0V) zw*TYJt1n08zm$(2^SNk%(ygX1)jf_a8KTqSrq}EQw?fyv@@czUPc2MpW$1DERGYFF zp{9G2;hMvJ&uXn19^^a1UT0mL=^kP5$7^L$ttMvI4fE`GTq{Mo#?N_IT&Hdc8&wrv z7f4me*qyL?*4?kyjEEz;Gsa)uaXIX3#=|jtjvCA{==jKKU44(9kLI;6{1V`m({;9H z{ew8$Nm+>p^ty*1eA{m2$|sBEzaF~3?7_2+b@?xxv%Xv(Yt?4c!t3g4o$ViNSrT@$ za@R8bcfqq#^*%59X~fpvs+U{!T{>@Hn5>p=nf58m8<)&f#?0><_@b@nJk`=^6DD~zi8U|?vfsbomvjuXFB|l$>Qhg@iphGZ7ha3DNMQJ{&x1>)+Wo^ zJnWsXseU=T-3FCU8?u^pH)|a6_Rh%V4xf$QtJ$|`wBxkKtO&WNYbW<#?mV`yVXLrf zh20%`-**{h@;)>qF0ahbbVkqlq3*)Pa!2CN4v&j}8Bn)iR=XJN#TxUpc& z)P&p9Zy$L2r0X}^)Ach(B({H2Q*cgamFf7g-b^~!#Eo8(5yKY9DGRr9O+juhBWHo0MN_}<@RfcLSfV>X#sKG&DKJ*shrxvXJT_@k`VHQq8+Yx|x%Jy73p zcBi6QUCdoW3iT84aZ=?QBM-<-+I zO3D|E%6EKyA?|^VWnAOwE7~m4cf6JM{-*;c3PvZMAGGw=-2E%&mKt;xtWVrdC~smzU`|Cz}(k z-O&Mk7LL#B_?;x)t7iG;BxFnK{vVBYm7)k9BK1ai{5R)BK!1b64#7<{vYp z^#RA;2igY9Nd*pF^Y!h9+9tQ>ybO_5+!vUhxh=CsZr4_U`|eS_?UvVHFtKzx-B;o1 z9L?5pRoxHn^B%B`%NnP)&86$MsVAGs_RQAWlUK0z&H~qguhLxYd)x{?cA{UG$q2!G zwMc4O=Zxzunm!)j*ZcGc)8f+P5j_^iI~g@fOPFSQ?5F9o_Fq~e+){daUVYfG#|u*3 zI@zynGj5h3*rw^Y88!RPyA5h@nAD?W%;26oyr$Q7II-Cyp}6LoR(O$0f=8K3?$n&n zOD7cLGTwYF>F!%}=-jhh>Dv<(pShnnwAJ|il&WZ-V(H4Wqh~p|eYiHpE4|Z>Y0a;1 zI(nyrxAsNrHJ8cLu_h5NJ?>o%`AMh4(dM$=6V4xhGSMdedY9;%XXmd>@o9YAqriBw z!-)4Qh4$@jCw9K{ajD;<8OwXG9`d-?O{os6Ru6Z0xGBX(Qr!zTlB>M}O=y*PO0yXeR}EsmQ`9Fx4japIb*O*?tty&R`NokJ~KPc`%4CYys}3+G&YyQf0xyzBs%6`q4UK6jngPC2Fe zUJs9Evx^eF18akynEFmxqw~OEbli#d(zmoX-l%PJUMu`U^)Pq;`)zkBoKRRXa9?|) z*iQYEx_tCX(R~{EA^Ey$8zlig+fb(!k%N?j56bcRFSn6>kXN;qa)n(VUI8>66vMt;WVxEb02VotZ|b?v5|c@7aHJ z(~*|vH>&oV7WCFlYw}}{gaHHr!Z}2V%3v} zyFLu~wBUB{ueav=7_Q%OUw-J)Hv99E#`S!y+OMK0(!{e+VatBGgE)~?Zo3TBHwc`9FAS`qS2;mOA}u3MKX$hsR8E|{Bqv1`V$ z@xB-CM1EV7?_0FsYmLls4fn0nxNgPT3Ts~2y3A};ZoD?R%rxa@<3`@Wb!WzBNf#9+ zDA;%Gbhc&c(W+igXBP<(nz8ogmYh%f-`A}6P%eEsUm@tom&N-chppK0QRa2$=d!cg z3^LZf=)NNCh;1XM6}#5m$-SGGHlewu-Ofoyj*Yd0dM3mO&i2VQebs+(tMu-5hUXTf zbq#J^q0x3iN%Z7ujf||2U=IWM()2HynLhkI&Goi$|k z8jbzlH|mO;728EN-P|r<;qg(=FOdBFCc_u@BNy8(e0(=|j`J6<6RmG*q)u!#epOso z%}LRbmmkmEuzcy!_77tBw@dRViMTjlSf$}(l<>fDi}uyJQmJLr=C_GD_1srV+Sa_e z_Y*da-a%Vx`R$fzABnG0R@{ zP+Q(@wSmgiP?>Qh>s%iV+1Ghbn}b?s1j{cyyxsVgmVCMxkQb7ys{*9ZG-RMpOiG;ui8#4J;D+{NMLy%*xB! zs?=F)pIy{HVT^M^@J;zvOtH5hnIZei_!f-l9db<3q5ytsK*W9LHGIS)4JUdoG| z{>1ab!bd6b+G9Vuf9>g(;52B)b}tWVSM|#9V<3YSu$n8`ks4RhIN?h9jq|FBx23^Z;v0hE8CNyk^bh^0hPk` z*9&qywe;GD)t8OGe(1vGmTiQ>5W#r6tTR(K_IB!=Qc&MZ(5 z-!f$DS$X@NEoEjOxm&q%W~*bLnhzf~Y02gGYv+6S?z$$xc17gcnwbMv>t!Dy?rw$ zC(6V7fA71#d+%CzXH6!*$?S6Wo;`c^4xIDNe5zpTs4Kp$gkr`SZrc@wxY8D*ce9v^ zm&RYQnZKz0^o|GLdfVo+*Q*{oQ@==OXV0wKpxrJRobmAqE2l5{aW$yqA%#&50(0^=hI?Yn?B~0)O5o~K(U7ipxdJ!JnX zq*uQAL_I*Aj*UgADgf8e8Yj>l~8 z)c1SWbLN5*4wARp{V<_#;oTEe?Gn+5xp8Z3zo$?6(JSL=q5a-D>+;ileRisk znR##C0RB#uA1XQ@g6A{&_VV7_kL@NKOd79Lj85E;waboq&+t~+>RRiEo;}YFa4y=u z=(7#)PJBzK{P6;{B5oPix9`%sZ>HY8_fqi8amdI3qtNfqo@xcwzG?l?a6`pmT7})coPkJN8|>fxerEox@5ci4-W^)LElE^FATkZiI3?p=FFf0ym^ zmi!8HJMh)=s)@yNZS9Ytr`M8umbf3>lj8o!sMGjaVVZsI_2|0Fhqv$NCJ(%Hy!_p& zrm2EaegBy;*VK8}`P;?*n?8Sc=hU6JWLM*!xT4R7@}b2W zuT7kMtRR{B(`JmzvImd3dKzMuF^W2x`y)xULfnehvrSm#VzKF{RC`~9(#I`)nXw*KVEg+J1b z8Jv<3-MaPcmxcR2-E^ORGP|EmL~75EnJ-oAr=K`{W%~2jky_%m?H`AZ9Q2Rz^YV7( z#-h1S18Tl2l;n(>v+Q2hIOCAhVZH7>xPE`f`B+!y&1P>FY&vjg_MXOJ$Mj5@5|jVa zbF=^B{L+JGEatyIf|lw0SBg>Mi z{?cu*5F6~* zJtRo8Gq5k!Jt{b@dqr?w_lDq-?p?t(-G_oU-Ir7yr|st0lY9*!i{D!~nr|fR#~&%Q z#sT`O~OK*g}uAWGLn4Y0NVuI+f+iCBhH&=g#-V#c(LC;G+NH0-;hhB(2 z%RbqDpI(}Ns$Qu+$NsQ=t==X5JiP`=ub+Ls{b2hN`1pdX8_zdAX>iTpqQOIhG~FUWwr;s#Fn_FYIA0(v;nxc*`6q<)^w#Px*7MNc zs~4&7tG8eOogQiMS&wCqq*tI{p?99T){Xq#e|iw>&$ctQzhviT?`a}$=4|rN^tGMX ze!a;r(|-h>RQph;dlDx6d3pW$B$dJaoP64|7#8ZQSW~(>{|2R zHpo7~Q@^`hw@g>sE7B{GYRa@^8Yt~juS7VOkeC7408IpP9!q^I`A5pTsQ&-|*wYJc z^&v}=B~bcmAVPv|=-QsY*wAY7EqS z>7Erd=r#);8GD%C)_p2y*L^Gapi2llbUz7R>wXt7O!k|yOb(jz`QwEKd@EsJlN?i1 zzMasK?;>2z-z4*oR(eu|Q?Gx+^Ow7%~^-}cX^|JN3_F4AjCbnirOeUJ0FqvVNsaK_6 ztan=fl-_OqV|v&0dkDA&s)FGLN`k=#O(t{AE}1Mc(-e$0=mU>K8YnO@7%DI|5DFX( z#tCcvC}Exc6oX(`OP>8%Ppa%3?Gtq~ z1QEsqOaqO%rb)(QOk<6QnYJ1)HO)0PHBB=XnpPV-n3fn@ncgv8ZF=5rzCD*eMA(zB zB7AEsHtjIpZu;9e-1LiafT@PbVbd&rneYhzjPRFTg#Bc_1^PxNji!8)qoxx~u9{ky zTricG=$iSOsGIFJQ8tS<8Eh6}(#I^pWTe>-J&wUWy$|}|O@hrnnE03}n#P;SnMRqZ znx>f93)~FW3nC0w3H%IZ2{!&|JDOu(hrtd8j*}hD9bFtJIL>!GZhzW7-J#AQ-{F)) zxx)pAu?|9q7W4b&*Ug`rqy7c^EB3#~tC%a8b16K*VWPt_$K8%=9sL})IEFdiw7+lP z>hQ|puER%%c88x1^BtBr=vvrY7+FlUu(X(M(Qg03Uf0~-+{k>YxuyAR^OX+k9Tr-w zw^(km)dI_ZYya7Pq4|3A<>p(d@^?CTImB5MTBKN1T4Y)r1)ZM|#qEXf0)QgS_cxndQPXj(ql$xpO_rgVjfsPmO^u|{Pet-pZ$&Cr-$lKxew!;;T(|mY^}y=4 z)e9>{>w)GY%!gQ6S&g-tXk}#OVs+i(zJ(;mhT%5@c^i%);RUx3hI{(e8@x6zGyDwSPj^tU;2A2} z3^i1<;TvX{<(rk6oi}VWNwp=F6|7RvtTQV3~_sInvjEeXj8 zAYC9MAWI;7ps7H!fffQS2U-ub)e`bZ_QIzCpa?{=B#E<30a>PHA-q>w9)Q0%ejBFdnNQrpkj5&(?2pgo8(V+$!DnJH;{sekf;E0fd&GN0MZ3A09UHOS|aBfhp9e5!;>Y) zE@0cKxN)2`JT*BA6=X2$GCP*js9C|>!S?6$Q6H{culA6mt;AvVVGmHz(U_sop)iXK zSN3K#v)`%gPz&c|aGKQLX=G?NXpU1|r#f8CjDs>%YPnN6tH-n75QZDfug}W7n`(sf4Qv)MC}{ zsjuTOG`ux9qy;%#F^ByL>KLFDt~5irgmp`GxQc~>x1u|yT%iZ zPZ|QvSqk2&Gc=ktN|gF2>`++63}%+VRW!1jRd#UtXbjhSqMV^&ND5dMEDqa=Jw+u) zMMssbW}#W4z)-HxSfxNWb1a*Bz}Ys%UzH`XVXlS;jctJ*gX zL)}&5mWDq$h0RcGVy{yP<}_#&XkODaW$CaR)oN55RXbGssHC#p)eRNKaR!iVlC3mO z`IG7_CWHM>xkJ5!Q=l{J*vMnI#oT? zVE+%dSed1cnoJEt4dieS8_ijouA23l<20HyTov{xL@P`oUCBgpisC9o55)q-8pT*< zGBZP|S?QWmr&6MFlX8c$D{BDTl)Z{w&%Vc=p(0S7qB=`;hN`RT0#!FvPt_f&$*Lu) z%`gI{YSwDA)b^+~tI2WXIIB1ubshBu>Tc>8>N)Ci8cdCQ8rqtsn#oFoxlf>V(00ZX zg$#u$3gHSh3QnXuw82!-Nzq-gM6p4U!Q?Q` zl-DVHDkm#HROYa>SURj6Rt=2I0`@Fur9ZS&OZ6dJOGR77O=XWts!F3u6ZB4p$~P6Z zDpS=|wE|lEM0J3gKy3=NR={!PG;_4nwV}1v>a*1Cpv|u8Goan;pxsZ@wKS$^tkbB0 z*8kGrXliSYgKG%a9H&*KRjSpl#bgK=hK%Lh7_Ks}kCu)WUf2Jv^o#L{!BBA0a#C#5gTtyuPD@)qf#^@QvsKam3znTlG9 zeH677bri=b8Y)^STEojpafae7MK?u%u#{lMb&8&fZ1S>VqGGaQs$#5Sj$(#lz2a7_ zTZ;D-pD4al{HCbI+@F6yd|Habx)q7q@~nHNn6RC zXR4H~m92G4%}L2g>7o32tz@pNlAF>Kc~2#OrC_CKrBtO(crJ5>Qh`>EQoT|GSWtt~ zWw4NTB})Ej&)C2j?tm~Oa7aDqe7DcgVm{Apytj%TkOLc#~RLR(_%2J zS%$0`ELT>C)&iCj%bmq!tYWQWd9e1dUTgWY*oe%uE3aPBqsL-r^3Xf9KQt-|LTaCKBnRR%CDRJ0k|j9DtKFgx5; zJXD4=f>lhp87h|C5|uQq1{GVbBXBSF$l$1&GAtNt zxWiS)!A!DdY~(Ib_2lm4?oo|ZwPPf!rmAMBin)I9s#kSl1amK|UQ?aIh~U0coxzY( z`=-iNOWsGGgPxvb7dUnW^orV^0^DtO1P`kJYhaoa*uGM)sAx$)h=ndF-p`b z)K)QS)C`%8+;iM(TDM`m@2P!KUk46?!C`Z(Ne)Mg(}$zYxyT*B8O|}~Sa5VW)|^@3 ze+)TJoGF|coL26A?k%nd!-M0=*~59y_2xY0dNOt}o^w07dl;#(_T_L2I5nIKP6MYN zd_g0piF29b&A7$6$MI)$a^7*iaDQ>+)Posp^?LcATsdAiBbs3fK4P8v9(4s?w0f+1 zfqIR)8gGeKqk4mSv-%3HTj)7>eR;z*1RACqgLoDit28_{c4&BL_-h1f4CBRW#4?gK zba;u3YZ{HrP7Ph22``zE%FxoZ;AJpuc;mp&z(Emjie?UDf#xbr56vB#1&qnOaLpXe z3e6Hm1*1lD2Cs%On>UZQn0HUJp7Boeo8~V~h89~(OKUan|Ar5;fkuXh_GWbsw*g4WN>HQkvxqpC>Fv;%T7zH?*lKriBA7CU*vU+0x zBVlThGGaeqq{TEw9t#)=(-kQr;s7IIx+G;pJm3UM_P5?dz(|K_9pncABVm%2mjoCI zQ>&B_$$*i(X^cDtFcK!24a47w5b2ccZ@n3SkucqoG9nXjRyVzDz(|;6dU=5JyXh4G zM(V0p2)L-5UNPVjTJNS*ohSud(M_)sFcPNQQbtq(uI{D>k9s8Py2*|LMv@)KB0mWj z2@_6r{CEo9kYF18roSQ@;R6zwJLMzryVHP?Fv;?s0gQy-(_ay1;R90FyiI_Sy5>Cx z7^!RC^MH}M=Dh&;4p7(maThRBF=WPXklzFRx|`lxz(|;6ZGHzBscXIO0V8#-_XFUM zKwazo1Q-cZ3SIYSz(|AaSJML?D^4BQH^HKq4=F4zD@!emaDXA2k!(*!9aCICjlgg-fA zvI9JolKm}j8epV>biK%@14imc%aG3ij5L6jA$JChG>&cu@|l2<1hfqKEWopYgtQF# zT);?%v<&$_fRPMn8S;66k*20guL1cYz(`%oTMQU!BCUsf31B2Wx;*5|03(g0^^m&* zMzW=4$X5VH(xvkvUkMm#EGHI0V7q@GUU;Kk%rMS$H0gSgCj&;}&@$u`dP-@g zw433->fsS}Aln4gbxwN%-r7yJ6Yy>zZ#pmXy?~K0ZI&{^A21T8;ZjBf0uH8S!)RG3 zU?fZ;>K)d6z!9{}l9ojQK19m~(XzvUbGym%03+R^`vrME;6k9=v)a5K~0!C_}^^jizjC7ioA#VkY zbcvQBzXlkoiIyS14jAbREkk|-@N1y1WBCR!QVy+${4HRlB3g$09bhB{X>%$59xzfU zt%v*rU?fZ@Y57OMND>+&{|xvGrT5o&eg%w#=_{@K4e%;JQb*oE+6?czzc!8Uhg8nUO-*@Dj4w5Zn9&5kua%98F3tNb2q&f zz({ZDdXZlQtSgV1{`P?$;8~Om_5*ZzivjxsU8M6Om#9Mg0)%N%KPf*A7zvY1b^$O_ zSJ_3t-++!ON#*$d6Y%eDG6|f)y{69Lpzb)S?i;`#X_?G+zX1LT)YaC+&?cnlr_xvj zxffuheY6a@H(;cLv<$fqU|*nQT87*YFj5jNL+%e4DUFsP4*-mGo0cID1dP-WB)taY zk$`J}Fo`}$+gJzqXgAsR{;+2Q>J=>2MZOy_(i6O8G$iEVfRT)8J&F&2{Q^+e@jU<- z=@dPd$ddshVX}HCZHol(Z%X#pHsGdDgaVMP-;tAmRe&(b`d<~WW;Z<^;Qrn81_2(? zO>ZP%-EMk(z((Eli~(DA(-Q%n&`r+)@Z@fK(*YxOy$)x7!|KznEzaxvflpswu;1RMc`NoEI;faAL9#RE?1 zrY8ZM*-bACaA7ySBEZGn^hyCEDN3uRcopDkAWX8h)BvufWfipT9|4Sn=`$^>2aI(4 z(eK|VM}7h@Qr9}p06qtVNw#*K2aJSCR^COxmw>wV)eXQmX+2r{ZUMec%MQ|QX#@NK zsB7MKz(`%!!DoP<17VVt*8%tiEsLbfdkGi`lWcu^4;ZQIwS58nmDUr}dA|YvPRqP$ z*$==-m}J*Gd@#gSK$s5GzC;Hw5+@7Xe;R z>%o#ir44}h0==R2koy4krS$&#u!^Cu4gz87BW1)zz|Vo6(0M672KGTfnD|mg@BuFX z!u1bD$QJ=#OzHit!woPJCdF$~-6epLF!h1O7x_}aNSJ!lddmPKwYExikh=p$xnwZvUh;rcay<`f{0;25_%3I9|0Jtt86S_q^>ei2J`_?*M1QL zKG033oeApfrROXt2A#U z;CYu$Pu*nBxv=g7E&3rH3*;LB9|hvCkjjt`h8b&0&0085 zqG|$P2G|v-Yb;On>OqVE!ZecB8wq$S&<)yeATI)ZrJLRjz~8&+iIsa0B|w-&)H}q@ zfZqWfqsv1s;q@Sn0%00Ny@MX$`#@dWhtG^(2!v@6^$yn#7@s5GRgZWM_mc&}q)qE- z1IFin-=pi5ar)~n44$0&Kpe{>;^O2V#3v7gd)kwPq=E;}3?YfCqxcM667H4Wzs<{w zB)q*1diwZG?&<5htf!wJtIgk^Bmx3hZGnL#5fsE~3l1iUkPuc|Xedd9g|XVg!$~3n z%22{G3LWK&igv^O)aS~Tl&q91Eu9SaQ{UgSyu9u~Ma6cx%E}WdaKr#>JkjlAv zBs0H=R4y(inI$Epa%maKEUzS$tEx$64dm@bkfb=B6lN5WWO1>GC;^!w%7RE{a1JTV zEhWjaavt16nn%{uh=|%Fq_7U#4tmg+qM;6tKsOKFhgDr|vNTwv4RL;pG$^3j$xuAe#7GnEKNMGsJ} z*9!d*O$zrN5|OE?r0_7*P2x3slYHne!nc|f*3^*v+FDYG&#A7fBl*}q71R-vd@pYi z;p0d0{R2f{8zetClr#$q6A|GNB#ecKh>9ioad9FdKAj{o3VB2kUMJ*d$@1fv_>zQQ zs0eI{B*HOI6iGy9iHPiMlE|qR5jE0!g;+0)y-@5$^1ZQb-SgCtX3&R!+DP?@7{;E` z7ZFrFXio_wk%;3_LK3C5B6t=7<`EHCJ~a>gMMOXlX%>v*9!~NjqDWzMj0m3F0ONuA z<4AsdiU=N(fY&5~=TMORl2RT~M%$1gj)jMh3d^cVGisdcdDNKU zQ)R_yi{U&X0{aVX{D6o!2<=eD?|emspC1YL1&8(okitM&zb1%4Z?Pgg*GDlaiG=%- zLtA8R7xM@&YJQr-{De6XM+)O*b0?ceR%oao+u&?K>5_X%OUw-_d>9HK3toyq>|)A8D`aJBWS~oxVFmK?# z+B_l{uWLWakEPlH{hmY$lO-fPhlu2-rjc+jb&{W%PZ9;#S7jtM2f;SrzU!pW8*R{+ z6#Ds-{D4qWNZALD2h~?3Kk*gna@sIh1Ac2H`Wh;qxG|H;?e4@<5w_Q$9{=>qM|@Jft>3#K()k zPvJF+piNzTRd@X&5j;x-?4n#mRG|N*=P=$?S}Yd9!+yaB`-upD^l!4Vp>CM3gjhB| z_KOJUQzBj_$1%eGNa4YQIz&Vr$ie@>GdXx*S70x6dng%I?}WChI;qW5*DMBmg*^C# zDRCZ;$S;69*HdNFww%a=@+Xe*_p zSy>s6D6bF^l~6YLLPAXGiHI1~$rHh|UC3|3NnubFX%>yXY#)z^i6vp4@`(5YB;30n?SvkaY!Q)zehB>v)dsY8=xcwTTtEPi z2n;?Z43UkiwBO`#Zo!@W<;3)LQsX4GOSu5_#o44>4z44G(zOfk`Y*;lhJ4gKMjJ~Z zg_2Z~e>j5_W@eH6>|7C%S4i@~cL>1`@k?jM8Uu044qKfi<&mZE+ASzo)>jdlk1mq8MlnLHv(+HPS{9Zx7* zkD+g1-GFO@w!!!d#XcmT^2_KS%Sb+~QNoJ9>kS|680?Dw#~=8R#*}`DhzO6phR0y`n zhc#4KSWFsIwph!f#|N(YFv(BDGD=B4*rl+dQbbgtpMmnIIfmnb@lhR*T33{bQEai; zitXh!m+kGnk?rFX#P;<&#P;{EW(Nf9mJdW95s@SxiRQnKAsv2@H3!8 z*>3LJp?P_uhUMq;;5kj(hZPnU4=XC-QDw+u87X2yBH*kwMwAh{(z#!8g(K5b{xLcP7XS zwzL)EHDDjrlV-T~QGJYl8+{tKKa&JKx@`1)U3@;}1EuRb5g0C##sM;)FY_C+>p-7O z_ZQVS(IR3Wbq#P$=&R62Cx2w8;2f0YDbZ9ZrTpk1SoaK6#774~zZ!7G5t_Xt;d2i- z7sho>4#!$7T?42#VH@H}VM5}=Q3nn%b-;%bNy&OTRM`?(zo|Sh59(LyNY{JFk8vEv zLq!HU#l-vysB0VjfX~a~9;Pcuf|J`lUJx2dFh;8B7UJwtK z^=|_o1?#rrpsK3l>mZh<))C5&N@Es`hs~%xQ!ptE2_cD4ng68x3;4xc(ku_xIvh)! zo6@$)iHpe|R7{GoB;7W+R`h*@H~JaSgSd(hKGO_*pwJK3tuTns@VasQagD*a0^_hYA>}uy2gGP~jSUZjP?Sr*AnMb71eNFjjjKgrwqwkmbyK0hO zgL?vcEe4x67KtefkyF-AvwExcfh``}*0D_d~{ zYeHno*a?zC)&!JMF@?;gWa}En6zDf|Nq$})Y4*og(e_2n8ETGo@weFSU>*@d#~nRz z9#B4E@&x2PiOG}2F|3LE_rIDNOUcK&NabVai+#gp`T1R#?+h2>%ED=PB0R~{V+b!^-v_SW0wvdn zZ36c}=s)T8h1wrcej0qwL5zpN*Gfc`KkSA5hdv4SL0A`*N%cFWCylrM#PB#*aSf#V zo@x)4g=2(k4dkV480Qque_UtL|6qHm7)iRmQ~8ph{WxdQZXq94hY##`asPnr!SxR0 z3}V6qalokufe{lPM8>f~;!}o&NN{bUzJvLKpUdEpnRML@923+j5y5kE@w^4f zt>KXv3xOYka(HAc#>CS8BPBRr>UmT>RC(x!Yk4I2IqF;n)+$nrHW|euqoEA&A=2|D z>~CsM0CNg`7M?9(U&WB*{x~@Qh$qPetQ+Gqv@tqX0DB_ERP4tiBXR$TZ9T#xG5&+T zCB+AMWD>o9GGzCpbS2riF1vzBfJJLQW?&Nm=L3qet|q?h*6or z!92wf^b3@|Nc}h15g)EudOn0}KaP#GFNCnKgf$%IKKh6#9uX}&>!HW(UwaJP$Kl$D z@i(4@P-kYa7eJe(;}Oblc!>yaoWEIcwuSSB_RaKp8{va{L#h83!amE4KC`3tkxYzR zskocu!+8jt2Z`|fl8B_%WQZ3qCZXpT*u~%d53a4~FX~A?eJ%s*G{kvS{0@6&jFG}f zKCIb7>Rg3dn{dwz@iW>T`Y3weNv%6kB6yZ5N$kURO7})^_C@X8jH$gF#vZu7(l$cn z!F2|G5!xZfQP`&#BP5~UB8ikN9-Q^zzFZo6Q+_X*6oNnF!=71qIGZ%fk?pU$u4lL& z(_==(MP8&C#Bf45GvZS=h5dx<8}^gzYz?mq&!Dj0Ln0y-#+!;qWMf!G@}=VkF$Enr zL2M&E>y(v`Jew8dvqHPE44$1?+j(+q2DLjb%(7he9 z^E8aF=zNr&U_QzY;B1h(E{ywN-N1Mf%AochI3HzpgnL+wgUU%`>6ss#H__)9lwZbu zD&&*KC9*Rl=y%-rV{CyoN$r=Z^9rz8I4cBw>N;gMAUgw;**(2BPqiiaYlF#92cCk zXv6;=XV{CuIAeS-vt8MK0pn08ml`i>9fET<^sN~GWs|}j*|{vn>0M&#f6YT2bL{)`?Q>g*PO2axV%g^^N! z!QU4{3gL{29~(=W!5NeEtW*|j!1d7UG$FyU!Fi4G7Ts^ux>E?gfj)9<^px*DE%#psu$ZK zYr}qNoJh&hPGxfJ5BU7&`lI38;V?=)2HwmV|ZL2;5#+}I7zW0IeB_TN=ib7MAD=3(4m!;si~JL4<9zEN=xJM z(=&L&O!PB(JUFWq^(?L7QRiOpJ0Sd~1!wubJfU9*j|hdkP3Pd))*Py;t$ki~PoHoR^di`X=zbxId8T#Nyr$WPfZI<`CL4 zef|daC#25Tac!>g=9^ypQk=l~*F#0&$ z*JGbUJ1ASB`~~_KlBlec?nNj$&VBryjrz?=YIBqv_qsU8aDAoc705~IHz1>+AdAte>A=lfS=LQ$WC_Ch1x1;B%3YR_CJ7e_`F| z>mWZB$KjfTGMP`NZJe5~U2Or!3H9)LATM=oIKK3`6?JV?90z+e>_60%)ghBpzNTCM zpl#9X@Sid)_*?HkXb=-83!Kiv0X8_||!?Z!Ee zzpDUd;XFiNRA@D@sOT)5udIaMIJd+8YWl#kvc&_-%Qp_JsPGzCSs693s_M|dYP2cH zNBNZ`X{takBckH!z-&7x7XBYM%31NwI6}}szmudvAD-uFaOqk z0l|xJg@hb`8yf2p6Bjr5ef;4qF=-ixK4j*!#^mM>{+O5dF(yCX>SIBn=Ki8$ua715 zqCw~zsJ7$v!)I#GFBbLm@`BhtMbs0=56)3~;@%7X9)$Y)207&PJSP5Qa(=w%!pbuO zZlGL0Qqmgntt@=rAnUrl?EPM9^1kf}2N#!Y%8Je#IOE#`7e@PnV<)~QN6x5>%Y3rU z^@V-1XVHgwOA_~8t{)j0!h8Qx+o>~N_(Np&+T5noPG6QS>+4=NXTRg8v8*>ow$JxGYLUA4K|#%(P1{w+jJff_d3|&6 z{RG$NE1yjaKG0WTdyM??iqVoAQN9oFt?_>75ckz?W18WaDHX#GXpuwu_WfBIA2!)` z$HPaT2eI2fzTyA!*t@N0Rp{DqgY4-Ggk$UKrl!Qs^LtH}c&k4#5N{ikKg9k>sr%@V zdwS;!2Twa^Hpw&3g+J)KR*3o0zB)teo$l}Bt{(ra`c6KpFjYT)ZU5`r?)pu1d**y| zMSi;|bg75`>Kx&E^Nm*n8h8Vz7ye|gVC*N(g@&EYes|A(Sl>F1oI}mApReDTU7bB~ z(Pw_e#2#xm$N$>zneIDwfw4i|;bg18D2qL2SDVwTxA=SKO=8UGFle6d6lC49Pci1w zi`O=rN*+jdH17}c`l9sp)RPw)sssBt_O|~1;?SolTer3i?{hU{(Sa1sH}|G8ZI}J= zMT3Ga8hhKvRS`dn3|!_fTvz7ey`(sF!KOjU{e5!uKL-td;dbP%u3==>smDWFdu)06 zJbmZr)>@k~&gXT8!v>!fme`LqTjr8ev^tULyKZIevE+m=LG>M14>FFkhBeuAY+xMo z9J6j1)7Ihb$k_{4MKgLCH{D)3+h6BG?7NpAdl`}PjYl{ZuSRSU9~rko*l6qI|9N#> z*t3n%k{A64w|!sLS-Ru!o;i8}|Jd$ZI_gG^e8-}>ladR5uJF*TsuPBf3K&|w{{DnM z<~>{bJek$@W&72NE9tqb`3$$?7bDj2w#EmgIYh+z9|@>=d$Kg(Ud*rD3w?y+vvNm` z8duS#q11nG$gwvm!yJ`rZr<4#dUNvQ1qE+jDy;7tK2mjNc;U3gNuO?xd3M$*wOF9> zeBKU zrH7v)7k#W9Hs!^eecpC&{HDD7#H@O!Q#g3|E8`(^)?_{?C}X)7e(aO8ex$;fb@rDg zzluDQ5_WT1(}eB5x6{shOGcL0D7;l^A0HRDjMKdL@EH%cY{ys51C)3F{1tnA;rSgZ zwdx0-JsURl&XM{b#an;pJ)ar6II4JSu_D~EsU;_cJ9O3S>W@jS{X=_hVfpMo-9O)U z^~g=~6Njz0y?pV}j<153Oq;LEA5GbMYL$;$^UDL4nHTnbwmPWY>N#QP_a4t0RMd`d z+cLvub@0_$ueQsjzR%9twmL|i>2u9?mVT(!gm~xHS&ggX&ks?)w%Y1-)U5if;Fp#D z^+(4kKjEg~8l$M-Ou-+xEg+WVESnQkeFP(G{m z_3Q6a&4ecpA4My5FL9A;IZ;%7^$7w#7cJYS(RMiA4Rs zoz~l{xBsrku+{Dz1|uD2{OGs$wZ-n>mQHzMnT_CIfx#9ity;muSEUwl^iky-R zXO%3u5tZ8OS%&Ra*A-K=A8wgy5ny;uKJ}ue=0>@PIj+u+SlK--0-9|9ab@`=y6BCZ zH~mV3f6OoD_Bqd@#H|AoZgPA*vP|kH$E|a#XbX1#9l=eH;G7vd*qr(OQT$lZ?@jZY z6O@vU=(|7J6~4D$;NBJA#NsI@UmX8Eu%AcDkX0#iCWi*OmAjYx9&va|K%T9=O~Bc# z8aE>4_uGlu+1E9DYdrs+U1q-Mgyq)tzvNrzR7 z><&5W>=}Jv=3Yrsk56l@f1I=3d~4kIwwS5Da>o-$=kLE<)S|wb^xm;#n2p}CrV%xJ za$O9z2d2z9(z(z4&AmDLx*;ydCzda%G}y9hc&yg?9^YT(6ep*SALbL?x2X0`)A8-u znhWgCg>(+ts(rBI?10`cgD!kiTFBkv8NB~c^iKDI%U_DWHXF|8XuSI7SlLJPR6OEA zrMK?~t+`p-`?aeEMiy1QEV*=fPJxl)dA$gD>eHPknFIY5UMKh|S^g?Xy!v2YTU6%q zv#W^Z&CPZ9+lH>4H>UPXTb=bH!s^hq5Z=1LO`o5Co3qw=n<&chd_i*1s%cx&ObQ)V z#72JnXYZ|^vDP!rGJMyL?Xh6T_JoK)AG0eNJIVGl+q^#BxW2bEXDKrYNz-a~C>^ZW)lbR2WY(fzRg*!{CNoJuo>-x~V%R*c!(kfPZ? z!uv0}IESpfMw*}UoZVb8e>-Qq_qwK~$`eC9XTI_pTF&L3OI7^2yJfy^O!kV@wW)XS z>^?VX*L)iTv#(d=loXXTXU_jsxVDc|k5fBOKFDYv9yaq^a$m(m2dyd+4H8vTHWWRt zYIK`;w&&#~Jx(0E+8Ekz=<+Z9TjpCYx!1P+i|vo=QJ$g$kF7s)erV2(H=Ol-vSEyB zL(;wy?#_SKTbvxd-}4KOEZz7y`AU}mkDoqrK6^jjd{H;K+@EyL+WB+ni6!?v zF1n9Bo->XU2(x2ZI@Ewm)vy|5#MF zH7D}J3EQy_nl9g?JI$)|G+WEwesJnHd93E$zFSVc4;d@3#!Z;NM6%8Gs@vs?H=Wz; zTIU_r-*rZ7W6*d1$9X#3c&7eq$z=0_CkFGcvh#MZQ~bsI6%U=CyU1sA5NCGp%XV39 zH51QTZZJ-}H2Qj8ivOI;@y}cCj<7q-ShACGe#p$NKEI=^TZ_4q&Y1NfkB%ATvUG37 zKBwgV3u~GNHFa*?w90(o70gyV zaChjnd^68bM(@sBVK=X}i<#HcC$*pDrnOwn`Vuf{;NT0BT2dAq=^xgUdF4~~z~w86 zK_~1zM=#spdp=b2aH&o@zrBU;B67Gf>22fDgw}lz2j+S0S~bm;Ey=IaCC(Y&9>GoR=lA%H8hJCr z?ATAn<+lf$mSpr_tK}3C>BO%Kv>Rvp^H+eN*Oc(NiQ_ChHD4ZdO8z;@((l3B*P@yW zSNe>wy?bichwvwJJ4as{c|7m|fB($S&2xJ5zih7cuHN=B)Z%VTVvoXs;|*u5di3;~ zfFG`5di;3eh;t{N*xor5YI&qMA@FVWu`dfuRdYwRS7vIeEczJx^i9PlhpU>K@1?8V z=2Vp&8JxdV{~yP`YO_?XMRDElztDeKPuye`H|;+=thPC2^*-y&PSMoq^Uc4TygvIfdEBIA`(=J!>-nD&KH$Ba>wi>X>#lvUQ)VR=Z@#NR!=u7P_9aEN08&X$j za@48P?(>BEKIv||hpx%H?Nb>p2(1ZO?U6aZIrhZFpry+Mmb%&N7*o|gdhIGp&aM0P zi@npCc_!7xBlW;y|7(T|7d{`enNjDrC1662pX&a-j4Fp1t2vB$I^%h))sOhhQ@zs1 z_-nd;mSi6OG2LwMrSIBLZ*Q6$pLo*YiMhJpYwwyDZI>@DvN-w2VDJW5ZrYyRC134s2|XdEQd{TbS|sRY*t0uPX;se!gAYnsO{+_49G* zOMjj5cHXtFrs;IirpCiNntz(_T(Y7sb7kGvDdfBi1n!p-tD#VL*}TzjVrDF zv`jY_2JZT`=9w*GpJ~*yXJuQ>yp@K<2e2AY}ROIF1jFi?LTxuRL!iR>d^^atSa&E zoUHuv@|9~|#eMqyK=sL@qph6YLmnMp@?pR?%dn=1gK?*FUw;fM*;SnJC4yg9>hrTA zcJ-#>d$;Fb{8YLtPxAQ4(p`2J@2<`^wchdO!s^HDPxY)ZslkoTXD`REIqshnT{=#! z(kZ_(Yp24|(;J`JZe6sab!pNK56Aqa*ZbM4g*fe6Bfrospyj{~bJpYd*0J*soNoMN znth^SN|lU`+iB3+^JSAr{CpVyUDw+EPHdrz~RYEVeZ1`C;bBV&rPnrrBU{RCwK0)+5zV+KR?Tr1@=BPJf)#-#x<|3 z%RkC{KFC?<_{L7S_UXjb849}&+a|Q$9y?1}l(u1g`aa*WPn!1n&8S|jGVQ{obKzC( zRVj7%Gcq&n)YFJTdrF26%v8vayLe`#a;Q6THC%VwrZYp&FYx{*P|+0=K^|taBEOB@ z`zf{h_hnOfu-nw8)%x4N4k$a9bu_^7jOwR{NBq66R}Me)>+JOpV|O>*WEp-adLpPA zno`U1*xt{4T9l36e2L|gSB*MR&2dX6rEQ7Xy*aRDVfL4rJ`XJF3;oaTYIZ1paC_x} z6^j#^^Z$AFy|3H>?OQW!8%|VPS|@ls{Fd5al^eOd^nl|7Fc#;mmX zCyf1={L*|ND`MXU+v;BI5 zK4XoZ?Qm-O7ttdXO>-i?%tgj8y{LG z2rt%o^qLWWFLq&~@3z|!M@6=4BmCSgVt0K$mOkt9rq@|cY1`F_r+4!c<41Td$=W|- zK5Gu|*dmv?$M+OF@8Z;El&P*8@TMxKaO1tC6@9Nif3~5imwIez6H6i2ZScn7(b}w^ zr{Z=lGQV`jrFJE&sAAQ$U6s2Nt3u_?M(dnZo%h(fBtJTQ(fh5Bdi|5QBe**J%7D2> zCB|=D`Zc~4^?tRyB+y;=)IGa3s}CEEi(2@s$9+wSx!J_LAwwD;9;q?YTO87dWHA@S zz0BR(cTINiZj*w+PLZJobx&hmv`;&~x^w#G%yGB2T3wsAXUmp(Gc`K;1wOC7*m_B+ z{qE)HO)C?I4$WEm%yweqlm+_(wq87ObZq`r3pJ(JW^Y~V%ADM8#f^XI8{T@MBRIeK z<>I^FF4j#Pk@3#SEBzJk-tw9llL`3)id(KXZwQEK=@5VTVKZ?|X|q?D+~n--KEn>_ z{m@wOd7*VG-$tT7=kYp43$sLnkDo6${csNCtxIYOVKosx@5%#y?$&o{S(>_FtHYkQ zsLD&5lasu3dj4`U+5drdoE~tq4nd_mCl{FHcylE zkMsR_B%@#Lhro_LYSBx{_9N|rH5VT}*BhO_cz?xirvWcpQf%DD34WU@%it_>RtRcF;CIp&d{>z^+k+#>B~l{v&$x0tB-qdWx_by$^gr+=K`m#S3G|t)Zw~` zX8OvA&%bhpo>Th$qOkAeKv%ZyrtFl zR>RL9&5M22ww}+O)OTes&q#s!5$hf8tuaThsT3b?a7?t!fQ7wKzRt+sxxa_-j<`i- zh_8KL`@B<`S!q*5>WfcY8NICc!#Ui_OV5Yvk$L@Gmzv$58Wy*X<8yd}IrDm#xAWan zw?kcVH!SIf&ve7z{*6Tk|Ba`e_%|N<;a^xB8~-mn=t%v)@W|Dj|H5D8_IJgiN}HOl zST+6Xv#wa@sc%#lEdDU)NqHA6(aT==s0;3O^laboF8I{ABdNuIu?QkMrF(zzv!Gr> zP6z+RZh5C(Y|H`}?gCq0S3AXtM{J~|jnU-2Bvj5;iug*93ZMY)C5?>9` z;^}jJW%x{b@5t)(_31Kfsxs)qh=_B|G#2?P#(ddkV(CTWY3)kYhSwD$4$(O6-jwCN zE}VULmd2A~wY?^YcCG&*#e?1?m2ViGm47Npibt-Ie>BOE)7$8j6bnu__H8>c>%Q+N z3XArRpQpCQG*(GHk;1Ae6H7G}&hBiEJ4WHF{sRWxcBt*sQ1=G0*j7XRLm;bsT7qXR zVu{O5uHK7j57R6)jvyv;Tju{9*4`(4YVQ|_+nWx#)*H24th)3%8lWiI-05w;d{6li zjk%S8FUnsyxVHCco5rHb*ml6FLkRE3>*sasY!>W^fZBq`h*R%|yno!s`{?{qf*6!< zG)Sp+9Y6Vyo323{LFk{?{xE#PgnM%7N#=t?;XiNpjxOF1du_iBTRv=5At6#*=y_Lp z{G^>%r`x@Ge~UP?>ibG&V7khMq3=g~-UuXiOxV$j)e-JYbiS_G$IcbsxE4PlGRbSFn!IG4AFSy%(X36pC6Td_`OWw zVav3MEf>=U2kl_L{c<$L_LUbW!pobrYIN`akG(g6t1)$ zFC$YF8KS6^wI~Wv6on{?vSx@v)Cgs48B5kF6S6cimMLUp8D;Q0&wcK#TiW={=llKt zUjN_o_B`i(-uro<^PGF1^W>gD)4va1$epHpt4;FbI*)|yMepBimL5kvTRpqw^5Oc? z-oM(mp$IW&4d##^e_9u@VVGO^Eu^Pz0pHMQ)b_W@l}GDjBi(M6EZzF@FWn2}je8S6_y0c3(jd-v3S6u$%uT}9IgJpNF$KHOik^kdK%@?hKPR}p?>YnA_eB%Cy)+u{S z_Izjb;g{bmc20Q_^KzbZ@uff4zSsPqKglz6gU3)-*65E9f3kffZ9Q@`zLIw&FLv+G zcPD#HyjVQ-yBklhT72?q4$Ao1Po~v!lKyC&{N#yEQ}*qfet+ezU8QWTidxeb$&Pt> z=Q;bXjw~2A_2Ev(G1nh!iT`55MGWwQpYgLTQ6p<$hfA!kW-|R`)*q zeP_kmq^GxjjD6vBe8`UIk9Yn&oWK9Cbjr19)D}y^FF!N&bWh*fzjqz-?7Cepq_;zF z?lU<=y8!kaNZcx&#-NT{^ZaeRgPtA?mvqhS&EI zLq9&bdKmkI#kiDFV-|#w&yNp1v{Z7T%&9bNO7u->*8ErT_jWYfi?0f0Kcm097+XJc zJ-bHlLWJuMpM97~vTJ_63&wp&*y1u|D)m|T!bhjCnU3IZ-LPzw<%wT+I}~Wey0vRf z{3UVfAIZ->)?PwHP}k3onD_Rw*#A0vRerM0q(6_xoSK%OTqHSr`-RK4KNB9tc)qMY zC1$j|_HVv^ZYO8+Io`gXUb6h+#?`(mJpTCkQioQ*UvoF!%PRGpm1&|qBl>TJ-PO^^16p2(1&(D#1sVpmYH>G!O$M}|Gme*R+IQ~Ei?AITfbU;JSg zbtKBzylM2i)0;z`exKKxil}>#cw)wz{Be>W(pND{eq4$Rx&3@a?CH|xS5c+88?Na1 z%%=U>yk?GQYAf>2{d-F|Yp_I%@^R_wK3U6Ga(~+%@|V|$6OFBVtesN>N<=mIIr|0M zX5_Whp1Jz)@o$IjW6n>%{t&&*QZN7X0eYGyH~pyBvb)PYKTkh3Jb!f2l!B-T!Bo~0 z-e<3uismZN-5V0 zC`8)a^g3_oCMsSuUROI}H_@$n)$PB>MIUNjvmoAT65cC1WbD&|(q)=c%WeiD>@qf< zH8(9hQ?N_##KhH6rF0HGtZ5iZl851e*FEB&mWMx zbt3sEPF_2l$<}`SvGCED z!$~(^f4Vu-_|1mUF}G{9VwxzC<0ch7$`@!Iw>H`q_;B^wC1!tLpLja-Q8Tj4^Qq|2 zT>ZE5+ny5w-+FfiCc5!1?T%;1z9Vjq z6PMQ&d!ldVjVZ7n|(3u>bLf4XHV^ zohIg8JU80rVmn{EN~$;i^6EFoWk>hAb$pmLnuAF&`Fv|Z#qzk~=q*)#(}Zd4x1XrD z9vWO{FFzYSv3gSExbo!M)jzzf7DT)WOKSMwGT;0q%09n7(frh=j@#Ee=s_P!(CMH3 z#(ii#X@7lL`)HG@+~rZHCYn{1v@Q#4TR3n0hWq6^Hg-%nY?Aw^y|sWD+rHuVl}^%m zVewTHkCh;Uui7Q?pRM+;tzm`O}l6slvLl z0RsU&AX4kL5Dty zYTsb?63?nGM_qrrpt`E{fri%Nw;m%Z4~C^!^5;gIG=xvRXUW^PN299n)4l8H__Yfc zuRpapEqmvXOU}QY^$47MXTpMmsHZlU%m3LkwIhbTk|5i6AnXwG)XS~Eemv$WD9I%7 zgh`s!rPI%OIvI`KHs(O)58F5W7*}xq-H7xB?;eiXZ<{~GrD%nYW5NAByu%tXW0x;+ zyuP-0$mP@Z0h)z7J!VF1C!c+NqwV8g20xYUdh9oKyZh6S1-~5Kme;D?NZmfsX$2>2 zPF_WX*Uv3`f@*OUl;V&?%0IfF$3AOYS?{L*Y7g=DMDUkLbn7S?!Fi!J@?YU2FFj=bpWnQezk7@qF^F zoHal3ISb#6et0}BCdf#-=I=QVvYuaAFmGn=`taOi?#BweR+k$gHr8HDvOiu`G$v9$ z?%+0y)Bj)>=Hp_be{DV$V0IU+{rLl`(tyR;7v|G`$-s5WLTJyuaP^X`7`NEuVbIjTbla$2aoB zf3HD5x7fX4!i~+>bgsk(7RJY7qLQ!WSzUBP8GlZ{vAp?wID#&B);SSfn7Dl!;mMB+ z7M>2Q9XV~-FT`;dQZs+Q5?nB6k7rn_oejmTJ^KjRHDPkm%FBz&+zK!JyxC?K?br41 zug844J8^wR`@U-Tk*r^iy<3L;6lnAQ+26sh{pPGnvPz0O+c;XX@b!4!rU~Dfg`5_Q zns;+=bI74r8Yk!eo;drj#&9NuJ#~&|>&_Q@hwk?bzI;FP=_=>*wZElp$g$<$8tR-o zv&rn59nNo0r5)z}l_P69F6LLAIk!TS`R7hul55VUEm}J``FDRSBV~`+NBQ;0NwmSm zkR>d?(2*5dH|fi#mU@`UhHG!USFz(^-Q$e9PtRK>=qJx@ERNl^#(UDR70!DN<{g;G z2AMhQM_n}ruAM=#tlo1*FMqq8@x z%Br@aSN;cf5;7CBf4N&WFDm*VqjcxE%bCw_RlGHRx%WZg%uD+t_@{2ZF3Qe-ZE|BA ziTIK4a(~v9LyUK)4!y;{{BFcQ_p>%+e!jQi^~z=k1BQG19E-P~2m0{Pi7y&Pvb)4tD z*IRe#2dxX`yfFsT^@~SlzZ+(KqWsZ<-?PU2U410uSCMFo>yejP`&N}1SIpJlzr0ZA z?5{uWi_0q&&)d1q^w#5=KVSc{I+*TwCue0u(xM{sQ7l1n0XJ1^0lXA)!)ydbTkNL)Y3XvNyxm9qLqo9XK(46#bHdo}HKl}ScsFxu({YJep`UBV|-PO+$V{iKgxBJg2oQXBt z>VLiGj6LsO=5y`gqL9N2&y%nlveJ)kxPK=_|vi!KeZ$ZmeTi?R8y zAE#)CnQMNGTl{v4_O;*6JYVe?C3Tqc^Ywdej(d=PZS31=575|?^~g*7bb@@=MuGpH z+aBqrBT|3fy2r29_rx|yE$!yh_xE=WO$*rSx#c;!!mZ})yRET{`() zd)b|4dEUMD<%j1+OLx4VyC5`RYTfbC_C-y9Ht9`W=tI6+o;)SU`Vah?@H@kt3Pjhk zCx!kTgS_W^=mTTH71u&}!r$@J&ml)oxVM#bdC5ggb8(gN6pf~zDlkT@QFC@)s3by}DFIH@3Vr(dWvQeOWJjPv1QGTXD#e^m*eyp9*f9Het@{ zR$tC=?Y&Hk&$FMKEt|XAJZ6IMAH%wR$)C@S{%CRW=)~%VwG+oJ3kqFwbnhbPDucI{ zzrLPlw(FVAq{np{*M`h4cll*FOLq0Alpn57sa=|wc70D$=m?Lc+ToUGf5tZ5iaZ-2 zv<(f~v8UtH>!IEaYh101wx6wtxfoFS>92R2MwNYkX6*{=DQO)ythNUioT{Bwcf0a8 zMCkf07ZKjimzt-O@T2}Drq~=i+i`lFQP^>#s~5w=ziVm$jjdHZKP_~*(v!2-@E%=Z&pS}#6xr-+x@(JxbeM+GJY z=2kr!v({iT_QuESdCQ&%_Ebgdn7lSScHaBrvPJqjzklB>2QOK)tnPi6Tz8c>Z&h7( zVDtL}k6hRfw7gR^1I)aS6zR=xxK9_1d%US|%H#IifA}P{>}es=$FBYC5o*3AD(epW zaX`eCx?yu&ZrV63LzdT$3oS}sf`32i`Uo`XQA%U#-yKE=4`M!Khtb{A&6umERJ6Y; zxO*<~opgPjQBwVZpLG|MrUcpv<`L{Kl->4gsNj;R+3R)J`e2u7&c1MMh3?&v-^bfO zD=#?z;~##B)y2;O!gl50iYCdAt=_VgZ}pqijh~A&ez|aW$m?4v)veo?BM39r=~h&- zUcVfvJGbS+ZUkwC^>p27w_Z+fYN0=tUU!ZB4Y7<{_$2<1D{aQ+%Ts<`LOk=wc;CsR zHJ8qQBYRx<%kLw~wv_!~KTU7)sNn2-9NQn%VMf`;%5|V z{Bbzvu5eqLKp#7I74gFQhZ^DY19zO;Bc6GFRO{tq_IG#6xKV_^hgf0my_&aVF1lv7 z$4u9Vf;JcIXtTgc-+MS*&t19h)9IIM&p)j+oIjOIaz9>T?fmMk@ZNCi1(!lcJ|R}L zJUE{hr^9xV^A;a@FzLH+gZu?Qul;lE>e?SPAKjk+d)2H{dCx*#9r-)FGCS*O$z|)^ zcFyY$9oSWI+{iYrF!xhR);a1i%?9d^C1q!?5gn3s+iaOn%J%%Zn>0!$dGaVLXl(VR zwOeb$M_qlmvRHdto5_o~6F*_o9e!M@@ofDb&x7%MukU|w)(RUr{8ik~D_5=YtwGLM zeRyg5l0^sBK8tDnYqJAt#la?>Y1{8^np=c5d69aldfMI9oI>{u7s5(+*>Bk=6D1jk zLNYc?A4Q7!&Bxc)>~{1%%|rVVz5ZCeoVfY!S*gFrO{PDYLZRJmd+Zu5dUU8IEmuOL zuVrS<*3L#tv?fOE`A}S2*OnVQA}Zb^dg@{4TCo20zjN$BKmZ*u*7vnH35BBa(zhne z8AxB<*8e#E|A+nICktN)d*2_vTtlV_rCfb~_;3Z~e`bI9J)QlHH6xob&Eka%gf!6_ z;X0v*=-=8O-c#r!tQY>j{o$26#Q%R_fB2u>;BL3;?0xXt)owW+{~P z`o#M*+P<@0;{$%f7I_1C5UJ;G?EVq?45^g-ilPD8iiGyRS%p;XzEj-I%KzJ+UOkyn zTIw|z@7ldwh5g^TKYgZ_P$x*|dz~*^I50)k^4|Am2ft4Jf9?MC(TM4Y*@$I`w}|%$ z9wrTufmj88HW!a1A;GIa#74ws!~?{3u#=q#BgPaWiV^z|hM1wq0|*n$8RRd>3&@X1 z1Zq8EH=rK?_v$a;Zi6U&XO!L#uWzlMoDYZ<2qf}11PQqYK}9lx#l!^}hu zL0V$wAT5w)NNc1WQigOwx+1?rjzT_11R{fwx|nguACMJ@FyvHZ6qs9}9_`t?aNRa# zDBzeVdbam||5~bbiX{NE6tKHeijBgnSxTvSmE|$>Uo20U*H~7YU$gwfK2CPm{Hf(* z^H-K{%n?>C=I<^GY`*nDe)t%wbtR4-2YjxLahPScwnC#SesZlSW7MZtgS6Pt-q7rm5rA+%fh68$)-vFmPK03x1MgX$U5F4 z-J0N??_DZ&a>%mSZoSE(*qZOX*SkXM;qbF`gu_{Bpu--EW7cIB7p%`&+_gS!anl-U z$+uxx8rqO8B{r9&Ar7_D$qro0p*AAR;WpZqHa7Z}G8-#PUmG(^4;y>S(Kb$&<80h4 zC)!N5TxgSMnQybwa<9!A%L6vqRwu0eZ8B}1XtXLn!4QaJUcTN1=0%ok?ZvW{_I%k^ z`(d&?djna${Z!dLdzoyPy_Kxe-bYq$FPGi3pDw%NHPM?tT+a$UoNo2XeyOa*K2i4B zK1=rAeua!9{ZY1e_+hJ`hhMb% zETuT)NF@%dq#}oW=@5s1ELb*;7H_OSNHZPYNS8SfWt$vOvTO&2Y`cTEWw_03%e6K! zmT5M@ma#VKqglg8;$!1G($~p1$k)?%qVE~+3*NhZPWT+~Ip%9in^!I2%iYw#lACr(|qH7*Z4Mg|L$Gy^TOx8&s(3zJ|BH1 z`b_aLclLI+a~|dF;yl**vG+4?b0=>nJEu`jE>2^eqJ3ujOmd#>9OXRU8M6P%`)}__ zPP3h&oaQU+FZ4G3_;P(sed#_n?t5(=+@(Hp_bOX&_uIB3-T$&3?Y_b%#2xZ?)ajJd zW_hK2xBRU9p!}-*rQ_d@PhGL{SFUvV2Unr|vlHI=mi(=}N&Z>>Oipyub~19(lgs6% z@)2@7d64{;^Y6}VHw!l{HwQN(H&3^XPTQR($rsC`1^7ubiyhwdz}CA;g}GTn#U?(o>-QR;EU z_Pj0M`GW@(Yn`o;vyZKtt*tE|#9ra?v&UHvl-)nJOPtZ3k8E3P33h9p7ud$xM%wDR zPqtmdewb#Pp8rrBKwncMF3)On1pmiuyBbN6+&v2H(tQQWBUP{SKB9(?C-)o9ab z2GXILYY_no$Obztjs_5d$OrU^i1k9qS{PyqB0>RBZMX26Mk%1j1N=DnW&@RD5zTI% zik<0JAx0oZ0?H3y4i}&_P-2t>%+?6RHjQUsu3m)v5gCaARmI_}nETfwa#aLHX|3z3 z`$kt&cZco}-6GwSx|ej#bbr;A>Hea7Q}>>3wdQEVL}7_Wq;MvpOn6hnUn^P|i#Q>? zqY(o9`vSk~5iLTo=4;^r#57T$X1LZnVHsk&C|ENe%-|W|(*^8A;|MN0^c|t^fkVO7 z5~@ST4#jnV%OZ2c4p)VRp7K)1`Q|C+-j4o|R-6*VJ+NA(Z}2qT0sVkp?C!5m?M zutKB>Rti=LvINM_n4neVCmMBh?AW9M?i&91DqD)biC|z@v<~q$>%>vEs zn!7ZMHA^*r(mbY_Dku_M60{0fLJgrrXe2ZhMry=p%+iR{NYF^qNY+TzNY}{J$kON# zeG;KGa2g~Hng&aQryoa0D44oDfGy zA|w+s2}OhwLN(z$;ToZlkVMQPUL!svwh&v1pNJxo7b%bwM@lB8lG4FG+&f9vNOwpN zNiC!f5{gVB+mdBuH?kMmpBzk%B&U))$TSLzl0(U(lu$}3M<^#L=P7lR4ho4Xre;wK zz<%sUsMXX<)N9l_>P_k$Y7XrV?Fp@g)=F!mbwq?h$6TnW*sqA!iIr|9vB)g7% zlikMdV1Huka@;tENKaI4+4x&5lshI1pi zv$(0;bZ#a$hnvUkHqv%<)^=#SAa)pm(;S?3;B*0}H#kRub1XO~finu6v%xvv1?cTq z0T(KPFSuL>*IO>XtIMh6`z-mL(wKZq{%f~(H^h#o zE>(uz6n1phcKi)|dN~;2h-&^mdE|*d%a9K{eH} zW47yjKwILv0$kU+ZUoouu6w}spzBdrl~6zB4g?H{mx}mLxn6L+?s^N>-0{2Xb;B66 z8QKzUi%v$%(9UQ#v=`bB?T-#b2cyTML(#wa-tm3l`^5LTZ=3IX-%q|6KawBAkLRc9 zr|UPw&&4gx)J>l{R9oStQsfA zU&AF6>u@c&o47nW3Ezl2k3*4ih?e+%+CC`Oc%8{QkvcPU;&c}1Bj20TLG0HRAZnW2^%xJk$<uyiS!4O>#x2 zMdz^2Bc0Pa?{o|$9ujAXrDUmuBhiuAONL2;B`ArXWS(S#; zPPn8|XPRV|#FB_3mryP-dIo(-W53{_pj=QPI3_qQI4L+I_(gD4@T=g4;HIEKa8JNP zi_yAh6Gbn|6#duLd*)_#W-eylW~0o;noTl`GMjI<#B7DxTC@vEKVxEl+Zyn z;d(k!g1-eFf{y}(5G}+B zi9(8yE4-q4SF=U4U6Y{2*D}DWwc7B&Z)hb_Qv!|ucuVG%~cp%uo)L)Q%XV775c;Sd+|YU6!FDu$dI(ro08)A*=#wNo8OhSe_4GT5VGZq?;HlJ?t{V-GG=%IGTX(n>x91|_`1ty6@x0^gN zG&3Jz9Av!TWRh{T@m%AKp_L}j45tj+W0pVkyvaSY#l|a)Z=G^tveT0^yDTE1GFBqfrcB^M>XNgha^OWsQ`x(wa#bjRsV)t#feNLQqJ zMJN@vXp9t15Y-7$nmElVLYk4L5#ESv^upwOk-aEVQ%BS;oFQB&93gzCF-~i=$UzjN znV>mLgc6Mx>S`X**r`#ck)&xZx-P_u9tpig$(oj;^Fo5iO|wHoBr?(T()^^MB{I`& z)kW!T5gKY%X%uPrYw8(Q8BG%TiBdIfM8P6w(JW0p(Lcf!!Vr;M6sKt@`Yg;8T56uu z7_H?fJS{vc{GeN)Q6uyhJ{1NC{}Rp?#tF$Hridf5)#QteMb4Ujnt8&BTGbl)!f??( zVU_St-G{mtG;eA?)_kLh)?#T%w1#WBXswoPlN^#%ORh=oNS;XAB%dTCT`%20-B8^a z-2~lK-Icmox*K#0boc9)>+&>{*qocuZ$z2`7+H!hDBs!xu12n4zq4P7K?Gl0Y5L?!ZNo^2nC-a(V*6 znGudpBHzKaQi~`o<|V=r;wO3}%b8t8?O;El$|z#icuFbV3}1q8#RpSAG2Su#*rA+I z0t*^M4bpT*2#Msl8T-f=9s!T3~0 zAmG#v2~ zZ5BO~Rm~~o-sH-tCbaX+D#m$63qwTTNsDCL;>}oM0*yc;n^E2|f=M`98>NNa!Ybt$ zvQ5aD_)sD=7ng(ULkfg-;C1Ow=zfeyMhqjF@rl#Qh+~31MOk2fMK;7IacntI3HH+F z26M-APjbyTmpJ3`$@m<+KVdwffZ$JzA;u9)iB-fr@cpoee2sjQ+)6H>T%xp4##6;K z87+o(lGaEIq+2rl8NrM|#&||3Bb<@INMdYblrye@9*{BJn8D0s<~1gYg<{39SZot^ zC_9{8#4cf@I3!LZN0%$(ZX-+hPe61acH9$u5#Ar4g|EW<5h6hhGNKo7Hi1rCX%(P_sgJ>;T<5|~OJhm=~){Py^ z_5v}FX9t3~XMwn%uz4JR&MZz9i2f6Y#nt7Sfi`4u&3MOnKk**(NH|NJEiQ_`flm>L zcqTlkUH{f`SJ)_Q64EqTnh~N1QD0UUYR%A!)mo~Rpw%U@$DNlV^cap3fM;5Llo84V zWs0&w*`oLeya&~T?8)|=PwtiO=Ky{goVD(^ z!1ccSAK?1Z{jK{4cccf~W3Bsq_fzi8?rBNJ4!08Rk70-y%KZ6!3KV0eUrp$P@UQ`A#bixSd2 z(meh`!SDhF0~t+5FY#ESSi9)T+qYnMQ82Wl+EMQS`~x6J2ZctVU!z{5J_8`2VOWP+ zhdN|%$Uw(X$MB`WO9QeY*$@MO1wg2PcLorE|Bj-7qXs7p?tuD7gSA>4wDPs~Y8}=3 zS?i3}d9BM@ceI+dTD4wlp~OrvPpl!<5u1yx#qMGs@ksFmahNz#JV(4=d|Z4* zI~^~b5ju7rP9AeTE_u{?-1hk0abmc{rlfur7sIu`+8_GqLhbj|t9Vn8$TIHaHkar5`k9hGW@m4X^ zrY)ci@3if7m%Qn9nxKx`ro6pt037M~OU zA^uamT$~}!0#??Gr;Cq>8^qtLr?L|d;%QTk7nlZ(5^WFdLERU8yMaHEquv(1V|pceWqQ8>xT<#-09GHXFVSz-Yu00&oK0p+7=DP(K8~ zWc^wCi}d65mjT$Mzg_=V{YL#;`o{r02JjpJ&p^vS-=IUEU@+9c(g3nCFUYyu)yLU{Gw} zYEYyfYp@A;iqb!uDV}q~*zoF=YsK%Vfglnivbbkk9 z2HvW40mMrXcwyWyOAt%IzUpkmQN(dX73L(S6jP4L!xUh$FgciQn4Op+Oo?J0bUtDs zVyPPpkj@eW{%qde}o1$q4L_JhYGw=fSW%D}_GV<>=`04x9`D!~!uh;mVa8_Esk zsRSPs3?oo5_@iJ5K*2BuH3l^nz<2-?0ZdlH6ch}RC>WwqFw8)~FdGF!914bb6buVc zFf2sDkc@&M1qH)$6bvg+Fl3@&Sc6&vJ`2{N)+>Q;#y10#vY8QpmD(${;S{BScaLd` zwcu5VHHfu{Y_MXS3*I~CgSFwUVAZ-1@gsPJ8%xvS9u_c`brN}S6}Uc>hOvWgn_+L5!Hyxh=pz! z5$6zoU<}W~_+tVw!I<%wI81_KOv7@0U7>dgQ3&WQ@J#R?I2JJ%yg~Su9=VTbQ@BV# zCW7}0OOUC^G~`O;Dr6Qi8@U0w5m|uTirfL-HxvO{F>*inn~rj11@ahpSBysCP@$Mh z;9YD3cz4_i{>p=hqM#sS62zCQ+y6EVy2nO^2SjL;8?J0Jy63p91_#|8V>WMECf+`-kHPdv5~^s`h7syH(YG z$bWbJFWavS7!+UT?`!lI2@(ZM1V0Kc2%ZV(LV-{$)EAm4-gChoazuHe0?{_nPEnDl zL{us&7ab8*iB5{DMdwAAMAt-hqMM>SqDIj}(GyXNs8!S^dM6rc;B=9cnC&P<|IBZvIdSWb!AL%CHuBRB^Mzmz3NGA9@lyX`*#e^`6T#c`y z@CYI%Sp8?;B+`hHG%>}GQjNQYqj4HZEx0ynXUO~4<)hVpXodH4eS5&S4#6?P}S8Xv-|!{5Qn z@DK4%@YVtpfkddr>JkhIW&}&Zd8{7+ddiI?#1Li?5(s(Vd3PtFoKQtLseqZhJX#&$ z4k3>BgwRTOM-UT9L>^H@)Fqk_&4{){XQCSbKVl#;m>5n>2T#hG#971yB8^Z-EFf+p z?j+_BONd3plf?PFJH$rf6Ji^&gUBN-;-&C(Nrog7l9*&kx`e%km66;4r1L^a;iO2? zEYd1o0x5|UNKPfyVY9$(wCwOiYTZ%s=m=Z&&=EYGWDWQ}$ zY!W4vl1WLXyu%hyc2X|zu2E3bMhXhoLivR4z@Eon!sDo|lu~9S4tf?BQO&4^)CW8q z&W&nI4Wy2zw(vr!e$+@R2^T}1MUA5-Q(yAZsWe;;^$jnN%EIlWmV&4Elhk(JI^HK< zBNfeWp|(*UQa@2?G%<}uj zTo!E`t$I(OvlE^j*Aax(DBv@6R{Enc+I<7Zi^XG!Sh}oV`C{-ODPuXaOjvHLV6gsT%kpFS zvjSQ5{NMR^_;I*6Rst)T^_ri`dc;q_CE=R+t^8!%PO$b@!YXA|v5v5+Str3-$a&T! zRvjx9cZb!;O2@T=_iXR^pI9h%CXU8FiT%h&39@iGI2l+YnFZdu;RQMDJa#F&ip>;E z;hkq!v#+tI@$Nt?Cjt$DA;*#<dAMyH6F~v)Cg(h< zm18cD3bx^P;&@zVK@rYfUf`22LVqY;#C#6#Nz>tM8aS&B$CX8 zgvOz9I8^6>BPou)osK8@0g3+k(WM1~rJLP01A1zq|K zub;3LaSg;DIQUN2iZD7aU>&pD0ee%CdN2W*@;`h)@pOg`_Eu5W|MPq(EDiS3&7Cp> zgVpUz4%h_41Nl|?L{fmf;ve!G53J%Kk*F996-VvXpVY5BdW{^m4_z@>EHFsRMMs_;Qk zh^cB{l>KwR5LYL3`d1Nqwbj!#NxPb5&Bkmar;_x-;5NL|wj%txoO4 zd)4XWeg&d3q{!u0=zXOqa04|N9FU^wZh$ERH1#Vz^)BA!zneEWfZkQUh1$({PXo|h zPm!6(OnNc~QCDS38L*;Ija)UJD#>c3FVRkSs=n_e{C5y20%c%|ko!pz%!1^5910ui zG)0HPgr34Z>*{KQ!FzE(keYH{0mVR)Fn^F@eHv5zkw@>`q?q3615gKQ^uYZ79emlP z{mXyJ1s0%D01g#TF$Q2#7Zuan2TRZX>8e9tu)pzfx+@S>Kwp-fv3|+wkD_djng^vJ zB?B5igB@%A`RSdfmYqJ(-u2+SyAR$V$Xy)_u+9&Ru9kzwLkHjt!dN#ESW)fTjr;W# zIE=5;Q?^bS{GglA8ML}LwSl2dR>R>4fgC{8$X|s*%0S^ivZ3CMeMbTX+1XG<=*k)t zuQGl`C@Q?0@YhseH(!;8p2CWSFf}5$N7QPHrKkbw2x8X(mfaAFC)?g`H6oq{9XMz; zPO%)PCWI@bYyCW8QqMok;ewL(HcRhUs2gSC{pY8w5bKpf($>;CWH=$_p>s4$>!ll=;I z8zcQ@VzA7<-TnJn>@y~{AbOQi!iH z%FqU--?xy;TAvaF&BwiGNS&(cdv#jBc%QNK#^~G9;QOF&8@+SX;}}>%UAp_ofjHp( zp5lW;l_h9Qs&IwvPIag!fWD#*f7U=P>}2;uz=}V_>|3Cx!dKT7rWG*`aQSM>DusTU zrxNK|_6(&bU%lR6`qbsR;XNFv^B|Ub{lAD0($#?Rd=YPt<_)&`?=W4bFpP0LgDGhWZs#nw;sFMfAf#SeI-6enmt?%?_wON478KusV3Py7g9KE;_8P^278F`a6Dni9 zTKYO-S5Q!s`ii12`q%mDAq~4$ej|ehRS*7uxeB?5T|f=*&w0PhZ;ujgKV*CW|B#Dr zv%$Cfgftc1te*S<%_%YkX~1K6K>2|MVE3@afu;MGfWm?#`s>2}E%d=vv{*Sb1~d-0 z2)fJru=WMHOQTDtOIeNkg=W75SW$WXig5Zh`USJgK7@V21_Y%i=5JFCK9RB&Y_#SC&w3e5H!o@aZv*dQ??Ct+3zIi;Af#l|l3rgNAAs3r1Bc z-&{fldnjXiK94D#_9XXP{}vsU!JZF@D*9l{p85mTd#?C(zis=kLAmQ+0_LjcxQF}~ z26`IoS?{5*taf=&yFnDZE>5r5x6cg9z)JXz;64nFuVv35XIz4Wa>H%?KgV7b!qc9}xblXCjgSemQGorw;-`3wU$_ zCsgJm^O5TH#ei0c{BOn-(anDYh;DIbY>N?)|6H(>jT0yd;1`wdgMD$J_^3z&An645 zl7V7_fC~1KAs}XUi!}`i>2C#eIHzgIkDy+Gyo!YEL3SQ@>4Ta&G$SGSh~$D_vGfGL z#1oH#d>dfkJVAH+PLMMQs?kmu)!m)Z#*ytV3J*dE3#hiHX_QA&oTOU*aIaPZGTRz65HLYm^ zBN=la^bjzg250)mS*1<Lzsn=+PZeiZsooYq1=c9tBXI@! z=|+LV0OMGV3Rwep+7|$OhvZ3cq`hCk+(cG*h2_;_Q&GCwp~6%>plVm=oz*SYE-Eai zvZvBkS?elc4itkz7n(Q0C_sR0LSq01C`XDuSIw#emxSS8#5EkyAaGDzyXV-d27|;( zv9Z`dH@tVL{pVL`F+)UT7v3u9#k3%i&mfp zw^P{{3aTO!paHjEsRwJrd=;L7JA-pYw0E{&!R^rkmA~FTdljG0Rthc1e~Qsegc>F`YJ0k%y zib&v+pzMED^a?r9PcWnqDxuj221PqMYbvUugzkU!@vqWXFM(xcl&bc@T)5U{w~GqV zV7fXD!c{t5xXNZ%3F`n^sFxMlhuaNj0?^@%^wR$B_B(y_(|(mNxKz&sjDx5Y5qvpM zcKPaxd@z_wue+=|RS|br|3g_&^gA30kc9Knv;7Jg_4cUx0LqubrZW5Lo?*Z0THSHr z3(j`ue5CXbeg3H3J4&0wyJt{I?Zh^OjU2kKscn)hZe}RF;Ue@ zMd_fp0(q52Em37(MInIynWUo0JF&!0tgI7LNvX|$I=O44Jd`4Pme|w(<|wTC@G?b-bAm!Hq#*a zb~=+`%&-7b0rW7soY8;?VO+&t#pcr?=?ZKtBZKi6o6jg?)G(SD?F>1vQ%TQYKolku zqV(M=V`ksH!E@xy5N0$pg=x&lXBIQhFdLY!m_(L@^${y&1+W%3MYB>^`K&Tl4XcUO z&SJ8S*>ZLWJC>cn=Hd$3mF!w}6T6+wPQ zUvVY80A9~}3a^aU#AEX1{8)Y=zn0&#jucpc-$u;_`?9?fNWi{TJ?l_ZDZ(;ggAkfo zkRm9m2wVuKOqh(b5N*Sq#QBL5Ma8085yWp7-N(gp-r_Pi#Uc~1XJw`a+^R|qRW2ZX zD!vfJUZ;W5wA6(8Vak#Kvg7%{0AI@)`5;NN4qc)N=~ZerYcjPU`%*0@d?kmAZRRv< z27_ODc16HH4bby?8jS{f4Y;CR$X~U7`co%co0q z;GGkony=0|LKvXevIU4lWf?%v)@i1NFa;oXB0Zn!iU06Nr*B zFk2EOSfVP%cE#Ka&C)6g^!YE51V~aOm6B$OP}f&CQMXvPL6@i})r;24*Q?QM*OSvF z`dUP(eg-2z--#FvcH4+X7wbyqz8H&L^SD|2U)@`Jdq(;&wl9)^~vNRfRlxkFBRAWRBjpoC40bUK1;4_*4gBVI zBlwkVG5B5WP?{70^$PR}m(T3^iP)g*S7>BGpJj=tXmkdumi;X{@~;?!@ci+uS647Q zfZ5f!o|a(@*-(E!&_qvR)zIbO^A?hU-y?MS2|;Br3XLm`dww2#YrXqZj$(Zu@~Zf* z1ljEB*X|>YYh+^-WE5|dYg7UDhk0wn9bz*iXh{5!T(Apd{gAgqxW+bMf5v#@T;mGk zE*t+I2F;MQ#!yUfZn{VJZ8g<5J;87Qz_JPqngob?>9+X@hGZMk+f zc0qRWcDZ&HcJ+2|?YQI_VxB}?YUALX^=Etnk%i4)=S??xiTABkSt!7 zE31&z%ihYk4mJ)!4)G4T4!NufhkA#%4qQhY#~{ae#|ph%#|lTOG(Z|HO_AnH%cM2Z zCTY8rDKnPIWg)UyS%$1oRwH{Q6FSHpq8+jwDjk{}h>lXnXvciVddD)yw~kyVQzuWS ziB9nVCOWNgs>knkI^k6B^uh`2tmSOuJkmMBd9ib@^8oRJdFP=VO`YS5pPlI3k^*oobz=&Kb_HoaHXrE=<=%*BV!$JX&5Wm%3%R zHMlX|!`y4!Ej*$=891 zgx^Jf*ZiGyWZ_7Of2@D8f0KXMsG3o}-{*fX3W{5`$`jgu(g2$g$F~m1AFx4H$y2ehl6+ zIJt6i?c_AqG}q?I$S`SGY*=wvQ&SWJ2B`qO2d>_Q+CUVQzcWSQ_smC%LArj-3;73-J+*PxTQ=j zo9Y{$=C<4IoZDl!=BdUJu@M;&Sogw+%81$s1NY_#WMp%MFw!E@)7>{REYdeJ!adF1 z6_FU39a$WCCK9ZuMlz#}qvTN`QL$0dsTom)QI%1<-D{)Hgr9SN?A{#ZiokjxrwON7 zO!J)SOyNM}UP z$e&R&qkV?)%#fKGGb?8{&lJuw@c7pGelU8_{13fP1JL=@teP945}E}EW2ZNnLYnU^ zg)Qa0{cW?4Y8LK3=k#6s(hDTpTYM@Sq@lw9H_DF>dd3XBSA;&FJ$vnYI3p0hLGh%n ziur5W5jM-1afX>VOTr=`vS$^~lCmOt^`)>KVHzPnq69kAUQDA# zn?{d}o*BI+`aty6=oit{7}J=MF*9S<#2kpZ8uKECI^A^o$muhuUrlu<+`_7YnJ2Oc#w@G;`6KMZ($g+0nBPEV{br#iH!lm9v{>Qx}^q{`bCpxFU#i zBy*&5MlPPYIABh|oW3ka&&i%sIj3n3F}6#>A{MM^#iqm-gJ+8T*s|D~*rwR_SY}+g zwsBlQTw+{VTyq?Au5@nL+>E(pa~tL&=NZof&tdZt=M~PYnfD6d!gyDNJU$v+v*Rnl zwJDyMV381#kdjcGP@B-6AerwwKNdiS5(?+TP&prl+W9av&xZlI00!X#7%UdR;JW~Z zumvzAE`T9>0Sv_piWi&#&;Z~S0AeCBQ361!gn&dCq7z|ANrWLkF+Z_P2{nl|iA_pq zPlSP)#7r^<(EHoXE^1d!`@-Z&FoYz9B*g;A007?QCKV=C0;mPhtOVpj< zXaLy&DgiVBATENyLIEL*VDL?kP0vq1lir-pTp?W%wjyIi*@}i0$d$$`16C%kEL>T$ z^3_UVhCCxWBRiuqqbY-!X^|O{nUYzYS)19BX|ihks?1eYt6EkGSIbwQSron6Vo~#= z?A4X4GZr_kE?eBNn7GDbO=5D$n!@CoiQWlI$gwOPZDtms%`MSz5fbc4_-kNs4bu+1l8Y{FE~(%_+=OX=+Al zS!zQna+&e6fMtox3YXO^lP`~6PE4~%3rT}wk)*>pX;`buh$SWZSxSx!R^a=r2T zfc1&%3)k1If3;q?LB1h+L-vNs4NV(}xfZ!K>q2rq@$lqMMnYcv`AaP6CmgX&ztswxix7KXUFRm>nmb}_a+|rOQ zFG(y>`Te)bvXbT!$-d})W&7Iq$@gdMuiY;^5O^TGw5b$s`)RBG!Q|i?FyG1!R-^q6 zjz4%{@zox)ulo0i-f&mMi^bIBn1e9~q4lPugP8|SlSd}cOg2qklY9W2SCd~PQJlgy)o2;;?|1OU5|y2+K&R^9rGs}4mTNa3 z>^Mj|RITlb5FIi(Bs=7HNR>a@(vU-DO9=%3rLKrsOH&SIEiFD&y0rGtwWaNcT9-=7 ze9OWBK$BQDfMNh=l<~)(?o3xRgeS_=#**hc@qQ$K@?GE zI!zP=gn){u*st^5o11+hdq`L$A!OgkM)q*y4o!lnNCIjTg)AzH({bGO`#e;pZE1=Ql0utsZ$?ko%-BXr#|=AsZV^J`sCNCPjj969H~>EkvjG9t5=^N z)vHfnz4|PySD*0u@Os(}x74doT76o5Gd=_OT+nbq167FL8eUf&)X-8*RXbEI8mPKd z(O*}OR3DkLtl`Vv57KJ*p!(6DU$_r5vhVMCL$kg5$NS2v?`XKYy6mTakN?Bf_cbI` zM>b4!Pjw%eve>=Y9pO%PSGv31r`;1Hr$#Q0jEGE*tc>iAJRLdFGu5-$6X8krRC>BS zr#%y+rbaD}I_-{#N{(6_SsB$GbvkNd^wj9Z(Gk(f(G#O9LEZSA#%E&8;^?U{i({t7 zM4(N^rxKrTd=|$ncAt)!7#r-E8oM|)A~qRR8QUFu8lQ=A6XT}hL%29DA}%?uGOj!B zwERqrS0A!F4R87^j-47iHJ;*3m6FBrh!{ULJ_1PkdrD z_*^i`UP+a;{DzKuyYxc+LA=j@SpONy-wW~Y#5f)y|K12kpIOrp#~UsEjJxzA{h=I; zUx<8W#Yb|_Qr|w~9`^GevLK%E^SZxvth_$6;3%Uc^j?m?=caGFWd^YP9G*W%^~{+{ z?(FX$M)ks8`kPU;4=caV_TAKi8=!G~_HFr>kB7dS`uo05_%VoCpP>> zpnd>Pa<|oOsUNBH!!uQ2{rk1?c=not=dOdblj;KS+~>w~ofFS#`E{jjxm!Bh`cNnG z$JMl+Dz+9!U*;d|V1HD#4!>arefA-L^-=yfixExrAMBw1$)7CTuw?(-Ex1yBp?{S> z-Yt&Ge{}yU|6oTaym|Z!@wCX}r~XI#e{uYru^RvA`h7M3e{Z|6{j&Dov@dJFyFIdf zdwXsBq4v+d0eGeT8y%N*h>kltB0KhUJlgR}$2SgKc0e4s<3QwrJqI2=@XCR2crWt` z?;YMq?;h`?-dDWe=nUw@uhYI!dRKTS{aMVfzRz#z99fmt>HL0a=RrjH>Ystm_d6#& z>YJbQ(JhbGJo;HR&7&iazWwN=#{wU_@v(a!OM9&5u_KSY{n(_(10TQf@p~Und%WiH zBagrR_@pNSpSbafd!I;qqUMPsPrUuaq$dNPyz$9C zN_(p2sUuIl{nVtV1E1!8!vF04bN-)~CwBgM;LmOQ(WX>(Hk(axg-NBv$1c)|HXuz&aqZhW$m@?YqDVc-S7V+~0G$DGF?KjuD` zf2{M^z%jqxqe%h1?<6^U!+YJm`MsUJ1HFEI0e#NC@IH6nCCT}HoqYp+e#Zlj&q{V4 zU!J@Ypa=(=SQs+wpFZsP3@UrvecapX&cT5}zoCF3=TP|2@)Y+_{?O)>td!27fg!))fMMrw_^^98f4FnFA!T6r zXo}xRuz$dab0mD^ofP*-{>UY%vr;=p21fi|3wX_mPxx!@*YaQMd~M)0zt;m^U!LlG zeRFE~>shJp*BergroNM!|9a=^1Fv6_HY;s;+U7LBHv;f+z7hV0`;GiJI^W1j8+gO- zbiirn>4voM(?`?ZNpqjhKizqH;I!YH0dHQCJ}Z5Bda%Fq&CTiIZ@S;ie={q+^UZ-b z{oV?A%lTGAdiY!JxANcWd~4t>zcWYE-$@TRb4iBt%&d&?Gww6_XO?Gd&geXol`(K8 z;9cjt;qSWN&3|`!R_D6|@A|zL@SgL%%~@Gl;qSTM%YU!)y@B`q-fzeXc;ESc`1|hn zk7m7-mH&R{`vdP^lI{0Fzz2)h%*u9t5dMMtgXP)zA9Q{&@PXfl0UtU)4F7O*w)?~U z4?921${zU8@1uZ^oF7H}u^~JBBlk!7A05r^{OFzRfsY10^85IbZ2=!UKMw!c{c--s zogWW;JZqcZCjp;0KMDWD{Ym~O%eQrYvUyw9wuWs3pZI+m@Tv3D@K4>J=6~Ax>CtU` z4vhyLPJd^B^D^h<&MWXe_b;8la!z(masJwQrSmH1ROdA3)z0b8KxdG1hI6KKmh&3t zZ08*3T<33`|LFX!bDk4F8E^(WolfDjoFVv@e7^Hq=K|+K=XK8Oor|1{oi{j_IF~x{ zb-(i_=grRL&Rd)-oVPk}bKdU!XXn2-fA9QP=O3J5&T!`)&O4ne@g4hJ&ehH}`0c^n z&UMc9&IsoQ=SJr}&U>BrIX5})cW!n*;C#^ekaG*ZjQOMUe>wl;{5SFF9`R^_c(hPF zS|lE=5RW#B$6~}|`^4i#;_+hfc#U`>Q9O|$p4=*)OchU-i>LR9ryIq=RBZd?9Eul*62zfIaVSX~N*0Gw#i2BDC|w-N5{Gt) zL%YSHX3>)-deTKthUm!@Jz1hBTl8!bJvpK$SM+QbJv&6tPSLYV^gJSZc8i`o(UUKF z3PjId(NidTibPMb=qV9BrJ|=s^wf%;I?+=vdKyH}e$mq?dYVKJx@ZwSt)iz*^t6kf z4$*T!9CnGrZgDtL9QKIAQQ~m4I2+amhhqAybPc|>27=!+J8F`_S4^u>uj{N^M< z^i_$zYSC9C`kF-_j9W!thv+*Xj=RKhk2oGBj>m}OvEq1~IG!YqCyV1-#ql(8JVzYQ z7svOC<3-|lsW@IKj#rE0HR5=kINlm z0&NFT>|LNoKzX2i&>m0$s2EfVDhE}7DnV7CYEUg`zcmnzyrR*6H2RC)2Fd~Df)FbP zImRHz7~~d%zGKjL4El~iUoq$>7JjkN#lklhdB$dd5F-};vB)WQH>d`LzUndV`fL#N z^~kv%`uaj^prO?o*dJ}Z;)(=$K&hY%P^R@tWU2K^40!bY3i^H}2J$%A#l?aki-Rl^ ze0HAo%CJ=KpfpfAC=-+g$_8z- zUX4VY$UUF}&|Xj>s0dUHDgl*(%0T6yN>DYZ22=-X05yV|L9L*6&;jdJ5AyPOKvAF= z5c2aNHxF|2AU6+k^B^}5a`PZ35AyNkfOdc$0qq9mfsmUAxp|PA2f2BWn+Lghkedg& zd61h2xp|PArvilhJjl(z9`PDifk;4{!iCi>k`1%mDokdbJWYui9n3x(~V6U_ABcYd`AR0=t$b z>(w@l=Rliv67zG?l>=(FPP${PlablhNsQ?v*62yh^~tzm>tsTnbu!5fs<%!i=UOLI zvOvJpMC)W)xpguVl(h?#55n=bZ6L(UX|PUi@32nph_y}@!Kb*$I$2r;+HajKtF=y6 z)LAF1w^}Fbh$=x%*2xC+-{b*bVZJE+(?6;%d;4bJUT(b1q}P$pkzMYE60%e1?fzU?`{9|ArQvqrK!6!Bzlmyxd zdIXdQf-VlR;yj>O5d7nIfzV$Z@{Mb?PQ}N7&`*3V2yqe+Ct(Mu08|I6w@xL(Hxcqg zNf>`p6A1B>F#cpWC<+9-WW-5M1ECJduuDe1 z$;c;p9|-*=BW`j#2!2~pgRT3mQz^(lB@UDT!WdI_gOFbeYM6pLq*Q}yK=4mR9;vWR z#h6kt7pWL;Dso9hu4#yu23;Czj`QqP`W_Ja%0M5Psn)41*k@&cFpez5&qmJK7<)Eq zo{c!!=qnq2WW#bec_wjo9i`pm_cauGKd_1b|N>_827pwFF{x1Hd3BIlhL<0FaI zsoh&au**Y^dB{5twa-VqeAFW!dF?@*J($})=&K+H1m6PmT~Gx=i~`sfV6OI}|GnsY zFY2-vIq!u(_JUJ;k<(tRt-YvgA;wUMF&84gLe#tvx_Y?99Ds^#++0mMm2n^kykZhR-?|9*awhywJJP`OAteqOnTMc|_F!oy1pbl~CQR4>0Y(Rev7;6Lc4Q17VA_a z@@&ipAx0zo8<9^V{2MWUjmQ)Gz$u*br^)D8Cxr`n)vL!a%)s~yMf$f2Eh^wW+!+Yt|Y!l@3d z%MR3~19Q*;T}P#L>Hx-b0OLCV`2p1RK(jT7>)W7fr#0wqum&UDpiFDf6AQ`#2-Fa|uX#e>)b24kv0wbmfc_d#6S2V?hJgE-#@3OQ1$m}KgOE!q#+16p8cf6Z(x6Lg1R+lPb`bi@fNdu7%|tFZ&jz!yK^34T zYY^wyVD>gpE(o!*_kmEWZHT=Mec>D%+*SZ8v<7pKXAWe!$Q$R{;C764dm0G+ZwJ34 z1_b{dbd1VKdd)L{*|c7PrMHCsdO1W-9>AE*)3ZVlmjIfVPQA>4Znd2oz-<{?}shoa*_Rn}0< zPHPDFvqQ0|))3b75Z3chTnVTQgjjJ6p#7j$&;e^GJ{APKc*Kf_ZTub(`c80xvOpD} zYHKJFJl6S865`-`GnCw74Q-7A!GA0I-kJz11l3wYDaaq!l%Z6}vA&1WV3UTtu*Qed zYOJAjQ2V=?E1wxG6ND%tW#dvd3yX~mYc8qxk`oy(nXh#947z8=i{?JZ0 z2)X0BGqeli-32>bdxjo?&2HH5MtrRCp?uUgAGO?*1WL1p3Sd`&;{xQiw+w{Z>_x5i zB2QdLh6*v(LgZDL4MJ{(=%Wz17b2G;^jVY)Ld>ER5OOJM0>QT!adFKVDn?%=s8K0$ zDut{RcBRO-6#bOJzYH}kN1o;IEyvv9ycw#3O*QPRQPXPlzYpTC8C_^9;M9K}n!= zP@Of5d+K3#9;h0$57YrVU=2scgAzfNpjvAf&!odq(8cC}3P2^GG7$8!h!fjp4aXsV zToefL<6wvLVmNNMH5^|BLVVoI4aYZunyujk#7;;9?E=++5F?@88cr+(6o+r=+mH2+hz@CpzjRGG7vul zIc8>C!&!T+;cdwv)CBiP!#RkbgSa^ucP`|)sUXD6MNF*i;oNd-82kC~b{y~6V-4@z z3c~nzLB0!Pc?2;YL9E^R)^HwbfPHxw_f5n3$SohW%}3q^k)RY1aw>QP1lt1Cq5yt- z(O)6_3XxYKYK&*p;Ud(h2)Py`w_^C0AYK__m7(Tk$P;UExE#82*pwspa>Oc!Zw2C1 zAg4;yANNJWRjARvMr*hRF>5e}nk*1(Yf;}?BKkA6RdAJevZiKuA{B+wOYftCmHTQj1G*s z1GXIvp#9c}s{qtwjbQ&BahHN>L2cGZWC|z^lxdCNId=rlv?F*P9r3hVBY3|t61Bq` z!9F~KXO@xZGHV3S9V0RI)<|p&CT-7jd?upY6zfJK}DK?RLnwBi0TN zXb%Xw9VH;>cR;@r{7#H*R~!g=;hH{zYx>A8*zUr(ccTyNdn3E^KYXtY7%yeKpUkDw{3KvP)|awb1xFPiNoXm*sLDUL%^k%OilZuyO*Z7d2o zvnR$w&2BVFHE4EZqRB_RJ^2Y}Dw5DtLs8%YTaeI%CK<*BTQjIZE(IwFP>_;^Can_9 zc645_rx;CHGMaMaS5VuArXKkfw5FkHr=yOoA!qi+!+39E6`HN(XmXI`-kl9-@{q>f zef!bWV&r=}@~J`Rg>Ix)=&7Zq4oy@pHFOjok0x~&nj8$PaQk*NJEGAPqVvKsBve?1 zJ_>7HXzEhYbi{<5DT;+%Q5?!t6d#Kw5%G$WI?!a0A`|%)Ws~+11Son0sTEZqUJ<2M zREI$qH6UnF8_HhPfie|)kZy4bYE_&IkK#QTTX7*0Dy~J8;#O3xxUD+mOvyIbm25-7 zN_N7eq#9)^X=n^NQyPt&OJh;u(l}&Lnu<`R>Dg$q(Pe4HzK}Cz9+a*u3U+02bd-Ra zmTg76vK*HP2oM3k6Vs-N=~s#A(?sA^A`tC#5f~@}gGAsA5jax>&Juywh``w*aE=I^ zD}t^PLDNLgbP*INf`UZQ3=uR_1kDmb*NC9mB4~~Xnk!~pC1y+$Gp36ffnr9Gm@z}l zm?>t=5;Lw5GiHk!bHt3fV&+w1<}@*Lx|kU#W(J9wGsMi9V&*I{^BOU8wwO6b%$zG` zT_t8s6SJm^YpxR4OcS%O60@g?Iai4})5P4X#N26O-aPTU0P(xu3FmSl?iE&u2)Ry# z+%7^M7S{@K?G~|MsaSA}Sg=|wcvvi4C>CBP7A_YHZxIV`71s-K{q^Gd#bVKQV$t1V zu@H+bu{cC5UM3dbA{MU@H(V!fxLe$?Q7l~`mM#-Z!^N^q;-(OB(_(ScP2#2p#LbJv zEepj8ORTtEthhtmx=`GCr?_*axHCem6k=t#Sh-%T#PP#o)h*(#yTn~<#a-*gT@hkU zxLCVZti4;T-5}OJAl5!4);YzxTg18*V%=)7ZoOC+A=ce5*557GM~L+s#QKLsM39J> zAtIb2;uaCHLPXplB36rt^&%odL~IfpoMOX#vEdf6VTIUmx7ZLNHf$0bZxQ!6#Xa-I zJvdk)?zvOkvq@~aPi(qhJg`R%Xa;B|Xcp)i&}`5g(A;TO5bS>Qn|ao}dGjo5<1}l&^H%HH1rJ--E)BO9E?j6W zx;eyJ^k}2C7_!BXE$%6`mM&cky2V<0bEtK5=pyT8=x%}St)TF$?*whK!Vh&=cZA<( z-Ffv!&}Qq-@b%W65ka6C)=JKa z`dq(pwY463M66wJML-?_dBn!`)_vhCtq0)q5a`i;7HGb8sBMGQ)8+)t2i*c%0a^`O z4~hV73Yi=@eF~aDYJ#YlLCs8RW>IquHM6OiL(N=EJC|70ePKxWw1{aT>rmp5d*}%DSQ~P*@P){bqxDA%sVS$XlA8S?M?26QOFgzT zq_?=QKBTv#w}P5VYO1KIp{5p1UodCI2?CQy`p6u$$uAc1b$*zG+8px!9 zOd80ffwT>z-A_^WlgWNE*-s|>$z(s7>?e~((l(N;kz|b|Ya+Ipe4FJFDVj;qLb4W; zwUDd@vOYItXez0xLIW+Dcxs@HBt<02B1slWGEZ+YHE{Eg)UkM3~6If2sE{5$Swvm zjRrwu$Rmb4V#y-Wm`vWZ9cViQ~^95O$nWj zJ#0p3;B<6G?anx~*iS+OXElFr|3k{^*4Xr$;tt~W=wzbee+Sky^ zW7^b018GAG4Wu0ntvsgfEHsd|vd}=<%h1YWFiWcC83W@==7XV+bVGc z#3@UF6e<&RLppRrLIQBuO(`aTgxFT8BW$dSlf7eel|mI093_a|mE5tvDo%Eb?X?$~ z0Z53Al|lo^vVpc62`ADCqzN`w5)!}!J1qHOD zs0V^73FHS(>8QG7u7osbaJbS*P(ms>B}9Ndmx2LEM}Xc5q)tY`j;w?-SPcBgM7d+{ zrO*I!$F56$*mospp|VWq%j_+N4gd!NbW4CS5Y#BBl^}!lW%k7=E>=OD0`v|C)kEe9 zWpYB9oKPkwQl-g>toi-T$^A{W^ZQ%M`&)7qI%3i1^cDJUm+#Z`;{0S)+n{ws0i_#aS(|L4EzZhh6AIRDkixK|?+ z0G0T)1fUN8OYp?a$L}=oa|u8Kew_i>p}5`njRm+e{M-UifnR3K$2a(=(v#-ni%@*m zGXGR_9ljEqKbW(1u(lOY3Ej20sike>TKwSTCj8)J0bSSzqVuQFK_nk|_#m1OV)!7I z590YCkq?qScTgn*Ze>XdAEfd@8Xu&~1D#gTg5F}>Rp3UE4x;dhUC>*D`>MFUC>)$f zBIyD;r|BGAfF=sl9=kxT?cVAIeQ_|xDX~!194(Hh?D&77sytd8QStHrLev45UQ|LJ zwIu1IQ;ECysEW1t9#P8%v$pZk&I)~mD-9p*P};~n_;m|@1hWu7;K7vP=QlVi!Y_Bg z;0P0kS#DNGu*<_yxil@qQ4RS@EgZ`+_mH)ojiQd?7UE|-uSVwL$38g10?L)WdA8zL zKHwosk@2E%lzvu=qwQE-kY!=%$Xq-*Qq~Sxj_i#*u*_8U`iMLpk?}Ah98n)B>Ii99 z;|QbF9vCGCPaf4Omqlmi0|$%FP6Q4XNmGn43%_{+Qz8crz6}flV@xdrDK$0L%V z+-aDKfei{uK9$lZkr_|nSxvRnz%37ENDMy6HyKO=jf+H-&H-sg)n9}WQf0_23XCe9 zGNXJ8qy`yK0g)(t4k!jb$RPbJLo*F#hcv_B$VV1a<^g6mXM~Y@@>N`!4h@TjsTjD* zBrsCkvz=;7IoY-yw`Vut?8SLlil68WL|08&f-N`7pBi}<#V(OGK0A~+#iNpH-uHl~ zedp|Kfp1W2O(v4JMAktLkT#lf@bIjrQpp(ykC9_(?3@2CR(juOJ>+nXQrJRq6fJgw-+qRip zAg_!049UMCroW!-feqx}5Ucpc-2TShe&-Fi3I|+Oz>4UBiUz`1jqw^2H709J)7YZ1 zO=E|~0}3l63C};17F7c(mPfUGlpK2|EvbWKbd?OjRTAt4V_yOLVEaVqZ1(3q()t9ib< z^!Wkl%11~SK0>fd(J#+{)rlAm#Z6%n;H)_QPjj!lSEAlHEGloHlryiJx6rKcB3h1MpM&#jzzv! zS0pu1SmYK$M)N<<#YJ>T)@STHdvn z8WeFk4Qn}7@)jETEu>vRL03@F6%=#@rLlshaRq5_CH7WgZzH?g$nG|>yNv?eMl*OD zncSvKkjri4c01YKPIkAGmNp+WQh{-VQz-l?FlrDboT7x&IKs&;oU#w6?8E6?2&csF zpeT1xfIFxVcara&6#h<9+(~XL>1d@og563g-AWqoO7d7mU9KXxRn+AwD%~pbSVf7i zqRv;5?<(qi6?MLf`dvi6>WNRq$8Vb6G z5?`aVI2YDXLTf3ZwG?kHd906>56m%^mw3d9=QbKDfp|uocEoHTq61tn*?k1CU z6lI+{g2_7SXdU&jo)qgzv7Th>X)xDbtO#^fr>mMoM=hrF##V+(V)6qoe!O5lrqQll#czKFaDo3c85~ zvx!VL(YoJ6iu;MZpNe=tMZTYMxu3N6D=iYbpL{n{LYt|N%@k!bWwn{I+DvD~W=d@{ z1=vjeZl-=WQ>e{!R&1tnZlX~^g+tyLCWPp3i=?KJVdgG zNVbKHw~+A`GTuT_w$NN|A(Ji21PN^+-!0_(Fd08g#t)MTU69d8MNRXBM@za~J=D6X z?T+l3@K_8SsEtCKBae%8OOhr!e&PT^O?a{qu_hc!r?w{ziBStJT3Diup|(5vr3pP* zQkx~U+vM>!bu6{HQj#krxzaaR`sQLd6MA+_?QW^f@5+RvP)Z7=q)^%yO8Y`-Un;ew zQd=tH*GQWhX;UL54brAT+B8Z@vy?PTNwc(XmiEovk?8S&)E*%1VRu)CY>~;~Xp*BP zc{F*U#i$QQlh@&RihMX-YSSsVXJTZVN;c1=%Hs^uJ|pXcmgHGdo-L2F5%${VD7zdYVA zj~iv%By(tzy);Q}la#l}2px2M#6w!N$PlfPAcrHd@;Fhp$+DHBJ5rC6Wx|mLYM+xM zdQQ&!b0uW+Tq(8k_K{lD9Bo$f1iX;IF}-r?o^Zk~+jQAxp*`2x6^Ugn!L7ifAf6yb z>9EcfCv`DhQWx75MZ!1*3Cg6PE0TmLYtOk>S1}1gRSyK3Lloi=CA2GwdLWQG=^hF{ zxGzL#2p1t3I$ENl5I{(PCWfjuw3=N937$C<>&#S2@sk9?gU8$vReYF zlid=BF%Y2Ja5YQSPI4sp(j&Mzmg4Vxx*e080WyAwZOksvrayI|1slQH3Uu4l>=1 zD&38$E(B61>q49iChM|M4P~R6j{8&+o78k{Qq!>sLQKbI)%#|2gl;#Z2TTV6LK7e* z0!+td)h&V4$!>{5w*;7ufevhEJrZC74%_~@0|z>!5J18M9VEn`z{3LtAYDPGgjgkv zRl-;$jPpocT%3YL1qBKU6|_l+SC;Y7ic=2p$%@NYuvdZdi?3B&or3)e8WprCXjPzl zXqQ|s3H3_Y05}hqxQy=TmkBc^W_4wt zi09#QhizSArsgvxzfIe3)AqUAo{;Q;C_AC@BUJKCDc`N_2}!jFL2HQC0U4v~~p&CaG>v8!ad4ukckm5Dy_=Lna>Nt%$PNVLpQO9Z2ahm0VJ+Ft5 z{D3mAW*whU$<_Fqbw7kkuEu{r+Y^%ffVLw9kBcvz7z#B{{Xj0~MWT|+e!$B*OH^{% z&*6AAE}*OrP}T=1=NT7vS)cyBCH;HbCZ5;7cb~>Og*7q#HQDj!$>;NgOU`@MO>c=O z0TVSQYfRCYrZGb!z4jveZ5r{~O!D;plH|KI;;p6R@jgQ$UZP6G`(KH8pCD1bfq)-y zJNegYIZ*Nqng>e0N%KI-)0;c;0}>yp`=__*Bv&s?fb{N{c-^0TA4fdiib%QcN4)@n z94|YhT*r@W*F3#)grCQ)F-l{MM)__8dR;$4%1gdw*C=^iM|zDYdAv21aemX4H`_663m zFZPJDTK2_xtbOT7`O>+qd~tT4)v_<0@k(2B)|ZZyFOJS?*%y1jSuOkGyw;KFNcrMO z`{Hart7Tu>0c5{)?kKH1lD_hMVy*V2b4x|0BjtN0EixC>G7;|~BX^uVDwId!(Rx42 zA1-J-)I?DeO-&3nvDCy-lR!-(H5t@oQd3-tri7ZhX3HPlp^1LU^6yLhJ({F&G|8*b zY+Z{cB?3+Ay=c-lqe6muX5bTfC(&I)5_9kj+C&DkgUTB;}ZPQ$8+d@N*rRny- z;*ewM@;F1bnX=7#p?O}&u`GF-F-xzYN^jPHbkYi<1QcIcR);;m})Mj*3nEyiWeOv2nUBmV1|bC@q$uJ zPy+=XbEts_o^47!c!=pn1GiNq!*ffi2Tv{C9z3%&d+>15jRukN3_=Z};Q50Zgvav* znIIuNTQqw%Q9^jGpav|SDZ0_X4UZ1g?5K&7ceK=Ic1O`&tZeC+u29s{G2Nw7OUJkq zl`S3Pt`jX?kEo?%y3eH6EnAY)9VS|AxKVU>DO-}zog}qnNmmwXrCeIl{bCf(Fp}e* z5H0QiWs74v<75j7j!8oIZ`2|hT9VT>1ude*sH=C6LbpPk^2F0dpis$aD~O@7OF1FQ zsTNAE>`@ghSN5oYv?nBcstDPmCR(oSsYWE1S7wc5FR#iHmA$+oD_+{8J~9p=*#os) z*`sn=F5^=L$X+7s3CSKP?IkKX*$dQehCu1iWOUEK-v*QK=Rmthwgs}?E89ZZ7Rk0) zwk5JHm2H`9%Vk?3+e+D1$+lXy`(#@q+gjPy$+lj$4b;ZSI59FpjEoQ?y<((SjP#0; zUNO=u23{d@3!Z_$bR~Dv1hm^HO~5aSYWmx2_xws7)EB7(Y)`*(_&M}{7vFWCI{GMC zVc}MVpDO-RtzR0h?EE!9S>tq#XZ}^``!x=0yjc7Binnq<+CNz5k&~?Q3jUMA1zNw9 z?JBfBMB}d&I)0Iexioq;I=-d-HM%r-ZX78oe4F-_d$)AFO$oMz2Q4#mdg5(W}uhN&9PbX>{-of@i*Y=EB?_$()N1(Qwq464pE{$Hc)AjXgxns7n^XhoPnh)lA&~aTFz07O9 zBS81Ve#~q1YPlmw_oL;G%M>51(WTL=(J@EsHM*GBaU6O*1Z#Bhes+cS)9BLZ)#&(z z)@yWW^lEhcQtLIkG*BY2M4I$M4YV zJ9w`0b7}N4KTFBI8XY|U+}}*?r_rm?q3we;x;|0&39b@l@1L2b?<^Gb7e62mSe|!K z@xRt~%=>#2q}@EfdnI11+#P2YDEsp?@7OasUT~G-7j!Cr=9e1$t<0B=_75u<&96Fn zkL>9}-JeVA`>$8y3*M{k|3i&CxMH-wzt%gnzW>l@z3b14Pu2M_pQHJ2U#7-?iSGX| zzf$}UG(T^`==!YqiQ>Pn^%+knK2Y=T|3UFT*Zdt*75_uc2VbxFpK3m(OYt)_U-+V` z$N8Ff=z0ggrtcRuA7=3P82nP^kF1lC&d*9y5w-txt@pZ>{^9~v@BWJw|I9AUPg49c zy?*?^tN1mV57WFu$A8aQKfFE`JZh{LgTGbtb#v8y?MJ$Ri!V_8C*M`+haFULxc-b> zuKs6~p4T%Y>nH1Z=lU|TKJ19{XE`J5U0Odu3m91+wk}Z~F4Y1?*5`ew=FzLMUnA=s z3sl{C{V}pW?+xXDjutSozV}I$|97;2k@a)*_&IMz);pe6{{C9P$oeK7f1(yJvc6;t zecrEBeZHw37}Gg4u7BI4Y`WWN)>iw1L%EJci!;n#zyog^~STFDm`HTENKq z;Mf1Qzjq9O$4h@ZzUx(`=ejd;|K2h5{$q^aF-HD*@2mcK-Wa)m#|M8~A2x=5to(vc ztN1)GjNHHfKdbdONedWR-#^CqU1R9|pHuzwx?<$`d1Lr{$I!dRh#x$L-Z6$gYz+Ms z`o8EJdO(akzUf-e<7Q<2L;5;)p%yT*{$I2|pEr!GkJJ9VZ!xmof3ce1pJ)Li>(}W0 zjbAu1vOf4X%AfOQWWE1WYJT~;$;kSPbJTqV%Nbek7(?%`-+OUg8QI@EU**T=6(j3& z#;8x{_Isu2WbI&%f22(5ue8z68DoC)^!4RZ?a!!LNASz4emt*?tpDX0>#P5UzdgTs zdVaZXj2wTuoWINo?~SF(_`Ep&;QFk(vK4?i^W*cLk>fjFQT=n>7+D{7WuiRf=TS!1 z`yW;QJTAtw`hQaXQCh%wR)3Y!|3M2FS?^6(dVHxO|6@F>Kdto7Yds_D!~US=Z=Mz~ zvfkfM`E&gkS?>)|{(RrW$ok;xl%B7C(RtPftO^krJW z$a+70!t%Q6y9ei)1 zx?laS<`*nfJikA*%VWh66^G9&J3CYUzijRgOZ0s=uU|&fKkOoP{&W6}-b<96&of3| z?;MBg#{5})LG4?-{u$5e^?{v#laKlP|5)Y8?}Hipg_8eR_rqxR@6z{Qyl*m^c6Pj7 z{&_ks*Nf4N^Ryl(>lsZuJ3h%~{(F6_U#5+}U4N$BZv0*!$3HyI@jGnRubHPEZBuWv@v&W^Y3-^cT3=Q!u@y>Zrm?>PGpJ6GL5t=1b9qw5Ds{;Dn< zqj}$O{$pyM_`G4XtG6k)tN*1sF7KO+zWVq3xc=?>cl_D6artXIUZ0F+o_4(VziItW z_OX866>6VerW0iJ&;N3{Isg6tP5HZgJpXOy?~Iy1zMeCh^Wg7M<9t{v7`;oC{4y

&(n*wfRXiMp;yoIh1!tOVe|Z9#`B-(Tb)fm=I!Rs<>UEVG0yuRyZ*gC&cFYV z8vhUV4GLrbM0NkvqzB4q-p9D~`%ixF#>n*<3v+DFU&k?ZUE=#;Ml+t>`15?Mf8LMO z`1NZh2ct``3%(vQ`r5zO$Nuf|@AuK)@w9JsGV^BMu75|Dip%>cBl|Iiou}%@zYAex z{a6@mbN_)qVkcd>Uq&-tiQW1!4Q+UrP5(CLUl7~XFU;5d$L9JS?Bn>uv>o5qF@7OY z8-ZQ^E+6~1^Uw3qKlne@Jbz2)$7qx87sPqLR_l+idyHQ&)B^K9+JC&~&nDIXdL5t9 z|7In>LdzM=eXRem8b9a7XqUe!x2u2fIQP$fANRj{o9kE8IPZU+9;d(8$Mt7dzus~7 zKkTEwcbxmrd%7Rq9~sScV#nK!zu(9DIS#6IUavb~%sZmwtF)Za%)_pK*ErX2@V8a} zeBEaBwg2-USLY?)?=YJF!QhpklWEKCoKG4D@GK3B^bHG3B9#_xFBx9dXKf7AL4_ObqU z`Fnk>pYDh6TNuw4Xp959{#`!iKS!?<-ZvS?==QAIuKzqA`?vFV466C(dN7{tSRb_6 zTz^eFJO1%;`a7QSZJpZnZ#(|J@$Dbpan^sqIQNfR$LZfc&ivPmv;T*D^bhV<``ms# z!Hi)qDES60XEfJ=-TcS-*nghB&hz^*MzbF~-mZT~k6M4cA26D6?EL+G^v`+1w|=-^ zGY`A|gMGYy*!k!9SbsbJ5+D7$#<~C4^&jkG{cZhy+<%(%IC)+edA`O%*J5>^2yMvd zh*xr_mNS~yfv3mWfA2W`hsWt}SO52PT)yvSH0x>Sf4)Ai*pJay|FChcAD55oCr^LR zaFI@o@zQbTKY5(~u5pfkj*tC2^!G2n(Bo$e{+(L?mufkqIgbl;KYZRXn)7VOKR?d> zCr{Uj&r3$T{!IC;o<6kT4(&{CK>yE^tao8 zf_=Pycbud8=kuP?Tqkz?i{o6s!2|04gWr!Zx_rz(Zk+Syu<74!yrw*Foa^6i{v7(f zEbk|bX8(5n{yzGj9OwMm^&jkG|91XiOCG=lZeBze&gC>jk4Zf8MXSe$4k+ z{`&iO{(UZ^_cnE2|5|s*X!^T!o%y=KXy$3hdu_gdd)mkG2ixr5y*~Q)N2qbG(+M*6 zFIVzkX*r`g{ydxg*YO?Y&-)SM7wT|a?O*)fkMRq3T444c{1yGpbu>KA_4~#+&wrQA z{@EX(>c`g;Mzb#eG2Z^aV*Ski-?OP-*ffJN}hFqyHUBezkUB{FV_Q zI9u7JYdNDgSIMu}az?}55oUA#czwKny7Y7Ug*q@}n7%LI^~`AY-~Sc&FVo+l|NJ4J z7mQ!9vl00JK-FoI)-&3efA$ySvB4tc|2xeyhCQU@v$dR&-5Ae*Ql0;NeP;CPb;;vl zWIsmNWvU;3zF=g%i9A0n&-;q|H|NLx{xg&LL;dIT_;-(tULVi@IX3Hmfsggev-$nSLq7U@ZLU9h*k1s1{d_du z>(4!^&g*nfjQ$gpocB$}FVz2CHUHnz{*3)L{^o$Z!^)q3_r_@2+40`ZD$n)WfYD{s zzj=RntIhn|^=Hc0jMINYry4(>7mQ{ zRQ-5;GTQb31^FLU{`Y7FWB(tNe43Us^8Uhcyq7CG-X9rRZ=yMVM~w3SH*LrmmZIbf zw4CumBcT5`l^yS|j9#1PPjmn9*ZK2xn=!{`|1!`2{(n^cU#atA3_e%Mc|I7=HS*89 zOWB2MIir7)l3QBNXyzaM73bfqf0WJs8Rp}kANu|{&%d9J)8G3Q&mVLAcJ~in{r4L1 zd@~x;=Q!|@I%D{~-;GzQKX1!_PeRQVisyadqIrtvKMxu+p!|8?PZ?4?uk)R6DE?cz z;}pZ*^*t4je|LP_p-awj9Qw(=HQ8y>skiuQQkGKmX0=rD5ji*MDB$lrw*oR~`AYKqJS$SjXr38)jq1 z|CLvHT&x}aH8Rin^PlT|Pv<+w$3NHpJ+BJL@pvAX=lHxXIsSAX<6myX_gCFHI6l{h z*CWUGHUA5Y_-6hbpU)4D?`!_w*YP=TGyZt%bKw~A$D2R@eHL7AhyIV(=Tbe7%(I?x zto6T38~U?@Mvlkv?cUFf75}$79_P>fFwgOMUU+_eT|fNZgyV4><~cqOkK<4GasBi2 z66gJ29sj#tl^O4c9G~xl%=LLj?+?D_&-=Vxe6v1ZH9p^OaJ@Nyt~bYLy+haC*Ze2x z`mnzlpX)P;JN%0Azd1(yi*>xS*Qc)-zobhg=FjWS;m{qp`WR{mq{4_A&6f2{n+iqH8ndb{qChkQMG$lw<~qx3u})cobVA!z;|j0eec`GnH?bBr5yKRzL~ z-j5$hnCA^s^9*nGsP)9%|KcUZ^YzoOPw{;IUSaUp8a&5kY&7DtoblOy6`!B4o-m%D z9Ac|94b$k==&%3Y=3xEzujOfU{8rm*^lJ2k(+imcB4E{cYFEsdUgU>Md%?5wa;2RCT-r)ae@P9Juv&*Q@1IG30 zN`p7^zuZ{QKR5Ut#{Rs`sDGQ0PpGkf|H;UY=fMsi^6~FKbNOf&=c8S!k9Ije+S!fo zzgoWZtLAg^TQ`4xD_&`r(1dmWG3ws>(Dr|{GaZ-QxNgkrRr>+&&xyu*{BgI^^X1`P zL%+cId*v1z{4#@Ia#+RV>&454{`B)o&-XijHTd@pKFGL!d}7=WookHGYg{kRG2X`= zHO}8^W4y-<{x;)!bGcEkSq5KWjQ25PJO>T_=lcC4@8{;+e?5O{z3_AP|8MhW&gbE8 zs{6%BTCv91?>nzjdVb&cSL6Nf$7fVM`2N889cBMr9WT|mpRF_2Z?3WazH`y&eEw?u zeUwT6q59+7$#&y@pwq~w(K!G9_<{20_5Io>is$#e-yBvv&u_7D{$zYO+CTo+Dqnsd zzuVxq8RO|T@-^=te`xFv=6o?9Z1e9_@OJC{AVHe)eJUeg8~i`~ay{?6E*m}Xqy08| zzU>eG=*#2tKAUHw=j(#w<1hE;`^YdGJ&)6CqrXrW(51iUW1f-kYaMT>{y85;Ug!Nb z{=6=O&rg&+aa_i48SC$g9cj{T;u~sRasMZ`EBPwp-(%|6^0$rW@?kB%$B6TWmd|}# z#pnFbX!%6r-N9b``ZIEl|8@zoniDpUB92=cz?NgbUi{1{kyM^ zu5YHnFE;keD~%_2C4XStU-kTObUi-(nd150HSr%t^N$X~^=evz{V=joJM*Yq8eUWiK{psITd_GTi8})w0 znEyk@_32|{zu05wHyir@ZRl4U_nYese!v*dhlc)TWB>Vu5&v7p{b_-5o^CeI|9GPw z2j3oDpPw7&&s0NyrJ?UL^11Ha(eqhrXJ?Qf5+N81HzJx|gLagt#_%h-QT8~guE!~a{x{oD#8|8tG;UvAtVoi@&Q zzCTGc?lWDlfBE&6?fJao`H^-uJ%!j`C;T?%xID@pImM z-~E%X=+Alcefs3D=+F5xZZ_Uqd0+YR`7_rI-+#Vs{JWvS?<;>k&l%aD$ItTb81v__ zSwFnq7bsO&)20%hQDhJf3Ew*`b0LrXY;rD zciH%S;q%`Pd7WMOXH^&G8JB4}&j-sxyOcfGiS=PN@>lisi}Pap^NoF+<4v@Y|LIxP zFV~grvyUn{*Ngjk%0@oXSjTL?|78`2*Bi^X80(hTg~vwTI-=s7T{n6Ha*g%J<0!O| zfBaV!hxZG%_ZZLjJnl3b`Aho#jQ0VyUu-;Av-}$4{RW@E*V@Q`Vf=d+Z2v>!cWYeN zc{cK28NY*L`yc;YU7z{>o6qN~ZRCH|_pAJVf$jgdai7cbmxEM%zW?WW`%fEr_-tj* zzq4igU(Qo<{#_xT_rW&uw}rCje-DuDR~r9b2+zOEM&7oxm?G&SYwZkyw0uc zuQ2Ryj#cts81iS6l>C=kK1t(yHu8%zl>M&^`?t3#`D88U=iwjae7XF>N0fYuVSm|P zCI7XS^K<4Ur*oe>acANO`8ujFVe`>;J zmFH!;Lmux##{9DUWg|YzT}D0KI^Hi0Irn?fb*f+f^V1w>_Ek#G?+aKSXUxk49sdTy z-mB#kjrUnB|ACGC=Z2j7oopiyw2}YDMsC^27um>{+sOabM!wocevgfOi;X=k$=}l{u3Md z6*lszhFqT(Ux0k${ha$Z>ipyTm6T7_eI;Li&zUy*{M=!@zgT1VPx_^@=Y4Rs@&2RB zxL*9ocwhSN8s+b=GcPydeR`qNPty878}IWn{gs~Y2WJ}JmrXO?NBwrLvgh$%V!Usu zH0n`jyvJWWLHYA_x9Aqd^Y!GLmnxpG_YQ2u-!>M{C1Y{ZK&=68`{|6QZMQ^xz?Yk#Wx zy#{8LONin_;PB7~ElCl2h8Sh)GjPV8=^E<~_FTX!m<;UyyWPsv%J>6`)kH6gL zZ&rx1=ljAyWBq;8STC;|&w~TT`5Tv{;_-d@cB9_^a=p^?{JEznp7)yMpQ$95AD}VO~rRV$SdyW0Cb+XcP zy%YXT@%()D;N6P%*Y){ihT{2rU1D4>&eP9L{5*BPYjnK3YZX6L$7^|5@qGV!^-mPf z=hyCUE1sXfLXGq7XU2Me(>Oo6jQlnk-xuz`M#bmx?3u54UjOw*yp6{BUupEe&p5wb zM!iceQt>D0@h>sXr)Ql?&->>O4gUj1|EEGn=UZufUsP+1_j?J-p3euJ##z{AyyrTr zFb<9y@7rRH_knC~+FfsaAI5e+HQocBZ@j0pv)gC9e`C8Bjr@je`ZevYHogzyc&{4q z7TAo}w7cF%yBmD8yU|Cxn|-uf;iKK}ZR|ca-V1QOOuWXp?p$SDXW2f~uw%K29^*ZN zsb{{`_#Ft#O{_BROH4iU@7vUY^^8yHe);_g%T3(n<2WAo(Qc)&|Cs$TUwMw&2lzgL zRbsWa;NhTo@hKPLXg$8}I=vrm}u9`n)e0^|1pW*p|< zHGa3iauW~x*zaF_v}-r+Z_WOgf6I98W4Vd*ZO&`c?g=0J-EfIor~Le3#$i6z$9}(Q z{N926O?=76{A!H*5i<_+;l_2I zI;P>*247d;>k52bfv+p@bp^hzz}FS{x&mKU;Oh!}U4gGF@O1^guE5t7___jLSKxoX G0{;hIggS%( From b7bcda33cfcac59a72a53f4d30efefca099d6548 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Sun, 31 Mar 2024 17:52:01 -0700 Subject: [PATCH 259/311] fix(ServerInstance): fix severe log message Looks like copy/pasted log message. --- .../java/build/buildfarm/instance/shard/ServerInstance.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/build/buildfarm/instance/shard/ServerInstance.java b/src/main/java/build/buildfarm/instance/shard/ServerInstance.java index 5b473165c2..9d9567f155 100644 --- a/src/main/java/build/buildfarm/instance/shard/ServerInstance.java +++ b/src/main/java/build/buildfarm/instance/shard/ServerInstance.java @@ -610,9 +610,7 @@ public void stop() throws InterruptedException { onStop.run(); backplane.stop(); if (!contextDeadlineScheduler.awaitTermination(10, SECONDS)) { - log.log( - Level.SEVERE, - "Could not shut down operation deletion service, some operations may be zombies"); + log.log(Level.SEVERE, "Could not shut down context deadline scheduler"); } if (!operationDeletionService.awaitTermination(10, SECONDS)) { log.log( From 684d79a38e1434cdb9be52cdc8466648bbbeddbb Mon Sep 17 00:00:00 2001 From: George Gensure Date: Thu, 4 Apr 2024 14:38:37 -0400 Subject: [PATCH 260/311] Remove switched_rules_by_language usage --- defs.bzl | 6 ------ 1 file changed, 6 deletions(-) diff --git a/defs.bzl b/defs.bzl index 020edac27e..f8d187e198 100644 --- a/defs.bzl +++ b/defs.bzl @@ -5,7 +5,6 @@ buildfarm definitions that can be imported into other WORKSPACE files load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") load("@com_grail_bazel_toolchain//toolchain:rules.bzl", "llvm_toolchain") load("@io_grpc_grpc_java//:repositories.bzl", "IO_GRPC_GRPC_JAVA_OVERRIDE_TARGETS", "grpc_java_repositories") -load("@remote_apis//:repository_rules.bzl", "switched_rules_by_language") load("@rules_jvm_external//:defs.bzl", "maven_install") IO_NETTY_MODULES = [ @@ -119,11 +118,6 @@ def buildfarm_init(name = "buildfarm"): ], ) - switched_rules_by_language( - name = "bazel_remote_apis_imports", - java = True, - ) - protobuf_deps() grpc_java_repositories() From 1366869ce4537d0b62c1ce7c207a78fe772d33e9 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Fri, 5 Apr 2024 00:30:51 -0400 Subject: [PATCH 261/311] Fix jedismock tests on mac --- .../build/buildfarm/instance/shard/JedisCasWorkerMapTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/build/buildfarm/instance/shard/JedisCasWorkerMapTest.java b/src/test/java/build/buildfarm/instance/shard/JedisCasWorkerMapTest.java index 0b6f3d2020..7b666f470d 100644 --- a/src/test/java/build/buildfarm/instance/shard/JedisCasWorkerMapTest.java +++ b/src/test/java/build/buildfarm/instance/shard/JedisCasWorkerMapTest.java @@ -8,6 +8,7 @@ import com.github.fppt.jedismock.RedisServer; import com.github.fppt.jedismock.server.ServiceOptions; import java.io.IOException; +import java.net.InetAddress; import java.util.Arrays; import java.util.Collections; import org.junit.After; @@ -29,7 +30,7 @@ public class JedisCasWorkerMapTest { @Before public void setup() throws IOException { redisServer = - RedisServer.newRedisServer() + RedisServer.newRedisServer(0, InetAddress.getByName("localhost")) .setOptions(ServiceOptions.defaultOptions().withClusterModeEnabled()) .start(); redisClient = From 3d2383f73586c161425f9a338ab1595269692716 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Fri, 5 Apr 2024 16:03:07 -0400 Subject: [PATCH 262/311] Terminate OperationQueue dequeue when interrupted --- .../java/build/buildfarm/instance/shard/OperationQueue.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/build/buildfarm/instance/shard/OperationQueue.java b/src/main/java/build/buildfarm/instance/shard/OperationQueue.java index 43e7384e5c..5cf7651b85 100644 --- a/src/main/java/build/buildfarm/instance/shard/OperationQueue.java +++ b/src/main/java/build/buildfarm/instance/shard/OperationQueue.java @@ -200,6 +200,9 @@ public String dequeue(UnifiedJedis jedis, List provisions) // Keep iterating over matched queues until we find one that is non-empty and provides a // dequeued value. for (int index = roundRobinPopIndex(queues); ; index = roundRobinPopIndex(queues)) { + if (Thread.currentThread().isInterrupted()) { + throw new InterruptedException(); + } String value = queues.get(index).poll(jedis); if (value != null) { return value; From 12faac7b3fa147c475a3f8a87d40c28f8f9917fb Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Thu, 4 Apr 2024 00:52:16 -0700 Subject: [PATCH 263/311] fix(metrics): convert Gauges to Counters These are only being `inc()` (incremented) and will be better represented as Counters rather than Gauges. --- .../metrics/AbstractMetricsPublisher.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/main/java/build/buildfarm/metrics/AbstractMetricsPublisher.java b/src/main/java/build/buildfarm/metrics/AbstractMetricsPublisher.java index 162d906ae4..493c378074 100644 --- a/src/main/java/build/buildfarm/metrics/AbstractMetricsPublisher.java +++ b/src/main/java/build/buildfarm/metrics/AbstractMetricsPublisher.java @@ -24,7 +24,6 @@ import com.google.protobuf.util.JsonFormat; import com.google.rpc.PreconditionFailure; import io.prometheus.client.Counter; -import io.prometheus.client.Gauge; import io.prometheus.client.Histogram; import java.util.logging.Level; import lombok.extern.java.Log; @@ -33,27 +32,27 @@ public abstract class AbstractMetricsPublisher implements MetricsPublisher { private static final Counter actionsCounter = Counter.build().name("actions").help("Number of actions.").register(); - private static final Gauge operationsInStage = - Gauge.build() + private static final Counter operationsInStage = + Counter.build() .name("operations_stage_load") .labelNames("stage_name") .help("Operations in stage.") .register(); - private static final Gauge operationStatus = - Gauge.build() + private static final Counter operationStatus = + Counter.build() .name("operation_status") .labelNames("status_code") .help("Operation execution status.") .register(); - private static final Gauge operationsPerWorker = - Gauge.build() + private static final Counter operationsPerWorker = + Counter.build() .name("operation_worker") .labelNames("worker_name") .help("Operations per worker.") .register(); - private static final Gauge operationExitCode = - Gauge.build() + private static final Counter operationExitCode = + Counter.build() .name("operation_exit_code") .labelNames("exit_code") .help("Operation execution exit code.") From d0bbc5fb706dfe4d61ba1aabf5e9c57eb4cc1ec4 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Thu, 4 Apr 2024 00:59:05 -0700 Subject: [PATCH 264/311] docs(metrics.md): update metric types Updating Gauge->Counter for: - operations_stage_load - operation_status - operation_exit_code - operation_worker --- _site/docs/metrics/metrics.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/_site/docs/metrics/metrics.md b/_site/docs/metrics/metrics.md index 84bbf7e3b5..7b55ab83bb 100644 --- a/_site/docs/metrics/metrics.md +++ b/_site/docs/metrics/metrics.md @@ -74,19 +74,19 @@ Counter for the number of actions processed **operations_stage_load** -Gauge for the number of operations in each stage (using a stage_name for each individual stage) +Counter for the number of operations in each stage (using a `stage_name` for each individual stage) **operation_status** -Gauge for the completed operations status (using a status_code label for each individual GRPC code) +Counter for the completed operations status (using a `status_code` label for each individual GRPC code) **operation_exit_code** -Gauge for the completed operations exit code (using a exit_code label for each individual execution exit code) +Counter for the completed operations exit code (using an `exit_code` label for each individual execution exit code) **operation_worker** -Gauge for the number of operations executed on each worker (using a worker_name label for each individual worker) +Counter for the number of operations executed on each worker (using a `worker_name` label for each individual worker) **action_results** @@ -162,4 +162,4 @@ server: grpcMetrics: enabled: true provideLatencyHistograms: false -``` \ No newline at end of file +``` From d270aa94232ac7a839331244b999624d724f8848 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Wed, 27 Mar 2024 10:18:01 -0700 Subject: [PATCH 265/311] fix(RedisShardBackplane): fix backplaneStatus - re-factor to use chained builder pattern - fix the calls to `client.call(jedis -> ...)` --- .../instance/shard/RedisShardBackplane.java | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java index 6ade389b93..27d16abad8 100644 --- a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java +++ b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java @@ -53,7 +53,9 @@ import build.buildfarm.v1test.GetClientStartTimeRequest; import build.buildfarm.v1test.GetClientStartTimeResult; import build.buildfarm.v1test.OperationChange; +import build.buildfarm.v1test.OperationQueueStatus; import build.buildfarm.v1test.QueueEntry; +import build.buildfarm.v1test.QueueStatus; import build.buildfarm.v1test.QueuedOperationMetadata; import build.buildfarm.v1test.ShardWorker; import build.buildfarm.v1test.WorkerChange; @@ -1497,16 +1499,17 @@ public boolean canPrequeue() throws IOException { @SuppressWarnings("ConstantConditions") @Override public BackplaneStatus backplaneStatus() throws IOException { - BackplaneStatus.Builder builder = BackplaneStatus.newBuilder(); Set executeWorkers = getExecuteWorkers(); Set storageWorkers = getStorageWorkers(); - builder.addAllActiveExecuteWorkers(executeWorkers); - builder.addAllActiveStorageWorkers(storageWorkers); - builder.addAllActiveWorkers(Sets.union(executeWorkers, storageWorkers)); - builder.setDispatchedSize(client.call(jedis -> state.dispatchedOperations.size(jedis))); - builder.setOperationQueue(state.operationQueue.status(client.call(jedis -> jedis))); - builder.setPrequeue(state.prequeue.status(client.call(jedis -> jedis))); - return builder.build(); + return BackplaneStatus.newBuilder() + .addAllActiveExecuteWorkers(executeWorkers) + .addAllActiveStorageWorkers(storageWorkers) + .addAllActiveWorkers(Sets.union(executeWorkers, storageWorkers)) + .setDispatchedSize(client.call(jedis -> state.dispatchedOperations.size(jedis))) + .setOperationQueue( + (OperationQueueStatus) client.call(jedis -> state.operationQueue.status(jedis))) + .setPrequeue((QueueStatus) client.call(jedis -> state.prequeue.status(jedis))) + .build(); } @SuppressWarnings("ConstantConditions") From 5c19f873e2c7a31dbd6478ff840022038d754342 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Thu, 4 Apr 2024 00:46:41 -0700 Subject: [PATCH 266/311] refactor for clarity Refactor for readability --- .../buildfarm/instance/shard/RedisShardBackplane.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java index 27d16abad8..ceafdd114b 100644 --- a/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java +++ b/src/main/java/build/buildfarm/instance/shard/RedisShardBackplane.java @@ -1501,14 +1501,16 @@ public boolean canPrequeue() throws IOException { public BackplaneStatus backplaneStatus() throws IOException { Set executeWorkers = getExecuteWorkers(); Set storageWorkers = getStorageWorkers(); + OperationQueueStatus operationQueueStatus = + client.call(jedis -> state.operationQueue.status(jedis)); + QueueStatus prequeueStatus = client.call(jedis -> state.prequeue.status(jedis)); return BackplaneStatus.newBuilder() .addAllActiveExecuteWorkers(executeWorkers) .addAllActiveStorageWorkers(storageWorkers) .addAllActiveWorkers(Sets.union(executeWorkers, storageWorkers)) .setDispatchedSize(client.call(jedis -> state.dispatchedOperations.size(jedis))) - .setOperationQueue( - (OperationQueueStatus) client.call(jedis -> state.operationQueue.status(jedis))) - .setPrequeue((QueueStatus) client.call(jedis -> state.prequeue.status(jedis))) + .setOperationQueue(operationQueueStatus) + .setPrequeue(prequeueStatus) .build(); } From d98902759ee9c3af0c05bfa3c684aca425ee1ab7 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Fri, 1 Mar 2024 16:34:09 -0800 Subject: [PATCH 267/311] build: remove macos-specific options --- .bazelrc | 2 -- 1 file changed, 2 deletions(-) diff --git a/.bazelrc b/.bazelrc index 8d13a79d36..3ca98330c3 100644 --- a/.bazelrc +++ b/.bazelrc @@ -29,5 +29,3 @@ common --lockfile_mode=off # It's off because we have mac/windows/linux developers who may not have access # to all three to update the platform-specific bits of the lockfile. -# Support protobuf on macOS with Xcode 15.x -common:macos --host_cxxopt=-std=c++14 --cxxopt=-std=c++14 From 296427d42224e6c72faccd9417f89e706a87ec3f Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Tue, 19 Mar 2024 16:13:32 -0700 Subject: [PATCH 268/311] build(MODULE.bazel): add build_deps from extensions.bzl --- MODULE.bazel | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/MODULE.bazel b/MODULE.bazel index bd656d1c49..fcb69f6a1b 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -65,6 +65,17 @@ python.toolchain( python_version = "3.11", ) +build_deps = use_extension("//:extensions.bzl", "build_deps") +use_repo( + build_deps, + "bazel", + "io_grpc_grpc_java", + "jedis", + "opentelemetry", + "skip_sleep", + "tini", +) + find_rpm = use_extension("@rules_pkg//toolchains/rpm:rpmbuild_configure.bzl", "find_system_rpmbuild_bzlmod") use_repo(find_rpm, "rules_pkg_rpmbuild") From 8a4046fd8a68a4911335b09b07176a481f69dcbb Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Tue, 19 Mar 2024 16:13:53 -0700 Subject: [PATCH 269/311] build(MODULE.bazel): com_google_googleapis --- MODULE.bazel | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/MODULE.bazel b/MODULE.bazel index fcb69f6a1b..e259ee2e9e 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -76,6 +76,27 @@ use_repo( "tini", ) +bazel_dep(name = "com_google_googleapis", version = "2a40f63ea714c7f4c6856a5db4d1f3cc7d4c4b18") +archive_override( + module_name = "com_google_googleapis", + integrity = "sha256-ZZb7DC2S7M9G53Uu3gALP7UpXctrvnZ/HcGmPXq+A6U=", + patch_strip = 1, + patches = [ + "third_party/googleapis_add_bzlmod_support.patch", + ], + strip_prefix = "googleapis-2a40f63ea714c7f4c6856a5db4d1f3cc7d4c4b18", + urls = [ + "https://github.com/googleapis/googleapis/archive/2a40f63ea714c7f4c6856a5db4d1f3cc7d4c4b18.zip", + ], +) + +googleapis_switched_rules = use_extension("@com_google_googleapis//:extensions.bzl", "switched_rules") +googleapis_switched_rules.use_languages( + #grpc = True, # This REALLY wants `@io_grpc_grpc_java` to be defined, but try as I might, it cannot be found. + java = True, +) +use_repo(googleapis_switched_rules, "com_google_googleapis_imports") + find_rpm = use_extension("@rules_pkg//toolchains/rpm:rpmbuild_configure.bzl", "find_system_rpmbuild_bzlmod") use_repo(find_rpm, "rules_pkg_rpmbuild") From 5c618f8dd120ef915fd1c003ba2ef5956dd92c1e Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Fri, 1 Mar 2024 11:58:57 -0800 Subject: [PATCH 270/311] build: add rules_java --- MODULE.bazel | 1 + persistentworkers/src/main/protobuf/BUILD | 1 + third_party/BUILD.googleapis | 4 ++-- third_party/BUILD.remote_apis | 5 +++-- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index e259ee2e9e..c4c24c1e77 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -11,6 +11,7 @@ bazel_dep(name = "platforms", version = "0.0.8") bazel_dep(name = "protobuf", version = "23.1", repo_name = "com_google_protobuf") bazel_dep(name = "rules_cc", version = "0.0.9") bazel_dep(name = "rules_go", version = "0.44.2", repo_name = "io_bazel_rules_go") +bazel_dep(name = "rules_java", version = "7.4.0") bazel_dep(name = "rules_jvm_external", version = "5.3") bazel_dep(name = "rules_license", version = "0.0.7") bazel_dep(name = "rules_oci", version = "1.7.4") diff --git a/persistentworkers/src/main/protobuf/BUILD b/persistentworkers/src/main/protobuf/BUILD index 24411a07a4..9c92e04c4c 100755 --- a/persistentworkers/src/main/protobuf/BUILD +++ b/persistentworkers/src/main/protobuf/BUILD @@ -1,4 +1,5 @@ load("@bazel_tools//tools/build_rules:utilities.bzl", "java_library_srcs") +load("@rules_java//java:defs.bzl", "java_proto_library") load("@rules_proto//proto:defs.bzl", "proto_library") package(default_visibility = ["//visibility:public"]) diff --git a/third_party/BUILD.googleapis b/third_party/BUILD.googleapis index 53638b757d..476caabc5d 100644 --- a/third_party/BUILD.googleapis +++ b/third_party/BUILD.googleapis @@ -1,3 +1,5 @@ +load("@io_grpc_grpc_java//:java_grpc_library.bzl", "java_grpc_library") +load("@rules_java//java:defs.bzl", "java_proto_library") load("@rules_proto//proto:defs.bzl", "proto_library") package(default_visibility = ["//visibility:public"]) @@ -6,8 +8,6 @@ licenses(["notice"]) exports_files(["LICENSE"]) -load("@io_grpc_grpc_java//:java_grpc_library.bzl", "java_grpc_library") - java_proto_library( name = "google_devtools_build_v1_build_status_java_proto", deps = [":google_devtools_build_v1_build_status_proto"], diff --git a/third_party/BUILD.remote_apis b/third_party/BUILD.remote_apis index 3277c127d0..a8f141fdb7 100644 --- a/third_party/BUILD.remote_apis +++ b/third_party/BUILD.remote_apis @@ -1,11 +1,12 @@ +load("@io_grpc_grpc_java//:java_grpc_library.bzl", "java_grpc_library") +load("@rules_java//java:defs.bzl", "java_proto_library") + package(default_visibility = ["//visibility:public"]) licenses(["notice"]) exports_files(["LICENSE"]) -load("@io_grpc_grpc_java//:java_grpc_library.bzl", "java_grpc_library") - java_proto_library( name = "build_bazel_remote_asset_v1_remote_asset_java_proto", deps = [ From 36614cd2d671646e29532ea42b74830189515f3b Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Fri, 1 Mar 2024 12:08:41 -0800 Subject: [PATCH 271/311] build: move maven things to MODULE.bazel Also, update maven mirrors --- MODULE.bazel | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++ defs.bzl | 104 ------------------------------------------------ 2 files changed, 110 insertions(+), 104 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index c4c24c1e77..9bef458674 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -29,6 +29,116 @@ bazel_dep( dev_dependency = True, ) +IO_NETTY_MODULES = [ + "buffer", + "codec", + "codec-http", + "codec-http2", + "codec-socks", + "common", + "handler", + "handler-proxy", + "resolver", + "transport", + "transport-native-epoll", + "transport-native-kqueue", + "transport-native-unix-common", +] + +IO_GRPC_MODULES = [ + "api", + "auth", + "core", + "context", + "netty", + "stub", + "protobuf", + "testing", + "services", + "netty-shaded", +] + +COM_AWS_MODULES = [ + "s3", + "secretsmanager", +] + +maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven") +maven.install( + artifacts = ["com.amazonaws:aws-java-sdk-%s:1.12.544" % module for module in COM_AWS_MODULES] + [ + "com.fasterxml.jackson.core:jackson-databind:2.15.0", + "com.github.ben-manes.caffeine:caffeine:2.9.0", + "com.github.docker-java:docker-java:3.3.3", + "com.github.fppt:jedis-mock:1.0.13", + "com.github.jnr:jffi:1.3.11", + "com.github.jnr:jffi:jar:native:1.3.11", + "com.github.jnr:jnr-constants:0.10.4", + "com.github.jnr:jnr-ffi:2.2.14", + "com.github.jnr:jnr-posix:3.1.17", + "com.github.luben:zstd-jni:1.5.5-7", + "com.github.oshi:oshi-core:6.4.5", + "com.github.pcj:google-options:1.0.0", + "com.github.serceman:jnr-fuse:0.5.7", + "com.google.auth:google-auth-library-credentials:1.19.0", + "com.google.auth:google-auth-library-oauth2-http:1.19.0", + "com.google.code.findbugs:jsr305:3.0.2", + "com.google.code.gson:gson:2.10.1", + "com.google.errorprone:error_prone_annotations:2.22.0", + "com.google.errorprone:error_prone_core:2.22.0", + "com.google.guava:failureaccess:1.0.1", + "com.google.guava:guava:32.1.1-jre", + "com.google.j2objc:j2objc-annotations:2.8", + "com.google.jimfs:jimfs:1.3.0", + "com.google.protobuf:protobuf-java-util:3.19.1", + "com.google.protobuf:protobuf-java:3.19.1", + "com.google.truth:truth:1.1.5", + "com.googlecode.json-simple:json-simple:1.1.1", + "com.jayway.jsonpath:json-path:2.8.0", + "net.jcip:jcip-annotations:1.0", + "org.bouncycastle:bcprov-jdk15on:1.70", + "org.slf4j:slf4j-simple:2.0.9", + ] + ["io.netty:netty-%s:4.1.97.Final" % module for module in IO_NETTY_MODULES] + + ["io.grpc:grpc-%s:1.62.2" % module for module in IO_GRPC_MODULES] + [ + "io.prometheus:simpleclient:0.15.0", + "io.prometheus:simpleclient_hotspot:0.15.0", + "io.prometheus:simpleclient_httpserver:0.15.0", + "javax.annotation:javax.annotation-api:1.3.2", + "junit:junit:4.13.2", + "me.dinowernli:java-grpc-prometheus:0.6.0", + "net.javacrumbs.future-converter:future-converter-java8-guava:1.2.0", + "org.apache.commons:commons-compress:1.23.0", + "org.apache.commons:commons-lang3:3.13.0", + "org.apache.commons:commons-pool2:2.11.1", + "org.apache.tomcat:annotations-api:6.0.53", + "org.bouncycastle:bcprov-jdk15on:1.70", + "org.checkerframework:checker-qual:3.38.0", + "org.jetbrains:annotations:16.0.2", + "org.mockito:mockito-core:5.10.0", + "org.openjdk.jmh:jmh-core:1.37", + "org.openjdk.jmh:jmh-generator-annprocess:1.37", + "org.projectlombok:lombok:1.18.30", + "org.redisson:redisson:3.23.4", + "org.slf4j:slf4j-simple:2.0.9", + "org.threeten:threetenbp:1.6.8", + "org.xerial:sqlite-jdbc:3.34.0", + "org.yaml:snakeyaml:2.2", + "redis.clients:jedis:5.1.2", + ], + excluded_artifacts = [ + "com.google.protobuf:protobuf-java", + "com.google.protobuf:protobuf-javalite", + ], + # generate_compat_repositories = True, + #fail_if_repin_required = True, + #lock_file = "//:maven_install.json", + #TODO override_targets = IO_GRPC_GRPC_JAVA_OVERRIDE_TARGETS, + repositories = [ + "https://repo.maven.apache.org/maven2", + ], + strict_visibility = True, +) +use_repo(maven, "maven") + oci = use_extension("@rules_oci//oci:extensions.bzl", "oci") # Server base image diff --git a/defs.bzl b/defs.bzl index f8d187e198..c04149a8e2 100644 --- a/defs.bzl +++ b/defs.bzl @@ -5,41 +5,6 @@ buildfarm definitions that can be imported into other WORKSPACE files load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") load("@com_grail_bazel_toolchain//toolchain:rules.bzl", "llvm_toolchain") load("@io_grpc_grpc_java//:repositories.bzl", "IO_GRPC_GRPC_JAVA_OVERRIDE_TARGETS", "grpc_java_repositories") -load("@rules_jvm_external//:defs.bzl", "maven_install") - -IO_NETTY_MODULES = [ - "buffer", - "codec", - "codec-http", - "codec-http2", - "codec-socks", - "common", - "handler", - "handler-proxy", - "resolver", - "transport", - "transport-native-epoll", - "transport-native-kqueue", - "transport-native-unix-common", -] - -IO_GRPC_MODULES = [ - "api", - "auth", - "core", - "context", - "netty", - "stub", - "protobuf", - "testing", - "services", - "netty-shaded", -] - -COM_AWS_MODULES = [ - "s3", - "secretsmanager", -] def buildfarm_init(name = "buildfarm"): """ @@ -48,75 +13,6 @@ def buildfarm_init(name = "buildfarm"): Args: name: the name of the repository """ - maven_install( - artifacts = ["com.amazonaws:aws-java-sdk-%s:1.12.544" % module for module in COM_AWS_MODULES] + - [ - "com.fasterxml.jackson.core:jackson-databind:2.15.0", - "com.github.ben-manes.caffeine:caffeine:2.9.0", - "com.github.docker-java:docker-java:3.3.3", - "com.github.fppt:jedis-mock:1.0.13", - "com.github.jnr:jffi:1.3.11", - "com.github.jnr:jffi:jar:native:1.3.11", - "com.github.jnr:jnr-constants:0.10.4", - "com.github.jnr:jnr-ffi:2.2.14", - "com.github.jnr:jnr-posix:3.1.17", - "com.github.pcj:google-options:1.0.0", - "com.github.serceman:jnr-fuse:0.5.7", - "com.github.luben:zstd-jni:1.5.5-7", - "com.github.oshi:oshi-core:6.4.5", - "com.google.auth:google-auth-library-credentials:1.19.0", - "com.google.auth:google-auth-library-oauth2-http:1.19.0", - "com.google.code.findbugs:jsr305:3.0.2", - "com.google.code.gson:gson:2.10.1", - "com.google.errorprone:error_prone_annotations:2.22.0", - "com.google.errorprone:error_prone_core:2.22.0", - "com.google.guava:failureaccess:1.0.1", - "com.google.guava:guava:32.1.1-jre", - "com.google.j2objc:j2objc-annotations:2.8", - "com.google.jimfs:jimfs:1.3.0", - "com.google.protobuf:protobuf-java-util:3.19.1", - "com.google.protobuf:protobuf-java:3.19.1", - "com.google.truth:truth:1.1.5", - "com.googlecode.json-simple:json-simple:1.1.1", - "com.jayway.jsonpath:json-path:2.8.0", - "org.bouncycastle:bcprov-jdk15on:1.70", - "net.jcip:jcip-annotations:1.0", - ] + ["io.netty:netty-%s:4.1.97.Final" % module for module in IO_NETTY_MODULES] + - ["io.grpc:grpc-%s:1.62.2" % module for module in IO_GRPC_MODULES] + - [ - "io.prometheus:simpleclient:0.15.0", - "io.prometheus:simpleclient_hotspot:0.15.0", - "io.prometheus:simpleclient_httpserver:0.15.0", - "javax.annotation:javax.annotation-api:1.3.2", - "junit:junit:4.13.2", - "net.javacrumbs.future-converter:future-converter-java8-guava:1.2.0", - "net.jcip:jcip-annotations:1.0", - "org.apache.commons:commons-compress:1.23.0", - "org.apache.commons:commons-pool2:2.11.1", - "org.apache.commons:commons-lang3:3.13.0", - "me.dinowernli:java-grpc-prometheus:0.6.0", - "org.apache.tomcat:annotations-api:6.0.53", - "org.bouncycastle:bcprov-jdk15on:1.70", - "org.checkerframework:checker-qual:3.38.0", - "org.mockito:mockito-core:5.10.0", - "org.openjdk.jmh:jmh-core:1.37", - "org.openjdk.jmh:jmh-generator-annprocess:1.37", - "org.redisson:redisson:3.23.4", - "org.threeten:threetenbp:1.6.8", - "org.xerial:sqlite-jdbc:3.34.0", - "org.jetbrains:annotations:16.0.2", - "org.yaml:snakeyaml:2.2", - "org.projectlombok:lombok:1.18.30", - "org.slf4j:slf4j-simple:2.0.9", - "redis.clients:jedis:5.1.2", - ], - generate_compat_repositories = True, - override_targets = IO_GRPC_GRPC_JAVA_OVERRIDE_TARGETS, - repositories = [ - "https://repo1.maven.org/maven2", - "https://mirrors.ibiblio.org/pub/mirrors/maven2", - ], - ) protobuf_deps() From b1e9c36e89c34fde1ee04d5e3dded14b59244702 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Thu, 21 Mar 2024 11:18:36 -0700 Subject: [PATCH 272/311] build: remove IO_GRPC_JAVA_OVERRIDE_TARGETS from defs.bzl --- defs.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/defs.bzl b/defs.bzl index c04149a8e2..b894599378 100644 --- a/defs.bzl +++ b/defs.bzl @@ -4,7 +4,7 @@ buildfarm definitions that can be imported into other WORKSPACE files load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") load("@com_grail_bazel_toolchain//toolchain:rules.bzl", "llvm_toolchain") -load("@io_grpc_grpc_java//:repositories.bzl", "IO_GRPC_GRPC_JAVA_OVERRIDE_TARGETS", "grpc_java_repositories") +load("@io_grpc_grpc_java//:repositories.bzl", "grpc_java_repositories") def buildfarm_init(name = "buildfarm"): """ From 4bb7d77f45318eded6fa7d71576b4b9da8a669b3 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Tue, 19 Mar 2024 15:53:38 -0700 Subject: [PATCH 273/311] build(bzlmod): add grpc to MODULE.bazel --- MODULE.bazel | 1 + 1 file changed, 1 insertion(+) diff --git a/MODULE.bazel b/MODULE.bazel index 9bef458674..e2d4bafb2d 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -7,6 +7,7 @@ module( bazel_dep(name = "blake3", version = "1.3.3.bcr.1") bazel_dep(name = "gazelle", version = "0.35.0", repo_name = "bazel_gazelle") +bazel_dep(name = "grpc", version = "1.48.1.bcr.2", repo_name = "com_github_grpc_grpc") bazel_dep(name = "platforms", version = "0.0.8") bazel_dep(name = "protobuf", version = "23.1", repo_name = "com_google_protobuf") bazel_dep(name = "rules_cc", version = "0.0.9") From ce0084b7218870761d3350f92be448bacca7305e Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Fri, 1 Mar 2024 16:26:46 -0800 Subject: [PATCH 274/311] build(bzlmod): add rules_proto to MODULE.bazel --- MODULE.bazel | 1 + 1 file changed, 1 insertion(+) diff --git a/MODULE.bazel b/MODULE.bazel index e2d4bafb2d..bdca199784 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -17,6 +17,7 @@ bazel_dep(name = "rules_jvm_external", version = "5.3") bazel_dep(name = "rules_license", version = "0.0.7") bazel_dep(name = "rules_oci", version = "1.7.4") bazel_dep(name = "rules_pkg", version = "0.10.1") +bazel_dep(name = "rules_proto", version = "6.0.0-rc2") # Test dependencies bazel_dep( From 6f8631c248225b02d7f83c711a9cc26dddaea6f7 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Fri, 1 Mar 2024 12:09:57 -0800 Subject: [PATCH 275/311] build(protobuf): remove protobuf_deps from defs.bzl --- defs.bzl | 3 --- 1 file changed, 3 deletions(-) diff --git a/defs.bzl b/defs.bzl index b894599378..341bd4b3fe 100644 --- a/defs.bzl +++ b/defs.bzl @@ -2,7 +2,6 @@ buildfarm definitions that can be imported into other WORKSPACE files """ -load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") load("@com_grail_bazel_toolchain//toolchain:rules.bzl", "llvm_toolchain") load("@io_grpc_grpc_java//:repositories.bzl", "grpc_java_repositories") @@ -14,8 +13,6 @@ def buildfarm_init(name = "buildfarm"): name: the name of the repository """ - protobuf_deps() - grpc_java_repositories() llvm_toolchain( From 3033a95e95b8f95b027ee7b20e6c2a839dbca822 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Fri, 1 Mar 2024 16:28:50 -0800 Subject: [PATCH 276/311] build: move deps.bzl to extensions.bzl --- MODULE.bazel | 4 +++- deps.bzl => extensions.bzl | 25 +++++++++++++++++-------- 2 files changed, 20 insertions(+), 9 deletions(-) rename deps.bzl => extensions.bzl (85%) diff --git a/MODULE.bazel b/MODULE.bazel index bdca199784..a56daf4550 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -182,9 +182,11 @@ build_deps = use_extension("//:extensions.bzl", "build_deps") use_repo( build_deps, "bazel", + "com_grail_bazel_toolchain", + "googleapis", "io_grpc_grpc_java", - "jedis", "opentelemetry", + "remote_apis", "skip_sleep", "tini", ) diff --git a/deps.bzl b/extensions.bzl similarity index 85% rename from deps.bzl rename to extensions.bzl index 8cff71c2a2..e2db40d0d6 100644 --- a/deps.bzl +++ b/extensions.bzl @@ -3,10 +3,16 @@ buildfarm dependencies that can be imported into other WORKSPACE files """ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive", "http_file", "http_jar") -load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") def archive_dependencies(third_party): return [ + # Needed for "well-known protos" and @com_google_protobuf//:protoc. + # { + # "name": "com_google_protobuf", + # "sha256": "79082dc68d8bab2283568ce0be3982b73e19ddd647c2411d1977ca5282d2d6b3", + # "strip_prefix": "protobuf-25.0", + # "urls": ["https://github.com/protocolbuffers/protobuf/archive/v25.0.zip"], + # }, # Needed for @grpc_java//compiler:grpc_java_plugin. { "name": "io_grpc_grpc_java", @@ -63,23 +69,22 @@ def archive_dependencies(third_party): }, ] -def buildfarm_dependencies(repository_name = "build_buildfarm"): +def _buildfarm_extension_impl(ctx): """ Define all 3rd party archive rules for buildfarm Args: repository_name: the name of the repository """ - third_party = "@%s//third_party" % repository_name + repository_name = "@build_buildfarm" + third_party = "//third_party" for dependency in archive_dependencies(third_party): params = {} params.update(**dependency) - name = params.pop("name") - maybe(http_archive, name, **params) + http_archive(**params) - maybe( - http_jar, - "opentelemetry", + http_jar( + name = "opentelemetry", sha256 = "eccd069da36031667e5698705a6838d173d527a5affce6cc514a14da9dbf57d7", urls = [ "https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v1.28.0/opentelemetry-javaagent.jar", @@ -91,3 +96,7 @@ def buildfarm_dependencies(repository_name = "build_buildfarm"): sha256 = "12d20136605531b09a2c2dac02ccee85e1b874eb322ef6baf7561cd93f93c855", urls = ["https://github.com/krallin/tini/releases/download/v0.18.0/tini"], ) + +build_deps = module_extension( + implementation = _buildfarm_extension_impl, +) From c2a1119458ce9698fa06fdbd3e1a554e8b6836ad Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Tue, 19 Mar 2024 15:59:39 -0700 Subject: [PATCH 277/311] chore(MODULE.bazel): remove googleapis from build_deps extension --- MODULE.bazel | 1 - 1 file changed, 1 deletion(-) diff --git a/MODULE.bazel b/MODULE.bazel index a56daf4550..9afae45c32 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -183,7 +183,6 @@ use_repo( build_deps, "bazel", "com_grail_bazel_toolchain", - "googleapis", "io_grpc_grpc_java", "opentelemetry", "remote_apis", From cf0af56b09bae7edb53a440bec1f84a8a01730d5 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Fri, 1 Mar 2024 12:11:40 -0800 Subject: [PATCH 278/311] build: remove compat_repositories() from WORKSPACE --- WORKSPACE | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WORKSPACE b/WORKSPACE index 2f1599f516..80c50687fb 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -8,9 +8,9 @@ load(":defs.bzl", "buildfarm_init") buildfarm_init() -load("@maven//:compat.bzl", "compat_repositories") +#load("@maven//:compat.bzl", "compat_repositories") -compat_repositories() +#compat_repositories() # Find rpmbuild if it exists. load("@rules_pkg//toolchains/rpm:rpmbuild_configure.bzl", "find_system_rpmbuild") From f3400828b814fc412f7ea1863aaac7959b1e47c9 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Thu, 29 Feb 2024 11:53:33 -0800 Subject: [PATCH 279/311] build: remove everything from WORKSPACE --- WORKSPACE | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/WORKSPACE b/WORKSPACE index 80c50687fb..abf429653f 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -1,18 +1,3 @@ -workspace(name = "build_buildfarm") - -load(":deps.bzl", "buildfarm_dependencies") - -buildfarm_dependencies() - -load(":defs.bzl", "buildfarm_init") - -buildfarm_init() - -#load("@maven//:compat.bzl", "compat_repositories") - -#compat_repositories() - -# Find rpmbuild if it exists. -load("@rules_pkg//toolchains/rpm:rpmbuild_configure.bzl", "find_system_rpmbuild") - -find_system_rpmbuild(name = "rules_pkg_rpmbuild") +# ================================================ # +# All dependencies have been moved to MODULE.bazel # +# ================================================ # From f7f9eda3cfb57212248df348e0ff64582ec431d2 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Fri, 1 Mar 2024 19:13:21 -0800 Subject: [PATCH 280/311] temp: remove llvm toolchain --- .bazelci/format.sh | 20 -------------------- MODULE.bazel | 1 - defs.bzl | 6 ------ extensions.bzl | 10 ---------- 4 files changed, 37 deletions(-) diff --git a/.bazelci/format.sh b/.bazelci/format.sh index d88f698cfd..794360086e 100755 --- a/.bazelci/format.sh +++ b/.bazelci/format.sh @@ -8,8 +8,6 @@ REMOVE_NEWLINES_AFTER_START_BRACKET=true JAVA_FORMATTER_URL=https://github.com/google/google-java-format/releases/download/v1.20.0/google-java-format-1.20.0-all-deps.jar LOCAL_FORMATTER="java_formatter.jar" -FORMAT_PROTO=true -CLANG_FORMAT=@llvm_toolchain//:clang-format if [ -z "$BAZEL" ]; then BAZEL=bazel fi @@ -71,20 +69,6 @@ run_java_formatter () { java -jar $LOCAL_FORMATTER -i $files } -run_proto_formatter () { - # Check whether any formatting changes need to be made. - # This is intended to be done by the CI. - if [[ "$@" == "--check" ]] - then - find $PWD -name '*.proto' -exec $BAZEL run $CLANG_FORMAT -- -i --dry-run --Werror {} + - handle_format_error_check - return - fi - - # Fixes formatting issues - find $PWD -name '*.proto' -exec $BAZEL run $CLANG_FORMAT -- -i {} + -} - run_buildifier () { $BAZEL run $BUILDIFIER -- -r > /dev/null 2>&1 } @@ -93,10 +77,6 @@ if [ "${FORMAT_JAVA:-false}" = true ]; then run_java_formatter "$@" fi; -if [ "${FORMAT_PROTO:-false}" = true ]; then - run_proto_formatter "$@" -fi; - if [ "${FORMAT_BUILD:-false}" = true ]; then run_buildifier "$@" fi; diff --git a/MODULE.bazel b/MODULE.bazel index 9afae45c32..825b360457 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -182,7 +182,6 @@ build_deps = use_extension("//:extensions.bzl", "build_deps") use_repo( build_deps, "bazel", - "com_grail_bazel_toolchain", "io_grpc_grpc_java", "opentelemetry", "remote_apis", diff --git a/defs.bzl b/defs.bzl index 341bd4b3fe..de409f43c7 100644 --- a/defs.bzl +++ b/defs.bzl @@ -2,7 +2,6 @@ buildfarm definitions that can be imported into other WORKSPACE files """ -load("@com_grail_bazel_toolchain//toolchain:rules.bzl", "llvm_toolchain") load("@io_grpc_grpc_java//:repositories.bzl", "grpc_java_repositories") def buildfarm_init(name = "buildfarm"): @@ -14,8 +13,3 @@ def buildfarm_init(name = "buildfarm"): """ grpc_java_repositories() - - llvm_toolchain( - name = "llvm_toolchain", - llvm_version = "16.0.0", - ) diff --git a/extensions.bzl b/extensions.bzl index e2db40d0d6..ebeaaca66e 100644 --- a/extensions.bzl +++ b/extensions.bzl @@ -39,16 +39,6 @@ def archive_dependencies(third_party): "url": "https://github.com/bazelbuild/remote-apis/archive/8f539af4b407a4f649707f9632fc2b715c9aa065.zip", }, - # Used to format proto files - { - "name": "com_grail_bazel_toolchain", - "sha256": "b2d168315dd0785f170b2b306b86e577c36e812b8f8b05568f9403141f2c24dd", - "strip_prefix": "toolchains_llvm-0.9", - "url": "https://github.com/bazel-contrib/toolchains_llvm/archive/refs/tags/0.9.tar.gz", - "patch_args": ["-p1"], - "patches": ["%s:clang_toolchain.patch" % third_party], - }, - # Bazel is referenced as a dependency so that buildfarm can access the linux-sandbox as a potential execution wrapper. { "name": "bazel", From 8e65eea80b5d42722c4b115541cf13c95488346c Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Tue, 19 Mar 2024 15:58:25 -0700 Subject: [PATCH 281/311] build: bazel_remote_apis bzlmod --- MODULE.bazel | 11 ++++++++++- extensions.bzl | 7 ------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 825b360457..9a29af43d0 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -31,6 +31,16 @@ bazel_dep( dev_dependency = True, ) +bazel_dep(name = "bazel_remote_apis", version = "66f0212d5cf703db65f7f56a1b54c60d4b41f920") +archive_override( + module_name = "bazel_remote_apis", + integrity = "sha256-1qzzTZxQh9IpK0GH1/n32onHKhknIrdOKC12Nu9sUds=", + strip_prefix = "remote-apis-66f0212d5cf703db65f7f56a1b54c60d4b41f920", + urls = [ + "https://github.com/bazelbuild/remote-apis/archive/66f0212d5cf703db65f7f56a1b54c60d4b41f920.zip", + ], +) + IO_NETTY_MODULES = [ "buffer", "codec", @@ -184,7 +194,6 @@ use_repo( "bazel", "io_grpc_grpc_java", "opentelemetry", - "remote_apis", "skip_sleep", "tini", ) diff --git a/extensions.bzl b/extensions.bzl index ebeaaca66e..29dda9b447 100644 --- a/extensions.bzl +++ b/extensions.bzl @@ -31,13 +31,6 @@ def archive_dependencies(third_party): "strip_prefix": "googleapis-5f8a02d6b7e77bd26e0375a00ca20eb2f3ee1ba2", "url": "https://github.com/googleapis/googleapis/archive/5f8a02d6b7e77bd26e0375a00ca20eb2f3ee1ba2.zip", }, - { - "name": "remote_apis", - "build_file": "%s:BUILD.remote_apis" % third_party, - "sha256": "e9a69cf51df14e20b7d3623ac9580bc8fb9275dda46305788e88eb768926b9c3", - "strip_prefix": "remote-apis-8f539af4b407a4f649707f9632fc2b715c9aa065", - "url": "https://github.com/bazelbuild/remote-apis/archive/8f539af4b407a4f649707f9632fc2b715c9aa065.zip", - }, # Bazel is referenced as a dependency so that buildfarm can access the linux-sandbox as a potential execution wrapper. { From 2bacdd4f50fd994b9e5202d722dd7378d37ed90a Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Tue, 19 Mar 2024 15:59:03 -0700 Subject: [PATCH 282/311] build: grpc is working now --- MODULE.bazel | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 9a29af43d0..ad25d4236f 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -135,11 +135,15 @@ maven.install( "org.xerial:sqlite-jdbc:3.34.0", "org.yaml:snakeyaml:2.2", "redis.clients:jedis:5.1.2", + ] + [ + # GRPC_JAVA stuff + "com.google.api.grpc:proto-google-common-protos:2.22.0", ], excluded_artifacts = [ "com.google.protobuf:protobuf-java", "com.google.protobuf:protobuf-javalite", ], + generate_compat_repositories = True, # generate_compat_repositories = True, #fail_if_repin_required = True, #lock_file = "//:maven_install.json", @@ -147,9 +151,19 @@ maven.install( repositories = [ "https://repo.maven.apache.org/maven2", ], - strict_visibility = True, + strict_visibility = False, # True breaks aws jars +) +use_repo( + maven, + "com_google_api_grpc_proto_google_common_protos", + "com_google_code_findbugs_jsr305", + "com_google_errorprone_error_prone_annotations", + "com_google_guava_failureaccess", + "com_google_guava_guava", + "com_google_j2objc_j2objc_annotations", + "maven", + "org_apache_tomcat_annotations_api", ) -use_repo(maven, "maven") oci = use_extension("@rules_oci//oci:extensions.bzl", "oci") From 69b2190699d9e95c0094abb61dcb65bcc7936bd5 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Sun, 31 Mar 2024 22:58:20 -0700 Subject: [PATCH 283/311] build: simplify maven dependencies --- MODULE.bazel | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index ad25d4236f..2d393075f7 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -135,19 +135,9 @@ maven.install( "org.xerial:sqlite-jdbc:3.34.0", "org.yaml:snakeyaml:2.2", "redis.clients:jedis:5.1.2", - ] + [ - # GRPC_JAVA stuff - "com.google.api.grpc:proto-google-common-protos:2.22.0", - ], - excluded_artifacts = [ - "com.google.protobuf:protobuf-java", - "com.google.protobuf:protobuf-javalite", ], generate_compat_repositories = True, - # generate_compat_repositories = True, - #fail_if_repin_required = True, - #lock_file = "//:maven_install.json", - #TODO override_targets = IO_GRPC_GRPC_JAVA_OVERRIDE_TARGETS, + lock_file = "//:maven_install.json", repositories = [ "https://repo.maven.apache.org/maven2", ], @@ -155,14 +145,8 @@ maven.install( ) use_repo( maven, - "com_google_api_grpc_proto_google_common_protos", - "com_google_code_findbugs_jsr305", - "com_google_errorprone_error_prone_annotations", - "com_google_guava_failureaccess", - "com_google_guava_guava", - "com_google_j2objc_j2objc_annotations", "maven", - "org_apache_tomcat_annotations_api", + "unpinned_maven", ) oci = use_extension("@rules_oci//oci:extensions.bzl", "oci") From f85f05e347beb76a8ca681d5050a9da3d402dd68 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Tue, 19 Mar 2024 16:00:25 -0700 Subject: [PATCH 284/311] build(third_party/googleapis): add BUILD and patch --- third_party/googleapis/BUILD | 11 +++ .../googleapis_add_bzlmod_support.patch | 92 +++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 third_party/googleapis/BUILD create mode 100644 third_party/googleapis_add_bzlmod_support.patch diff --git a/third_party/googleapis/BUILD b/third_party/googleapis/BUILD new file mode 100644 index 0000000000..c44c257584 --- /dev/null +++ b/third_party/googleapis/BUILD @@ -0,0 +1,11 @@ +load("@io_grpc_grpc_java//:java_grpc_library.bzl", "java_grpc_library") + +package(default_visibility = ["//visibility:public"]) + +java_grpc_library( + name = "google_bytestream_bytestream_java_grpc", + srcs = ["@com_google_googleapis//google/bytestream:bytestream_proto"], + deps = [ + "@com_google_googleapis//google/bytestream:bytestream_java_proto", + ], +) diff --git a/third_party/googleapis_add_bzlmod_support.patch b/third_party/googleapis_add_bzlmod_support.patch new file mode 100644 index 0000000000..8986756fd6 --- /dev/null +++ b/third_party/googleapis_add_bzlmod_support.patch @@ -0,0 +1,92 @@ +diff --git a/MODULE.bazel b/MODULE.bazel +new file mode 100644 +index 000000000..c26575773 +--- /dev/null ++++ b/MODULE.bazel +@@ -0,0 +1,22 @@ ++module( ++ name = "com_google_googleapis", ++ version = "64926d52febbf298cb82a8f472ade4a3969ba922", ++) ++ ++bazel_dep(name = "protobuf", version = "21.7", repo_name = "com_google_protobuf") ++bazel_dep(name = "rules_proto", version = "5.3.0-21.7") ++ ++switched_rules = use_extension("//:extensions.bzl", "switched_rules") ++switched_rules.use_languages( ++ cc = True, ++ csharp = True, ++ gapic = True, ++ go = True, ++ grpc = True, ++ java = True, ++ nodejs = True, ++ php = True, ++ python = True, ++ ruby = True, ++) ++use_repo(switched_rules, "com_google_googleapis_imports") +diff --git a/WORKSPACE.bzlmod b/WORKSPACE.bzlmod +new file mode 100644 +index 000000000..fafa28da3 +--- /dev/null ++++ b/WORKSPACE.bzlmod +@@ -0,0 +1,2 @@ ++# When Bzlmod is enabled, this file replaces the content of the original WORKSPACE ++# and makes sure no WORKSPACE prefix or suffix are added when Bzlmod is enabled. +diff --git a/extensions.bzl b/extensions.bzl +new file mode 100644 +index 000000000..d8f04cf6c +--- /dev/null ++++ b/extensions.bzl +@@ -0,0 +1,50 @@ ++load(":repository_rules.bzl", "switched_rules_by_language") ++ ++_use_languages_tag = tag_class( ++ attrs = { ++ "cc": attr.bool(default = False), ++ "csharp": attr.bool(default = False), ++ "gapic": attr.bool(default = False), ++ "go": attr.bool(default = False), ++ "go_test": attr.bool(default = False), ++ "grpc": attr.bool(default = False), ++ "java": attr.bool(default = False), ++ "nodejs": attr.bool(default = False), ++ "php": attr.bool(default = False), ++ "python": attr.bool(default = False), ++ "ruby": attr.bool(default = False), ++ }, ++) ++ ++def _switched_rules_impl(ctx): ++ attrs = {} ++ for module in ctx.modules: ++ if not module.is_root: ++ continue ++ ++ for t in module.tags.use_languages: ++ attrs = { ++ "cc": t.cc, ++ "csharp": t.csharp, ++ "gapic": t.gapic, ++ "go": t.go, ++ "go_test": t.go_test, ++ "grpc": t.grpc, ++ "java": t.java, ++ "nodejs": t.nodejs, ++ "php": t.php, ++ "python": t.python, ++ "ruby": t.ruby, ++ } ++ ++ switched_rules_by_language( ++ name = "com_google_googleapis_imports", ++ **attrs ++ ) ++ ++switched_rules = module_extension( ++ implementation = _switched_rules_impl, ++ tag_classes = { ++ "use_languages": _use_languages_tag, ++ }, ++) From 62b5689045160d4e7c65d7d98d22bd88aa5cfa96 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Tue, 19 Mar 2024 15:47:21 -0700 Subject: [PATCH 285/311] build(third_party/googleapis): add google_longrunning_operations_java_grpc --- third_party/googleapis/BUILD | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/third_party/googleapis/BUILD b/third_party/googleapis/BUILD index c44c257584..d8a2b34f2b 100644 --- a/third_party/googleapis/BUILD +++ b/third_party/googleapis/BUILD @@ -9,3 +9,11 @@ java_grpc_library( "@com_google_googleapis//google/bytestream:bytestream_java_proto", ], ) + +java_grpc_library( + name = "google_longrunning_operations_java_grpc", + srcs = ["@com_google_googleapis//google/longrunning:operations_proto"], + deps = [ + "@com_google_googleapis//google/longrunning:longrunning_java_proto", + ], +) From edc8809fb1060cb8c8ef0e923de9b0a626ce6c76 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Tue, 19 Mar 2024 15:48:55 -0700 Subject: [PATCH 286/311] build(third_party/googleapis): add more _java_grpc --- third_party/BUILD.remote_apis | 2 +- third_party/googleapis/BUILD | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/third_party/BUILD.remote_apis b/third_party/BUILD.remote_apis index a8f141fdb7..407a7c9291 100644 --- a/third_party/BUILD.remote_apis +++ b/third_party/BUILD.remote_apis @@ -24,7 +24,7 @@ java_proto_library( name = "build_bazel_remote_execution_v2_remote_execution_java_proto", deps = [ "//build/bazel/remote/execution/v2:remote_execution_proto", - "@googleapis//:google_longrunning_operations_proto", + "@com_google_googleapis//google/longrunning:operations_proto", ], ) diff --git a/third_party/googleapis/BUILD b/third_party/googleapis/BUILD index d8a2b34f2b..34ca69d4c2 100644 --- a/third_party/googleapis/BUILD +++ b/third_party/googleapis/BUILD @@ -17,3 +17,11 @@ java_grpc_library( "@com_google_googleapis//google/longrunning:longrunning_java_proto", ], ) + +java_grpc_library( + name = "google_devtools_build_v1_publish_build_event_java_grpc", + srcs = ["@com_google_googleapis//google/devtools/build/v1:build_proto"], + deps = [ + "@com_google_googleapis//google/devtools/build/v1:build_java_proto", + ], +) From 4c7ed1694e33b81485ccc4969ac1f8242697c233 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Mon, 4 Mar 2024 12:56:21 -0800 Subject: [PATCH 287/311] chore: re-write a ton of dependencies --- .../main/java/persistent/common/util/BUILD | 1 - .../java/build/buildfarm/actioncache/BUILD | 4 +- src/main/java/build/buildfarm/backplane/BUILD | 4 +- src/main/java/build/buildfarm/cas/BUILD | 10 ++-- src/main/java/build/buildfarm/common/BUILD | 14 +++--- .../java/build/buildfarm/common/config/BUILD | 4 +- .../java/build/buildfarm/common/grpc/BUILD | 6 +-- .../build/buildfarm/common/resources/BUILD | 15 +++--- .../build/buildfarm/common/services/BUILD | 15 +++--- src/main/java/build/buildfarm/instance/BUILD | 4 +- .../build/buildfarm/instance/server/BUILD | 8 ++-- .../java/build/buildfarm/instance/shard/BUILD | 5 +- .../java/build/buildfarm/instance/stub/BUILD | 14 +++--- src/main/java/build/buildfarm/metrics/BUILD | 6 +-- .../java/build/buildfarm/metrics/log/BUILD | 6 +-- .../java/build/buildfarm/operations/BUILD | 8 ++-- .../build/buildfarm/operations/finder/BUILD | 5 +- .../java/build/buildfarm/proxy/http/BUILD | 12 ++--- src/main/java/build/buildfarm/server/BUILD | 3 +- .../build/buildfarm/server/services/BUILD | 19 ++++---- src/main/java/build/buildfarm/tools/BUILD | 47 +++++++++---------- src/main/java/build/buildfarm/worker/BUILD | 3 +- .../java/build/buildfarm/worker/shard/BUILD | 4 +- src/main/protobuf/BUILD.bazel | 14 +++--- src/test/java/build/buildfarm/cas/BUILD | 9 ++-- src/test/java/build/buildfarm/common/BUILD | 4 +- .../java/build/buildfarm/common/grpc/BUILD | 9 ++-- src/test/java/build/buildfarm/common/io/BUILD | 4 +- .../build/buildfarm/common/resources/BUILD | 6 +-- .../build/buildfarm/common/services/BUILD | 6 +-- src/test/java/build/buildfarm/examples/BUILD | 4 +- .../build/buildfarm/instance/server/BUILD | 6 +-- .../java/build/buildfarm/instance/shard/BUILD | 42 +++++++---------- .../java/build/buildfarm/instance/stub/BUILD | 9 ++-- src/test/java/build/buildfarm/metrics/BUILD | 2 +- .../java/build/buildfarm/proxy/http/BUILD | 6 +-- src/test/java/build/buildfarm/server/BUILD | 13 +++-- .../build/buildfarm/server/services/BUILD | 2 +- src/test/java/build/buildfarm/worker/BUILD | 5 +- .../build/buildfarm/worker/persistent/BUILD | 4 +- .../java/build/buildfarm/worker/util/BUILD | 8 ++-- 41 files changed, 172 insertions(+), 198 deletions(-) diff --git a/persistentworkers/src/main/java/persistent/common/util/BUILD b/persistentworkers/src/main/java/persistent/common/util/BUILD index 32312aff44..b391f50527 100644 --- a/persistentworkers/src/main/java/persistent/common/util/BUILD +++ b/persistentworkers/src/main/java/persistent/common/util/BUILD @@ -2,5 +2,4 @@ java_library( name = "util", srcs = glob(["**/*.java"]), visibility = ["//visibility:public"], - deps = [], ) diff --git a/src/main/java/build/buildfarm/actioncache/BUILD b/src/main/java/build/buildfarm/actioncache/BUILD index 46e8614c90..874782067b 100644 --- a/src/main/java/build/buildfarm/actioncache/BUILD +++ b/src/main/java/build/buildfarm/actioncache/BUILD @@ -6,13 +6,13 @@ java_library( "//src/main/java/build/buildfarm/backplane", "//src/main/java/build/buildfarm/common", "//src/main/java/build/buildfarm/common/config", + "//third_party/remote-apis:build_bazel_remote_execution_v2_remote_execution_java_grpc", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@maven//:com_github_ben_manes_caffeine_caffeine", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_core", "@maven//:net_javacrumbs_future_converter_future_converter_java8_guava", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_grpc", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/backplane/BUILD b/src/main/java/build/buildfarm/backplane/BUILD index 090d2cd2ef..6d4934f68c 100644 --- a/src/main/java/build/buildfarm/backplane/BUILD +++ b/src/main/java/build/buildfarm/backplane/BUILD @@ -7,9 +7,9 @@ java_library( "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/operations", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@googleapis//:google_longrunning_operations_java_proto", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/longrunning:longrunning_java_proto", "@maven//:com_google_guava_guava", "@maven//:net_jcip_jcip_annotations", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/cas/BUILD b/src/main/java/build/buildfarm/cas/BUILD index 2af2edc8df..77532d0cac 100644 --- a/src/main/java/build/buildfarm/cas/BUILD +++ b/src/main/java/build/buildfarm/cas/BUILD @@ -15,9 +15,11 @@ java_library( "//src/main/java/build/buildfarm/common/resources:resource_java_proto", "//src/main/java/build/buildfarm/instance/stub", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@googleapis//:google_bytestream_bytestream_java_grpc", - "@googleapis//:google_bytestream_bytestream_java_proto", - "@googleapis//:google_rpc_code_java_proto", + "//third_party/googleapis:google_bytestream_bytestream_java_grpc", + "//third_party/remote-apis:build_bazel_remote_execution_v2_remote_execution_java_grpc", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_jnr_jnr_ffi", "@maven//:com_google_code_findbugs_jsr305", "@maven//:com_google_guava_guava", @@ -32,7 +34,5 @@ java_library( "@maven//:io_prometheus_simpleclient", "@maven//:net_jcip_jcip_annotations", "@maven//:org_projectlombok_lombok", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_grpc", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/common/BUILD b/src/main/java/build/buildfarm/common/BUILD index a4af6fcb4c..a31d381792 100644 --- a/src/main/java/build/buildfarm/common/BUILD +++ b/src/main/java/build/buildfarm/common/BUILD @@ -16,9 +16,9 @@ java_library( "//src/main/java/build/buildfarm/common/resources", "//src/main/java/build/buildfarm/common/resources:resource_java_proto", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@googleapis//:google_longrunning_operations_java_proto", - "@googleapis//:google_rpc_code_java_proto", - "@googleapis//:google_rpc_error_details_java_proto", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/longrunning:longrunning_java_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_jnr_jnr_constants", "@maven//:com_github_jnr_jnr_ffi", "@maven//:com_github_jnr_jnr_posix", @@ -38,7 +38,6 @@ java_library( "@maven//:org_projectlombok_lombok", "@maven//:org_threeten_threetenbp", "@maven//:redis_clients_jedis", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) @@ -55,9 +54,9 @@ java_library( "//src/main/java/build/buildfarm/common/resources", "//src/main/java/build/buildfarm/common/resources:resource_java_proto", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@googleapis//:google_longrunning_operations_java_proto", - "@googleapis//:google_rpc_code_java_proto", - "@googleapis//:google_rpc_error_details_java_proto", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/longrunning:longrunning_java_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_jnr_jnr_constants", "@maven//:com_github_jnr_jnr_ffi", "@maven//:com_github_jnr_jnr_posix", @@ -77,7 +76,6 @@ java_library( "@maven//:org_projectlombok_lombok", "@maven//:org_threeten_threetenbp", "@maven//:redis_clients_jedis", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/common/config/BUILD b/src/main/java/build/buildfarm/common/config/BUILD index 40be76887d..0d416b827d 100644 --- a/src/main/java/build/buildfarm/common/config/BUILD +++ b/src/main/java/build/buildfarm/common/config/BUILD @@ -8,8 +8,8 @@ java_library( deps = [ "//src/main/java/build/buildfarm/common", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@googleapis//:google_longrunning_operations_java_proto", - "@googleapis//:google_rpc_code_java_proto", + "@com_google_googleapis//google/longrunning:longrunning_java_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_oshi_oshi_core", "@maven//:com_github_pcj_google_options", "@maven//:com_google_code_findbugs_jsr305", diff --git a/src/main/java/build/buildfarm/common/grpc/BUILD b/src/main/java/build/buildfarm/common/grpc/BUILD index af68ba7d63..97bd3db339 100644 --- a/src/main/java/build/buildfarm/common/grpc/BUILD +++ b/src/main/java/build/buildfarm/common/grpc/BUILD @@ -5,8 +5,9 @@ java_library( visibility = ["//visibility:public"], deps = [ "//src/main/java/build/buildfarm/common", - "@googleapis//:google_bytestream_bytestream_java_grpc", - "@googleapis//:google_bytestream_bytestream_java_proto", + "//third_party/googleapis:google_bytestream_bytestream_java_grpc", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_proto", "@maven//:com_google_code_findbugs_jsr305", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", @@ -17,6 +18,5 @@ java_library( "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", "@maven//:org_projectlombok_lombok", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/common/resources/BUILD b/src/main/java/build/buildfarm/common/resources/BUILD index 7f03c6def5..6689ed969d 100644 --- a/src/main/java/build/buildfarm/common/resources/BUILD +++ b/src/main/java/build/buildfarm/common/resources/BUILD @@ -7,12 +7,12 @@ proto_library( name = "resource_proto", srcs = ["resource.proto"], deps = [ + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_proto", + "@com_google_googleapis//google/api:annotations_proto", + "@com_google_googleapis//google/longrunning:operations_proto", + "@com_google_googleapis//google/rpc:status_proto", "@com_google_protobuf//:duration_proto", "@com_google_protobuf//:timestamp_proto", - "@googleapis//:google_api_annotations_proto", - "@googleapis//:google_longrunning_operations_proto", - "@googleapis//:google_rpc_status_proto", - "@remote_apis//build/bazel/remote/execution/v2:remote_execution_proto", ], ) @@ -30,9 +30,9 @@ java_library( deps = [ "//src/main/java/build/buildfarm/common/resources:resource_java_proto", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@googleapis//:google_longrunning_operations_java_proto", - "@googleapis//:google_rpc_code_java_proto", - "@googleapis//:google_rpc_error_details_java_proto", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/longrunning:longrunning_java_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_jnr_jnr_constants", "@maven//:com_github_jnr_jnr_ffi", "@maven//:com_github_jnr_jnr_posix", @@ -49,6 +49,5 @@ java_library( "@maven//:org_apache_commons_commons_lang3", "@maven//:org_threeten_threetenbp", "@maven//:redis_clients_jedis", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/common/services/BUILD b/src/main/java/build/buildfarm/common/services/BUILD index 9a885cbafe..7d7cabd919 100644 --- a/src/main/java/build/buildfarm/common/services/BUILD +++ b/src/main/java/build/buildfarm/common/services/BUILD @@ -12,11 +12,13 @@ java_library( "//src/main/java/build/buildfarm/common/resources:resource_java_proto", "//src/main/java/build/buildfarm/instance", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@googleapis//:google_bytestream_bytestream_java_grpc", - "@googleapis//:google_bytestream_bytestream_java_proto", - "@googleapis//:google_devtools_build_v1_build_events_java_proto", - "@googleapis//:google_devtools_build_v1_publish_build_event_java_proto", - "@googleapis//:google_rpc_code_java_proto", + "//third_party/googleapis:google_bytestream_bytestream_java_grpc", + "//third_party/remote-apis:build_bazel_remote_execution_v2_remote_execution_java_grpc", + "@bazel_remote_apis//build/bazel/remote/asset/v1:remote_asset_java_grpc", + "@bazel_remote_apis//build/bazel/semver:semver_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_proto", + "@com_google_googleapis//google/devtools/build/v1:build_java_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_code_findbugs_jsr305", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", @@ -28,8 +30,5 @@ java_library( "@maven//:io_grpc_grpc_stub", "@maven//:io_prometheus_simpleclient", "@maven//:org_projectlombok_lombok", - "@remote_apis//:build_bazel_remote_asset_v1_remote_asset_java_proto", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_grpc", - "@remote_apis//:build_bazel_semver_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/instance/BUILD b/src/main/java/build/buildfarm/instance/BUILD index 5bb0451e96..b376b9ab99 100644 --- a/src/main/java/build/buildfarm/instance/BUILD +++ b/src/main/java/build/buildfarm/instance/BUILD @@ -5,7 +5,8 @@ java_library( deps = [ "//src/main/java/build/buildfarm/common", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@googleapis//:google_longrunning_operations_java_proto", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/longrunning:longrunning_java_proto", "@maven//:com_google_code_findbugs_jsr305", "@maven//:com_google_guava_failureaccess", "@maven//:com_google_guava_guava", @@ -15,6 +16,5 @@ java_library( "@maven//:io_grpc_grpc_core", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/instance/server/BUILD b/src/main/java/build/buildfarm/instance/server/BUILD index 1c63e9896c..ef7ff446c5 100644 --- a/src/main/java/build/buildfarm/instance/server/BUILD +++ b/src/main/java/build/buildfarm/instance/server/BUILD @@ -17,10 +17,9 @@ java_library( "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/operations", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@googleapis//:google_longrunning_operations_java_proto", - "@googleapis//:google_rpc_code_java_proto", - "@googleapis//:google_rpc_error_details_java_proto", - "@googleapis//:google_rpc_status_java_proto", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/longrunning:longrunning_java_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_code_findbugs_jsr305", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", @@ -31,6 +30,5 @@ java_library( "@maven//:io_grpc_grpc_stub", "@maven//:io_netty_netty_codec_http", "@maven//:org_projectlombok_lombok", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/instance/shard/BUILD b/src/main/java/build/buildfarm/instance/shard/BUILD index 03bf0d45dc..a0d197b0a3 100644 --- a/src/main/java/build/buildfarm/instance/shard/BUILD +++ b/src/main/java/build/buildfarm/instance/shard/BUILD @@ -18,8 +18,8 @@ java_library( "//src/main/java/build/buildfarm/operations", "//src/main/java/build/buildfarm/operations/finder", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@googleapis//:google_rpc_code_java_proto", - "@googleapis//:google_rpc_error_details_java_proto", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_ben_manes_caffeine_caffeine", "@maven//:com_google_code_findbugs_jsr305", "@maven//:com_google_guava_guava", @@ -36,6 +36,5 @@ java_library( "@maven//:org_projectlombok_lombok", "@maven//:org_redisson_redisson", "@maven//:redis_clients_jedis", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/instance/stub/BUILD b/src/main/java/build/buildfarm/instance/stub/BUILD index 1f5a2b916d..4cab9b8772 100644 --- a/src/main/java/build/buildfarm/instance/stub/BUILD +++ b/src/main/java/build/buildfarm/instance/stub/BUILD @@ -11,11 +11,13 @@ java_library( "//src/main/java/build/buildfarm/instance", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_grpc", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@googleapis//:google_bytestream_bytestream_java_grpc", - "@googleapis//:google_bytestream_bytestream_java_proto", - "@googleapis//:google_longrunning_operations_java_grpc", - "@googleapis//:google_longrunning_operations_java_proto", - "@googleapis//:google_rpc_code_java_proto", + "//third_party/googleapis:google_bytestream_bytestream_java_grpc", + "//third_party/googleapis:google_longrunning_operations_java_grpc", + "//third_party/remote-apis:build_bazel_remote_execution_v2_remote_execution_java_grpc", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_proto", + "@com_google_googleapis//google/longrunning:longrunning_java_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_code_findbugs_jsr305", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", @@ -26,7 +28,5 @@ java_library( "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", "@maven//:org_projectlombok_lombok", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_grpc", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/metrics/BUILD b/src/main/java/build/buildfarm/metrics/BUILD index 69166f1ca8..162404e359 100644 --- a/src/main/java/build/buildfarm/metrics/BUILD +++ b/src/main/java/build/buildfarm/metrics/BUILD @@ -5,14 +5,12 @@ java_library( visibility = ["//visibility:public"], deps = [ "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@googleapis//:google_rpc_code_java_proto", - "@googleapis//:google_rpc_error_details_java_proto", - "@googleapis//:google_rpc_status_java_proto", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:io_prometheus_simpleclient", "@maven//:org_projectlombok_lombok", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/metrics/log/BUILD b/src/main/java/build/buildfarm/metrics/log/BUILD index 88ea37849e..cde0d99591 100644 --- a/src/main/java/build/buildfarm/metrics/log/BUILD +++ b/src/main/java/build/buildfarm/metrics/log/BUILD @@ -7,12 +7,10 @@ java_library( "//src/main/java/build/buildfarm/common/config", "//src/main/java/build/buildfarm/metrics", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@googleapis//:google_rpc_code_java_proto", - "@googleapis//:google_rpc_error_details_java_proto", - "@googleapis//:google_rpc_status_java_proto", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:org_projectlombok_lombok", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/operations/BUILD b/src/main/java/build/buildfarm/operations/BUILD index ee8df831d9..6630ba9617 100644 --- a/src/main/java/build/buildfarm/operations/BUILD +++ b/src/main/java/build/buildfarm/operations/BUILD @@ -11,10 +11,9 @@ java_library( deps = [ "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_proto", - "@googleapis//:google_bytestream_bytestream_java_proto", - "@googleapis//:google_rpc_code_java_proto", - "@googleapis//:google_rpc_error_details_java_proto", - "@googleapis//:google_rpc_error_details_proto", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_code_findbugs_jsr305", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", @@ -26,6 +25,5 @@ java_library( "@maven//:io_grpc_grpc_core", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/operations/finder/BUILD b/src/main/java/build/buildfarm/operations/finder/BUILD index fdbbe85199..2e00b7d1df 100644 --- a/src/main/java/build/buildfarm/operations/finder/BUILD +++ b/src/main/java/build/buildfarm/operations/finder/BUILD @@ -10,8 +10,8 @@ java_library( "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/operations", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@googleapis//:google_rpc_code_java_proto", - "@googleapis//:google_rpc_error_details_java_proto", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_code_findbugs_jsr305", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", @@ -26,6 +26,5 @@ java_library( "@maven//:org_apache_commons_commons_pool2", "@maven//:org_projectlombok_lombok", "@maven//:redis_clients_jedis", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/proxy/http/BUILD b/src/main/java/build/buildfarm/proxy/http/BUILD index cfb4fa2674..a6ce0d4dac 100644 --- a/src/main/java/build/buildfarm/proxy/http/BUILD +++ b/src/main/java/build/buildfarm/proxy/http/BUILD @@ -7,10 +7,11 @@ java_library( "//src/main/java/build/buildfarm/common", "//src/main/java/build/buildfarm/common/resources:resource_java_proto", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@googleapis//:google_bytestream_bytestream_java_grpc", - "@googleapis//:google_bytestream_bytestream_java_proto", - "@googleapis//:google_rpc_code_java_proto", - "@googleapis//:google_rpc_status_java_proto", + "//third_party/googleapis:google_bytestream_bytestream_java_grpc", + "//third_party/remote-apis:build_bazel_remote_execution_v2_remote_execution_java_grpc", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_pcj_google_options", "@maven//:com_google_auth_google_auth_library_credentials", "@maven//:com_google_auth_google_auth_library_oauth2_http", @@ -23,6 +24,7 @@ java_library( "@maven//:io_grpc_grpc_netty", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", + "@maven//:io_grpc_grpc_util", "@maven//:io_netty_netty_buffer", "@maven//:io_netty_netty_codec", "@maven//:io_netty_netty_codec_http", @@ -35,7 +37,5 @@ java_library( "@maven//:io_netty_netty_transport_native_kqueue", "@maven//:io_netty_netty_transport_native_unix_common", "@maven//:org_projectlombok_lombok", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_grpc", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/server/BUILD b/src/main/java/build/buildfarm/server/BUILD index 2cd750a4ff..83b8060640 100644 --- a/src/main/java/build/buildfarm/server/BUILD +++ b/src/main/java/build/buildfarm/server/BUILD @@ -16,13 +16,12 @@ java_library( "//src/main/java/build/buildfarm/metrics/prometheus", "//src/main/java/build/buildfarm/server/services", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@io_grpc_grpc_proto//:health_java_proto", - "@io_grpc_grpc_proto//:health_proto", "@maven//:com_github_pcj_google_options", "@maven//:com_google_guava_guava", "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_core", "@maven//:io_grpc_grpc_services", + "@maven//:io_grpc_grpc_util", "@maven//:io_prometheus_simpleclient", "@maven//:javax_annotation_javax_annotation_api", "@maven//:org_bouncycastle_bcprov_jdk15on", diff --git a/src/main/java/build/buildfarm/server/services/BUILD b/src/main/java/build/buildfarm/server/services/BUILD index 6bb44b94f8..693b778235 100644 --- a/src/main/java/build/buildfarm/server/services/BUILD +++ b/src/main/java/build/buildfarm/server/services/BUILD @@ -13,12 +13,15 @@ java_library( "//src/main/java/build/buildfarm/metrics/log", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_grpc", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@googleapis//:google_bytestream_bytestream_java_proto", - "@googleapis//:google_devtools_build_v1_build_events_java_proto", - "@googleapis//:google_devtools_build_v1_publish_build_event_java_grpc", - "@googleapis//:google_devtools_build_v1_publish_build_event_java_proto", - "@googleapis//:google_longrunning_operations_java_grpc", - "@googleapis//:google_rpc_code_java_proto", + "//third_party/googleapis:google_devtools_build_v1_publish_build_event_java_grpc", + "//third_party/googleapis:google_longrunning_operations_java_grpc", + "//third_party/remote-apis:build_bazel_remote_asset_v1_remote_asset_java_grpc", + "//third_party/remote-apis:build_bazel_remote_execution_v2_remote_execution_java_grpc", + "@bazel_remote_apis//build/bazel/remote/asset/v1:remote_asset_java_grpc", + "@bazel_remote_apis//build/bazel/semver:semver_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_proto", + "@com_google_googleapis//google/devtools/build/v1:build_java_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_code_findbugs_jsr305", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", @@ -30,9 +33,5 @@ java_library( "@maven//:io_grpc_grpc_stub", "@maven//:io_prometheus_simpleclient", "@maven//:org_projectlombok_lombok", - "@remote_apis//:build_bazel_remote_asset_v1_remote_asset_java_grpc", - "@remote_apis//:build_bazel_remote_asset_v1_remote_asset_java_proto", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_grpc", - "@remote_apis//:build_bazel_semver_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/tools/BUILD b/src/main/java/build/buildfarm/tools/BUILD index 120012ac2a..058d3d196b 100644 --- a/src/main/java/build/buildfarm/tools/BUILD +++ b/src/main/java/build/buildfarm/tools/BUILD @@ -10,7 +10,7 @@ java_binary( "//src/main/java/build/buildfarm/instance/stub", "//src/main/java/build/buildfarm/worker", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@googleapis//:google_rpc_code_java_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:io_grpc_grpc_api", @@ -33,11 +33,11 @@ java_binary( "//src/main/java/build/buildfarm/cas", "//src/main/java/build/buildfarm/common", "//src/main/java/build/buildfarm/common/config", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@maven//:com_github_jnr_jnr_constants", "@maven//:com_github_jnr_jnr_ffi", "@maven//:com_github_jnr_jnr_posix", "@maven//:com_google_guava_guava", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) @@ -59,10 +59,13 @@ java_binary( "//src/main/java/build/buildfarm/common", "//src/main/java/build/buildfarm/common/grpc", "//src/main/java/build/buildfarm/instance/stub", - "@googleapis//:google_bytestream_bytestream_java_grpc", - "@googleapis//:google_bytestream_bytestream_java_proto", - "@googleapis//:google_rpc_code_java_proto", - "@googleapis//:google_rpc_status_java_proto", + "//third_party/googleapis:google_bytestream_bytestream_java_grpc", + "//third_party/remote-apis:build_bazel_remote_execution_v2_remote_execution_java_grpc", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_proto", + "@com_google_googleapis//google/longrunning:longrunning_java_proto", + "@com_google_googleapis//google/longrunning:operations_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:io_grpc_grpc_api", @@ -70,8 +73,6 @@ java_binary( "@maven//:io_grpc_grpc_core", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_grpc", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) @@ -83,8 +84,9 @@ java_binary( deps = [ "//src/main/java/build/buildfarm/common", "//src/main/java/build/buildfarm/common/grpc", - "@googleapis//:google_bytestream_bytestream_java_grpc", - "@googleapis//:google_bytestream_bytestream_java_proto", + "//third_party/googleapis:google_bytestream_bytestream_java_grpc", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:io_grpc_grpc_api", @@ -92,7 +94,6 @@ java_binary( "@maven//:io_grpc_grpc_core", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) @@ -111,8 +112,7 @@ java_binary( "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/instance/stub", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@googleapis//:google_rpc_code_java_proto", - "@googleapis//:google_rpc_error_details_java_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", @@ -171,8 +171,7 @@ java_binary( "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/instance/stub", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@googleapis//:google_rpc_code_java_proto", - "@googleapis//:google_rpc_error_details_java_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", @@ -207,8 +206,9 @@ java_binary( "//src/main/java/build/buildfarm/common/grpc", "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/instance/stub", - "@googleapis//:google_longrunning_operations_java_proto", - "@googleapis//:google_rpc_code_java_proto", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/longrunning:longrunning_java_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:io_grpc_grpc_api", @@ -216,7 +216,6 @@ java_binary( "@maven//:io_grpc_grpc_core", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) @@ -230,8 +229,9 @@ java_binary( "//src/main/java/build/buildfarm/common/grpc", "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/instance/stub", - "@googleapis//:google_longrunning_operations_java_proto", - "@googleapis//:google_rpc_code_java_proto", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/longrunning:longrunning_java_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:io_grpc_grpc_api", @@ -239,7 +239,6 @@ java_binary( "@maven//:io_grpc_grpc_core", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) @@ -253,8 +252,9 @@ java_binary( "//src/main/java/build/buildfarm/common/grpc", "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/instance/stub", - "@googleapis//:google_longrunning_operations_java_proto", - "@googleapis//:google_rpc_code_java_proto", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/longrunning:longrunning_java_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:io_grpc_grpc_api", @@ -262,7 +262,6 @@ java_binary( "@maven//:io_grpc_grpc_core", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/worker/BUILD b/src/main/java/build/buildfarm/worker/BUILD index 7352a3900e..016eb89092 100644 --- a/src/main/java/build/buildfarm/worker/BUILD +++ b/src/main/java/build/buildfarm/worker/BUILD @@ -16,8 +16,7 @@ java_library( "//src/main/java/build/buildfarm/worker/util", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "@bazel//src/main/protobuf:execution_statistics_java_proto", - "@googleapis//:google_rpc_code_java_proto", - "@googleapis//:google_rpc_error_details_java_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_docker_java_docker_java", "@maven//:com_github_docker_java_docker_java_api", "@maven//:com_github_docker_java_docker_java_core", diff --git a/src/main/java/build/buildfarm/worker/shard/BUILD b/src/main/java/build/buildfarm/worker/shard/BUILD index 4fa52c985d..662c2d5969 100644 --- a/src/main/java/build/buildfarm/worker/shard/BUILD +++ b/src/main/java/build/buildfarm/worker/shard/BUILD @@ -21,9 +21,7 @@ java_library( "//src/main/java/build/buildfarm/worker/resources", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_grpc", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@googleapis//:google_rpc_error_details_java_proto", - "@io_grpc_grpc_proto//:health_java_proto", - "@io_grpc_grpc_proto//:health_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_ben_manes_caffeine_caffeine", "@maven//:com_github_pcj_google_options", "@maven//:com_google_code_findbugs_jsr305", diff --git a/src/main/protobuf/BUILD.bazel b/src/main/protobuf/BUILD.bazel index 4e37226bf1..b1a4fadbe1 100644 --- a/src/main/protobuf/BUILD.bazel +++ b/src/main/protobuf/BUILD.bazel @@ -8,12 +8,12 @@ proto_library( name = "build_buildfarm_v1test_buildfarm_proto", srcs = ["build/buildfarm/v1test/buildfarm.proto"], deps = [ + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_proto", + "@com_google_googleapis//google/api:annotations_proto", + "@com_google_googleapis//google/longrunning:operations_proto", + "@com_google_googleapis//google/rpc:status_proto", "@com_google_protobuf//:duration_proto", "@com_google_protobuf//:timestamp_proto", - "@googleapis//:google_api_annotations_proto", - "@googleapis//:google_longrunning_operations_proto", - "@googleapis//:google_rpc_status_proto", - "@remote_apis//build/bazel/remote/execution/v2:remote_execution_proto", ], ) @@ -21,9 +21,9 @@ java_proto_library( name = "build_buildfarm_v1test_buildfarm_java_proto", deps = [ ":build_buildfarm_v1test_buildfarm_proto", - "@googleapis//:google_longrunning_operations_proto", - "@googleapis//:google_rpc_status_proto", - "@remote_apis//build/bazel/remote/execution/v2:remote_execution_proto", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_proto", + "@com_google_googleapis//google/longrunning:operations_proto", + "@com_google_googleapis//google/rpc:status_proto", ], ) diff --git a/src/test/java/build/buildfarm/cas/BUILD b/src/test/java/build/buildfarm/cas/BUILD index 11d3dad231..6acc6b67a6 100644 --- a/src/test/java/build/buildfarm/cas/BUILD +++ b/src/test/java/build/buildfarm/cas/BUILD @@ -12,8 +12,10 @@ java_test( "//src/main/java/build/buildfarm/instance/stub", "//src/test/java/build/buildfarm:test_runner", "//src/test/java/build/buildfarm/common/grpc", - "@googleapis//:google_bytestream_bytestream_java_grpc", - "@googleapis//:google_bytestream_bytestream_java_proto", + "//third_party/googleapis:google_bytestream_bytestream_java_grpc", + "//third_party/remote-apis:build_bazel_remote_execution_v2_remote_execution_java_grpc", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_jimfs_jimfs", "@maven//:com_google_protobuf_protobuf_java", @@ -23,8 +25,7 @@ java_test( "@maven//:io_grpc_grpc_core", "@maven//:io_grpc_grpc_inprocess", "@maven//:io_grpc_grpc_stub", + "@maven//:io_grpc_grpc_util", "@maven//:org_mockito_mockito_core", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_grpc", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) diff --git a/src/test/java/build/buildfarm/common/BUILD b/src/test/java/build/buildfarm/common/BUILD index 971c0745d2..b1b996440f 100644 --- a/src/test/java/build/buildfarm/common/BUILD +++ b/src/test/java/build/buildfarm/common/BUILD @@ -10,8 +10,8 @@ java_test( "//src/main/java/build/buildfarm/common", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "@googleapis//:google_bytestream_bytestream_java_proto", - "@googleapis//:google_rpc_error_details_java_proto", + "@com_google_googleapis//google/bytestream:bytestream_java_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_jimfs_jimfs", "@maven//:com_google_protobuf_protobuf_java", diff --git a/src/test/java/build/buildfarm/common/grpc/BUILD b/src/test/java/build/buildfarm/common/grpc/BUILD index ab703cf463..121705563a 100644 --- a/src/test/java/build/buildfarm/common/grpc/BUILD +++ b/src/test/java/build/buildfarm/common/grpc/BUILD @@ -4,8 +4,8 @@ java_library( visibility = ["//src/test/java/build/buildfarm:__subpackages__"], deps = [ "//src/main/java/build/buildfarm/common/grpc", - "@googleapis//:google_bytestream_bytestream_java_grpc", - "@googleapis//:google_bytestream_bytestream_java_proto", + "//third_party/googleapis:google_bytestream_bytestream_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:io_grpc_grpc_api", @@ -21,8 +21,8 @@ java_test( deps = [ "//src/main/java/build/buildfarm/common/grpc", "//src/test/java/build/buildfarm:test_runner", - "@googleapis//:google_bytestream_bytestream_java_grpc", - "@googleapis//:google_bytestream_bytestream_java_proto", + "//third_party/googleapis:google_bytestream_bytestream_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_truth_truth", @@ -31,6 +31,7 @@ java_test( "@maven//:io_grpc_grpc_inprocess", "@maven//:io_grpc_grpc_stub", "@maven//:io_grpc_grpc_testing", + "@maven//:io_grpc_grpc_util", "@maven//:org_mockito_mockito_core", ], ) diff --git a/src/test/java/build/buildfarm/common/io/BUILD b/src/test/java/build/buildfarm/common/io/BUILD index 1f5d1ca179..c9758d4980 100644 --- a/src/test/java/build/buildfarm/common/io/BUILD +++ b/src/test/java/build/buildfarm/common/io/BUILD @@ -6,8 +6,8 @@ java_test( "//src/main/java/build/buildfarm/common", "//src/main/java/build/buildfarm/common/grpc", "//src/test/java/build/buildfarm:test_runner", - "@googleapis//:google_bytestream_bytestream_java_grpc", - "@googleapis//:google_bytestream_bytestream_java_proto", + "//third_party/googleapis:google_bytestream_bytestream_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_jimfs_jimfs", "@maven//:com_google_protobuf_protobuf_java", diff --git a/src/test/java/build/buildfarm/common/resources/BUILD b/src/test/java/build/buildfarm/common/resources/BUILD index ab39387fc7..bb64bbcba7 100644 --- a/src/test/java/build/buildfarm/common/resources/BUILD +++ b/src/test/java/build/buildfarm/common/resources/BUILD @@ -9,8 +9,9 @@ java_test( "//src/main/java/build/buildfarm/common/resources:resource_java_proto", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "@googleapis//:google_bytestream_bytestream_java_proto", - "@googleapis//:google_rpc_error_details_java_proto", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_jimfs_jimfs", "@maven//:com_google_protobuf_protobuf_java", @@ -22,6 +23,5 @@ java_test( "@maven//:io_grpc_grpc_testing", "@maven//:org_mockito_mockito_core", "@maven//:redis_clients_jedis", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) diff --git a/src/test/java/build/buildfarm/common/services/BUILD b/src/test/java/build/buildfarm/common/services/BUILD index 929489036b..1de572dba6 100644 --- a/src/test/java/build/buildfarm/common/services/BUILD +++ b/src/test/java/build/buildfarm/common/services/BUILD @@ -14,8 +14,9 @@ java_test( "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/instance/stub", "//src/test/java/build/buildfarm:test_runner", - "@googleapis//:google_bytestream_bytestream_java_grpc", - "@googleapis//:google_bytestream_bytestream_java_proto", + "//third_party/googleapis:google_bytestream_bytestream_java_grpc", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_truth_truth", @@ -25,6 +26,5 @@ java_test( "@maven//:io_grpc_grpc_inprocess", "@maven//:io_grpc_grpc_stub", "@maven//:org_mockito_mockito_core", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) diff --git a/src/test/java/build/buildfarm/examples/BUILD b/src/test/java/build/buildfarm/examples/BUILD index 5bfd97b6e3..25014e5b53 100644 --- a/src/test/java/build/buildfarm/examples/BUILD +++ b/src/test/java/build/buildfarm/examples/BUILD @@ -8,8 +8,8 @@ java_test( "//src/main/java/build/buildfarm/common/config", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "@googleapis//:google_bytestream_bytestream_java_proto", - "@googleapis//:google_rpc_error_details_java_proto", + "@com_google_googleapis//google/bytestream:bytestream_java_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_jimfs_jimfs", "@maven//:com_google_protobuf_protobuf_java", diff --git a/src/test/java/build/buildfarm/instance/server/BUILD b/src/test/java/build/buildfarm/instance/server/BUILD index 39e545d042..373c95ba24 100644 --- a/src/test/java/build/buildfarm/instance/server/BUILD +++ b/src/test/java/build/buildfarm/instance/server/BUILD @@ -13,8 +13,9 @@ java_test( "//src/main/java/build/buildfarm/operations", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "@googleapis//:google_longrunning_operations_java_proto", - "@googleapis//:google_rpc_error_details_java_proto", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/longrunning:longrunning_java_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_truth_truth", @@ -22,6 +23,5 @@ java_test( "@maven//:io_grpc_grpc_stub", "@maven//:org_mockito_mockito_core", "@maven//:org_projectlombok_lombok", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) diff --git a/src/test/java/build/buildfarm/instance/shard/BUILD b/src/test/java/build/buildfarm/instance/shard/BUILD index 66a5b71f2d..a92b0795d5 100644 --- a/src/test/java/build/buildfarm/instance/shard/BUILD +++ b/src/test/java/build/buildfarm/instance/shard/BUILD @@ -17,9 +17,9 @@ java_test( "//src/main/java/build/buildfarm/instance/shard", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "@googleapis//:google_longrunning_operations_java_proto", - "@googleapis//:google_rpc_code_java_proto", - "@googleapis//:google_rpc_error_details_java_proto", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/longrunning:longrunning_java_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_ben_manes_caffeine_caffeine", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", @@ -31,7 +31,6 @@ java_test( "@maven//:io_grpc_grpc_stub", "@maven//:org_mockito_mockito_core", "@maven//:redis_clients_jedis", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) @@ -55,9 +54,9 @@ java_test( "//src/main/java/build/buildfarm/instance/shard", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "@googleapis//:google_longrunning_operations_java_proto", - "@googleapis//:google_rpc_code_java_proto", - "@googleapis//:google_rpc_error_details_java_proto", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/longrunning:longrunning_java_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_ben_manes_caffeine_caffeine", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", @@ -69,7 +68,6 @@ java_test( "@maven//:io_grpc_grpc_stub", "@maven//:org_mockito_mockito_core", "@maven//:redis_clients_jedis", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) @@ -92,9 +90,9 @@ java_test( "//src/main/java/build/buildfarm/instance/shard", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "@googleapis//:google_longrunning_operations_java_proto", - "@googleapis//:google_rpc_code_java_proto", - "@googleapis//:google_rpc_error_details_java_proto", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/longrunning:longrunning_java_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_ben_manes_caffeine_caffeine", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", @@ -106,7 +104,6 @@ java_test( "@maven//:io_grpc_grpc_stub", "@maven//:org_mockito_mockito_core", "@maven//:redis_clients_jedis", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) @@ -129,9 +126,9 @@ java_test( "//src/main/java/build/buildfarm/instance/shard", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "@googleapis//:google_longrunning_operations_java_proto", - "@googleapis//:google_rpc_code_java_proto", - "@googleapis//:google_rpc_error_details_java_proto", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/longrunning:longrunning_java_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_ben_manes_caffeine_caffeine", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", @@ -143,7 +140,6 @@ java_test( "@maven//:io_grpc_grpc_stub", "@maven//:org_mockito_mockito_core", "@maven//:redis_clients_jedis", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) @@ -166,9 +162,9 @@ java_test( "//src/main/java/build/buildfarm/instance/shard", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "@googleapis//:google_longrunning_operations_java_proto", - "@googleapis//:google_rpc_code_java_proto", - "@googleapis//:google_rpc_error_details_java_proto", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/longrunning:longrunning_java_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_ben_manes_caffeine_caffeine", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", @@ -180,7 +176,6 @@ java_test( "@maven//:io_grpc_grpc_stub", "@maven//:org_mockito_mockito_core", "@maven//:redis_clients_jedis", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) @@ -203,9 +198,9 @@ java_test( "//src/main/java/build/buildfarm/instance/shard", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "@googleapis//:google_longrunning_operations_java_proto", - "@googleapis//:google_rpc_code_java_proto", - "@googleapis//:google_rpc_error_details_java_proto", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/longrunning:longrunning_java_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_ben_manes_caffeine_caffeine", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", @@ -217,7 +212,6 @@ java_test( "@maven//:io_grpc_grpc_stub", "@maven//:org_mockito_mockito_core", "@maven//:redis_clients_jedis", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) diff --git a/src/test/java/build/buildfarm/instance/stub/BUILD b/src/test/java/build/buildfarm/instance/stub/BUILD index 861267775c..d827645094 100644 --- a/src/test/java/build/buildfarm/instance/stub/BUILD +++ b/src/test/java/build/buildfarm/instance/stub/BUILD @@ -12,8 +12,10 @@ java_test( "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/instance/stub", "//src/test/java/build/buildfarm:test_runner", - "@googleapis//:google_bytestream_bytestream_java_grpc", - "@googleapis//:google_bytestream_bytestream_java_proto", + "//third_party/googleapis:google_bytestream_bytestream_java_grpc", + "//third_party/remote-apis:build_bazel_remote_execution_v2_remote_execution_java_grpc", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_truth_truth", @@ -21,8 +23,7 @@ java_test( "@maven//:io_grpc_grpc_core", "@maven//:io_grpc_grpc_inprocess", "@maven//:io_grpc_grpc_stub", + "@maven//:io_grpc_grpc_util", "@maven//:org_mockito_mockito_core", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_grpc", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) diff --git a/src/test/java/build/buildfarm/metrics/BUILD b/src/test/java/build/buildfarm/metrics/BUILD index c32955e20d..3d570580a9 100644 --- a/src/test/java/build/buildfarm/metrics/BUILD +++ b/src/test/java/build/buildfarm/metrics/BUILD @@ -11,7 +11,7 @@ java_test( "//src/main/java/build/buildfarm/metrics/log", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "@googleapis//:google_rpc_error_details_java_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_jimfs_jimfs", "@maven//:com_google_protobuf_protobuf_java", diff --git a/src/test/java/build/buildfarm/proxy/http/BUILD b/src/test/java/build/buildfarm/proxy/http/BUILD index 73a1ee1196..8dafef160b 100644 --- a/src/test/java/build/buildfarm/proxy/http/BUILD +++ b/src/test/java/build/buildfarm/proxy/http/BUILD @@ -7,8 +7,9 @@ java_test( "//src/main/java/build/buildfarm/common", "//src/main/java/build/buildfarm/proxy/http", "//src/test/java/build/buildfarm:test_runner", - "@googleapis//:google_bytestream_bytestream_java_grpc", - "@googleapis//:google_bytestream_bytestream_java_proto", + "//third_party/googleapis:google_bytestream_bytestream_java_grpc", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_truth_truth", @@ -17,6 +18,5 @@ java_test( "@maven//:io_grpc_grpc_inprocess", "@maven//:io_grpc_grpc_stub", "@maven//:org_mockito_mockito_core", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) diff --git a/src/test/java/build/buildfarm/server/BUILD b/src/test/java/build/buildfarm/server/BUILD index e87890ba07..be02e4579c 100644 --- a/src/test/java/build/buildfarm/server/BUILD +++ b/src/test/java/build/buildfarm/server/BUILD @@ -18,12 +18,13 @@ java_test( "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_grpc", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", + "//third_party/googleapis:google_bytestream_bytestream_java_grpc", + "//third_party/googleapis:google_longrunning_operations_java_grpc", + "//third_party/remote-apis:build_bazel_remote_execution_v2_remote_execution_java_grpc", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_proto", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@com_google_protobuf//:protobuf_java", - "@googleapis//:google_bytestream_bytestream_java_grpc", - "@googleapis//:google_bytestream_bytestream_java_proto", - "@googleapis//:google_longrunning_operations_java_grpc", - "@googleapis//:google_rpc_code_java_proto", - "@googleapis//:google_rpc_error_details_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", @@ -37,7 +38,5 @@ java_test( "@maven//:io_grpc_grpc_stub", "@maven//:me_dinowernli_java_grpc_prometheus", "@maven//:org_mockito_mockito_core", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_grpc", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) diff --git a/src/test/java/build/buildfarm/server/services/BUILD b/src/test/java/build/buildfarm/server/services/BUILD index a83385da04..45d2acbe79 100644 --- a/src/test/java/build/buildfarm/server/services/BUILD +++ b/src/test/java/build/buildfarm/server/services/BUILD @@ -11,11 +11,11 @@ java_test( "//src/main/java/build/buildfarm/server/services", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", + "@bazel_remote_apis//build/bazel/remote/asset/v1:remote_asset_java_grpc", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_truth_truth", "@maven//:io_grpc_grpc_stub", "@maven//:org_mockito_mockito_core", - "@remote_apis//:build_bazel_remote_asset_v1_remote_asset_java_proto", ], ) diff --git a/src/test/java/build/buildfarm/worker/BUILD b/src/test/java/build/buildfarm/worker/BUILD index 999aea0910..32bc565d78 100644 --- a/src/test/java/build/buildfarm/worker/BUILD +++ b/src/test/java/build/buildfarm/worker/BUILD @@ -25,8 +25,8 @@ java_test( "//src/main/java/build/buildfarm/worker/resources", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "@googleapis//:google_rpc_code_java_proto", - "@googleapis//:google_rpc_error_details_java_proto", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_jnr_jnr_constants", "@maven//:com_github_jnr_jnr_ffi", "@maven//:com_github_serceman_jnr_fuse", @@ -40,6 +40,5 @@ java_test( "@maven//:io_grpc_grpc_protobuf", "@maven//:org_mockito_mockito_core", "@maven//:org_projectlombok_lombok", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) diff --git a/src/test/java/build/buildfarm/worker/persistent/BUILD b/src/test/java/build/buildfarm/worker/persistent/BUILD index 0520097ff6..1c96884643 100644 --- a/src/test/java/build/buildfarm/worker/persistent/BUILD +++ b/src/test/java/build/buildfarm/worker/persistent/BUILD @@ -17,7 +17,8 @@ java_test( "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", "//src/test/java/build/buildfarm/worker/util:worker_test_utils", - "@googleapis//:google_rpc_code_java_proto", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_jnr_jnr_constants", "@maven//:com_github_jnr_jnr_ffi", "@maven//:com_github_serceman_jnr_fuse", @@ -31,6 +32,5 @@ java_test( "@maven//:io_grpc_grpc_protobuf", "@maven//:org_mockito_mockito_core", "@maven//:org_projectlombok_lombok", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) diff --git a/src/test/java/build/buildfarm/worker/util/BUILD b/src/test/java/build/buildfarm/worker/util/BUILD index c0d0bbe46f..9645bfb85d 100644 --- a/src/test/java/build/buildfarm/worker/util/BUILD +++ b/src/test/java/build/buildfarm/worker/util/BUILD @@ -10,7 +10,8 @@ java_library( "//src/main/java/build/buildfarm/worker/util", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "@googleapis//:google_rpc_code_java_proto", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_jnr_jnr_constants", "@maven//:com_github_jnr_jnr_ffi", "@maven//:com_github_serceman_jnr_fuse", @@ -24,7 +25,6 @@ java_library( "@maven//:io_grpc_grpc_protobuf", "@maven//:org_mockito_mockito_core", "@maven//:org_projectlombok_lombok", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) @@ -42,7 +42,8 @@ java_test( "//src/main/java/build/buildfarm/worker/util", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "@googleapis//:google_rpc_code_java_proto", + "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_jnr_jnr_constants", "@maven//:com_github_jnr_jnr_ffi", "@maven//:com_github_serceman_jnr_fuse", @@ -56,6 +57,5 @@ java_test( "@maven//:io_grpc_grpc_protobuf", "@maven//:org_mockito_mockito_core", "@maven//:org_projectlombok_lombok", - "@remote_apis//:build_bazel_remote_execution_v2_remote_execution_java_proto", ], ) From 23396ec5041787969048e11be7d7bf7d9d8932e0 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Thu, 14 Mar 2024 09:48:45 -0700 Subject: [PATCH 288/311] chore: remove dead code from extensions.bzl --- extensions.bzl | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/extensions.bzl b/extensions.bzl index 29dda9b447..d0c9a95b8e 100644 --- a/extensions.bzl +++ b/extensions.bzl @@ -6,13 +6,6 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive", "http_file" def archive_dependencies(third_party): return [ - # Needed for "well-known protos" and @com_google_protobuf//:protoc. - # { - # "name": "com_google_protobuf", - # "sha256": "79082dc68d8bab2283568ce0be3982b73e19ddd647c2411d1977ca5282d2d6b3", - # "strip_prefix": "protobuf-25.0", - # "urls": ["https://github.com/protocolbuffers/protobuf/archive/v25.0.zip"], - # }, # Needed for @grpc_java//compiler:grpc_java_plugin. { "name": "io_grpc_grpc_java", @@ -21,17 +14,6 @@ def archive_dependencies(third_party): "urls": ["https://github.com/grpc/grpc-java/archive/v1.62.2.zip"], # Bzlmod: Waiting for https://github.com/bazelbuild/bazel-central-registry/issues/353 }, - # The APIs that we implement. - { - "name": "googleapis", - "build_file": "%s:BUILD.googleapis" % third_party, - "patch_cmds": ["find google -name 'BUILD.bazel' -type f -delete"], - "patch_cmds_win": ["Remove-Item google -Recurse -Include *.bazel"], - "sha256": "1980dc4a4d02420d4da588665e3ecbe55e02a1c2e32d8906a2268c67d1085e0b", - "strip_prefix": "googleapis-5f8a02d6b7e77bd26e0375a00ca20eb2f3ee1ba2", - "url": "https://github.com/googleapis/googleapis/archive/5f8a02d6b7e77bd26e0375a00ca20eb2f3ee1ba2.zip", - }, - # Bazel is referenced as a dependency so that buildfarm can access the linux-sandbox as a potential execution wrapper. { "name": "bazel", From 0b2ce1288ec4a9427ef35313babb64bd22151a0a Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Thu, 21 Mar 2024 11:15:01 -0700 Subject: [PATCH 289/311] build(bzlmod): add bazel_skylib --- MODULE.bazel | 1 + 1 file changed, 1 insertion(+) diff --git a/MODULE.bazel b/MODULE.bazel index 2d393075f7..6606a90afa 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -5,6 +5,7 @@ module( repo_name = "build_buildfarm", ) +bazel_dep(name = "bazel_skylib", version = "1.5.0") bazel_dep(name = "blake3", version = "1.3.3.bcr.1") bazel_dep(name = "gazelle", version = "0.35.0", repo_name = "bazel_gazelle") bazel_dep(name = "grpc", version = "1.48.1.bcr.2", repo_name = "com_github_grpc_grpc") From 2f9c85e36751d0fe9666ea2af6d354cfb6e27431 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Thu, 21 Mar 2024 11:28:12 -0700 Subject: [PATCH 290/311] chore: buildifier complaints in extensions.bzl --- extensions.bzl | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/extensions.bzl b/extensions.bzl index d0c9a95b8e..0b94b86a06 100644 --- a/extensions.bzl +++ b/extensions.bzl @@ -34,14 +34,10 @@ def archive_dependencies(third_party): }, ] -def _buildfarm_extension_impl(ctx): +def _buildfarm_extension_impl(_ctx): """ Define all 3rd party archive rules for buildfarm - - Args: - repository_name: the name of the repository """ - repository_name = "@build_buildfarm" third_party = "//third_party" for dependency in archive_dependencies(third_party): params = {} From 29e8114437b7e0c52ee1a787f82c708a7ac918ab Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Thu, 21 Mar 2024 11:50:17 -0700 Subject: [PATCH 291/311] chore: remove defs.bzl --- defs.bzl | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 defs.bzl diff --git a/defs.bzl b/defs.bzl deleted file mode 100644 index de409f43c7..0000000000 --- a/defs.bzl +++ /dev/null @@ -1,15 +0,0 @@ -""" -buildfarm definitions that can be imported into other WORKSPACE files -""" - -load("@io_grpc_grpc_java//:repositories.bzl", "grpc_java_repositories") - -def buildfarm_init(name = "buildfarm"): - """ - Initialize the WORKSPACE for buildfarm-related targets - - Args: - name: the name of the repository - """ - - grpc_java_repositories() From 4b9b2fbd141a58f3bc3b7d86e7b5de75d7de7139 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Thu, 28 Mar 2024 17:54:19 -0700 Subject: [PATCH 292/311] chore: remove unused patches --- third_party/BUILD.googleapis | 205 ------------------ third_party/googleapis/BUILD | 27 --- .../googleapis_add_bzlmod_support.patch | 92 -------- 3 files changed, 324 deletions(-) delete mode 100644 third_party/BUILD.googleapis delete mode 100644 third_party/googleapis/BUILD delete mode 100644 third_party/googleapis_add_bzlmod_support.patch diff --git a/third_party/BUILD.googleapis b/third_party/BUILD.googleapis deleted file mode 100644 index 476caabc5d..0000000000 --- a/third_party/BUILD.googleapis +++ /dev/null @@ -1,205 +0,0 @@ -load("@io_grpc_grpc_java//:java_grpc_library.bzl", "java_grpc_library") -load("@rules_java//java:defs.bzl", "java_proto_library") -load("@rules_proto//proto:defs.bzl", "proto_library") - -package(default_visibility = ["//visibility:public"]) - -licenses(["notice"]) - -exports_files(["LICENSE"]) - -java_proto_library( - name = "google_devtools_build_v1_build_status_java_proto", - deps = [":google_devtools_build_v1_build_status_proto"], -) - -java_proto_library( - name = "google_devtools_build_v1_build_events_java_proto", - deps = [":google_devtools_build_v1_build_events_proto"], -) - -java_grpc_library( - name = "google_devtools_build_v1_publish_build_event_java_grpc", - srcs = [":google_devtools_build_v1_publish_build_event_proto"], - deps = [":google_devtools_build_v1_publish_build_event_java_proto"], -) - -java_proto_library( - name = "google_devtools_build_v1_publish_build_event_java_proto", - deps = [":google_devtools_build_v1_publish_build_event_proto"], -) - -java_proto_library( - name = "google_bytestream_bytestream_java_proto", - deps = [":google_bytestream_bytestream_proto"], -) - -java_proto_library( - name = "google_longrunning_operations_java_proto", - deps = [":google_longrunning_operations_proto"], -) - -java_proto_library( - name = "google_rpc_status_java_proto", - deps = [":google_rpc_status_proto"], -) - -java_proto_library( - name = "google_rpc_error_details_java_proto", - deps = [":google_rpc_error_details_proto"], -) - -java_proto_library( - name = "google_rpc_code_java_proto", - deps = [":google_rpc_code_proto"], -) - -java_proto_library( - name = "google_api_annotations_java_proto", - deps = [":google_api_annotations_proto"], -) - -java_proto_library( - name = "google_api_http_java_proto", - deps = [":google_api_http_proto"], -) - -java_proto_library( - name = "google_api_auth_java_proto", - deps = [":google_api_auth_proto"], -) - -java_grpc_library( - name = "google_bytestream_bytestream_java_grpc", - srcs = [":google_bytestream_bytestream_proto"], - deps = [":google_bytestream_bytestream_java_proto"], -) - -java_grpc_library( - name = "google_longrunning_operations_java_grpc", - srcs = [":google_longrunning_operations_proto"], - deps = [":google_longrunning_operations_java_proto"], -) - -proto_library( - name = "google_rpc_code_proto", - srcs = ["google/rpc/code.proto"], -) - -proto_library( - name = "google_rpc_error_details_proto", - srcs = ["google/rpc/error_details.proto"], - deps = [ - "@com_google_protobuf//:any_proto", - "@com_google_protobuf//:duration_proto", - ], -) - -proto_library( - name = "google_bytestream_bytestream_proto", - srcs = ["google/bytestream/bytestream.proto"], - deps = [ - ":google_api_annotations_proto", - "@com_google_protobuf//:wrappers_proto", - ], -) - -proto_library( - name = "google_longrunning_operations_proto", - srcs = ["google/longrunning/operations.proto"], - deps = [ - ":google_api_annotations_proto", - ":google_api_client_proto", - ":google_api_http_proto", - ":google_rpc_status_proto", - "@com_google_protobuf//:any_proto", - "@com_google_protobuf//:descriptor_proto", - "@com_google_protobuf//:duration_proto", - "@com_google_protobuf//:empty_proto", - ], -) - -proto_library( - name = "google_devtools_build_v1_build_status_proto", - srcs = ["google/devtools/build/v1/build_status.proto"], - deps = [ - ":google_api_annotations_proto", - "@com_google_protobuf//:any_proto", - "@com_google_protobuf//:wrappers_proto", - ], -) - -proto_library( - name = "google_devtools_build_v1_build_events_proto", - srcs = ["google/devtools/build/v1/build_events.proto"], - deps = [ - ":google_api_annotations_proto", - ":google_devtools_build_v1_build_status_proto", - ":google_rpc_status_proto", - "@com_google_protobuf//:any_proto", - "@com_google_protobuf//:timestamp_proto", - "@com_google_protobuf//:wrappers_proto", - ], -) - -proto_library( - name = "google_devtools_build_v1_publish_build_event_proto", - srcs = ["google/devtools/build/v1/publish_build_event.proto"], - deps = [ - ":google_api_annotations_proto", - ":google_api_auth_proto", - ":google_api_client_proto", - ":google_api_field_behavior_proto", - ":google_devtools_build_v1_build_events_proto", - "@com_google_protobuf//:any_proto", - "@com_google_protobuf//:duration_proto", - "@com_google_protobuf//:empty_proto", - ], -) - -proto_library( - name = "google_api_annotations_proto", - srcs = ["google/api/annotations.proto"], - deps = [ - ":google_api_http_proto", - "@com_google_protobuf//:descriptor_proto", - ], -) - -proto_library( - name = "google_api_http_proto", - srcs = ["google/api/http.proto"], -) - -proto_library( - name = "google_api_client_proto", - srcs = ["google/api/client.proto"], - deps = [ - ":google_api_field_behavior_proto", - ":google_api_launch_stage_proto", - "@com_google_protobuf//:descriptor_proto", - "@com_google_protobuf//:duration_proto", - ], -) - -proto_library( - name = "google_api_field_behavior_proto", - srcs = ["google/api/field_behavior.proto"], - deps = ["@com_google_protobuf//:descriptor_proto"], -) - -proto_library( - name = "google_rpc_status_proto", - srcs = ["google/rpc/status.proto"], - deps = ["@com_google_protobuf//:any_proto"], -) - -proto_library( - name = "google_api_auth_proto", - srcs = ["google/api/auth.proto"], -) - -proto_library( - name = "google_api_launch_stage_proto", - srcs = ["google/api/launch_stage.proto"], -) diff --git a/third_party/googleapis/BUILD b/third_party/googleapis/BUILD deleted file mode 100644 index 34ca69d4c2..0000000000 --- a/third_party/googleapis/BUILD +++ /dev/null @@ -1,27 +0,0 @@ -load("@io_grpc_grpc_java//:java_grpc_library.bzl", "java_grpc_library") - -package(default_visibility = ["//visibility:public"]) - -java_grpc_library( - name = "google_bytestream_bytestream_java_grpc", - srcs = ["@com_google_googleapis//google/bytestream:bytestream_proto"], - deps = [ - "@com_google_googleapis//google/bytestream:bytestream_java_proto", - ], -) - -java_grpc_library( - name = "google_longrunning_operations_java_grpc", - srcs = ["@com_google_googleapis//google/longrunning:operations_proto"], - deps = [ - "@com_google_googleapis//google/longrunning:longrunning_java_proto", - ], -) - -java_grpc_library( - name = "google_devtools_build_v1_publish_build_event_java_grpc", - srcs = ["@com_google_googleapis//google/devtools/build/v1:build_proto"], - deps = [ - "@com_google_googleapis//google/devtools/build/v1:build_java_proto", - ], -) diff --git a/third_party/googleapis_add_bzlmod_support.patch b/third_party/googleapis_add_bzlmod_support.patch deleted file mode 100644 index 8986756fd6..0000000000 --- a/third_party/googleapis_add_bzlmod_support.patch +++ /dev/null @@ -1,92 +0,0 @@ -diff --git a/MODULE.bazel b/MODULE.bazel -new file mode 100644 -index 000000000..c26575773 ---- /dev/null -+++ b/MODULE.bazel -@@ -0,0 +1,22 @@ -+module( -+ name = "com_google_googleapis", -+ version = "64926d52febbf298cb82a8f472ade4a3969ba922", -+) -+ -+bazel_dep(name = "protobuf", version = "21.7", repo_name = "com_google_protobuf") -+bazel_dep(name = "rules_proto", version = "5.3.0-21.7") -+ -+switched_rules = use_extension("//:extensions.bzl", "switched_rules") -+switched_rules.use_languages( -+ cc = True, -+ csharp = True, -+ gapic = True, -+ go = True, -+ grpc = True, -+ java = True, -+ nodejs = True, -+ php = True, -+ python = True, -+ ruby = True, -+) -+use_repo(switched_rules, "com_google_googleapis_imports") -diff --git a/WORKSPACE.bzlmod b/WORKSPACE.bzlmod -new file mode 100644 -index 000000000..fafa28da3 ---- /dev/null -+++ b/WORKSPACE.bzlmod -@@ -0,0 +1,2 @@ -+# When Bzlmod is enabled, this file replaces the content of the original WORKSPACE -+# and makes sure no WORKSPACE prefix or suffix are added when Bzlmod is enabled. -diff --git a/extensions.bzl b/extensions.bzl -new file mode 100644 -index 000000000..d8f04cf6c ---- /dev/null -+++ b/extensions.bzl -@@ -0,0 +1,50 @@ -+load(":repository_rules.bzl", "switched_rules_by_language") -+ -+_use_languages_tag = tag_class( -+ attrs = { -+ "cc": attr.bool(default = False), -+ "csharp": attr.bool(default = False), -+ "gapic": attr.bool(default = False), -+ "go": attr.bool(default = False), -+ "go_test": attr.bool(default = False), -+ "grpc": attr.bool(default = False), -+ "java": attr.bool(default = False), -+ "nodejs": attr.bool(default = False), -+ "php": attr.bool(default = False), -+ "python": attr.bool(default = False), -+ "ruby": attr.bool(default = False), -+ }, -+) -+ -+def _switched_rules_impl(ctx): -+ attrs = {} -+ for module in ctx.modules: -+ if not module.is_root: -+ continue -+ -+ for t in module.tags.use_languages: -+ attrs = { -+ "cc": t.cc, -+ "csharp": t.csharp, -+ "gapic": t.gapic, -+ "go": t.go, -+ "go_test": t.go_test, -+ "grpc": t.grpc, -+ "java": t.java, -+ "nodejs": t.nodejs, -+ "php": t.php, -+ "python": t.python, -+ "ruby": t.ruby, -+ } -+ -+ switched_rules_by_language( -+ name = "com_google_googleapis_imports", -+ **attrs -+ ) -+ -+switched_rules = module_extension( -+ implementation = _switched_rules_impl, -+ tag_classes = { -+ "use_languages": _use_languages_tag, -+ }, -+) From 381420352dfdd80e2f7e271120b9d1a477ed0c02 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Thu, 28 Mar 2024 17:54:37 -0700 Subject: [PATCH 293/311] chore(bzlmod): bump rules_go --- MODULE.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MODULE.bazel b/MODULE.bazel index 6606a90afa..861651b347 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -12,7 +12,7 @@ bazel_dep(name = "grpc", version = "1.48.1.bcr.2", repo_name = "com_github_grpc_ bazel_dep(name = "platforms", version = "0.0.8") bazel_dep(name = "protobuf", version = "23.1", repo_name = "com_google_protobuf") bazel_dep(name = "rules_cc", version = "0.0.9") -bazel_dep(name = "rules_go", version = "0.44.2", repo_name = "io_bazel_rules_go") +bazel_dep(name = "rules_go", version = "0.46.0", repo_name = "io_bazel_rules_go") bazel_dep(name = "rules_java", version = "7.4.0") bazel_dep(name = "rules_jvm_external", version = "5.3") bazel_dep(name = "rules_license", version = "0.0.7") From e7bf216776254ab0f45e456a38609f36ed5d090c Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Thu, 28 Mar 2024 17:54:49 -0700 Subject: [PATCH 294/311] chore(bzlmod): bump rules_jvm_external --- MODULE.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MODULE.bazel b/MODULE.bazel index 861651b347..5b4c102721 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -14,7 +14,7 @@ bazel_dep(name = "protobuf", version = "23.1", repo_name = "com_google_protobuf" bazel_dep(name = "rules_cc", version = "0.0.9") bazel_dep(name = "rules_go", version = "0.46.0", repo_name = "io_bazel_rules_go") bazel_dep(name = "rules_java", version = "7.4.0") -bazel_dep(name = "rules_jvm_external", version = "5.3") +bazel_dep(name = "rules_jvm_external", version = "6.0") bazel_dep(name = "rules_license", version = "0.0.7") bazel_dep(name = "rules_oci", version = "1.7.4") bazel_dep(name = "rules_pkg", version = "0.10.1") From 013fd4d0ee820ae6633b4cf916d17cd1242a9daf Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Thu, 28 Mar 2024 17:55:35 -0700 Subject: [PATCH 295/311] chore(bzlmod): bump rules_python --- MODULE.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MODULE.bazel b/MODULE.bazel index 5b4c102721..ad55257565 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -178,7 +178,7 @@ use_repo( # https://github.com/bazelbuild/rules_python/pull/713#issuecomment-1885628496 # Satisfy running tests in Docker as root. -bazel_dep(name = "rules_python", version = "0.24.0") +bazel_dep(name = "rules_python", version = "0.31.0") python = use_extension("@rules_python//python/extensions:python.bzl", "python") python.toolchain( From 745d7d25fb44b7744ec144d7612fcacac0deb2b2 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Sat, 30 Mar 2024 08:17:30 -0700 Subject: [PATCH 296/311] build: swap grpc for grpc-java and googleapis from BCR --- MODULE.bazel | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index ad55257565..726c36e3b7 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -8,7 +8,8 @@ module( bazel_dep(name = "bazel_skylib", version = "1.5.0") bazel_dep(name = "blake3", version = "1.3.3.bcr.1") bazel_dep(name = "gazelle", version = "0.35.0", repo_name = "bazel_gazelle") -bazel_dep(name = "grpc", version = "1.48.1.bcr.2", repo_name = "com_github_grpc_grpc") +bazel_dep(name = "grpc-java", version = "1.62.2") +bazel_dep(name = "googleapis", version = "0.0.0-20240326-1c8d509c5", repo_name = "com_google_googleapis") bazel_dep(name = "platforms", version = "0.0.8") bazel_dep(name = "protobuf", version = "23.1", repo_name = "com_google_protobuf") bazel_dep(name = "rules_cc", version = "0.0.9") @@ -32,13 +33,13 @@ bazel_dep( dev_dependency = True, ) -bazel_dep(name = "bazel_remote_apis", version = "66f0212d5cf703db65f7f56a1b54c60d4b41f920") +bazel_dep(name = "remoteapis", version = "eb433accc6a666b782ea4b787eb598e5c3d27c93") archive_override( - module_name = "bazel_remote_apis", - integrity = "sha256-1qzzTZxQh9IpK0GH1/n32onHKhknIrdOKC12Nu9sUds=", - strip_prefix = "remote-apis-66f0212d5cf703db65f7f56a1b54c60d4b41f920", + module_name = "remoteapis", + integrity = "sha256-68wzxNAkPZ49/zFwPYQ5z9MYbgxoeIEazKJ24+4YqIQ=", + strip_prefix = "remote-apis-eb433accc6a666b782ea4b787eb598e5c3d27c93", urls = [ - "https://github.com/bazelbuild/remote-apis/archive/66f0212d5cf703db65f7f56a1b54c60d4b41f920.zip", + "https://github.com/bazelbuild/remote-apis/archive/eb433accc6a666b782ea4b787eb598e5c3d27c93.zip", ], ) @@ -197,20 +198,6 @@ use_repo( "tini", ) -bazel_dep(name = "com_google_googleapis", version = "2a40f63ea714c7f4c6856a5db4d1f3cc7d4c4b18") -archive_override( - module_name = "com_google_googleapis", - integrity = "sha256-ZZb7DC2S7M9G53Uu3gALP7UpXctrvnZ/HcGmPXq+A6U=", - patch_strip = 1, - patches = [ - "third_party/googleapis_add_bzlmod_support.patch", - ], - strip_prefix = "googleapis-2a40f63ea714c7f4c6856a5db4d1f3cc7d4c4b18", - urls = [ - "https://github.com/googleapis/googleapis/archive/2a40f63ea714c7f4c6856a5db4d1f3cc7d4c4b18.zip", - ], -) - googleapis_switched_rules = use_extension("@com_google_googleapis//:extensions.bzl", "switched_rules") googleapis_switched_rules.use_languages( #grpc = True, # This REALLY wants `@io_grpc_grpc_java` to be defined, but try as I might, it cannot be found. From cd71055967dc1e8f7742afb9e52e3bf2dfe7a4e7 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Sun, 31 Mar 2024 18:16:53 -0700 Subject: [PATCH 297/311] chore: rewrite @bazel_remote_apis to @remoteapis --- src/main/java/build/buildfarm/actioncache/BUILD | 2 +- src/main/java/build/buildfarm/backplane/BUILD | 2 +- src/main/java/build/buildfarm/cas/BUILD | 2 +- src/main/java/build/buildfarm/common/BUILD | 4 ++-- src/main/java/build/buildfarm/common/grpc/BUILD | 2 +- src/main/java/build/buildfarm/common/resources/BUILD | 4 ++-- src/main/java/build/buildfarm/common/services/BUILD | 4 +++- src/main/java/build/buildfarm/instance/BUILD | 2 +- src/main/java/build/buildfarm/instance/server/BUILD | 2 +- src/main/java/build/buildfarm/instance/shard/BUILD | 2 +- src/main/java/build/buildfarm/instance/stub/BUILD | 1 + 11 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/main/java/build/buildfarm/actioncache/BUILD b/src/main/java/build/buildfarm/actioncache/BUILD index 874782067b..efe57cdbf2 100644 --- a/src/main/java/build/buildfarm/actioncache/BUILD +++ b/src/main/java/build/buildfarm/actioncache/BUILD @@ -7,12 +7,12 @@ java_library( "//src/main/java/build/buildfarm/common", "//src/main/java/build/buildfarm/common/config", "//third_party/remote-apis:build_bazel_remote_execution_v2_remote_execution_java_grpc", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@maven//:com_github_ben_manes_caffeine_caffeine", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_core", "@maven//:net_javacrumbs_future_converter_future_converter_java8_guava", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/backplane/BUILD b/src/main/java/build/buildfarm/backplane/BUILD index 6d4934f68c..e694fedc55 100644 --- a/src/main/java/build/buildfarm/backplane/BUILD +++ b/src/main/java/build/buildfarm/backplane/BUILD @@ -7,9 +7,9 @@ java_library( "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/operations", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@com_google_googleapis//google/longrunning:longrunning_java_proto", "@maven//:com_google_guava_guava", "@maven//:net_jcip_jcip_annotations", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/cas/BUILD b/src/main/java/build/buildfarm/cas/BUILD index 77532d0cac..0d8baa88d4 100644 --- a/src/main/java/build/buildfarm/cas/BUILD +++ b/src/main/java/build/buildfarm/cas/BUILD @@ -17,7 +17,6 @@ java_library( "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//third_party/googleapis:google_bytestream_bytestream_java_grpc", "//third_party/remote-apis:build_bazel_remote_execution_v2_remote_execution_java_grpc", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@com_google_googleapis//google/bytestream:bytestream_java_proto", "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_jnr_jnr_ffi", @@ -34,5 +33,6 @@ java_library( "@maven//:io_prometheus_simpleclient", "@maven//:net_jcip_jcip_annotations", "@maven//:org_projectlombok_lombok", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/common/BUILD b/src/main/java/build/buildfarm/common/BUILD index a31d381792..b639ee4478 100644 --- a/src/main/java/build/buildfarm/common/BUILD +++ b/src/main/java/build/buildfarm/common/BUILD @@ -16,7 +16,6 @@ java_library( "//src/main/java/build/buildfarm/common/resources", "//src/main/java/build/buildfarm/common/resources:resource_java_proto", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@com_google_googleapis//google/longrunning:longrunning_java_proto", "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_jnr_jnr_constants", @@ -38,6 +37,7 @@ java_library( "@maven//:org_projectlombok_lombok", "@maven//:org_threeten_threetenbp", "@maven//:redis_clients_jedis", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) @@ -54,7 +54,6 @@ java_library( "//src/main/java/build/buildfarm/common/resources", "//src/main/java/build/buildfarm/common/resources:resource_java_proto", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@com_google_googleapis//google/longrunning:longrunning_java_proto", "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_jnr_jnr_constants", @@ -76,6 +75,7 @@ java_library( "@maven//:org_projectlombok_lombok", "@maven//:org_threeten_threetenbp", "@maven//:redis_clients_jedis", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/common/grpc/BUILD b/src/main/java/build/buildfarm/common/grpc/BUILD index 97bd3db339..0b16086ad4 100644 --- a/src/main/java/build/buildfarm/common/grpc/BUILD +++ b/src/main/java/build/buildfarm/common/grpc/BUILD @@ -6,7 +6,6 @@ java_library( deps = [ "//src/main/java/build/buildfarm/common", "//third_party/googleapis:google_bytestream_bytestream_java_grpc", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@com_google_googleapis//google/bytestream:bytestream_java_proto", "@maven//:com_google_code_findbugs_jsr305", "@maven//:com_google_guava_guava", @@ -18,5 +17,6 @@ java_library( "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", "@maven//:org_projectlombok_lombok", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/common/resources/BUILD b/src/main/java/build/buildfarm/common/resources/BUILD index 6689ed969d..e4d965223f 100644 --- a/src/main/java/build/buildfarm/common/resources/BUILD +++ b/src/main/java/build/buildfarm/common/resources/BUILD @@ -7,12 +7,12 @@ proto_library( name = "resource_proto", srcs = ["resource.proto"], deps = [ - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_proto", "@com_google_googleapis//google/api:annotations_proto", "@com_google_googleapis//google/longrunning:operations_proto", "@com_google_googleapis//google/rpc:status_proto", "@com_google_protobuf//:duration_proto", "@com_google_protobuf//:timestamp_proto", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_proto", ], ) @@ -30,7 +30,6 @@ java_library( deps = [ "//src/main/java/build/buildfarm/common/resources:resource_java_proto", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@com_google_googleapis//google/longrunning:longrunning_java_proto", "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_jnr_jnr_constants", @@ -49,5 +48,6 @@ java_library( "@maven//:org_apache_commons_commons_lang3", "@maven//:org_threeten_threetenbp", "@maven//:redis_clients_jedis", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/common/services/BUILD b/src/main/java/build/buildfarm/common/services/BUILD index 7d7cabd919..fea561db05 100644 --- a/src/main/java/build/buildfarm/common/services/BUILD +++ b/src/main/java/build/buildfarm/common/services/BUILD @@ -12,10 +12,11 @@ java_library( "//src/main/java/build/buildfarm/common/resources:resource_java_proto", "//src/main/java/build/buildfarm/instance", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "//third_party/googleapis:google_bytestream_bytestream_java_grpc", + "//third_party/remote-apis:build_bazel_remote_asset_v1_remote_asset_java_grpc", "//third_party/remote-apis:build_bazel_remote_execution_v2_remote_execution_java_grpc", "@bazel_remote_apis//build/bazel/remote/asset/v1:remote_asset_java_grpc", "@bazel_remote_apis//build/bazel/semver:semver_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_grpc", "@com_google_googleapis//google/bytestream:bytestream_java_proto", "@com_google_googleapis//google/devtools/build/v1:build_java_proto", "@com_google_googleapis//google/rpc:rpc_java_proto", @@ -30,5 +31,6 @@ java_library( "@maven//:io_grpc_grpc_stub", "@maven//:io_prometheus_simpleclient", "@maven//:org_projectlombok_lombok", + "@remoteapis//build/bazel/semver:semver_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/instance/BUILD b/src/main/java/build/buildfarm/instance/BUILD index b376b9ab99..ae290a6ea3 100644 --- a/src/main/java/build/buildfarm/instance/BUILD +++ b/src/main/java/build/buildfarm/instance/BUILD @@ -5,7 +5,6 @@ java_library( deps = [ "//src/main/java/build/buildfarm/common", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@com_google_googleapis//google/longrunning:longrunning_java_proto", "@maven//:com_google_code_findbugs_jsr305", "@maven//:com_google_guava_failureaccess", @@ -16,5 +15,6 @@ java_library( "@maven//:io_grpc_grpc_core", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/instance/server/BUILD b/src/main/java/build/buildfarm/instance/server/BUILD index ef7ff446c5..210535a96e 100644 --- a/src/main/java/build/buildfarm/instance/server/BUILD +++ b/src/main/java/build/buildfarm/instance/server/BUILD @@ -17,7 +17,6 @@ java_library( "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/operations", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@com_google_googleapis//google/longrunning:longrunning_java_proto", "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_code_findbugs_jsr305", @@ -30,5 +29,6 @@ java_library( "@maven//:io_grpc_grpc_stub", "@maven//:io_netty_netty_codec_http", "@maven//:org_projectlombok_lombok", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/instance/shard/BUILD b/src/main/java/build/buildfarm/instance/shard/BUILD index a0d197b0a3..bde47183db 100644 --- a/src/main/java/build/buildfarm/instance/shard/BUILD +++ b/src/main/java/build/buildfarm/instance/shard/BUILD @@ -18,7 +18,6 @@ java_library( "//src/main/java/build/buildfarm/operations", "//src/main/java/build/buildfarm/operations/finder", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_ben_manes_caffeine_caffeine", "@maven//:com_google_code_findbugs_jsr305", @@ -36,5 +35,6 @@ java_library( "@maven//:org_projectlombok_lombok", "@maven//:org_redisson_redisson", "@maven//:redis_clients_jedis", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/instance/stub/BUILD b/src/main/java/build/buildfarm/instance/stub/BUILD index 4cab9b8772..671bc31cec 100644 --- a/src/main/java/build/buildfarm/instance/stub/BUILD +++ b/src/main/java/build/buildfarm/instance/stub/BUILD @@ -28,5 +28,6 @@ java_library( "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", "@maven//:org_projectlombok_lombok", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) From 65f892322d340ccbde697a8a0c6f19f7f12e7edd Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Sun, 31 Mar 2024 18:21:40 -0700 Subject: [PATCH 298/311] chore: rewrite //third_party/googleapis to @@com_google_googleapis --- src/main/java/build/buildfarm/cas/BUILD | 2 +- src/main/java/build/buildfarm/common/grpc/BUILD | 2 +- src/main/java/build/buildfarm/instance/stub/BUILD | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/build/buildfarm/cas/BUILD b/src/main/java/build/buildfarm/cas/BUILD index 0d8baa88d4..f2ab5c5a83 100644 --- a/src/main/java/build/buildfarm/cas/BUILD +++ b/src/main/java/build/buildfarm/cas/BUILD @@ -15,8 +15,8 @@ java_library( "//src/main/java/build/buildfarm/common/resources:resource_java_proto", "//src/main/java/build/buildfarm/instance/stub", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "//third_party/googleapis:google_bytestream_bytestream_java_grpc", "//third_party/remote-apis:build_bazel_remote_execution_v2_remote_execution_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_grpc", "@com_google_googleapis//google/bytestream:bytestream_java_proto", "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_jnr_jnr_ffi", diff --git a/src/main/java/build/buildfarm/common/grpc/BUILD b/src/main/java/build/buildfarm/common/grpc/BUILD index 0b16086ad4..14a866e052 100644 --- a/src/main/java/build/buildfarm/common/grpc/BUILD +++ b/src/main/java/build/buildfarm/common/grpc/BUILD @@ -5,7 +5,7 @@ java_library( visibility = ["//visibility:public"], deps = [ "//src/main/java/build/buildfarm/common", - "//third_party/googleapis:google_bytestream_bytestream_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_grpc", "@com_google_googleapis//google/bytestream:bytestream_java_proto", "@maven//:com_google_code_findbugs_jsr305", "@maven//:com_google_guava_guava", diff --git a/src/main/java/build/buildfarm/instance/stub/BUILD b/src/main/java/build/buildfarm/instance/stub/BUILD index 671bc31cec..ac5bbe80f8 100644 --- a/src/main/java/build/buildfarm/instance/stub/BUILD +++ b/src/main/java/build/buildfarm/instance/stub/BUILD @@ -11,11 +11,11 @@ java_library( "//src/main/java/build/buildfarm/instance", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_grpc", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "//third_party/googleapis:google_bytestream_bytestream_java_grpc", - "//third_party/googleapis:google_longrunning_operations_java_grpc", "//third_party/remote-apis:build_bazel_remote_execution_v2_remote_execution_java_grpc", "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_grpc", "@com_google_googleapis//google/bytestream:bytestream_java_proto", + "@com_google_googleapis//google/longrunning:longrunning_java_grpc", "@com_google_googleapis//google/longrunning:longrunning_java_proto", "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_code_findbugs_jsr305", From 2581a299b92cc21a9ab6659a383650a0f283120c Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Sun, 31 Mar 2024 18:22:21 -0700 Subject: [PATCH 299/311] build: remove io_grpc_grpc_java --- MODULE.bazel | 1 - extensions.bzl | 8 -------- 2 files changed, 9 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 726c36e3b7..c646ef986e 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -192,7 +192,6 @@ build_deps = use_extension("//:extensions.bzl", "build_deps") use_repo( build_deps, "bazel", - "io_grpc_grpc_java", "opentelemetry", "skip_sleep", "tini", diff --git a/extensions.bzl b/extensions.bzl index 0b94b86a06..e60b085e2c 100644 --- a/extensions.bzl +++ b/extensions.bzl @@ -6,14 +6,6 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive", "http_file" def archive_dependencies(third_party): return [ - # Needed for @grpc_java//compiler:grpc_java_plugin. - { - "name": "io_grpc_grpc_java", - "sha256": "5d617856c295d863307f4036a1b1e93f9eeaf6da41424d2de7c9b330a810fc3b", - "strip_prefix": "grpc-java-1.62.2", - "urls": ["https://github.com/grpc/grpc-java/archive/v1.62.2.zip"], - # Bzlmod: Waiting for https://github.com/bazelbuild/bazel-central-registry/issues/353 - }, # Bazel is referenced as a dependency so that buildfarm can access the linux-sandbox as a potential execution wrapper. { "name": "bazel", From 5d56d30d628cb51914073916db189351c89e2b7c Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Sun, 31 Mar 2024 18:48:42 -0700 Subject: [PATCH 300/311] build: googleapis --- MODULE.bazel | 2 +- src/main/java/build/buildfarm/instance/stub/BUILD | 1 - src/main/java/build/buildfarm/metrics/BUILD | 2 +- src/main/java/build/buildfarm/metrics/log/BUILD | 2 +- src/main/java/build/buildfarm/operations/BUILD | 2 +- .../java/build/buildfarm/operations/finder/BUILD | 2 +- src/main/java/build/buildfarm/proxy/http/BUILD | 2 +- src/main/java/build/buildfarm/server/services/BUILD | 4 ++-- src/main/java/build/buildfarm/tools/BUILD | 3 ++- src/main/protobuf/BUILD.bazel | 4 ++-- src/test/java/build/buildfarm/cas/BUILD | 1 + src/test/java/build/buildfarm/common/resources/BUILD | 2 +- src/test/java/build/buildfarm/common/services/BUILD | 1 + src/test/java/build/buildfarm/instance/server/BUILD | 2 +- src/test/java/build/buildfarm/instance/shard/BUILD | 12 ++++++------ src/test/java/build/buildfarm/server/services/BUILD | 3 ++- src/test/java/build/buildfarm/worker/BUILD | 2 +- .../java/build/buildfarm/worker/persistent/BUILD | 2 +- src/test/java/build/buildfarm/worker/util/BUILD | 4 ++-- 19 files changed, 28 insertions(+), 25 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index c646ef986e..c8389f74e8 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -199,7 +199,7 @@ use_repo( googleapis_switched_rules = use_extension("@com_google_googleapis//:extensions.bzl", "switched_rules") googleapis_switched_rules.use_languages( - #grpc = True, # This REALLY wants `@io_grpc_grpc_java` to be defined, but try as I might, it cannot be found. + grpc = True, java = True, ) use_repo(googleapis_switched_rules, "com_google_googleapis_imports") diff --git a/src/main/java/build/buildfarm/instance/stub/BUILD b/src/main/java/build/buildfarm/instance/stub/BUILD index ac5bbe80f8..e4e6d15b25 100644 --- a/src/main/java/build/buildfarm/instance/stub/BUILD +++ b/src/main/java/build/buildfarm/instance/stub/BUILD @@ -12,7 +12,6 @@ java_library( "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_grpc", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//third_party/remote-apis:build_bazel_remote_execution_v2_remote_execution_java_grpc", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@com_google_googleapis//google/bytestream:bytestream_java_grpc", "@com_google_googleapis//google/bytestream:bytestream_java_proto", "@com_google_googleapis//google/longrunning:longrunning_java_grpc", diff --git a/src/main/java/build/buildfarm/metrics/BUILD b/src/main/java/build/buildfarm/metrics/BUILD index 162404e359..6a280f05b2 100644 --- a/src/main/java/build/buildfarm/metrics/BUILD +++ b/src/main/java/build/buildfarm/metrics/BUILD @@ -5,12 +5,12 @@ java_library( visibility = ["//visibility:public"], deps = [ "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:io_prometheus_simpleclient", "@maven//:org_projectlombok_lombok", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/metrics/log/BUILD b/src/main/java/build/buildfarm/metrics/log/BUILD index cde0d99591..aa325a3cc7 100644 --- a/src/main/java/build/buildfarm/metrics/log/BUILD +++ b/src/main/java/build/buildfarm/metrics/log/BUILD @@ -7,10 +7,10 @@ java_library( "//src/main/java/build/buildfarm/common/config", "//src/main/java/build/buildfarm/metrics", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java_util", "@maven//:org_projectlombok_lombok", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/operations/BUILD b/src/main/java/build/buildfarm/operations/BUILD index 6630ba9617..3e32dc934b 100644 --- a/src/main/java/build/buildfarm/operations/BUILD +++ b/src/main/java/build/buildfarm/operations/BUILD @@ -11,7 +11,6 @@ java_library( deps = [ "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_proto", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@com_google_googleapis//google/bytestream:bytestream_java_proto", "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_code_findbugs_jsr305", @@ -25,5 +24,6 @@ java_library( "@maven//:io_grpc_grpc_core", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/operations/finder/BUILD b/src/main/java/build/buildfarm/operations/finder/BUILD index 2e00b7d1df..a49f083fae 100644 --- a/src/main/java/build/buildfarm/operations/finder/BUILD +++ b/src/main/java/build/buildfarm/operations/finder/BUILD @@ -10,7 +10,6 @@ java_library( "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/operations", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_code_findbugs_jsr305", "@maven//:com_google_guava_guava", @@ -26,5 +25,6 @@ java_library( "@maven//:org_apache_commons_commons_pool2", "@maven//:org_projectlombok_lombok", "@maven//:redis_clients_jedis", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/proxy/http/BUILD b/src/main/java/build/buildfarm/proxy/http/BUILD index a6ce0d4dac..7b3ec55276 100644 --- a/src/main/java/build/buildfarm/proxy/http/BUILD +++ b/src/main/java/build/buildfarm/proxy/http/BUILD @@ -9,7 +9,6 @@ java_library( "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//third_party/googleapis:google_bytestream_bytestream_java_grpc", "//third_party/remote-apis:build_bazel_remote_execution_v2_remote_execution_java_grpc", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@com_google_googleapis//google/bytestream:bytestream_java_proto", "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_pcj_google_options", @@ -37,5 +36,6 @@ java_library( "@maven//:io_netty_netty_transport_native_kqueue", "@maven//:io_netty_netty_transport_native_unix_common", "@maven//:org_projectlombok_lombok", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/server/services/BUILD b/src/main/java/build/buildfarm/server/services/BUILD index 693b778235..6a4075f30c 100644 --- a/src/main/java/build/buildfarm/server/services/BUILD +++ b/src/main/java/build/buildfarm/server/services/BUILD @@ -17,8 +17,6 @@ java_library( "//third_party/googleapis:google_longrunning_operations_java_grpc", "//third_party/remote-apis:build_bazel_remote_asset_v1_remote_asset_java_grpc", "//third_party/remote-apis:build_bazel_remote_execution_v2_remote_execution_java_grpc", - "@bazel_remote_apis//build/bazel/remote/asset/v1:remote_asset_java_grpc", - "@bazel_remote_apis//build/bazel/semver:semver_java_grpc", "@com_google_googleapis//google/bytestream:bytestream_java_proto", "@com_google_googleapis//google/devtools/build/v1:build_java_proto", "@com_google_googleapis//google/rpc:rpc_java_proto", @@ -33,5 +31,7 @@ java_library( "@maven//:io_grpc_grpc_stub", "@maven//:io_prometheus_simpleclient", "@maven//:org_projectlombok_lombok", + "@remoteapis//build/bazel/remote/asset/v1:remote_asset_java_proto", + "@remoteapis//build/bazel/semver:semver_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/tools/BUILD b/src/main/java/build/buildfarm/tools/BUILD index 058d3d196b..c688ddd5d9 100644 --- a/src/main/java/build/buildfarm/tools/BUILD +++ b/src/main/java/build/buildfarm/tools/BUILD @@ -33,11 +33,11 @@ java_binary( "//src/main/java/build/buildfarm/cas", "//src/main/java/build/buildfarm/common", "//src/main/java/build/buildfarm/common/config", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@maven//:com_github_jnr_jnr_constants", "@maven//:com_github_jnr_jnr_ffi", "@maven//:com_github_jnr_jnr_posix", "@maven//:com_google_guava_guava", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) @@ -73,6 +73,7 @@ java_binary( "@maven//:io_grpc_grpc_core", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) diff --git a/src/main/protobuf/BUILD.bazel b/src/main/protobuf/BUILD.bazel index b1a4fadbe1..f31d75e029 100644 --- a/src/main/protobuf/BUILD.bazel +++ b/src/main/protobuf/BUILD.bazel @@ -8,12 +8,12 @@ proto_library( name = "build_buildfarm_v1test_buildfarm_proto", srcs = ["build/buildfarm/v1test/buildfarm.proto"], deps = [ - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_proto", "@com_google_googleapis//google/api:annotations_proto", "@com_google_googleapis//google/longrunning:operations_proto", "@com_google_googleapis//google/rpc:status_proto", "@com_google_protobuf//:duration_proto", "@com_google_protobuf//:timestamp_proto", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_proto", ], ) @@ -21,9 +21,9 @@ java_proto_library( name = "build_buildfarm_v1test_buildfarm_java_proto", deps = [ ":build_buildfarm_v1test_buildfarm_proto", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_proto", "@com_google_googleapis//google/longrunning:operations_proto", "@com_google_googleapis//google/rpc:status_proto", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_proto", ], ) diff --git a/src/test/java/build/buildfarm/cas/BUILD b/src/test/java/build/buildfarm/cas/BUILD index 6acc6b67a6..f9c91d44a7 100644 --- a/src/test/java/build/buildfarm/cas/BUILD +++ b/src/test/java/build/buildfarm/cas/BUILD @@ -27,5 +27,6 @@ java_test( "@maven//:io_grpc_grpc_stub", "@maven//:io_grpc_grpc_util", "@maven//:org_mockito_mockito_core", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) diff --git a/src/test/java/build/buildfarm/common/resources/BUILD b/src/test/java/build/buildfarm/common/resources/BUILD index bb64bbcba7..824240fa73 100644 --- a/src/test/java/build/buildfarm/common/resources/BUILD +++ b/src/test/java/build/buildfarm/common/resources/BUILD @@ -9,7 +9,6 @@ java_test( "//src/main/java/build/buildfarm/common/resources:resource_java_proto", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@com_google_googleapis//google/bytestream:bytestream_java_proto", "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_guava_guava", @@ -23,5 +22,6 @@ java_test( "@maven//:io_grpc_grpc_testing", "@maven//:org_mockito_mockito_core", "@maven//:redis_clients_jedis", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) diff --git a/src/test/java/build/buildfarm/common/services/BUILD b/src/test/java/build/buildfarm/common/services/BUILD index 1de572dba6..083d0a1813 100644 --- a/src/test/java/build/buildfarm/common/services/BUILD +++ b/src/test/java/build/buildfarm/common/services/BUILD @@ -26,5 +26,6 @@ java_test( "@maven//:io_grpc_grpc_inprocess", "@maven//:io_grpc_grpc_stub", "@maven//:org_mockito_mockito_core", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) diff --git a/src/test/java/build/buildfarm/instance/server/BUILD b/src/test/java/build/buildfarm/instance/server/BUILD index 373c95ba24..4becb0230c 100644 --- a/src/test/java/build/buildfarm/instance/server/BUILD +++ b/src/test/java/build/buildfarm/instance/server/BUILD @@ -13,7 +13,6 @@ java_test( "//src/main/java/build/buildfarm/operations", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@com_google_googleapis//google/longrunning:longrunning_java_proto", "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_guava_guava", @@ -23,5 +22,6 @@ java_test( "@maven//:io_grpc_grpc_stub", "@maven//:org_mockito_mockito_core", "@maven//:org_projectlombok_lombok", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) diff --git a/src/test/java/build/buildfarm/instance/shard/BUILD b/src/test/java/build/buildfarm/instance/shard/BUILD index a92b0795d5..dc22e29237 100644 --- a/src/test/java/build/buildfarm/instance/shard/BUILD +++ b/src/test/java/build/buildfarm/instance/shard/BUILD @@ -17,7 +17,6 @@ java_test( "//src/main/java/build/buildfarm/instance/shard", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@com_google_googleapis//google/longrunning:longrunning_java_proto", "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_ben_manes_caffeine_caffeine", @@ -31,6 +30,7 @@ java_test( "@maven//:io_grpc_grpc_stub", "@maven//:org_mockito_mockito_core", "@maven//:redis_clients_jedis", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) @@ -54,7 +54,6 @@ java_test( "//src/main/java/build/buildfarm/instance/shard", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@com_google_googleapis//google/longrunning:longrunning_java_proto", "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_ben_manes_caffeine_caffeine", @@ -68,6 +67,7 @@ java_test( "@maven//:io_grpc_grpc_stub", "@maven//:org_mockito_mockito_core", "@maven//:redis_clients_jedis", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) @@ -90,7 +90,6 @@ java_test( "//src/main/java/build/buildfarm/instance/shard", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@com_google_googleapis//google/longrunning:longrunning_java_proto", "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_ben_manes_caffeine_caffeine", @@ -104,6 +103,7 @@ java_test( "@maven//:io_grpc_grpc_stub", "@maven//:org_mockito_mockito_core", "@maven//:redis_clients_jedis", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) @@ -126,7 +126,6 @@ java_test( "//src/main/java/build/buildfarm/instance/shard", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@com_google_googleapis//google/longrunning:longrunning_java_proto", "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_ben_manes_caffeine_caffeine", @@ -140,6 +139,7 @@ java_test( "@maven//:io_grpc_grpc_stub", "@maven//:org_mockito_mockito_core", "@maven//:redis_clients_jedis", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) @@ -162,7 +162,6 @@ java_test( "//src/main/java/build/buildfarm/instance/shard", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@com_google_googleapis//google/longrunning:longrunning_java_proto", "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_ben_manes_caffeine_caffeine", @@ -176,6 +175,7 @@ java_test( "@maven//:io_grpc_grpc_stub", "@maven//:org_mockito_mockito_core", "@maven//:redis_clients_jedis", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) @@ -198,7 +198,6 @@ java_test( "//src/main/java/build/buildfarm/instance/shard", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@com_google_googleapis//google/longrunning:longrunning_java_proto", "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_ben_manes_caffeine_caffeine", @@ -212,6 +211,7 @@ java_test( "@maven//:io_grpc_grpc_stub", "@maven//:org_mockito_mockito_core", "@maven//:redis_clients_jedis", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) diff --git a/src/test/java/build/buildfarm/server/services/BUILD b/src/test/java/build/buildfarm/server/services/BUILD index 45d2acbe79..7c6d1b6b1e 100644 --- a/src/test/java/build/buildfarm/server/services/BUILD +++ b/src/test/java/build/buildfarm/server/services/BUILD @@ -11,11 +11,12 @@ java_test( "//src/main/java/build/buildfarm/server/services", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "@bazel_remote_apis//build/bazel/remote/asset/v1:remote_asset_java_grpc", + "//third_party/remote-apis:build_bazel_remote_asset_v1_remote_asset_java_grpc", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:com_google_truth_truth", "@maven//:io_grpc_grpc_stub", "@maven//:org_mockito_mockito_core", + "@remoteapis//build/bazel/remote/asset/v1:remote_asset_java_proto", ], ) diff --git a/src/test/java/build/buildfarm/worker/BUILD b/src/test/java/build/buildfarm/worker/BUILD index 32bc565d78..cbd186e922 100644 --- a/src/test/java/build/buildfarm/worker/BUILD +++ b/src/test/java/build/buildfarm/worker/BUILD @@ -25,7 +25,6 @@ java_test( "//src/main/java/build/buildfarm/worker/resources", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_jnr_jnr_constants", "@maven//:com_github_jnr_jnr_ffi", @@ -40,5 +39,6 @@ java_test( "@maven//:io_grpc_grpc_protobuf", "@maven//:org_mockito_mockito_core", "@maven//:org_projectlombok_lombok", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) diff --git a/src/test/java/build/buildfarm/worker/persistent/BUILD b/src/test/java/build/buildfarm/worker/persistent/BUILD index 1c96884643..b7d0c4d056 100644 --- a/src/test/java/build/buildfarm/worker/persistent/BUILD +++ b/src/test/java/build/buildfarm/worker/persistent/BUILD @@ -17,7 +17,6 @@ java_test( "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", "//src/test/java/build/buildfarm/worker/util:worker_test_utils", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_jnr_jnr_constants", "@maven//:com_github_jnr_jnr_ffi", @@ -32,5 +31,6 @@ java_test( "@maven//:io_grpc_grpc_protobuf", "@maven//:org_mockito_mockito_core", "@maven//:org_projectlombok_lombok", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) diff --git a/src/test/java/build/buildfarm/worker/util/BUILD b/src/test/java/build/buildfarm/worker/util/BUILD index 9645bfb85d..dbf262c781 100644 --- a/src/test/java/build/buildfarm/worker/util/BUILD +++ b/src/test/java/build/buildfarm/worker/util/BUILD @@ -10,7 +10,6 @@ java_library( "//src/main/java/build/buildfarm/worker/util", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_jnr_jnr_constants", "@maven//:com_github_jnr_jnr_ffi", @@ -25,6 +24,7 @@ java_library( "@maven//:io_grpc_grpc_protobuf", "@maven//:org_mockito_mockito_core", "@maven//:org_projectlombok_lombok", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) @@ -42,7 +42,6 @@ java_test( "//src/main/java/build/buildfarm/worker/util", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_jnr_jnr_constants", "@maven//:com_github_jnr_jnr_ffi", @@ -57,5 +56,6 @@ java_test( "@maven//:io_grpc_grpc_protobuf", "@maven//:org_mockito_mockito_core", "@maven//:org_projectlombok_lombok", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) From 880771a4b0221d160fae64397c560754fe912990 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Sun, 31 Mar 2024 21:50:24 -0700 Subject: [PATCH 301/311] build: add com_github_grpc_grpc --- extensions.bzl | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/extensions.bzl b/extensions.bzl index e60b085e2c..95a782eedf 100644 --- a/extensions.bzl +++ b/extensions.bzl @@ -50,6 +50,16 @@ def _buildfarm_extension_impl(_ctx): urls = ["https://github.com/krallin/tini/releases/download/v0.18.0/tini"], ) + if not native.existing_rule("com_github_grpc_grpc"): + http_archive( + name = "com_github_grpc_grpc", + strip_prefix = "grpc-1.46.0", + sha256 = "67423a4cd706ce16a88d1549297023f0f9f0d695a96dd684adc21e67b021f9bc", + urls = [ + "https://github.com/grpc/grpc/archive/v1.46.0.tar.gz", + ], + ) + build_deps = module_extension( implementation = _buildfarm_extension_impl, ) From 9169a4ec9da930b412d977ae7f092f9f7bf17044 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Thu, 4 Apr 2024 15:25:12 -0700 Subject: [PATCH 302/311] chore: delete third_party/BUILD.remote_apis --- third_party/BUILD.remote_apis | 40 ----------------------------------- 1 file changed, 40 deletions(-) delete mode 100644 third_party/BUILD.remote_apis diff --git a/third_party/BUILD.remote_apis b/third_party/BUILD.remote_apis deleted file mode 100644 index 407a7c9291..0000000000 --- a/third_party/BUILD.remote_apis +++ /dev/null @@ -1,40 +0,0 @@ -load("@io_grpc_grpc_java//:java_grpc_library.bzl", "java_grpc_library") -load("@rules_java//java:defs.bzl", "java_proto_library") - -package(default_visibility = ["//visibility:public"]) - -licenses(["notice"]) - -exports_files(["LICENSE"]) - -java_proto_library( - name = "build_bazel_remote_asset_v1_remote_asset_java_proto", - deps = [ - "//build/bazel/remote/asset/v1:remote_asset_proto", - ], -) - -java_grpc_library( - name = "build_bazel_remote_asset_v1_remote_asset_java_grpc", - srcs = ["//build/bazel/remote/asset/v1:remote_asset_proto"], - deps = [":build_bazel_remote_asset_v1_remote_asset_java_proto"], -) - -java_proto_library( - name = "build_bazel_remote_execution_v2_remote_execution_java_proto", - deps = [ - "//build/bazel/remote/execution/v2:remote_execution_proto", - "@com_google_googleapis//google/longrunning:operations_proto", - ], -) - -java_grpc_library( - name = "build_bazel_remote_execution_v2_remote_execution_java_grpc", - srcs = ["//build/bazel/remote/execution/v2:remote_execution_proto"], - deps = [":build_bazel_remote_execution_v2_remote_execution_java_proto"], -) - -java_proto_library( - name = "build_bazel_semver_java_proto", - deps = ["//build/bazel/semver:semver_proto"], -) From 813ac03c14b5e3428cd7ca220e18838833be7786 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Sun, 31 Mar 2024 21:50:56 -0700 Subject: [PATCH 303/311] build: BUILD --- src/main/java/build/buildfarm/common/services/BUILD | 3 +-- src/main/java/build/buildfarm/proxy/http/BUILD | 2 +- src/main/java/build/buildfarm/server/BUILD | 2 ++ src/main/java/build/buildfarm/server/services/BUILD | 4 ++-- src/main/java/build/buildfarm/tools/BUILD | 13 ++++++------- src/main/java/build/buildfarm/worker/shard/BUILD | 1 + src/main/protobuf/BUILD.bazel | 2 +- src/test/java/build/buildfarm/cas/BUILD | 3 +-- src/test/java/build/buildfarm/common/grpc/BUILD | 4 ++-- src/test/java/build/buildfarm/common/io/BUILD | 2 +- src/test/java/build/buildfarm/common/services/BUILD | 3 +-- src/test/java/build/buildfarm/instance/stub/BUILD | 4 ++-- src/test/java/build/buildfarm/proxy/http/BUILD | 4 ++-- src/test/java/build/buildfarm/server/BUILD | 6 +++--- 14 files changed, 26 insertions(+), 27 deletions(-) diff --git a/src/main/java/build/buildfarm/common/services/BUILD b/src/main/java/build/buildfarm/common/services/BUILD index fea561db05..59f962b320 100644 --- a/src/main/java/build/buildfarm/common/services/BUILD +++ b/src/main/java/build/buildfarm/common/services/BUILD @@ -14,8 +14,7 @@ java_library( "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//third_party/remote-apis:build_bazel_remote_asset_v1_remote_asset_java_grpc", "//third_party/remote-apis:build_bazel_remote_execution_v2_remote_execution_java_grpc", - "@bazel_remote_apis//build/bazel/remote/asset/v1:remote_asset_java_grpc", - "@bazel_remote_apis//build/bazel/semver:semver_java_grpc", + "@remoteapis//build/bazel/remote/asset/v1:remote_asset_java_proto", "@com_google_googleapis//google/bytestream:bytestream_java_grpc", "@com_google_googleapis//google/bytestream:bytestream_java_proto", "@com_google_googleapis//google/devtools/build/v1:build_java_proto", diff --git a/src/main/java/build/buildfarm/proxy/http/BUILD b/src/main/java/build/buildfarm/proxy/http/BUILD index 7b3ec55276..9e82c18735 100644 --- a/src/main/java/build/buildfarm/proxy/http/BUILD +++ b/src/main/java/build/buildfarm/proxy/http/BUILD @@ -7,8 +7,8 @@ java_library( "//src/main/java/build/buildfarm/common", "//src/main/java/build/buildfarm/common/resources:resource_java_proto", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "//third_party/googleapis:google_bytestream_bytestream_java_grpc", "//third_party/remote-apis:build_bazel_remote_execution_v2_remote_execution_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_grpc", "@com_google_googleapis//google/bytestream:bytestream_java_proto", "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_pcj_google_options", diff --git a/src/main/java/build/buildfarm/server/BUILD b/src/main/java/build/buildfarm/server/BUILD index 83b8060640..9d332e9ebc 100644 --- a/src/main/java/build/buildfarm/server/BUILD +++ b/src/main/java/build/buildfarm/server/BUILD @@ -16,7 +16,9 @@ java_library( "//src/main/java/build/buildfarm/metrics/prometheus", "//src/main/java/build/buildfarm/server/services", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", + "@@grpc-java~1.62.2~grpc_java_repositories_extension~io_grpc_grpc_proto//:health_java_proto", "@maven//:com_github_pcj_google_options", + "@maven//:com_google_api_grpc_proto_google_common_protos", "@maven//:com_google_guava_guava", "@maven//:io_grpc_grpc_api", "@maven//:io_grpc_grpc_core", diff --git a/src/main/java/build/buildfarm/server/services/BUILD b/src/main/java/build/buildfarm/server/services/BUILD index 6a4075f30c..d210928fe7 100644 --- a/src/main/java/build/buildfarm/server/services/BUILD +++ b/src/main/java/build/buildfarm/server/services/BUILD @@ -13,12 +13,12 @@ java_library( "//src/main/java/build/buildfarm/metrics/log", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_grpc", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "//third_party/googleapis:google_devtools_build_v1_publish_build_event_java_grpc", - "//third_party/googleapis:google_longrunning_operations_java_grpc", "//third_party/remote-apis:build_bazel_remote_asset_v1_remote_asset_java_grpc", "//third_party/remote-apis:build_bazel_remote_execution_v2_remote_execution_java_grpc", "@com_google_googleapis//google/bytestream:bytestream_java_proto", + "@com_google_googleapis//google/devtools/build/v1:build_java_grpc", "@com_google_googleapis//google/devtools/build/v1:build_java_proto", + "@com_google_googleapis//google/longrunning:longrunning_java_grpc", "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_code_findbugs_jsr305", "@maven//:com_google_guava_guava", diff --git a/src/main/java/build/buildfarm/tools/BUILD b/src/main/java/build/buildfarm/tools/BUILD index c688ddd5d9..60ea837540 100644 --- a/src/main/java/build/buildfarm/tools/BUILD +++ b/src/main/java/build/buildfarm/tools/BUILD @@ -59,9 +59,8 @@ java_binary( "//src/main/java/build/buildfarm/common", "//src/main/java/build/buildfarm/common/grpc", "//src/main/java/build/buildfarm/instance/stub", - "//third_party/googleapis:google_bytestream_bytestream_java_grpc", "//third_party/remote-apis:build_bazel_remote_execution_v2_remote_execution_java_grpc", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_grpc", "@com_google_googleapis//google/bytestream:bytestream_java_proto", "@com_google_googleapis//google/longrunning:longrunning_java_proto", "@com_google_googleapis//google/longrunning:operations_proto", @@ -85,8 +84,7 @@ java_binary( deps = [ "//src/main/java/build/buildfarm/common", "//src/main/java/build/buildfarm/common/grpc", - "//third_party/googleapis:google_bytestream_bytestream_java_grpc", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_grpc", "@com_google_googleapis//google/bytestream:bytestream_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", @@ -95,6 +93,7 @@ java_binary( "@maven//:io_grpc_grpc_core", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) @@ -207,7 +206,6 @@ java_binary( "//src/main/java/build/buildfarm/common/grpc", "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/instance/stub", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@com_google_googleapis//google/longrunning:longrunning_java_proto", "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_guava_guava", @@ -217,6 +215,7 @@ java_binary( "@maven//:io_grpc_grpc_core", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) @@ -230,7 +229,6 @@ java_binary( "//src/main/java/build/buildfarm/common/grpc", "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/instance/stub", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@com_google_googleapis//google/longrunning:longrunning_java_proto", "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_guava_guava", @@ -240,6 +238,7 @@ java_binary( "@maven//:io_grpc_grpc_core", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) @@ -253,7 +252,6 @@ java_binary( "//src/main/java/build/buildfarm/common/grpc", "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/instance/stub", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", "@com_google_googleapis//google/longrunning:longrunning_java_proto", "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_google_guava_guava", @@ -263,6 +261,7 @@ java_binary( "@maven//:io_grpc_grpc_core", "@maven//:io_grpc_grpc_protobuf", "@maven//:io_grpc_grpc_stub", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) diff --git a/src/main/java/build/buildfarm/worker/shard/BUILD b/src/main/java/build/buildfarm/worker/shard/BUILD index 662c2d5969..c72d35245d 100644 --- a/src/main/java/build/buildfarm/worker/shard/BUILD +++ b/src/main/java/build/buildfarm/worker/shard/BUILD @@ -21,6 +21,7 @@ java_library( "//src/main/java/build/buildfarm/worker/resources", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_grpc", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", + "@@grpc-java~1.62.2~grpc_java_repositories_extension~io_grpc_grpc_proto//:health_java_proto", "@com_google_googleapis//google/rpc:rpc_java_proto", "@maven//:com_github_ben_manes_caffeine_caffeine", "@maven//:com_github_pcj_google_options", diff --git a/src/main/protobuf/BUILD.bazel b/src/main/protobuf/BUILD.bazel index f31d75e029..5f21b2d4b0 100644 --- a/src/main/protobuf/BUILD.bazel +++ b/src/main/protobuf/BUILD.bazel @@ -1,4 +1,4 @@ -load("@io_grpc_grpc_java//:java_grpc_library.bzl", "java_grpc_library") +load("@grpc-java//:java_grpc_library.bzl", "java_grpc_library") load("@rules_java//java:defs.bzl", "java_proto_library") load("@rules_proto//proto:defs.bzl", "proto_library") diff --git a/src/test/java/build/buildfarm/cas/BUILD b/src/test/java/build/buildfarm/cas/BUILD index f9c91d44a7..be43dc41db 100644 --- a/src/test/java/build/buildfarm/cas/BUILD +++ b/src/test/java/build/buildfarm/cas/BUILD @@ -12,9 +12,8 @@ java_test( "//src/main/java/build/buildfarm/instance/stub", "//src/test/java/build/buildfarm:test_runner", "//src/test/java/build/buildfarm/common/grpc", - "//third_party/googleapis:google_bytestream_bytestream_java_grpc", "//third_party/remote-apis:build_bazel_remote_execution_v2_remote_execution_java_grpc", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_grpc", "@com_google_googleapis//google/bytestream:bytestream_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_jimfs_jimfs", diff --git a/src/test/java/build/buildfarm/common/grpc/BUILD b/src/test/java/build/buildfarm/common/grpc/BUILD index 121705563a..b4f87c088c 100644 --- a/src/test/java/build/buildfarm/common/grpc/BUILD +++ b/src/test/java/build/buildfarm/common/grpc/BUILD @@ -4,7 +4,7 @@ java_library( visibility = ["//src/test/java/build/buildfarm:__subpackages__"], deps = [ "//src/main/java/build/buildfarm/common/grpc", - "//third_party/googleapis:google_bytestream_bytestream_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_grpc", "@com_google_googleapis//google/bytestream:bytestream_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", @@ -21,7 +21,7 @@ java_test( deps = [ "//src/main/java/build/buildfarm/common/grpc", "//src/test/java/build/buildfarm:test_runner", - "//third_party/googleapis:google_bytestream_bytestream_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_grpc", "@com_google_googleapis//google/bytestream:bytestream_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", diff --git a/src/test/java/build/buildfarm/common/io/BUILD b/src/test/java/build/buildfarm/common/io/BUILD index c9758d4980..a002ee4923 100644 --- a/src/test/java/build/buildfarm/common/io/BUILD +++ b/src/test/java/build/buildfarm/common/io/BUILD @@ -6,7 +6,7 @@ java_test( "//src/main/java/build/buildfarm/common", "//src/main/java/build/buildfarm/common/grpc", "//src/test/java/build/buildfarm:test_runner", - "//third_party/googleapis:google_bytestream_bytestream_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_grpc", "@com_google_googleapis//google/bytestream:bytestream_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_jimfs_jimfs", diff --git a/src/test/java/build/buildfarm/common/services/BUILD b/src/test/java/build/buildfarm/common/services/BUILD index 083d0a1813..87f9f943b1 100644 --- a/src/test/java/build/buildfarm/common/services/BUILD +++ b/src/test/java/build/buildfarm/common/services/BUILD @@ -14,8 +14,7 @@ java_test( "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/instance/stub", "//src/test/java/build/buildfarm:test_runner", - "//third_party/googleapis:google_bytestream_bytestream_java_grpc", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_grpc", "@com_google_googleapis//google/bytestream:bytestream_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", diff --git a/src/test/java/build/buildfarm/instance/stub/BUILD b/src/test/java/build/buildfarm/instance/stub/BUILD index d827645094..9b75da1698 100644 --- a/src/test/java/build/buildfarm/instance/stub/BUILD +++ b/src/test/java/build/buildfarm/instance/stub/BUILD @@ -12,9 +12,8 @@ java_test( "//src/main/java/build/buildfarm/instance", "//src/main/java/build/buildfarm/instance/stub", "//src/test/java/build/buildfarm:test_runner", - "//third_party/googleapis:google_bytestream_bytestream_java_grpc", "//third_party/remote-apis:build_bazel_remote_execution_v2_remote_execution_java_grpc", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_grpc", "@com_google_googleapis//google/bytestream:bytestream_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", @@ -25,5 +24,6 @@ java_test( "@maven//:io_grpc_grpc_stub", "@maven//:io_grpc_grpc_util", "@maven//:org_mockito_mockito_core", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) diff --git a/src/test/java/build/buildfarm/proxy/http/BUILD b/src/test/java/build/buildfarm/proxy/http/BUILD index 8dafef160b..ddce214e13 100644 --- a/src/test/java/build/buildfarm/proxy/http/BUILD +++ b/src/test/java/build/buildfarm/proxy/http/BUILD @@ -7,8 +7,7 @@ java_test( "//src/main/java/build/buildfarm/common", "//src/main/java/build/buildfarm/proxy/http", "//src/test/java/build/buildfarm:test_runner", - "//third_party/googleapis:google_bytestream_bytestream_java_grpc", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_grpc", "@com_google_googleapis//google/bytestream:bytestream_java_proto", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", @@ -18,5 +17,6 @@ java_test( "@maven//:io_grpc_grpc_inprocess", "@maven//:io_grpc_grpc_stub", "@maven//:org_mockito_mockito_core", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) diff --git a/src/test/java/build/buildfarm/server/BUILD b/src/test/java/build/buildfarm/server/BUILD index be02e4579c..1bb96f6674 100644 --- a/src/test/java/build/buildfarm/server/BUILD +++ b/src/test/java/build/buildfarm/server/BUILD @@ -18,11 +18,10 @@ java_test( "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_grpc", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//src/test/java/build/buildfarm:test_runner", - "//third_party/googleapis:google_bytestream_bytestream_java_grpc", - "//third_party/googleapis:google_longrunning_operations_java_grpc", "//third_party/remote-apis:build_bazel_remote_execution_v2_remote_execution_java_grpc", - "@bazel_remote_apis//build/bazel/remote/execution/v2:remote_execution_java_grpc", + "@com_google_googleapis//google/bytestream:bytestream_java_grpc", "@com_google_googleapis//google/bytestream:bytestream_java_proto", + "@com_google_googleapis//google/longrunning:longrunning_java_grpc", "@com_google_googleapis//google/rpc:rpc_java_proto", "@com_google_protobuf//:protobuf_java", "@maven//:com_google_guava_guava", @@ -38,5 +37,6 @@ java_test( "@maven//:io_grpc_grpc_stub", "@maven//:me_dinowernli_java_grpc_prometheus", "@maven//:org_mockito_mockito_core", + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", ], ) From 808a01c30b00abd0e4ddf7e14b1e72a7a2eed378 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Sun, 31 Mar 2024 21:51:06 -0700 Subject: [PATCH 304/311] chore: pin maven deps --- MODULE.bazel | 1 + maven_install.json | 4504 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 4505 insertions(+) create mode 100755 maven_install.json diff --git a/MODULE.bazel b/MODULE.bazel index c8389f74e8..20f3ed1912 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -138,6 +138,7 @@ maven.install( "org.yaml:snakeyaml:2.2", "redis.clients:jedis:5.1.2", ], + fail_if_repin_required = True, # TO RE-PIN: REPIN=1 bazel run @unpinned_maven//:pin generate_compat_repositories = True, lock_file = "//:maven_install.json", repositories = [ diff --git a/maven_install.json b/maven_install.json new file mode 100755 index 0000000000..41a9f2a0e9 --- /dev/null +++ b/maven_install.json @@ -0,0 +1,4504 @@ +{ + "__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": "THERE_IS_NO_DATA_ONLY_ZUUL", + "__INPUT_ARTIFACTS_HASH": 1128517071, + "__RESOLVED_ARTIFACTS_HASH": 1494115846, + "conflict_resolution": { + "com.fasterxml.jackson.core:jackson-databind:2.15.0": "com.fasterxml.jackson.core:jackson-databind:2.15.2", + "com.github.ben-manes.caffeine:caffeine:2.9.0": "com.github.ben-manes.caffeine:caffeine:3.0.5", + "com.google.code.gson:gson:2.8.9": "com.google.code.gson:gson:2.10.1", + "com.google.errorprone:error_prone_annotations:2.22.0": "com.google.errorprone:error_prone_annotations:2.23.0", + "com.google.errorprone:error_prone_annotations:2.3.2": "com.google.errorprone:error_prone_annotations:2.23.0", + "com.google.guava:guava:31.1-jre": "com.google.guava:guava:32.1.3-jre", + "com.google.guava:guava:32.1.1-jre": "com.google.guava:guava:32.1.3-jre", + "com.google.j2objc:j2objc-annotations:1.3": "com.google.j2objc:j2objc-annotations:2.8", + "com.google.protobuf:protobuf-java-util:3.19.1": "com.google.protobuf:protobuf-java-util:3.25.1", + "com.google.protobuf:protobuf-java:3.19.1": "com.google.protobuf:protobuf-java:3.25.1", + "com.google.truth:truth:1.1.2": "com.google.truth:truth:1.1.5", + "io.netty:netty-buffer:4.1.97.Final": "io.netty:netty-buffer:4.1.100.Final", + "io.netty:netty-codec-http2:4.1.97.Final": "io.netty:netty-codec-http2:4.1.100.Final", + "io.netty:netty-codec-http:4.1.97.Final": "io.netty:netty-codec-http:4.1.100.Final", + "io.netty:netty-codec-socks:4.1.97.Final": "io.netty:netty-codec-socks:4.1.100.Final", + "io.netty:netty-codec:4.1.97.Final": "io.netty:netty-codec:4.1.100.Final", + "io.netty:netty-common:4.1.97.Final": "io.netty:netty-common:4.1.100.Final", + "io.netty:netty-handler-proxy:4.1.97.Final": "io.netty:netty-handler-proxy:4.1.100.Final", + "io.netty:netty-handler:4.1.97.Final": "io.netty:netty-handler:4.1.100.Final", + "io.netty:netty-resolver:4.1.97.Final": "io.netty:netty-resolver:4.1.100.Final", + "io.netty:netty-transport-native-unix-common:4.1.97.Final": "io.netty:netty-transport-native-unix-common:4.1.100.Final", + "io.netty:netty-transport:4.1.97.Final": "io.netty:netty-transport:4.1.100.Final", + "org.apache.commons:commons-pool2:2.11.1": "org.apache.commons:commons-pool2:2.12.0", + "org.mockito:mockito-core:4.3.1": "org.mockito:mockito-core:5.10.0" + }, + "artifacts": { + "aopalliance:aopalliance": { + "shasums": { + "jar": "0addec670fedcd3f113c5c8091d783280d23f75e3acb841b61a9cdb079376a08" + }, + "version": "1.0" + }, + "com.amazonaws:aws-java-sdk-core": { + "shasums": { + "jar": "79682855ea21bd65094ad97109f9b3e4361d3e02926f5ee14ade3411c7ca43da" + }, + "version": "1.12.544" + }, + "com.amazonaws:aws-java-sdk-kms": { + "shasums": { + "jar": "a79a3768887ea675f2e7b617b361d5250b2128413dbd5d8fa43755a9ecc1b032" + }, + "version": "1.12.544" + }, + "com.amazonaws:aws-java-sdk-s3": { + "shasums": { + "jar": "817b2fac490d3e02ecaf3253c2e2ab0bf6d2291a841574cec70464312d669230" + }, + "version": "1.12.544" + }, + "com.amazonaws:aws-java-sdk-secretsmanager": { + "shasums": { + "jar": "b6a0953948949282b46769896c9d1eb1660ed77632c52137fdb72b8372fe685e" + }, + "version": "1.12.544" + }, + "com.amazonaws:jmespath-java": { + "shasums": { + "jar": "b707d67e8fcc87ffdf426bbe61bbe60ae97e865d35d6cec429a934d47fa2976c" + }, + "version": "1.12.544" + }, + "com.esotericsoftware:kryo": { + "shasums": { + "jar": "4b902a21d99f7b4c32e6f7400e91f9284fd184db881bb9e18328e14d8127f7f9" + }, + "version": "5.5.0" + }, + "com.esotericsoftware:minlog": { + "shasums": { + "jar": "5d4d632cfbebfe0a7644501cc303570b691406181bee65e9916b921c767d7c72" + }, + "version": "1.3.1" + }, + "com.esotericsoftware:reflectasm": { + "shasums": { + "jar": "712b44da79a5b7f47a28cbfcb3d8ecfc872fae349c48aa4d3e38a5d69956afce" + }, + "version": "1.11.9" + }, + "com.fasterxml.jackson.core:jackson-annotations": { + "shasums": { + "jar": "04e21f94dcfee4b078fa5a5f53047b785aaba69d19de392f616e7a7fe5d3882f" + }, + "version": "2.15.2" + }, + "com.fasterxml.jackson.core:jackson-core": { + "shasums": { + "jar": "303c99e82b1faa91a0bae5d8fbeb56f7e2adf9b526a900dd723bf140d62bd4b4" + }, + "version": "2.15.2" + }, + "com.fasterxml.jackson.core:jackson-databind": { + "shasums": { + "jar": "0eb2fdad6e40ab8832a78c9b22f58196dd970594e8d3d5a26ead87847c4f3a96" + }, + "version": "2.15.2" + }, + "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": { + "shasums": { + "jar": "cfa008d15f052e69221e8c3193056ff95c3c594271321ccac8d72dc1a770619c" + }, + "version": "2.12.6" + }, + "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": { + "shasums": { + "jar": "37795cc1e8cb94b18d860dc3abd2e593617ce402149ae45aa89ed8bfb881c851" + }, + "version": "2.15.2" + }, + "com.fasterxml.jackson.jaxrs:jackson-jaxrs-base": { + "shasums": { + "jar": "3b6b74311d094990e6d8de356363988050fb2bf5389138b198b01a0ceb9a9668" + }, + "version": "2.10.3" + }, + "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": { + "shasums": { + "jar": "93026591dbb332030dbe865b9c811a016e470d8ff6daaa7031556d2185e62054" + }, + "version": "2.10.3" + }, + "com.fasterxml.jackson.module:jackson-module-jaxb-annotations": { + "shasums": { + "jar": "8099caad4ae189525ef94d337d72d3e888abefabbbacbc9f3d2f096d534f2fb5" + }, + "version": "2.10.3" + }, + "com.github.ben-manes.caffeine:caffeine": { + "shasums": { + "jar": "8a9b54d3506a3b92ee46b217bcee79196b21ca6d52dc2967c686a205fb2f9c15" + }, + "version": "3.0.5" + }, + "com.github.docker-java:docker-java": { + "shasums": { + "jar": "3afb208216a17d8ce26a8f689303292701c87b974d43780cfba47bb2199a4467" + }, + "version": "3.3.3" + }, + "com.github.docker-java:docker-java-api": { + "shasums": { + "jar": "8be2f41ddc33306b83f91e413fc1a07cee02db05e4c493456de3399e5bcb7b6c" + }, + "version": "3.3.3" + }, + "com.github.docker-java:docker-java-core": { + "shasums": { + "jar": "d1f60040b4666a6073d4a2e0b72fc86cfb1b77f36b093e46a4115ea255995267" + }, + "version": "3.3.3" + }, + "com.github.docker-java:docker-java-transport": { + "shasums": { + "jar": "103b94685f398b036cf9243cb8899680bcdb4e54c32340a32b2b5737a87a33ba" + }, + "version": "3.3.3" + }, + "com.github.docker-java:docker-java-transport-jersey": { + "shasums": { + "jar": "7574d831272a56268f4468b901059cafdca6e10176c87fec83f65d26d28c6fb0" + }, + "version": "3.3.3" + }, + "com.github.docker-java:docker-java-transport-netty": { + "shasums": { + "jar": "30152706a19f46f97bea55e85182762d8b5d2d23bea5e465af403537677f879b" + }, + "version": "3.3.3" + }, + "com.github.fppt:jedis-mock": { + "shasums": { + "jar": "2588555326a117a8120b43e388483caef8fd52c0fc96f2badec5aa59c26dd521" + }, + "version": "1.0.13" + }, + "com.github.jnr:jffi": { + "shasums": { + "jar": "74d3bce7397b4872ccb6a6fd84b8f260503f76509adc9548029f665852ad38d7", + "native": "f4c26c0a4a3eddfdbaaf4dda77d4d9f7d148ba4208798f32ce475ce4d6778744" + }, + "version": "1.3.11" + }, + "com.github.jnr:jnr-a64asm": { + "shasums": { + "jar": "53ae5ea7fa5c284e8279aa348e7b9de4548b0cae10bfd058fa217c791875e4cf" + }, + "version": "1.0.0" + }, + "com.github.jnr:jnr-constants": { + "shasums": { + "jar": "9a5b8cf9798d9d0331b8d8966c5235a22c4307676e35803a24659e6d76096f78" + }, + "version": "0.10.4" + }, + "com.github.jnr:jnr-ffi": { + "shasums": { + "jar": "01fafe177b1e3136b3789aeb0ff0884ae1e24b5ada711192f67084103697f2d4" + }, + "version": "2.2.14" + }, + "com.github.jnr:jnr-posix": { + "shasums": { + "jar": "9e24abedd700a1d8f0a2787566f2d0c4f3e4fbdb8be543d4b434ce445923c757" + }, + "version": "3.1.17" + }, + "com.github.jnr:jnr-x86asm": { + "shasums": { + "jar": "39f3675b910e6e9b93825f8284bec9f4ad3044cd20a6f7c8ff9e2f8695ebf21e" + }, + "version": "1.0.2" + }, + "com.github.kevinstern:software-and-algorithms": { + "shasums": { + "jar": "61ab82439cef37343b14f53154c461619375373a56b9338e895709fb54e0864c" + }, + "version": "1.0" + }, + "com.github.luben:zstd-jni": { + "shasums": { + "jar": "edd7fc60c2aaa6b77d3436f667bf30b06202633761ec20d683638b40e8f11426" + }, + "version": "1.5.5-7" + }, + "com.github.oshi:oshi-core": { + "shasums": { + "jar": "7e634fb57b8763b7803d5f9caaed46d19c3bdbe81ddd8a93e61528c700cdc09e" + }, + "version": "6.4.5" + }, + "com.github.pcj:google-options": { + "shasums": { + "jar": "f1f84449b46390a7fa73aac0b5acdec4312d6174146af0db1c92425c7005fdce" + }, + "version": "1.0.0" + }, + "com.github.serceman:jnr-fuse": { + "shasums": { + "jar": "ebe81ccbcbe1464996e5213ee24947cfba9eda7e9ffe154333f9bd8321217989" + }, + "version": "0.5.7" + }, + "com.google.android:annotations": { + "shasums": { + "jar": "ba734e1e84c09d615af6a09d33034b4f0442f8772dec120efb376d86a565ae15" + }, + "version": "4.1.1.4" + }, + "com.google.api.grpc:proto-google-common-protos": { + "shasums": { + "jar": "ee9c751f06b112e92b37f75e4f73a17d03ef2c3302c6e8d986adbcc721b63cb0" + }, + "version": "2.29.0" + }, + "com.google.auth:google-auth-library-credentials": { + "shasums": { + "jar": "095984b0594888a47f311b3c9dcf6da9ed86feeea8f78140c55e14c27b0593e5" + }, + "version": "1.19.0" + }, + "com.google.auth:google-auth-library-oauth2-http": { + "shasums": { + "jar": "01bdf5c5cd85e10b794e401775d9909b56a38ffce313fbd39510a5d87ed56f58" + }, + "version": "1.19.0" + }, + "com.google.auto.service:auto-service-annotations": { + "shasums": { + "jar": "c7bec54b7b5588b5967e870341091c5691181d954cf2039f1bf0a6eeb837473b" + }, + "version": "1.0.1" + }, + "com.google.auto.value:auto-value-annotations": { + "shasums": { + "jar": "a4fe0a211925e938a8510d741763ee1171a11bf931f5891ef4d4ee84fca72be2" + }, + "version": "1.10.1" + }, + "com.google.auto:auto-common": { + "shasums": { + "jar": "f43f29fe2a6ebaf04b2598cdeec32a4e346d49a9404e990f5fc19c19f3a28d0e" + }, + "version": "1.2.1" + }, + "com.google.code.findbugs:jsr305": { + "shasums": { + "jar": "766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7" + }, + "version": "3.0.2" + }, + "com.google.code.gson:gson": { + "shasums": { + "jar": "4241c14a7727c34feea6507ec801318a3d4a90f070e4525681079fb94ee4c593" + }, + "version": "2.10.1" + }, + "com.google.errorprone:error_prone_annotation": { + "shasums": { + "jar": "554c42449c9920ea1f6baec1d1b8aaac404a88be653f7cb441ee059316f8a1d1" + }, + "version": "2.22.0" + }, + "com.google.errorprone:error_prone_annotations": { + "shasums": { + "jar": "ec6f39f068b6ff9ac323c68e28b9299f8c0a80ca512dccb1d4a70f40ac3ec054" + }, + "version": "2.23.0" + }, + "com.google.errorprone:error_prone_check_api": { + "shasums": { + "jar": "1717bbf65757b8e1a83f3b0aa78c5ac25a6493008bc730091d404cf798fc0639" + }, + "version": "2.22.0" + }, + "com.google.errorprone:error_prone_core": { + "shasums": { + "jar": "32a3df226a9a47f48dd895a9a89678d50ac404282c33400781c38757e8143f2c" + }, + "version": "2.22.0" + }, + "com.google.errorprone:error_prone_type_annotations": { + "shasums": { + "jar": "6618b1d28df562622b77187b5c6dfc9c4c97851af73bd64dc0300efe9a439b20" + }, + "version": "2.22.0" + }, + "com.google.guava:failureaccess": { + "shasums": { + "jar": "a171ee4c734dd2da837e4b16be9df4661afab72a41adaf31eb84dfdaf936ca26" + }, + "version": "1.0.1" + }, + "com.google.guava:guava": { + "shasums": { + "jar": "6d4e2b5a118aab62e6e5e29d185a0224eed82c85c40ac3d33cf04a270c3b3744" + }, + "version": "32.1.3-jre" + }, + "com.google.guava:guava-testlib": { + "shasums": { + "jar": "aadc71b10d5c3ac474dd16be84cfb18d257e584d1e0a59f8cab64ef4376226ce" + }, + "version": "31.1-jre" + }, + "com.google.guava:listenablefuture": { + "shasums": { + "jar": "b372a037d4230aa57fbeffdef30fd6123f9c0c2db85d0aced00c91b974f33f99" + }, + "version": "9999.0-empty-to-avoid-conflict-with-guava" + }, + "com.google.http-client:google-http-client": { + "shasums": { + "jar": "e395dd1765e3e6bceb0c610706bcf4128de84bd6e65cf1d4adbf998b4114161c" + }, + "version": "1.42.3" + }, + "com.google.http-client:google-http-client-gson": { + "shasums": { + "jar": "8196efaa89c5f73b00b2b48edad02fcd78524259407c37ab1860737988545cee" + }, + "version": "1.42.3" + }, + "com.google.inject:guice": { + "shasums": { + "jar": "4130e50bfac48099c860f0d903b91860c81a249c90f38245f8fed58fc817bc26" + }, + "version": "5.1.0" + }, + "com.google.j2objc:j2objc-annotations": { + "shasums": { + "jar": "f02a95fa1a5e95edb3ed859fd0fb7df709d121a35290eff8b74dce2ab7f4d6ed" + }, + "version": "2.8" + }, + "com.google.jimfs:jimfs": { + "shasums": { + "jar": "82494408bb513f5512652e7b7f63d6f31f01eff57ce35c878644ffc2d25aee4f" + }, + "version": "1.3.0" + }, + "com.google.protobuf:protobuf-java": { + "shasums": { + "jar": "48a8e58a1a8f82eff141a7a388d38dfe77d7a48d5e57c9066ee37f19147e20df" + }, + "version": "3.25.1" + }, + "com.google.protobuf:protobuf-java-util": { + "shasums": { + "jar": "faf398ad0fe8c5a7d867f76d322e2e71bb31898fe86ec3223f787a6ed6fb4622" + }, + "version": "3.25.1" + }, + "com.google.truth:truth": { + "shasums": { + "jar": "7f6d50d6f43a102942ef2c5a05f37a84f77788bb448cf33cceebf86d34e575c0" + }, + "version": "1.1.5" + }, + "com.googlecode.json-simple:json-simple": { + "shasums": { + "jar": "4e69696892b88b41c55d49ab2fdcc21eead92bf54acc588c0050596c3b75199c" + }, + "version": "1.1.1" + }, + "com.jayway.jsonpath:json-path": { + "shasums": { + "jar": "9601707e95cd79fb98570a01ea8cfb857b5cde948744d6e0edf733c11002c95b" + }, + "version": "2.8.0" + }, + "com.kohlschutter.junixsocket:junixsocket-common": { + "shasums": { + "jar": "93d120e2d49ddf5bfdee8258762fc874b26c657f027f8d6ccc1a055156bfcde1" + }, + "version": "2.6.1" + }, + "com.kohlschutter.junixsocket:junixsocket-native-common": { + "shasums": { + "jar": "61fbbd6cfd2b6df65c0e7b19b16ff4f755d6cb1d333b566f4286407f12f18670" + }, + "version": "2.6.1" + }, + "com.sun.activation:jakarta.activation": { + "shasums": { + "jar": "d84d4ba8b55cdb7fdcbb885e6939386367433f56f5ab8cfdc302a7c3587fa92b" + }, + "version": "1.2.1" + }, + "commons-codec:commons-codec": { + "shasums": { + "jar": "b3e9f6d63a790109bf0d056611fbed1cf69055826defeb9894a71369d246ed63" + }, + "version": "1.15" + }, + "commons-io:commons-io": { + "shasums": { + "jar": "f877d304660ac2a142f3865badfc971dec7ed73c747c7f8d5d2f5139ca736513" + }, + "version": "2.6" + }, + "commons-logging:commons-logging": { + "shasums": { + "jar": "daddea1ea0be0f56978ab3006b8ac92834afeefbd9b7e4e6316fca57df0fa636" + }, + "version": "1.2" + }, + "io.github.eisop:dataflow-errorprone": { + "shasums": { + "jar": "89b4f5d2bd5059f067c5982a0e5988b87dfc8a8234795d68c6f3178846de3319" + }, + "version": "3.34.0-eisop1" + }, + "io.github.java-diff-utils:java-diff-utils": { + "shasums": { + "jar": "9990a2039778f6b4cc94790141c2868864eacee0620c6c459451121a901cd5b5" + }, + "version": "4.12" + }, + "io.grpc:grpc-api": { + "shasums": { + "jar": "2e896944cf513e0e5cfd32bcd72c89601a27c6ca56916f84b20f3a13bacf1b1f" + }, + "version": "1.62.2" + }, + "io.grpc:grpc-auth": { + "shasums": { + "jar": "6a16c43d956c79190486d3d0b951836a6706b3282b5d275a9bc4d33eb79d5618" + }, + "version": "1.62.2" + }, + "io.grpc:grpc-context": { + "shasums": { + "jar": "9959747df6a753119e1c1a3dff01aa766d2455f5e4860acaa305359e1d533a05" + }, + "version": "1.62.2" + }, + "io.grpc:grpc-core": { + "shasums": { + "jar": "18439902c473a2c1511e517d13b8ae796378850a8eda43787c6ba778fa90fcc5" + }, + "version": "1.62.2" + }, + "io.grpc:grpc-inprocess": { + "shasums": { + "jar": "f3c28a9d7f13fa995e4dd89e4f6aa08fa3b383665314fdfccb9f87f346625df7" + }, + "version": "1.62.2" + }, + "io.grpc:grpc-netty": { + "shasums": { + "jar": "6060217fe26a9f8b2d899d02d95c9b52513be774233326ee43a6b8433edb03c8" + }, + "version": "1.62.2" + }, + "io.grpc:grpc-netty-shaded": { + "shasums": { + "jar": "b3f1823ef30ca02ac721020f4b6492248efdbd0548c78e893d5d245cbca2cc60" + }, + "version": "1.62.2" + }, + "io.grpc:grpc-protobuf": { + "shasums": { + "jar": "66a0b196318bdfd817d965d2d82b9c81dfced8eb08c0f7510fcb728d2994237a" + }, + "version": "1.62.2" + }, + "io.grpc:grpc-protobuf-lite": { + "shasums": { + "jar": "79997989a8c2b5bf4dd18182a2df2e2f668703d68ba7c317e7a07809d33f91f4" + }, + "version": "1.62.2" + }, + "io.grpc:grpc-services": { + "shasums": { + "jar": "72f6eba0670184b634e7dcde0b97cde378a7cd74cdf63300f453d15c23bbbb6a" + }, + "version": "1.62.2" + }, + "io.grpc:grpc-stub": { + "shasums": { + "jar": "fb4ca679a4214143406c65ac4167b2b5e2ee2cab1fc101566bb1c4695d105e36" + }, + "version": "1.62.2" + }, + "io.grpc:grpc-testing": { + "shasums": { + "jar": "a952fed1a1b43569ececd832ed820bd149a6f214905a9c7d4fc8853dfd553df4" + }, + "version": "1.62.2" + }, + "io.grpc:grpc-util": { + "shasums": { + "jar": "3c7103e6f3738571e3aeda420fe2a6ac68e354534d8b66f41897b6755b48b735" + }, + "version": "1.62.2" + }, + "io.netty:netty-buffer": { + "shasums": { + "jar": "462874b44ee782fbefec64078cda6eb8e7bf9f0e0af71a928ef4c1f2d564f7ee" + }, + "version": "4.1.100.Final" + }, + "io.netty:netty-codec": { + "shasums": { + "jar": "180a01ed67af399602e24ff1c32864e7f57f57c4a0fa5e9ab3fe9b0e5e9cf051" + }, + "version": "4.1.100.Final" + }, + "io.netty:netty-codec-dns": { + "shasums": { + "jar": "857d0213bd4e504ad897a7c0f967ef3f728f120feea3e824729dad525b44bbce" + }, + "version": "4.1.96.Final" + }, + "io.netty:netty-codec-http": { + "shasums": { + "jar": "326811d249cb0e5555e78e026e877834e792261c38f0666d80464426695d9590" + }, + "version": "4.1.100.Final" + }, + "io.netty:netty-codec-http2": { + "shasums": { + "jar": "23b4a74350f4cf8d41b93fb93d52b5050667d8d53fffc385672c86eab83b8749" + }, + "version": "4.1.100.Final" + }, + "io.netty:netty-codec-socks": { + "shasums": { + "jar": "608a453b90f8384ba4efcdc6db7f899a1f10b9ea1890954696e6cfac45ff1ba9" + }, + "version": "4.1.100.Final" + }, + "io.netty:netty-common": { + "shasums": { + "jar": "d2908301f1ac6f2910900742473c15d701765d3d4467acdb1eebb9df3aa82885" + }, + "version": "4.1.100.Final" + }, + "io.netty:netty-handler": { + "shasums": { + "jar": "0e10e584c2e7fdf7f4804e14760ed987003f1b62ab982f62eaf13a9892793d3a" + }, + "version": "4.1.100.Final" + }, + "io.netty:netty-handler-proxy": { + "shasums": { + "jar": "686dbc2e61407f216d6cb267dd7954896f851dd34b58be3e757c5a89f20a5e67" + }, + "version": "4.1.100.Final" + }, + "io.netty:netty-resolver": { + "shasums": { + "jar": "c42c481c776e9d367a45cc3a67a06f65897d280334eb30b2362b8c55b7523f4f" + }, + "version": "4.1.100.Final" + }, + "io.netty:netty-resolver-dns": { + "shasums": { + "jar": "09a4f0cc4fc7af083515cfb84d6e70af4223dfe129858274cf506cc626f5175e" + }, + "version": "4.1.96.Final" + }, + "io.netty:netty-transport": { + "shasums": { + "jar": "b1deeceedab3734cdb959c55f4be5ab4a667a8aed59121ff93763f49470f5470" + }, + "version": "4.1.100.Final" + }, + "io.netty:netty-transport-classes-epoll": { + "shasums": { + "jar": "ee65fa17fe65f18fd22269f92bddad85bfb3a263cf65eba01e116a2f30b86ff5" + }, + "version": "4.1.97.Final" + }, + "io.netty:netty-transport-classes-kqueue": { + "shasums": { + "jar": "964ef63eb24a5c979f0af473da13f9574497e11bd41543a66d10609d34013b9f" + }, + "version": "4.1.97.Final" + }, + "io.netty:netty-transport-native-epoll": { + "shasums": { + "jar": "418a0d0d66d2d52a63a0e2cd5377f8c3186db47c09e3b8af39a43fec39c077fe", + "linux-x86_64": "1e83fc9f82e5415cdbb688c6a5c6bbbd7d198e9fdd6fdf64b3dc5d54dd1acfd0" + }, + "version": "4.1.97.Final" + }, + "io.netty:netty-transport-native-kqueue": { + "shasums": { + "jar": "85916dd7569148bb3d4bc831d45846807b39d2b6f593dc8794a42ca71a4086c9", + "osx-x86_64": "6870051aca7fa4dc5d0f2938036215a269504c50d2e36c4af38fd00d22ad7d95" + }, + "version": "4.1.97.Final" + }, + "io.netty:netty-transport-native-unix-common": { + "shasums": { + "jar": "5d888230a04c4a3e647c64e933cefb64fd49056f969bfb734c8a3fcedf0bea8a" + }, + "version": "4.1.100.Final" + }, + "io.opencensus:opencensus-api": { + "shasums": { + "jar": "f1474d47f4b6b001558ad27b952e35eda5cc7146788877fc52938c6eba24b382" + }, + "version": "0.31.1" + }, + "io.opencensus:opencensus-contrib-http-util": { + "shasums": { + "jar": "3ea995b55a4068be22989b70cc29a4d788c2d328d1d50613a7a9afd13fdd2d0a" + }, + "version": "0.31.1" + }, + "io.perfmark:perfmark-api": { + "shasums": { + "jar": "b7d23e93a34537ce332708269a0d1404788a5b5e1949e82f5535fce51b3ea95b" + }, + "version": "0.26.0" + }, + "io.projectreactor:reactor-core": { + "shasums": { + "jar": "86017581188627ae6de5d3822882f3594f87f9289ec4479391790ccfd5631508" + }, + "version": "3.5.3" + }, + "io.prometheus:simpleclient": { + "shasums": { + "jar": "a43d6c00e3964a7063c1360ddcddc598df4f8e659a8313b27f90e4c555badb1d" + }, + "version": "0.15.0" + }, + "io.prometheus:simpleclient_common": { + "shasums": { + "jar": "8d2fa21b5c7959010818245788bd43131633dea989d3facb28cec45b2da37918" + }, + "version": "0.15.0" + }, + "io.prometheus:simpleclient_hotspot": { + "shasums": { + "jar": "3c99768b090065bc0b25219061f94970aa569a2e363488d9120c79769d78c1a6" + }, + "version": "0.15.0" + }, + "io.prometheus:simpleclient_httpserver": { + "shasums": { + "jar": "a1a16e1f804e3382ed8b400220ecb2913c96412d937e618f54a7088e6eb432b6" + }, + "version": "0.15.0" + }, + "io.prometheus:simpleclient_tracer_common": { + "shasums": { + "jar": "1baef082e619c06262e23de1b46ad35eb4df36ceb19be06ac7ef32a9833e12a4" + }, + "version": "0.15.0" + }, + "io.prometheus:simpleclient_tracer_otel": { + "shasums": { + "jar": "0595251da49aa7997777b365ffdf97f5e2e88cd7f0dacf49add91b4fc8222b50" + }, + "version": "0.15.0" + }, + "io.prometheus:simpleclient_tracer_otel_agent": { + "shasums": { + "jar": "0cbb4c29d17e9fe71bb2cec013c2999ae8a9050f237ad33211761b40d2586e0b" + }, + "version": "0.15.0" + }, + "io.reactivex.rxjava3:rxjava": { + "shasums": { + "jar": "34682bd3ec6f043c5defb589a2d18113ba3e2d2372dd401744f8e4815c1db638" + }, + "version": "3.1.6" + }, + "jakarta.activation:jakarta.activation-api": { + "shasums": { + "jar": "8b0a0f52fa8b05c5431921a063ed866efaa41dadf2e3a7ee3e1961f2b0d9645b" + }, + "version": "1.2.1" + }, + "jakarta.annotation:jakarta.annotation-api": { + "shasums": { + "jar": "85fb03fc054cdf4efca8efd9b6712bbb418e1ab98241c4539c8585bbc23e1b8a" + }, + "version": "1.3.5" + }, + "jakarta.ws.rs:jakarta.ws.rs-api": { + "shasums": { + "jar": "4cea299c846c8a6e6470cbfc2f7c391bc29b9caa2f9264ac1064ba91691f4adf" + }, + "version": "2.1.6" + }, + "jakarta.xml.bind:jakarta.xml.bind-api": { + "shasums": { + "jar": "69156304079bdeed9fc0ae3b39389f19b3cc4ba4443bc80508995394ead742ea" + }, + "version": "2.3.2" + }, + "javax.annotation:javax.annotation-api": { + "shasums": { + "jar": "e04ba5195bcd555dc95650f7cc614d151e4bcd52d29a10b8aa2197f3ab89ab9b" + }, + "version": "1.3.2" + }, + "javax.cache:cache-api": { + "shasums": { + "jar": "9f34e007edfa82a7b2a2e1b969477dcf5099ce7f4f926fb54ce7e27c4a0cd54b" + }, + "version": "1.1.1" + }, + "javax.inject:javax.inject": { + "shasums": { + "jar": "91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff" + }, + "version": "1" + }, + "joda-time:joda-time": { + "shasums": { + "jar": "b4670b95f75957c974284c5f3ada966040be2578f643c5c6083d262162061fa2" + }, + "version": "2.8.1" + }, + "junit:junit": { + "shasums": { + "jar": "8e495b634469d64fb8acfa3495a065cbacc8a0fff55ce1e31007be4c16dc57d3" + }, + "version": "4.13.2" + }, + "me.dinowernli:java-grpc-prometheus": { + "shasums": { + "jar": "badf9c84d9ea4b598bfa3fc690c85a8f6d863265829b9cb79f33884d48729ed8" + }, + "version": "0.6.0" + }, + "net.bytebuddy:byte-buddy": { + "shasums": { + "jar": "62ae28187ed2b062813da6a9d567bfee733c341582699b62dd980230729a0313" + }, + "version": "1.14.11" + }, + "net.bytebuddy:byte-buddy-agent": { + "shasums": { + "jar": "2f537a621a64fa7013d68c695a76a34ee8d79dad74e635caca16dd56257aeb80" + }, + "version": "1.14.11" + }, + "net.java.dev.jna:jna": { + "shasums": { + "jar": "66d4f819a062a51a1d5627bffc23fac55d1677f0e0a1feba144aabdd670a64bb" + }, + "version": "5.13.0" + }, + "net.java.dev.jna:jna-platform": { + "shasums": { + "jar": "474d7b88f6e97009b6ec1d98c3024dd95c23187c65dabfbc35331bcac3d173dd" + }, + "version": "5.13.0" + }, + "net.javacrumbs.future-converter:future-converter-common": { + "shasums": { + "jar": "567aeb2907088298fe5e67fd0fb1843571c24b46ef5b369f495c3d52c654b67b" + }, + "version": "1.2.0" + }, + "net.javacrumbs.future-converter:future-converter-guava-common": { + "shasums": { + "jar": "82bfab706005ea51c3e76958a62564367cf9cae207c0b1d55b9734876b9780c1" + }, + "version": "1.2.0" + }, + "net.javacrumbs.future-converter:future-converter-java8-common": { + "shasums": { + "jar": "bed25293fabbf59e048f67f88e55140ebc1cfa4fa899e397545d0193e866a65c" + }, + "version": "1.2.0" + }, + "net.javacrumbs.future-converter:future-converter-java8-guava": { + "shasums": { + "jar": "3b47ae8e2b2bfad810586c37537f002273c05237bd3adecafe9f9f57a2b18fde" + }, + "version": "1.2.0" + }, + "net.jcip:jcip-annotations": { + "shasums": { + "jar": "be5805392060c71474bf6c9a67a099471274d30b83eef84bfc4e0889a4f1dcc0" + }, + "version": "1.0" + }, + "net.minidev:accessors-smart": { + "shasums": { + "jar": "accdd5c7ac4c49b155890aaea1ffca2a9ccd5826b562dd95a99fc1887003e031" + }, + "version": "2.4.9" + }, + "net.minidev:json-smart": { + "shasums": { + "jar": "70cab5e9488630dc631b1fc6e7fa550d95cddd19ba14db39ceca7cabfbd4e5ae" + }, + "version": "2.4.10" + }, + "net.sf.jopt-simple:jopt-simple": { + "shasums": { + "jar": "df26cc58f235f477db07f753ba5a3ab243ebe5789d9f89ecf68dd62ea9a66c28" + }, + "version": "5.0.4" + }, + "org.apache.commons:commons-compress": { + "shasums": { + "jar": "c267f17160e9ef662b4d78b7f29dca7c82b15c5cff2cb6a9865ef4ab3dd5b787" + }, + "version": "1.23.0" + }, + "org.apache.commons:commons-lang3": { + "shasums": { + "jar": "82f528cf718c7a3c2f30fc5bc784e3c6a0a10b17605dadb9e16c82ede11e6064" + }, + "version": "3.13.0" + }, + "org.apache.commons:commons-math3": { + "shasums": { + "jar": "1e56d7b058d28b65abd256b8458e3885b674c1d588fa43cd7d1cbb9c7ef2b308" + }, + "version": "3.6.1" + }, + "org.apache.commons:commons-pool2": { + "shasums": { + "jar": "6d3bd18df8410f3e31b031aca582cc109342358a62a2759ebd0c4cdf30d06f8b" + }, + "version": "2.12.0" + }, + "org.apache.httpcomponents:httpclient": { + "shasums": { + "jar": "6fe9026a566c6a5001608cf3fc32196641f6c1e5e1986d1037ccdbd5f31ef743" + }, + "version": "4.5.13" + }, + "org.apache.httpcomponents:httpcore": { + "shasums": { + "jar": "3cbaed088c499a10f96dde58f39dc0e7985171abd88138ca1655a872011bb142" + }, + "version": "4.4.15" + }, + "org.apache.tomcat:annotations-api": { + "shasums": { + "jar": "253829d3c12b7381d1044fc22c6436cff025fe0d459e4a329413e560a7d0dd13" + }, + "version": "6.0.53" + }, + "org.bouncycastle:bcpkix-jdk18on": { + "shasums": { + "jar": "9e2c1db5a6ed29fbc36b438d39ca9feb901bb69bad0ce8d7bc735264bea79bd3" + }, + "version": "1.75" + }, + "org.bouncycastle:bcprov-jdk15on": { + "shasums": { + "jar": "8f3c20e3e2d565d26f33e8d4857a37d0d7f8ac39b62a7026496fcab1bdac30d4" + }, + "version": "1.70" + }, + "org.bouncycastle:bcprov-jdk18on": { + "shasums": { + "jar": "7f24018e9212dbda61c69212f8d7b1524c28efb978f10df590df3b4ccac47bd5" + }, + "version": "1.75" + }, + "org.bouncycastle:bcutil-jdk18on": { + "shasums": { + "jar": "027f36578c1ffdf08878c1cc2aa1e191f4b9da119c1e8f113299c53f298fa664" + }, + "version": "1.75" + }, + "org.checkerframework:checker-qual": { + "shasums": { + "jar": "9bd02cbe679a58afa0fba44c9621fe70130653e8c4564eb8d65e14bbfe26b7f8" + }, + "version": "3.38.0" + }, + "org.codehaus.mojo:animal-sniffer-annotations": { + "shasums": { + "jar": "9ffe526bf43a6348e9d8b33b9cd6f580a7f5eed0cf055913007eda263de974d0" + }, + "version": "1.23" + }, + "org.glassfish.hk2.external:aopalliance-repackaged": { + "shasums": { + "jar": "bad77f9278d753406360af9e4747bd9b3161554ea9cd3d62411a0ae1f2c141fd" + }, + "version": "2.6.1" + }, + "org.glassfish.hk2.external:jakarta.inject": { + "shasums": { + "jar": "5e88c123b3e41bca788b2683118867d9b6dec714247ea91c588aed46a36ee24f" + }, + "version": "2.6.1" + }, + "org.glassfish.hk2:hk2-api": { + "shasums": { + "jar": "c2cb80a01e58440ae57d5ee59af4d4d94e5180e04aff112b0cb611c07d61e773" + }, + "version": "2.6.1" + }, + "org.glassfish.hk2:hk2-locator": { + "shasums": { + "jar": "febc668deb9f2000c76bd4918d8086c0a4c74d07bd0c60486b72c6bd38b62874" + }, + "version": "2.6.1" + }, + "org.glassfish.hk2:hk2-utils": { + "shasums": { + "jar": "30727f79086452fdefdab08451d982c2082aa239d9f75cdeb1ba271e3c887036" + }, + "version": "2.6.1" + }, + "org.glassfish.hk2:osgi-resource-locator": { + "shasums": { + "jar": "aab5d7849f7cfcda2cc7c541ba1bd365151d42276f151c825387245dfde3dd74" + }, + "version": "1.0.3" + }, + "org.glassfish.jersey.connectors:jersey-apache-connector": { + "shasums": { + "jar": "28e87f2edc5284e293072941cea5e8ff462bb60f41c67b4ad7b906de2a7a8bd8" + }, + "version": "2.30.1" + }, + "org.glassfish.jersey.core:jersey-client": { + "shasums": { + "jar": "fe0aa736ce216e9efb6e17392142b87e704cf09e75a0cb6b3fd2d146937225c1" + }, + "version": "2.30.1" + }, + "org.glassfish.jersey.core:jersey-common": { + "shasums": { + "jar": "273c3ea4e3ff9b960eb8dbb7c74e0127436678e486ccd94a351729f22a249830" + }, + "version": "2.30.1" + }, + "org.glassfish.jersey.inject:jersey-hk2": { + "shasums": { + "jar": "cd5f4c10cf4915d1c217c295fc8b4eadceda7a28f9488b1d01de6b8792b33496" + }, + "version": "2.30.1" + }, + "org.hamcrest:hamcrest-core": { + "shasums": { + "jar": "66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9" + }, + "version": "1.3" + }, + "org.javassist:javassist": { + "shasums": { + "jar": "57d0a9e9286f82f4eaa851125186997f811befce0e2060ff0a15a77f5a9dd9a7" + }, + "version": "3.28.0-GA" + }, + "org.jboss.marshalling:jboss-marshalling": { + "shasums": { + "jar": "93d6257e1ac0f93ba6ff85827c9ef65b5efabf7bd2241fb3b4caf6c426f4f149" + }, + "version": "2.0.11.Final" + }, + "org.jboss.marshalling:jboss-marshalling-river": { + "shasums": { + "jar": "f3fa6545d15163468e1639fe3087de22234a9fd027a52be6e532bfe7bde6c554" + }, + "version": "2.0.11.Final" + }, + "org.jetbrains:annotations": { + "shasums": { + "jar": "245abad9a39eab1266ac9a8796980f462577e708ef3f6d43be2e008e4b72b9b4" + }, + "version": "16.0.2" + }, + "org.jodd:jodd-bean": { + "shasums": { + "jar": "d07d805fe0d59b5d2dbc85d0ebfcf30f52d7fd5a3ff89ff4fbea1e46b1319705" + }, + "version": "5.1.6" + }, + "org.jodd:jodd-core": { + "shasums": { + "jar": "4b504519263a98202480d3cf73562dff8245edc582350cc5f37d5965a0298122" + }, + "version": "5.1.6" + }, + "org.json:json": { + "shasums": { + "jar": "0f18192df289114e17aa1a0d0a7f8372cc9f5c7e4f7e39adcf8906fe714fa7d3" + }, + "version": "20231013" + }, + "org.luaj:luaj-jse": { + "shasums": { + "jar": "9b1f0a3e8f68427c6d74c2bf00ae0e6dbfce35994d3001fed4cef6ecda50be55" + }, + "version": "3.0.1" + }, + "org.mockito:mockito-core": { + "shasums": { + "jar": "0323f591b04d3a0d7ca9ebeebb9e9f34a07c0ec9169b7444ee3951b71d4cad56" + }, + "version": "5.10.0" + }, + "org.objenesis:objenesis": { + "shasums": { + "jar": "02dfd0b0439a5591e35b708ed2f5474eb0948f53abf74637e959b8e4ef69bfeb" + }, + "version": "3.3" + }, + "org.openjdk.jmh:jmh-core": { + "shasums": { + "jar": "dc0eaf2bbf0036a70b60798c785d6e03a9daf06b68b8edb0f1ba9eb3421baeb3" + }, + "version": "1.37" + }, + "org.openjdk.jmh:jmh-generator-annprocess": { + "shasums": { + "jar": "6a5604b5b804e0daca1145df1077609321687734a8b49387e49f10557c186c77" + }, + "version": "1.37" + }, + "org.ow2.asm:asm": { + "shasums": { + "jar": "b62e84b5980729751b0458c534cf1366f727542bb8d158621335682a460f0353" + }, + "version": "9.5" + }, + "org.ow2.asm:asm-analysis": { + "shasums": { + "jar": "878fbe521731c072d14d2d65b983b1beae6ad06fda0007b6a8bae81f73f433c4" + }, + "version": "9.2" + }, + "org.ow2.asm:asm-commons": { + "shasums": { + "jar": "be4ce53138a238bb522cd781cf91f3ba5ce2f6ca93ec62d46a162a127225e0a6" + }, + "version": "9.2" + }, + "org.ow2.asm:asm-tree": { + "shasums": { + "jar": "aabf9bd23091a4ebfc109c1f3ee7cf3e4b89f6ba2d3f51c5243f16b3cffae011" + }, + "version": "9.2" + }, + "org.ow2.asm:asm-util": { + "shasums": { + "jar": "ff5b3cd331ae8a9a804768280da98f50f424fef23dd3c788bb320e08c94ee598" + }, + "version": "9.2" + }, + "org.pcollections:pcollections": { + "shasums": { + "jar": "34f579ba075c8da2c8a0fedd0f04e21eac2fb6c660d90d0fabb573e8b4dc6918" + }, + "version": "3.1.4" + }, + "org.projectlombok:lombok": { + "shasums": { + "jar": "14151b47582d570b4de16a147ece3bdbd19ace4aee5bde3a5578c87db9ecb998" + }, + "version": "1.18.30" + }, + "org.reactivestreams:reactive-streams": { + "shasums": { + "jar": "f75ca597789b3dac58f61857b9ac2e1034a68fa672db35055a8fb4509e325f28" + }, + "version": "1.0.4" + }, + "org.redisson:redisson": { + "shasums": { + "jar": "fe59768d63419b0073c0cbd6029d0be864ad5c9d233dd1337945f9edfe3df3ca" + }, + "version": "3.23.4" + }, + "org.reflections:reflections": { + "shasums": { + "jar": "938a2d08fe54050d7610b944d8ddc3a09355710d9e6be0aac838dbc04e9a2825" + }, + "version": "0.10.2" + }, + "org.slf4j:jcl-over-slf4j": { + "shasums": { + "jar": "71e9ee37b9e4eb7802a2acc5f41728a4cf3915e7483d798db3b4ff2ec8847c50" + }, + "version": "1.7.30" + }, + "org.slf4j:slf4j-api": { + "shasums": { + "jar": "0818930dc8d7debb403204611691da58e49d42c50b6ffcfdce02dadb7c3c2b6c" + }, + "version": "2.0.9" + }, + "org.slf4j:slf4j-simple": { + "shasums": { + "jar": "71f9c6de6dbaec2d10caa303faf08c5e749be53b242896c64c96b7c6bb6d62dc" + }, + "version": "2.0.9" + }, + "org.threeten:threetenbp": { + "shasums": { + "jar": "e4b1eb3d90c38a54c7f3384fda957e0b5bf0b41b40672a44ae8b03cb6c87ce06" + }, + "version": "1.6.8" + }, + "org.xerial:sqlite-jdbc": { + "shasums": { + "jar": "605979c94e7fe00437f1e10dcfa657a23f125c8eb4d2f0ec17e3f84613894cc3" + }, + "version": "3.34.0" + }, + "org.yaml:snakeyaml": { + "shasums": { + "jar": "1467931448a0817696ae2805b7b8b20bfb082652bf9c4efaed528930dc49389b" + }, + "version": "2.2" + }, + "redis.clients:jedis": { + "shasums": { + "jar": "d171e10406c0362178ee15f5098d0be51390638f702bb55941571a2ff8c12a57" + }, + "version": "5.1.2" + }, + "software.amazon.ion:ion-java": { + "shasums": { + "jar": "0d127b205a1fce0abc2a3757a041748651bc66c15cf4c059bac5833b27d471a5" + }, + "version": "1.0.2" + } + }, + "dependencies": { + "com.amazonaws:aws-java-sdk-core": [ + "com.fasterxml.jackson.core:jackson-databind", + "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor", + "commons-codec:commons-codec", + "commons-logging:commons-logging", + "joda-time:joda-time", + "org.apache.httpcomponents:httpclient", + "software.amazon.ion:ion-java" + ], + "com.amazonaws:aws-java-sdk-kms": [ + "com.amazonaws:aws-java-sdk-core", + "com.amazonaws:jmespath-java" + ], + "com.amazonaws:aws-java-sdk-s3": [ + "com.amazonaws:aws-java-sdk-core", + "com.amazonaws:aws-java-sdk-kms", + "com.amazonaws:jmespath-java" + ], + "com.amazonaws:aws-java-sdk-secretsmanager": [ + "com.amazonaws:aws-java-sdk-core", + "com.amazonaws:jmespath-java" + ], + "com.amazonaws:jmespath-java": [ + "com.fasterxml.jackson.core:jackson-databind" + ], + "com.esotericsoftware:kryo": [ + "com.esotericsoftware:minlog", + "com.esotericsoftware:reflectasm", + "org.objenesis:objenesis" + ], + "com.fasterxml.jackson.core:jackson-databind": [ + "com.fasterxml.jackson.core:jackson-annotations", + "com.fasterxml.jackson.core:jackson-core" + ], + "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": [ + "com.fasterxml.jackson.core:jackson-core", + "com.fasterxml.jackson.core:jackson-databind" + ], + "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": [ + "com.fasterxml.jackson.core:jackson-core", + "com.fasterxml.jackson.core:jackson-databind", + "org.yaml:snakeyaml" + ], + "com.fasterxml.jackson.jaxrs:jackson-jaxrs-base": [ + "com.fasterxml.jackson.core:jackson-core", + "com.fasterxml.jackson.core:jackson-databind" + ], + "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": [ + "com.fasterxml.jackson.jaxrs:jackson-jaxrs-base", + "com.fasterxml.jackson.module:jackson-module-jaxb-annotations" + ], + "com.fasterxml.jackson.module:jackson-module-jaxb-annotations": [ + "com.fasterxml.jackson.core:jackson-annotations", + "com.fasterxml.jackson.core:jackson-core", + "com.fasterxml.jackson.core:jackson-databind", + "jakarta.activation:jakarta.activation-api", + "jakarta.xml.bind:jakarta.xml.bind-api" + ], + "com.github.ben-manes.caffeine:caffeine": [ + "com.google.errorprone:error_prone_annotations", + "org.checkerframework:checker-qual" + ], + "com.github.docker-java:docker-java": [ + "com.github.docker-java:docker-java-core", + "com.github.docker-java:docker-java-transport-jersey", + "com.github.docker-java:docker-java-transport-netty", + "org.slf4j:jcl-over-slf4j" + ], + "com.github.docker-java:docker-java-api": [ + "com.fasterxml.jackson.core:jackson-annotations", + "org.slf4j:slf4j-api" + ], + "com.github.docker-java:docker-java-core": [ + "com.fasterxml.jackson.core:jackson-databind", + "com.github.docker-java:docker-java-api", + "com.github.docker-java:docker-java-transport", + "com.google.guava:guava", + "commons-io:commons-io", + "org.apache.commons:commons-compress", + "org.apache.commons:commons-lang3", + "org.bouncycastle:bcpkix-jdk18on", + "org.slf4j:slf4j-api" + ], + "com.github.docker-java:docker-java-transport-jersey": [ + "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider", + "com.github.docker-java:docker-java-core", + "com.kohlschutter.junixsocket:junixsocket-common", + "com.kohlschutter.junixsocket:junixsocket-native-common", + "org.apache.httpcomponents:httpclient", + "org.apache.httpcomponents:httpcore", + "org.glassfish.jersey.connectors:jersey-apache-connector", + "org.glassfish.jersey.core:jersey-client", + "org.glassfish.jersey.inject:jersey-hk2" + ], + "com.github.docker-java:docker-java-transport-netty": [ + "com.github.docker-java:docker-java-core", + "io.netty:netty-codec-http", + "io.netty:netty-handler", + "io.netty:netty-handler-proxy", + "io.netty:netty-transport-native-epoll:jar:linux-x86_64", + "io.netty:netty-transport-native-kqueue:jar:osx-x86_64" + ], + "com.github.fppt:jedis-mock": [ + "org.luaj:luaj-jse", + "org.reflections:reflections", + "org.slf4j:slf4j-api", + "redis.clients:jedis" + ], + "com.github.jnr:jnr-ffi": [ + "com.github.jnr:jffi", + "com.github.jnr:jffi:jar:native", + "com.github.jnr:jnr-a64asm", + "com.github.jnr:jnr-x86asm", + "org.ow2.asm:asm", + "org.ow2.asm:asm-analysis", + "org.ow2.asm:asm-commons", + "org.ow2.asm:asm-tree", + "org.ow2.asm:asm-util" + ], + "com.github.jnr:jnr-posix": [ + "com.github.jnr:jnr-constants", + "com.github.jnr:jnr-ffi" + ], + "com.github.oshi:oshi-core": [ + "net.java.dev.jna:jna", + "net.java.dev.jna:jna-platform", + "org.slf4j:slf4j-api" + ], + "com.github.pcj:google-options": [ + "com.google.code.findbugs:jsr305", + "com.google.guava:guava" + ], + "com.github.serceman:jnr-fuse": [ + "com.github.jnr:jnr-constants", + "com.github.jnr:jnr-ffi", + "com.github.jnr:jnr-posix" + ], + "com.google.api.grpc:proto-google-common-protos": [ + "com.google.protobuf:protobuf-java" + ], + "com.google.auth:google-auth-library-oauth2-http": [ + "com.google.auth:google-auth-library-credentials", + "com.google.auto.value:auto-value-annotations", + "com.google.code.findbugs:jsr305", + "com.google.guava:guava", + "com.google.http-client:google-http-client", + "com.google.http-client:google-http-client-gson" + ], + "com.google.auto:auto-common": [ + "com.google.guava:guava" + ], + "com.google.errorprone:error_prone_annotation": [ + "com.google.guava:guava" + ], + "com.google.errorprone:error_prone_check_api": [ + "com.github.ben-manes.caffeine:caffeine", + "com.github.kevinstern:software-and-algorithms", + "com.google.auto.value:auto-value-annotations", + "com.google.code.findbugs:jsr305", + "com.google.errorprone:error_prone_annotation", + "com.google.errorprone:error_prone_annotations", + "com.google.inject:guice", + "io.github.eisop:dataflow-errorprone", + "io.github.java-diff-utils:java-diff-utils" + ], + "com.google.errorprone:error_prone_core": [ + "com.google.auto.service:auto-service-annotations", + "com.google.auto.value:auto-value-annotations", + "com.google.auto:auto-common", + "com.google.code.findbugs:jsr305", + "com.google.errorprone:error_prone_annotation", + "com.google.errorprone:error_prone_annotations", + "com.google.errorprone:error_prone_check_api", + "com.google.errorprone:error_prone_type_annotations", + "com.google.guava:guava", + "com.google.protobuf:protobuf-java", + "io.github.eisop:dataflow-errorprone", + "javax.inject:javax.inject", + "org.pcollections:pcollections" + ], + "com.google.guava:guava": [ + "com.google.code.findbugs:jsr305", + "com.google.errorprone:error_prone_annotations", + "com.google.guava:failureaccess", + "com.google.guava:listenablefuture", + "com.google.j2objc:j2objc-annotations", + "org.checkerframework:checker-qual" + ], + "com.google.guava:guava-testlib": [ + "com.google.code.findbugs:jsr305", + "com.google.errorprone:error_prone_annotations", + "com.google.guava:guava", + "com.google.j2objc:j2objc-annotations", + "junit:junit", + "org.checkerframework:checker-qual" + ], + "com.google.http-client:google-http-client": [ + "com.google.code.findbugs:jsr305", + "com.google.errorprone:error_prone_annotations", + "com.google.guava:guava", + "com.google.j2objc:j2objc-annotations", + "io.opencensus:opencensus-api", + "io.opencensus:opencensus-contrib-http-util", + "org.apache.httpcomponents:httpclient", + "org.apache.httpcomponents:httpcore" + ], + "com.google.http-client:google-http-client-gson": [ + "com.google.code.gson:gson", + "com.google.http-client:google-http-client" + ], + "com.google.inject:guice": [ + "aopalliance:aopalliance", + "com.google.guava:guava", + "javax.inject:javax.inject" + ], + "com.google.jimfs:jimfs": [ + "com.google.guava:guava" + ], + "com.google.protobuf:protobuf-java-util": [ + "com.google.code.findbugs:jsr305", + "com.google.code.gson:gson", + "com.google.errorprone:error_prone_annotations", + "com.google.guava:guava", + "com.google.j2objc:j2objc-annotations", + "com.google.protobuf:protobuf-java" + ], + "com.google.truth:truth": [ + "com.google.auto.value:auto-value-annotations", + "com.google.errorprone:error_prone_annotations", + "com.google.guava:guava", + "junit:junit", + "org.checkerframework:checker-qual", + "org.ow2.asm:asm" + ], + "com.googlecode.json-simple:json-simple": [ + "junit:junit" + ], + "com.jayway.jsonpath:json-path": [ + "net.minidev:json-smart", + "org.slf4j:slf4j-api" + ], + "io.grpc:grpc-api": [ + "com.google.code.findbugs:jsr305", + "com.google.errorprone:error_prone_annotations", + "com.google.guava:guava" + ], + "io.grpc:grpc-auth": [ + "com.google.auth:google-auth-library-credentials", + "com.google.guava:guava", + "io.grpc:grpc-api" + ], + "io.grpc:grpc-context": [ + "io.grpc:grpc-api" + ], + "io.grpc:grpc-core": [ + "com.google.android:annotations", + "com.google.code.gson:gson", + "com.google.errorprone:error_prone_annotations", + "com.google.guava:guava", + "io.grpc:grpc-api", + "io.grpc:grpc-context", + "io.perfmark:perfmark-api", + "org.codehaus.mojo:animal-sniffer-annotations" + ], + "io.grpc:grpc-inprocess": [ + "com.google.guava:guava", + "io.grpc:grpc-api", + "io.grpc:grpc-core" + ], + "io.grpc:grpc-netty": [ + "com.google.errorprone:error_prone_annotations", + "com.google.guava:guava", + "io.grpc:grpc-api", + "io.grpc:grpc-core", + "io.grpc:grpc-util", + "io.netty:netty-codec-http2", + "io.netty:netty-handler-proxy", + "io.netty:netty-transport-native-unix-common", + "io.perfmark:perfmark-api" + ], + "io.grpc:grpc-netty-shaded": [ + "com.google.errorprone:error_prone_annotations", + "com.google.guava:guava", + "io.grpc:grpc-api", + "io.grpc:grpc-core", + "io.grpc:grpc-util", + "io.perfmark:perfmark-api" + ], + "io.grpc:grpc-protobuf": [ + "com.google.api.grpc:proto-google-common-protos", + "com.google.code.findbugs:jsr305", + "com.google.guava:guava", + "com.google.protobuf:protobuf-java", + "io.grpc:grpc-api", + "io.grpc:grpc-protobuf-lite" + ], + "io.grpc:grpc-protobuf-lite": [ + "com.google.code.findbugs:jsr305", + "com.google.guava:guava", + "io.grpc:grpc-api" + ], + "io.grpc:grpc-services": [ + "com.google.code.gson:gson", + "com.google.errorprone:error_prone_annotations", + "com.google.guava:guava", + "com.google.j2objc:j2objc-annotations", + "com.google.protobuf:protobuf-java-util", + "io.grpc:grpc-core", + "io.grpc:grpc-protobuf", + "io.grpc:grpc-stub", + "io.grpc:grpc-util" + ], + "io.grpc:grpc-stub": [ + "com.google.errorprone:error_prone_annotations", + "com.google.guava:guava", + "io.grpc:grpc-api" + ], + "io.grpc:grpc-testing": [ + "io.grpc:grpc-api", + "io.grpc:grpc-core", + "io.grpc:grpc-inprocess", + "io.grpc:grpc-stub", + "io.grpc:grpc-util", + "junit:junit" + ], + "io.grpc:grpc-util": [ + "com.google.guava:guava", + "io.grpc:grpc-api", + "io.grpc:grpc-core", + "org.codehaus.mojo:animal-sniffer-annotations" + ], + "io.netty:netty-buffer": [ + "io.netty:netty-common" + ], + "io.netty:netty-codec": [ + "io.netty:netty-buffer", + "io.netty:netty-common", + "io.netty:netty-transport" + ], + "io.netty:netty-codec-dns": [ + "io.netty:netty-buffer", + "io.netty:netty-codec", + "io.netty:netty-common", + "io.netty:netty-transport" + ], + "io.netty:netty-codec-http": [ + "io.netty:netty-buffer", + "io.netty:netty-codec", + "io.netty:netty-common", + "io.netty:netty-handler", + "io.netty:netty-transport" + ], + "io.netty:netty-codec-http2": [ + "io.netty:netty-buffer", + "io.netty:netty-codec", + "io.netty:netty-codec-http", + "io.netty:netty-common", + "io.netty:netty-handler", + "io.netty:netty-transport" + ], + "io.netty:netty-codec-socks": [ + "io.netty:netty-buffer", + "io.netty:netty-codec", + "io.netty:netty-common", + "io.netty:netty-transport" + ], + "io.netty:netty-handler": [ + "io.netty:netty-buffer", + "io.netty:netty-codec", + "io.netty:netty-common", + "io.netty:netty-resolver", + "io.netty:netty-transport", + "io.netty:netty-transport-native-unix-common" + ], + "io.netty:netty-handler-proxy": [ + "io.netty:netty-buffer", + "io.netty:netty-codec", + "io.netty:netty-codec-http", + "io.netty:netty-codec-socks", + "io.netty:netty-common", + "io.netty:netty-transport" + ], + "io.netty:netty-resolver": [ + "io.netty:netty-common" + ], + "io.netty:netty-resolver-dns": [ + "io.netty:netty-buffer", + "io.netty:netty-codec", + "io.netty:netty-codec-dns", + "io.netty:netty-common", + "io.netty:netty-handler", + "io.netty:netty-resolver", + "io.netty:netty-transport" + ], + "io.netty:netty-transport": [ + "io.netty:netty-buffer", + "io.netty:netty-common", + "io.netty:netty-resolver" + ], + "io.netty:netty-transport-classes-epoll": [ + "io.netty:netty-buffer", + "io.netty:netty-common", + "io.netty:netty-transport", + "io.netty:netty-transport-native-unix-common" + ], + "io.netty:netty-transport-classes-kqueue": [ + "io.netty:netty-buffer", + "io.netty:netty-common", + "io.netty:netty-transport", + "io.netty:netty-transport-native-unix-common" + ], + "io.netty:netty-transport-native-epoll": [ + "io.netty:netty-buffer", + "io.netty:netty-common", + "io.netty:netty-transport", + "io.netty:netty-transport-classes-epoll", + "io.netty:netty-transport-native-unix-common" + ], + "io.netty:netty-transport-native-epoll:jar:linux-x86_64": [ + "io.netty:netty-buffer", + "io.netty:netty-common", + "io.netty:netty-transport", + "io.netty:netty-transport-classes-epoll", + "io.netty:netty-transport-native-unix-common" + ], + "io.netty:netty-transport-native-kqueue": [ + "io.netty:netty-buffer", + "io.netty:netty-common", + "io.netty:netty-transport", + "io.netty:netty-transport-classes-kqueue", + "io.netty:netty-transport-native-unix-common" + ], + "io.netty:netty-transport-native-kqueue:jar:osx-x86_64": [ + "io.netty:netty-buffer", + "io.netty:netty-common", + "io.netty:netty-transport", + "io.netty:netty-transport-classes-kqueue", + "io.netty:netty-transport-native-unix-common" + ], + "io.netty:netty-transport-native-unix-common": [ + "io.netty:netty-buffer", + "io.netty:netty-common", + "io.netty:netty-transport" + ], + "io.opencensus:opencensus-api": [ + "io.grpc:grpc-context" + ], + "io.opencensus:opencensus-contrib-http-util": [ + "com.google.guava:guava", + "io.opencensus:opencensus-api" + ], + "io.projectreactor:reactor-core": [ + "org.reactivestreams:reactive-streams" + ], + "io.prometheus:simpleclient": [ + "io.prometheus:simpleclient_tracer_otel", + "io.prometheus:simpleclient_tracer_otel_agent" + ], + "io.prometheus:simpleclient_common": [ + "io.prometheus:simpleclient" + ], + "io.prometheus:simpleclient_hotspot": [ + "io.prometheus:simpleclient" + ], + "io.prometheus:simpleclient_httpserver": [ + "io.prometheus:simpleclient", + "io.prometheus:simpleclient_common" + ], + "io.prometheus:simpleclient_tracer_otel": [ + "io.prometheus:simpleclient_tracer_common" + ], + "io.prometheus:simpleclient_tracer_otel_agent": [ + "io.prometheus:simpleclient_tracer_common" + ], + "io.reactivex.rxjava3:rxjava": [ + "org.reactivestreams:reactive-streams" + ], + "jakarta.xml.bind:jakarta.xml.bind-api": [ + "jakarta.activation:jakarta.activation-api" + ], + "junit:junit": [ + "org.hamcrest:hamcrest-core" + ], + "me.dinowernli:java-grpc-prometheus": [ + "com.google.code.findbugs:jsr305", + "com.google.guava:failureaccess", + "com.google.guava:guava", + "com.google.j2objc:j2objc-annotations", + "io.prometheus:simpleclient" + ], + "net.java.dev.jna:jna-platform": [ + "net.java.dev.jna:jna" + ], + "net.javacrumbs.future-converter:future-converter-guava-common": [ + "com.google.guava:guava", + "net.javacrumbs.future-converter:future-converter-common" + ], + "net.javacrumbs.future-converter:future-converter-java8-common": [ + "net.javacrumbs.future-converter:future-converter-common" + ], + "net.javacrumbs.future-converter:future-converter-java8-guava": [ + "net.javacrumbs.future-converter:future-converter-common", + "net.javacrumbs.future-converter:future-converter-guava-common", + "net.javacrumbs.future-converter:future-converter-java8-common" + ], + "net.minidev:accessors-smart": [ + "org.ow2.asm:asm" + ], + "net.minidev:json-smart": [ + "net.minidev:accessors-smart" + ], + "org.apache.httpcomponents:httpclient": [ + "commons-codec:commons-codec", + "commons-logging:commons-logging", + "org.apache.httpcomponents:httpcore" + ], + "org.bouncycastle:bcpkix-jdk18on": [ + "org.bouncycastle:bcprov-jdk18on", + "org.bouncycastle:bcutil-jdk18on" + ], + "org.bouncycastle:bcutil-jdk18on": [ + "org.bouncycastle:bcprov-jdk18on" + ], + "org.glassfish.hk2:hk2-api": [ + "org.glassfish.hk2.external:aopalliance-repackaged", + "org.glassfish.hk2.external:jakarta.inject", + "org.glassfish.hk2:hk2-utils" + ], + "org.glassfish.hk2:hk2-locator": [ + "org.glassfish.hk2.external:aopalliance-repackaged", + "org.glassfish.hk2.external:jakarta.inject", + "org.glassfish.hk2:hk2-api", + "org.glassfish.hk2:hk2-utils" + ], + "org.glassfish.hk2:hk2-utils": [ + "org.glassfish.hk2.external:jakarta.inject" + ], + "org.glassfish.jersey.connectors:jersey-apache-connector": [ + "jakarta.ws.rs:jakarta.ws.rs-api", + "org.apache.httpcomponents:httpclient", + "org.glassfish.jersey.core:jersey-client", + "org.glassfish.jersey.core:jersey-common" + ], + "org.glassfish.jersey.core:jersey-client": [ + "jakarta.ws.rs:jakarta.ws.rs-api", + "org.glassfish.hk2.external:jakarta.inject", + "org.glassfish.jersey.core:jersey-common" + ], + "org.glassfish.jersey.core:jersey-common": [ + "com.sun.activation:jakarta.activation", + "jakarta.annotation:jakarta.annotation-api", + "jakarta.ws.rs:jakarta.ws.rs-api", + "org.glassfish.hk2.external:jakarta.inject", + "org.glassfish.hk2:osgi-resource-locator" + ], + "org.glassfish.jersey.inject:jersey-hk2": [ + "org.glassfish.hk2:hk2-locator", + "org.glassfish.jersey.core:jersey-common", + "org.javassist:javassist" + ], + "org.jboss.marshalling:jboss-marshalling-river": [ + "org.jboss.marshalling:jboss-marshalling" + ], + "org.jodd:jodd-bean": [ + "org.jodd:jodd-core" + ], + "org.mockito:mockito-core": [ + "net.bytebuddy:byte-buddy", + "net.bytebuddy:byte-buddy-agent", + "org.objenesis:objenesis" + ], + "org.openjdk.jmh:jmh-core": [ + "net.sf.jopt-simple:jopt-simple", + "org.apache.commons:commons-math3" + ], + "org.openjdk.jmh:jmh-generator-annprocess": [ + "org.openjdk.jmh:jmh-core" + ], + "org.ow2.asm:asm-analysis": [ + "org.ow2.asm:asm-tree" + ], + "org.ow2.asm:asm-commons": [ + "org.ow2.asm:asm", + "org.ow2.asm:asm-analysis", + "org.ow2.asm:asm-tree" + ], + "org.ow2.asm:asm-tree": [ + "org.ow2.asm:asm" + ], + "org.ow2.asm:asm-util": [ + "org.ow2.asm:asm", + "org.ow2.asm:asm-analysis", + "org.ow2.asm:asm-tree" + ], + "org.redisson:redisson": [ + "com.esotericsoftware:kryo", + "com.fasterxml.jackson.core:jackson-annotations", + "com.fasterxml.jackson.core:jackson-core", + "com.fasterxml.jackson.core:jackson-databind", + "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml", + "io.netty:netty-buffer", + "io.netty:netty-codec", + "io.netty:netty-common", + "io.netty:netty-handler", + "io.netty:netty-resolver", + "io.netty:netty-resolver-dns", + "io.netty:netty-transport", + "io.projectreactor:reactor-core", + "io.reactivex.rxjava3:rxjava", + "javax.cache:cache-api", + "net.bytebuddy:byte-buddy", + "org.jboss.marshalling:jboss-marshalling", + "org.jboss.marshalling:jboss-marshalling-river", + "org.jodd:jodd-bean", + "org.reactivestreams:reactive-streams", + "org.slf4j:slf4j-api" + ], + "org.reflections:reflections": [ + "com.google.code.findbugs:jsr305", + "org.javassist:javassist", + "org.slf4j:slf4j-api" + ], + "org.slf4j:jcl-over-slf4j": [ + "org.slf4j:slf4j-api" + ], + "org.slf4j:slf4j-simple": [ + "org.slf4j:slf4j-api" + ], + "redis.clients:jedis": [ + "com.google.code.gson:gson", + "org.apache.commons:commons-pool2", + "org.json:json", + "org.slf4j:slf4j-api" + ] + }, + "packages": { + "aopalliance:aopalliance": [ + "org.aopalliance.aop", + "org.aopalliance.intercept" + ], + "com.amazonaws:aws-java-sdk-core": [ + "com.amazonaws", + "com.amazonaws.adapters.types", + "com.amazonaws.annotation", + "com.amazonaws.arn", + "com.amazonaws.auth", + "com.amazonaws.auth.internal", + "com.amazonaws.auth.policy", + "com.amazonaws.auth.policy.conditions", + "com.amazonaws.auth.policy.internal", + "com.amazonaws.auth.presign", + "com.amazonaws.auth.profile", + "com.amazonaws.auth.profile.internal", + "com.amazonaws.auth.profile.internal.securitytoken", + "com.amazonaws.cache", + "com.amazonaws.client", + "com.amazonaws.client.builder", + "com.amazonaws.endpointdiscovery", + "com.amazonaws.event", + "com.amazonaws.event.request", + "com.amazonaws.handlers", + "com.amazonaws.http", + "com.amazonaws.http.apache", + "com.amazonaws.http.apache.client.impl", + "com.amazonaws.http.apache.request.impl", + "com.amazonaws.http.apache.utils", + "com.amazonaws.http.client", + "com.amazonaws.http.conn", + "com.amazonaws.http.conn.ssl", + "com.amazonaws.http.conn.ssl.privileged", + "com.amazonaws.http.exception", + "com.amazonaws.http.impl.client", + "com.amazonaws.http.protocol", + "com.amazonaws.http.request", + "com.amazonaws.http.response", + "com.amazonaws.http.settings", + "com.amazonaws.http.timers", + "com.amazonaws.http.timers.client", + "com.amazonaws.http.timers.request", + "com.amazonaws.internal", + "com.amazonaws.internal.auth", + "com.amazonaws.internal.config", + "com.amazonaws.internal.http", + "com.amazonaws.jmx", + "com.amazonaws.jmx.spi", + "com.amazonaws.log", + "com.amazonaws.metrics", + "com.amazonaws.metrics.internal", + "com.amazonaws.monitoring", + "com.amazonaws.monitoring.internal", + "com.amazonaws.partitions", + "com.amazonaws.partitions.model", + "com.amazonaws.profile.path", + "com.amazonaws.profile.path.config", + "com.amazonaws.profile.path.cred", + "com.amazonaws.protocol", + "com.amazonaws.protocol.json", + "com.amazonaws.protocol.json.internal", + "com.amazonaws.regions", + "com.amazonaws.retry", + "com.amazonaws.retry.internal", + "com.amazonaws.retry.v2", + "com.amazonaws.transform", + "com.amazonaws.util", + "com.amazonaws.util.endpoint", + "com.amazonaws.util.json", + "com.amazonaws.waiters" + ], + "com.amazonaws:aws-java-sdk-kms": [ + "com.amazonaws.auth.policy.actions", + "com.amazonaws.services.kms", + "com.amazonaws.services.kms.model", + "com.amazonaws.services.kms.model.transform" + ], + "com.amazonaws:aws-java-sdk-s3": [ + "com.amazonaws.auth", + "com.amazonaws.auth.policy.actions", + "com.amazonaws.auth.policy.conditions", + "com.amazonaws.auth.policy.resources", + "com.amazonaws.services.s3", + "com.amazonaws.services.s3.event", + "com.amazonaws.services.s3.internal", + "com.amazonaws.services.s3.internal.auth", + "com.amazonaws.services.s3.internal.crypto", + "com.amazonaws.services.s3.internal.crypto.keywrap", + "com.amazonaws.services.s3.internal.crypto.v1", + "com.amazonaws.services.s3.internal.crypto.v2", + "com.amazonaws.services.s3.internal.eventstreaming", + "com.amazonaws.services.s3.iterable", + "com.amazonaws.services.s3.metrics", + "com.amazonaws.services.s3.model", + "com.amazonaws.services.s3.model.analytics", + "com.amazonaws.services.s3.model.intelligenttiering", + "com.amazonaws.services.s3.model.inventory", + "com.amazonaws.services.s3.model.lifecycle", + "com.amazonaws.services.s3.model.metrics", + "com.amazonaws.services.s3.model.ownership", + "com.amazonaws.services.s3.model.replication", + "com.amazonaws.services.s3.model.transform", + "com.amazonaws.services.s3.request", + "com.amazonaws.services.s3.transfer", + "com.amazonaws.services.s3.transfer.exception", + "com.amazonaws.services.s3.transfer.internal", + "com.amazonaws.services.s3.transfer.internal.future", + "com.amazonaws.services.s3.transfer.model", + "com.amazonaws.services.s3.waiters" + ], + "com.amazonaws:aws-java-sdk-secretsmanager": [ + "com.amazonaws.services.secretsmanager", + "com.amazonaws.services.secretsmanager.model", + "com.amazonaws.services.secretsmanager.model.transform" + ], + "com.amazonaws:jmespath-java": [ + "com.amazonaws.jmespath" + ], + "com.esotericsoftware:kryo": [ + "com.esotericsoftware.kryo", + "com.esotericsoftware.kryo.io", + "com.esotericsoftware.kryo.serializers", + "com.esotericsoftware.kryo.unsafe", + "com.esotericsoftware.kryo.util" + ], + "com.esotericsoftware:minlog": [ + "com.esotericsoftware.minlog" + ], + "com.esotericsoftware:reflectasm": [ + "com.esotericsoftware.asm", + "com.esotericsoftware.reflectasm" + ], + "com.fasterxml.jackson.core:jackson-annotations": [ + "com.fasterxml.jackson.annotation" + ], + "com.fasterxml.jackson.core:jackson-core": [ + "com.fasterxml.jackson.core", + "com.fasterxml.jackson.core.async", + "com.fasterxml.jackson.core.base", + "com.fasterxml.jackson.core.exc", + "com.fasterxml.jackson.core.filter", + "com.fasterxml.jackson.core.format", + "com.fasterxml.jackson.core.io", + "com.fasterxml.jackson.core.io.doubleparser", + "com.fasterxml.jackson.core.io.schubfach", + "com.fasterxml.jackson.core.json", + "com.fasterxml.jackson.core.json.async", + "com.fasterxml.jackson.core.sym", + "com.fasterxml.jackson.core.type", + "com.fasterxml.jackson.core.util" + ], + "com.fasterxml.jackson.core:jackson-databind": [ + "com.fasterxml.jackson.databind", + "com.fasterxml.jackson.databind.annotation", + "com.fasterxml.jackson.databind.cfg", + "com.fasterxml.jackson.databind.deser", + "com.fasterxml.jackson.databind.deser.impl", + "com.fasterxml.jackson.databind.deser.std", + "com.fasterxml.jackson.databind.exc", + "com.fasterxml.jackson.databind.ext", + "com.fasterxml.jackson.databind.introspect", + "com.fasterxml.jackson.databind.jdk14", + "com.fasterxml.jackson.databind.json", + "com.fasterxml.jackson.databind.jsonFormatVisitors", + "com.fasterxml.jackson.databind.jsonschema", + "com.fasterxml.jackson.databind.jsontype", + "com.fasterxml.jackson.databind.jsontype.impl", + "com.fasterxml.jackson.databind.module", + "com.fasterxml.jackson.databind.node", + "com.fasterxml.jackson.databind.ser", + "com.fasterxml.jackson.databind.ser.impl", + "com.fasterxml.jackson.databind.ser.std", + "com.fasterxml.jackson.databind.type", + "com.fasterxml.jackson.databind.util", + "com.fasterxml.jackson.databind.util.internal" + ], + "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor": [ + "com.fasterxml.jackson.dataformat.cbor", + "com.fasterxml.jackson.dataformat.cbor.databind" + ], + "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml": [ + "com.fasterxml.jackson.dataformat.yaml", + "com.fasterxml.jackson.dataformat.yaml.snakeyaml.error", + "com.fasterxml.jackson.dataformat.yaml.util" + ], + "com.fasterxml.jackson.jaxrs:jackson-jaxrs-base": [ + "com.fasterxml.jackson.jaxrs.annotation", + "com.fasterxml.jackson.jaxrs.base", + "com.fasterxml.jackson.jaxrs.base.nocontent", + "com.fasterxml.jackson.jaxrs.cfg", + "com.fasterxml.jackson.jaxrs.util" + ], + "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider": [ + "com.fasterxml.jackson.jaxrs.json", + "com.fasterxml.jackson.jaxrs.json.annotation" + ], + "com.fasterxml.jackson.module:jackson-module-jaxb-annotations": [ + "com.fasterxml.jackson.module.jaxb", + "com.fasterxml.jackson.module.jaxb.deser", + "com.fasterxml.jackson.module.jaxb.ser" + ], + "com.github.ben-manes.caffeine:caffeine": [ + "com.github.benmanes.caffeine.cache", + "com.github.benmanes.caffeine.cache.stats" + ], + "com.github.docker-java:docker-java": [ + "com.github.dockerjava.core" + ], + "com.github.docker-java:docker-java-api": [ + "com.github.dockerjava.api", + "com.github.dockerjava.api.async", + "com.github.dockerjava.api.command", + "com.github.dockerjava.api.exception", + "com.github.dockerjava.api.model" + ], + "com.github.docker-java:docker-java-core": [ + "com.github.dockerjava.core", + "com.github.dockerjava.core.async", + "com.github.dockerjava.core.command", + "com.github.dockerjava.core.dockerfile", + "com.github.dockerjava.core.exception", + "com.github.dockerjava.core.exec", + "com.github.dockerjava.core.util" + ], + "com.github.docker-java:docker-java-transport": [ + "com.github.dockerjava.transport" + ], + "com.github.docker-java:docker-java-transport-jersey": [ + "com.github.dockerjava.jaxrs", + "com.github.dockerjava.jaxrs.filter", + "com.github.dockerjava.jaxrs.util" + ], + "com.github.docker-java:docker-java-transport-netty": [ + "com.github.dockerjava.netty", + "com.github.dockerjava.netty.handler" + ], + "com.github.fppt:jedis-mock": [ + "com.github.fppt.jedismock", + "com.github.fppt.jedismock.commands", + "com.github.fppt.jedismock.datastructures", + "com.github.fppt.jedismock.exception", + "com.github.fppt.jedismock.operations", + "com.github.fppt.jedismock.operations.bitmaps", + "com.github.fppt.jedismock.operations.cluster", + "com.github.fppt.jedismock.operations.connection", + "com.github.fppt.jedismock.operations.hashes", + "com.github.fppt.jedismock.operations.hyperloglog", + "com.github.fppt.jedismock.operations.keys", + "com.github.fppt.jedismock.operations.lists", + "com.github.fppt.jedismock.operations.pubsub", + "com.github.fppt.jedismock.operations.scripting", + "com.github.fppt.jedismock.operations.server", + "com.github.fppt.jedismock.operations.sets", + "com.github.fppt.jedismock.operations.sortedsets", + "com.github.fppt.jedismock.operations.strings", + "com.github.fppt.jedismock.operations.transactions", + "com.github.fppt.jedismock.server", + "com.github.fppt.jedismock.storage" + ], + "com.github.jnr:jffi": [ + "com.kenai.jffi", + "com.kenai.jffi.internal" + ], + "com.github.jnr:jnr-a64asm": [ + "jnr.a64asm" + ], + "com.github.jnr:jnr-constants": [ + "jnr.constants", + "jnr.constants.platform", + "jnr.constants.platform.aix", + "jnr.constants.platform.darwin", + "jnr.constants.platform.dragonflybsd", + "jnr.constants.platform.fake", + "jnr.constants.platform.freebsd", + "jnr.constants.platform.freebsd.aarch64", + "jnr.constants.platform.linux", + "jnr.constants.platform.linux.aarch64", + "jnr.constants.platform.linux.loongarch64", + "jnr.constants.platform.linux.mips64el", + "jnr.constants.platform.linux.powerpc64", + "jnr.constants.platform.linux.s390x", + "jnr.constants.platform.openbsd", + "jnr.constants.platform.solaris", + "jnr.constants.platform.windows" + ], + "com.github.jnr:jnr-ffi": [ + "jnr.ffi", + "jnr.ffi.annotations", + "jnr.ffi.byref", + "jnr.ffi.mapper", + "jnr.ffi.provider", + "jnr.ffi.provider.converters", + "jnr.ffi.provider.jffi", + "jnr.ffi.provider.jffi.platform.aarch64.darwin", + "jnr.ffi.provider.jffi.platform.aarch64.freebsd", + "jnr.ffi.provider.jffi.platform.aarch64.linux", + "jnr.ffi.provider.jffi.platform.arm.linux", + "jnr.ffi.provider.jffi.platform.i386.darwin", + "jnr.ffi.provider.jffi.platform.i386.freebsd", + "jnr.ffi.provider.jffi.platform.i386.linux", + "jnr.ffi.provider.jffi.platform.i386.midnightbsd", + "jnr.ffi.provider.jffi.platform.i386.openbsd", + "jnr.ffi.provider.jffi.platform.i386.solaris", + "jnr.ffi.provider.jffi.platform.i386.windows", + "jnr.ffi.provider.jffi.platform.loongarch64.linux", + "jnr.ffi.provider.jffi.platform.mips.linux", + "jnr.ffi.provider.jffi.platform.mips64.linux", + "jnr.ffi.provider.jffi.platform.mips64el.linux", + "jnr.ffi.provider.jffi.platform.mipsel.linux", + "jnr.ffi.provider.jffi.platform.ppc.aix", + "jnr.ffi.provider.jffi.platform.ppc.darwin", + "jnr.ffi.provider.jffi.platform.ppc.linux", + "jnr.ffi.provider.jffi.platform.ppc64.aix", + "jnr.ffi.provider.jffi.platform.ppc64.freebsd", + "jnr.ffi.provider.jffi.platform.ppc64.ibmi", + "jnr.ffi.provider.jffi.platform.ppc64.linux", + "jnr.ffi.provider.jffi.platform.ppc64le.linux", + "jnr.ffi.provider.jffi.platform.s390.linux", + "jnr.ffi.provider.jffi.platform.s390x.linux", + "jnr.ffi.provider.jffi.platform.sparc.solaris", + "jnr.ffi.provider.jffi.platform.sparcv9.linux", + "jnr.ffi.provider.jffi.platform.sparcv9.solaris", + "jnr.ffi.provider.jffi.platform.x86_64.darwin", + "jnr.ffi.provider.jffi.platform.x86_64.dragonfly", + "jnr.ffi.provider.jffi.platform.x86_64.freebsd", + "jnr.ffi.provider.jffi.platform.x86_64.linux", + "jnr.ffi.provider.jffi.platform.x86_64.midnightbsd", + "jnr.ffi.provider.jffi.platform.x86_64.openbsd", + "jnr.ffi.provider.jffi.platform.x86_64.solaris", + "jnr.ffi.provider.jffi.platform.x86_64.windows", + "jnr.ffi.types", + "jnr.ffi.util", + "jnr.ffi.util.ref", + "jnr.ffi.util.ref.internal" + ], + "com.github.jnr:jnr-posix": [ + "jnr.posix", + "jnr.posix.util", + "jnr.posix.windows" + ], + "com.github.jnr:jnr-x86asm": [ + "com.kenai.jnr.x86asm", + "jnr.x86asm" + ], + "com.github.kevinstern:software-and-algorithms": [ + "blogspot.software_and_algorithms.stern_library.data_structure", + "blogspot.software_and_algorithms.stern_library.geometry", + "blogspot.software_and_algorithms.stern_library.optimization", + "blogspot.software_and_algorithms.stern_library.string" + ], + "com.github.luben:zstd-jni": [ + "com.github.luben.zstd", + "com.github.luben.zstd.util" + ], + "com.github.oshi:oshi-core": [ + "oshi", + "oshi.annotation.concurrent", + "oshi.driver.linux", + "oshi.driver.linux.proc", + "oshi.driver.mac", + "oshi.driver.mac.disk", + "oshi.driver.mac.net", + "oshi.driver.unix", + "oshi.driver.unix.aix", + "oshi.driver.unix.aix.perfstat", + "oshi.driver.unix.freebsd", + "oshi.driver.unix.freebsd.disk", + "oshi.driver.unix.openbsd.disk", + "oshi.driver.unix.solaris", + "oshi.driver.unix.solaris.disk", + "oshi.driver.unix.solaris.kstat", + "oshi.driver.windows", + "oshi.driver.windows.perfmon", + "oshi.driver.windows.registry", + "oshi.driver.windows.wmi", + "oshi.hardware", + "oshi.hardware.common", + "oshi.hardware.platform.linux", + "oshi.hardware.platform.mac", + "oshi.hardware.platform.unix", + "oshi.hardware.platform.unix.aix", + "oshi.hardware.platform.unix.freebsd", + "oshi.hardware.platform.unix.openbsd", + "oshi.hardware.platform.unix.solaris", + "oshi.hardware.platform.windows", + "oshi.jna", + "oshi.jna.platform.linux", + "oshi.jna.platform.mac", + "oshi.jna.platform.unix", + "oshi.jna.platform.windows", + "oshi.software.common", + "oshi.software.os", + "oshi.software.os.linux", + "oshi.software.os.mac", + "oshi.software.os.unix.aix", + "oshi.software.os.unix.freebsd", + "oshi.software.os.unix.openbsd", + "oshi.software.os.unix.solaris", + "oshi.software.os.windows", + "oshi.util", + "oshi.util.platform.linux", + "oshi.util.platform.mac", + "oshi.util.platform.unix.freebsd", + "oshi.util.platform.unix.openbsd", + "oshi.util.platform.unix.solaris", + "oshi.util.platform.windows", + "oshi.util.tuples" + ], + "com.github.pcj:google-options": [ + "com.google.devtools.common.options" + ], + "com.github.serceman:jnr-fuse": [ + "jnr.ffi", + "jnr.ffi.provider.jffi", + "ru.serce.jnrfuse", + "ru.serce.jnrfuse.examples", + "ru.serce.jnrfuse.flags", + "ru.serce.jnrfuse.struct", + "ru.serce.jnrfuse.utils" + ], + "com.google.android:annotations": [ + "android.annotation" + ], + "com.google.api.grpc:proto-google-common-protos": [ + "com.google.api", + "com.google.cloud", + "com.google.cloud.audit", + "com.google.cloud.location", + "com.google.geo.type", + "com.google.logging.type", + "com.google.longrunning", + "com.google.rpc", + "com.google.rpc.context", + "com.google.type" + ], + "com.google.auth:google-auth-library-credentials": [ + "com.google.auth" + ], + "com.google.auth:google-auth-library-oauth2-http": [ + "com.google.auth.http", + "com.google.auth.oauth2" + ], + "com.google.auto.service:auto-service-annotations": [ + "com.google.auto.service" + ], + "com.google.auto.value:auto-value-annotations": [ + "com.google.auto.value", + "com.google.auto.value.extension.memoized", + "com.google.auto.value.extension.serializable", + "com.google.auto.value.extension.toprettystring" + ], + "com.google.auto:auto-common": [ + "com.google.auto.common" + ], + "com.google.code.findbugs:jsr305": [ + "javax.annotation", + "javax.annotation.concurrent", + "javax.annotation.meta" + ], + "com.google.code.gson:gson": [ + "com.google.gson", + "com.google.gson.annotations", + "com.google.gson.internal", + "com.google.gson.internal.bind", + "com.google.gson.internal.bind.util", + "com.google.gson.internal.reflect", + "com.google.gson.internal.sql", + "com.google.gson.reflect", + "com.google.gson.stream" + ], + "com.google.errorprone:error_prone_annotation": [ + "com.google.errorprone" + ], + "com.google.errorprone:error_prone_annotations": [ + "com.google.errorprone.annotations", + "com.google.errorprone.annotations.concurrent" + ], + "com.google.errorprone:error_prone_check_api": [ + "com.google.errorprone", + "com.google.errorprone.apply", + "com.google.errorprone.bugpatterns", + "com.google.errorprone.dataflow", + "com.google.errorprone.dataflow.nullnesspropagation", + "com.google.errorprone.dataflow.nullnesspropagation.inference", + "com.google.errorprone.fixes", + "com.google.errorprone.matchers", + "com.google.errorprone.matchers.method", + "com.google.errorprone.names", + "com.google.errorprone.predicates", + "com.google.errorprone.predicates.type", + "com.google.errorprone.scanner", + "com.google.errorprone.suppliers", + "com.google.errorprone.util" + ], + "com.google.errorprone:error_prone_core": [ + "com.google.errorprone", + "com.google.errorprone.bugpatterns", + "com.google.errorprone.bugpatterns.android", + "com.google.errorprone.bugpatterns.apidiff", + "com.google.errorprone.bugpatterns.argumentselectiondefects", + "com.google.errorprone.bugpatterns.checkreturnvalue", + "com.google.errorprone.bugpatterns.collectionincompatibletype", + "com.google.errorprone.bugpatterns.flogger", + "com.google.errorprone.bugpatterns.formatstring", + "com.google.errorprone.bugpatterns.inject", + "com.google.errorprone.bugpatterns.inject.dagger", + "com.google.errorprone.bugpatterns.inject.guice", + "com.google.errorprone.bugpatterns.inlineme", + "com.google.errorprone.bugpatterns.javadoc", + "com.google.errorprone.bugpatterns.nullness", + "com.google.errorprone.bugpatterns.overloading", + "com.google.errorprone.bugpatterns.threadsafety", + "com.google.errorprone.bugpatterns.time", + "com.google.errorprone.refaster", + "com.google.errorprone.refaster.annotation", + "com.google.errorprone.scanner" + ], + "com.google.errorprone:error_prone_type_annotations": [ + "com.google.errorprone.annotations" + ], + "com.google.guava:failureaccess": [ + "com.google.common.util.concurrent.internal" + ], + "com.google.guava:guava": [ + "com.google.common.annotations", + "com.google.common.base", + "com.google.common.base.internal", + "com.google.common.cache", + "com.google.common.collect", + "com.google.common.escape", + "com.google.common.eventbus", + "com.google.common.graph", + "com.google.common.hash", + "com.google.common.html", + "com.google.common.io", + "com.google.common.math", + "com.google.common.net", + "com.google.common.primitives", + "com.google.common.reflect", + "com.google.common.util.concurrent", + "com.google.common.xml", + "com.google.thirdparty.publicsuffix" + ], + "com.google.guava:guava-testlib": [ + "com.google.common.collect.testing", + "com.google.common.collect.testing.features", + "com.google.common.collect.testing.google", + "com.google.common.collect.testing.testers", + "com.google.common.escape.testing", + "com.google.common.testing", + "com.google.common.util.concurrent.testing" + ], + "com.google.http-client:google-http-client": [ + "com.google.api.client.http", + "com.google.api.client.http.apache", + "com.google.api.client.http.javanet", + "com.google.api.client.http.json", + "com.google.api.client.json", + "com.google.api.client.json.rpc2", + "com.google.api.client.json.webtoken", + "com.google.api.client.testing.http", + "com.google.api.client.testing.http.apache", + "com.google.api.client.testing.http.javanet", + "com.google.api.client.testing.json", + "com.google.api.client.testing.json.webtoken", + "com.google.api.client.testing.util", + "com.google.api.client.util", + "com.google.api.client.util.escape", + "com.google.api.client.util.store" + ], + "com.google.http-client:google-http-client-gson": [ + "com.google.api.client.json.gson" + ], + "com.google.inject:guice": [ + "com.google.inject", + "com.google.inject.binder", + "com.google.inject.internal", + "com.google.inject.internal.aop", + "com.google.inject.internal.asm", + "com.google.inject.internal.util", + "com.google.inject.matcher", + "com.google.inject.multibindings", + "com.google.inject.name", + "com.google.inject.spi", + "com.google.inject.util" + ], + "com.google.j2objc:j2objc-annotations": [ + "com.google.j2objc.annotations" + ], + "com.google.jimfs:jimfs": [ + "com.google.common.jimfs" + ], + "com.google.protobuf:protobuf-java": [ + "com.google.protobuf", + "com.google.protobuf.compiler" + ], + "com.google.protobuf:protobuf-java-util": [ + "com.google.protobuf.util" + ], + "com.google.truth:truth": [ + "com.google.common.truth" + ], + "com.googlecode.json-simple:json-simple": [ + "org.json.simple", + "org.json.simple.parser" + ], + "com.jayway.jsonpath:json-path": [ + "com.jayway.jsonpath", + "com.jayway.jsonpath.internal", + "com.jayway.jsonpath.internal.filter", + "com.jayway.jsonpath.internal.function", + "com.jayway.jsonpath.internal.function.json", + "com.jayway.jsonpath.internal.function.latebinding", + "com.jayway.jsonpath.internal.function.numeric", + "com.jayway.jsonpath.internal.function.sequence", + "com.jayway.jsonpath.internal.function.text", + "com.jayway.jsonpath.internal.path", + "com.jayway.jsonpath.spi.cache", + "com.jayway.jsonpath.spi.json", + "com.jayway.jsonpath.spi.mapper" + ], + "com.kohlschutter.junixsocket:junixsocket-common": [ + "org.newsclub.net.unix" + ], + "com.kohlschutter.junixsocket:junixsocket-native-common": [ + "org.newsclub.lib.junixsocket.common" + ], + "com.sun.activation:jakarta.activation": [ + "com.sun.activation.registries", + "com.sun.activation.viewers", + "javax.activation" + ], + "commons-codec:commons-codec": [ + "org.apache.commons.codec", + "org.apache.commons.codec.binary", + "org.apache.commons.codec.cli", + "org.apache.commons.codec.digest", + "org.apache.commons.codec.language", + "org.apache.commons.codec.language.bm", + "org.apache.commons.codec.net" + ], + "commons-io:commons-io": [ + "org.apache.commons.io", + "org.apache.commons.io.comparator", + "org.apache.commons.io.filefilter", + "org.apache.commons.io.input", + "org.apache.commons.io.monitor", + "org.apache.commons.io.output", + "org.apache.commons.io.serialization" + ], + "commons-logging:commons-logging": [ + "org.apache.commons.logging", + "org.apache.commons.logging.impl" + ], + "io.github.eisop:dataflow-errorprone": [ + "org.checkerframework.dataflow.qual", + "org.checkerframework.errorprone.checker.builder.qual", + "org.checkerframework.errorprone.checker.calledmethods.qual", + "org.checkerframework.errorprone.checker.compilermsgs.qual", + "org.checkerframework.errorprone.checker.fenum.qual", + "org.checkerframework.errorprone.checker.formatter.qual", + "org.checkerframework.errorprone.checker.guieffect.qual", + "org.checkerframework.errorprone.checker.i18n.qual", + "org.checkerframework.errorprone.checker.i18nformatter.qual", + "org.checkerframework.errorprone.checker.index.qual", + "org.checkerframework.errorprone.checker.initialization.qual", + "org.checkerframework.errorprone.checker.interning.qual", + "org.checkerframework.errorprone.checker.lock.qual", + "org.checkerframework.errorprone.checker.mustcall.qual", + "org.checkerframework.errorprone.checker.nullness.qual", + "org.checkerframework.errorprone.checker.optional.qual", + "org.checkerframework.errorprone.checker.propkey.qual", + "org.checkerframework.errorprone.checker.regex.qual", + "org.checkerframework.errorprone.checker.signature.qual", + "org.checkerframework.errorprone.checker.signedness.qual", + "org.checkerframework.errorprone.checker.tainting.qual", + "org.checkerframework.errorprone.checker.units.qual", + "org.checkerframework.errorprone.common.aliasing.qual", + "org.checkerframework.errorprone.common.initializedfields.qual", + "org.checkerframework.errorprone.common.reflection.qual", + "org.checkerframework.errorprone.common.returnsreceiver.qual", + "org.checkerframework.errorprone.common.subtyping.qual", + "org.checkerframework.errorprone.common.util.report.qual", + "org.checkerframework.errorprone.common.value.qual", + "org.checkerframework.errorprone.dataflow.analysis", + "org.checkerframework.errorprone.dataflow.busyexpr", + "org.checkerframework.errorprone.dataflow.cfg", + "org.checkerframework.errorprone.dataflow.cfg.block", + "org.checkerframework.errorprone.dataflow.cfg.builder", + "org.checkerframework.errorprone.dataflow.cfg.node", + "org.checkerframework.errorprone.dataflow.cfg.playground", + "org.checkerframework.errorprone.dataflow.cfg.visualize", + "org.checkerframework.errorprone.dataflow.constantpropagation", + "org.checkerframework.errorprone.dataflow.expression", + "org.checkerframework.errorprone.dataflow.livevariable", + "org.checkerframework.errorprone.dataflow.reachingdef", + "org.checkerframework.errorprone.dataflow.util", + "org.checkerframework.errorprone.framework.qual", + "org.checkerframework.errorprone.javacutil", + "org.checkerframework.errorprone.javacutil.trees", + "org.checkerframework.errorprone.org.plumelib.reflection", + "org.checkerframework.errorprone.org.plumelib.util" + ], + "io.github.java-diff-utils:java-diff-utils": [ + "com.github.difflib", + "com.github.difflib.algorithm", + "com.github.difflib.algorithm.myers", + "com.github.difflib.patch", + "com.github.difflib.text", + "com.github.difflib.unifieddiff" + ], + "io.grpc:grpc-api": [ + "io.grpc" + ], + "io.grpc:grpc-auth": [ + "io.grpc.auth" + ], + "io.grpc:grpc-core": [ + "io.grpc.internal" + ], + "io.grpc:grpc-inprocess": [ + "io.grpc.inprocess" + ], + "io.grpc:grpc-netty": [ + "io.grpc.netty" + ], + "io.grpc:grpc-netty-shaded": [ + "io.grpc.netty.shaded.io.grpc.netty", + "io.grpc.netty.shaded.io.netty.bootstrap", + "io.grpc.netty.shaded.io.netty.buffer", + "io.grpc.netty.shaded.io.netty.buffer.search", + "io.grpc.netty.shaded.io.netty.channel", + "io.grpc.netty.shaded.io.netty.channel.embedded", + "io.grpc.netty.shaded.io.netty.channel.epoll", + "io.grpc.netty.shaded.io.netty.channel.group", + "io.grpc.netty.shaded.io.netty.channel.internal", + "io.grpc.netty.shaded.io.netty.channel.local", + "io.grpc.netty.shaded.io.netty.channel.nio", + "io.grpc.netty.shaded.io.netty.channel.oio", + "io.grpc.netty.shaded.io.netty.channel.pool", + "io.grpc.netty.shaded.io.netty.channel.socket", + "io.grpc.netty.shaded.io.netty.channel.socket.nio", + "io.grpc.netty.shaded.io.netty.channel.socket.oio", + "io.grpc.netty.shaded.io.netty.channel.unix", + "io.grpc.netty.shaded.io.netty.handler.address", + "io.grpc.netty.shaded.io.netty.handler.codec", + "io.grpc.netty.shaded.io.netty.handler.codec.base64", + "io.grpc.netty.shaded.io.netty.handler.codec.bytes", + "io.grpc.netty.shaded.io.netty.handler.codec.compression", + "io.grpc.netty.shaded.io.netty.handler.codec.http", + "io.grpc.netty.shaded.io.netty.handler.codec.http.cookie", + "io.grpc.netty.shaded.io.netty.handler.codec.http.cors", + "io.grpc.netty.shaded.io.netty.handler.codec.http.multipart", + "io.grpc.netty.shaded.io.netty.handler.codec.http.websocketx", + "io.grpc.netty.shaded.io.netty.handler.codec.http.websocketx.extensions", + "io.grpc.netty.shaded.io.netty.handler.codec.http.websocketx.extensions.compression", + "io.grpc.netty.shaded.io.netty.handler.codec.http2", + "io.grpc.netty.shaded.io.netty.handler.codec.json", + "io.grpc.netty.shaded.io.netty.handler.codec.marshalling", + "io.grpc.netty.shaded.io.netty.handler.codec.protobuf", + "io.grpc.netty.shaded.io.netty.handler.codec.rtsp", + "io.grpc.netty.shaded.io.netty.handler.codec.serialization", + "io.grpc.netty.shaded.io.netty.handler.codec.socks", + "io.grpc.netty.shaded.io.netty.handler.codec.socksx", + "io.grpc.netty.shaded.io.netty.handler.codec.socksx.v4", + "io.grpc.netty.shaded.io.netty.handler.codec.socksx.v5", + "io.grpc.netty.shaded.io.netty.handler.codec.spdy", + "io.grpc.netty.shaded.io.netty.handler.codec.string", + "io.grpc.netty.shaded.io.netty.handler.codec.xml", + "io.grpc.netty.shaded.io.netty.handler.flow", + "io.grpc.netty.shaded.io.netty.handler.flush", + "io.grpc.netty.shaded.io.netty.handler.ipfilter", + "io.grpc.netty.shaded.io.netty.handler.logging", + "io.grpc.netty.shaded.io.netty.handler.pcap", + "io.grpc.netty.shaded.io.netty.handler.proxy", + "io.grpc.netty.shaded.io.netty.handler.ssl", + "io.grpc.netty.shaded.io.netty.handler.ssl.ocsp", + "io.grpc.netty.shaded.io.netty.handler.ssl.util", + "io.grpc.netty.shaded.io.netty.handler.stream", + "io.grpc.netty.shaded.io.netty.handler.timeout", + "io.grpc.netty.shaded.io.netty.handler.traffic", + "io.grpc.netty.shaded.io.netty.internal.tcnative", + "io.grpc.netty.shaded.io.netty.resolver", + "io.grpc.netty.shaded.io.netty.util", + "io.grpc.netty.shaded.io.netty.util.collection", + "io.grpc.netty.shaded.io.netty.util.concurrent", + "io.grpc.netty.shaded.io.netty.util.internal", + "io.grpc.netty.shaded.io.netty.util.internal.logging", + "io.grpc.netty.shaded.io.netty.util.internal.shaded.org.jctools.queues", + "io.grpc.netty.shaded.io.netty.util.internal.shaded.org.jctools.queues.atomic", + "io.grpc.netty.shaded.io.netty.util.internal.shaded.org.jctools.util", + "io.grpc.netty.shaded.io.netty.util.internal.svm" + ], + "io.grpc:grpc-protobuf": [ + "io.grpc.protobuf" + ], + "io.grpc:grpc-protobuf-lite": [ + "io.grpc.protobuf.lite" + ], + "io.grpc:grpc-services": [ + "io.grpc.binarylog.v1", + "io.grpc.channelz.v1", + "io.grpc.health.v1", + "io.grpc.protobuf.services", + "io.grpc.protobuf.services.internal", + "io.grpc.reflection.v1alpha", + "io.grpc.services" + ], + "io.grpc:grpc-stub": [ + "io.grpc.stub", + "io.grpc.stub.annotations" + ], + "io.grpc:grpc-testing": [ + "io.grpc.internal.testing", + "io.grpc.testing" + ], + "io.grpc:grpc-util": [ + "io.grpc.util" + ], + "io.netty:netty-buffer": [ + "io.netty.buffer", + "io.netty.buffer.search" + ], + "io.netty:netty-codec": [ + "io.netty.handler.codec", + "io.netty.handler.codec.base64", + "io.netty.handler.codec.bytes", + "io.netty.handler.codec.compression", + "io.netty.handler.codec.json", + "io.netty.handler.codec.marshalling", + "io.netty.handler.codec.protobuf", + "io.netty.handler.codec.serialization", + "io.netty.handler.codec.string", + "io.netty.handler.codec.xml" + ], + "io.netty:netty-codec-dns": [ + "io.netty.handler.codec.dns" + ], + "io.netty:netty-codec-http": [ + "io.netty.handler.codec.http", + "io.netty.handler.codec.http.cookie", + "io.netty.handler.codec.http.cors", + "io.netty.handler.codec.http.multipart", + "io.netty.handler.codec.http.websocketx", + "io.netty.handler.codec.http.websocketx.extensions", + "io.netty.handler.codec.http.websocketx.extensions.compression", + "io.netty.handler.codec.rtsp", + "io.netty.handler.codec.spdy" + ], + "io.netty:netty-codec-http2": [ + "io.netty.handler.codec.http2" + ], + "io.netty:netty-codec-socks": [ + "io.netty.handler.codec.socks", + "io.netty.handler.codec.socksx", + "io.netty.handler.codec.socksx.v4", + "io.netty.handler.codec.socksx.v5" + ], + "io.netty:netty-common": [ + "io.netty.util", + "io.netty.util.collection", + "io.netty.util.concurrent", + "io.netty.util.internal", + "io.netty.util.internal.logging", + "io.netty.util.internal.shaded.org.jctools.queues", + "io.netty.util.internal.shaded.org.jctools.queues.atomic", + "io.netty.util.internal.shaded.org.jctools.util", + "io.netty.util.internal.svm" + ], + "io.netty:netty-handler": [ + "io.netty.handler.address", + "io.netty.handler.flow", + "io.netty.handler.flush", + "io.netty.handler.ipfilter", + "io.netty.handler.logging", + "io.netty.handler.pcap", + "io.netty.handler.ssl", + "io.netty.handler.ssl.ocsp", + "io.netty.handler.ssl.util", + "io.netty.handler.stream", + "io.netty.handler.timeout", + "io.netty.handler.traffic" + ], + "io.netty:netty-handler-proxy": [ + "io.netty.handler.proxy" + ], + "io.netty:netty-resolver": [ + "io.netty.resolver" + ], + "io.netty:netty-resolver-dns": [ + "io.netty.resolver.dns" + ], + "io.netty:netty-transport": [ + "io.netty.bootstrap", + "io.netty.channel", + "io.netty.channel.embedded", + "io.netty.channel.group", + "io.netty.channel.internal", + "io.netty.channel.local", + "io.netty.channel.nio", + "io.netty.channel.oio", + "io.netty.channel.pool", + "io.netty.channel.socket", + "io.netty.channel.socket.nio", + "io.netty.channel.socket.oio" + ], + "io.netty:netty-transport-classes-epoll": [ + "io.netty.channel.epoll" + ], + "io.netty:netty-transport-classes-kqueue": [ + "io.netty.channel.kqueue" + ], + "io.netty:netty-transport-native-unix-common": [ + "io.netty.channel.unix" + ], + "io.opencensus:opencensus-api": [ + "io.opencensus.common", + "io.opencensus.internal", + "io.opencensus.metrics", + "io.opencensus.metrics.data", + "io.opencensus.metrics.export", + "io.opencensus.resource", + "io.opencensus.stats", + "io.opencensus.tags", + "io.opencensus.tags.propagation", + "io.opencensus.tags.unsafe", + "io.opencensus.trace", + "io.opencensus.trace.config", + "io.opencensus.trace.export", + "io.opencensus.trace.internal", + "io.opencensus.trace.propagation", + "io.opencensus.trace.samplers", + "io.opencensus.trace.unsafe" + ], + "io.opencensus:opencensus-contrib-http-util": [ + "io.opencensus.contrib.http", + "io.opencensus.contrib.http.util" + ], + "io.perfmark:perfmark-api": [ + "io.perfmark" + ], + "io.projectreactor:reactor-core": [ + "reactor.adapter", + "reactor.core", + "reactor.core.observability", + "reactor.core.publisher", + "reactor.core.scheduler", + "reactor.util", + "reactor.util.annotation", + "reactor.util.concurrent", + "reactor.util.context", + "reactor.util.function", + "reactor.util.retry" + ], + "io.prometheus:simpleclient": [ + "io.prometheus.client", + "io.prometheus.client.exemplars" + ], + "io.prometheus:simpleclient_common": [ + "io.prometheus.client.exporter.common" + ], + "io.prometheus:simpleclient_hotspot": [ + "io.prometheus.client.hotspot" + ], + "io.prometheus:simpleclient_httpserver": [ + "io.prometheus.client.exporter" + ], + "io.prometheus:simpleclient_tracer_common": [ + "io.prometheus.client.exemplars.tracer.common" + ], + "io.prometheus:simpleclient_tracer_otel": [ + "io.prometheus.client.exemplars.tracer.otel" + ], + "io.prometheus:simpleclient_tracer_otel_agent": [ + "io.prometheus.client.exemplars.tracer.otel_agent" + ], + "io.reactivex.rxjava3:rxjava": [ + "io.reactivex.rxjava3.annotations", + "io.reactivex.rxjava3.core", + "io.reactivex.rxjava3.disposables", + "io.reactivex.rxjava3.exceptions", + "io.reactivex.rxjava3.flowables", + "io.reactivex.rxjava3.functions", + "io.reactivex.rxjava3.internal.disposables", + "io.reactivex.rxjava3.internal.functions", + "io.reactivex.rxjava3.internal.fuseable", + "io.reactivex.rxjava3.internal.jdk8", + "io.reactivex.rxjava3.internal.observers", + "io.reactivex.rxjava3.internal.operators.completable", + "io.reactivex.rxjava3.internal.operators.flowable", + "io.reactivex.rxjava3.internal.operators.maybe", + "io.reactivex.rxjava3.internal.operators.mixed", + "io.reactivex.rxjava3.internal.operators.observable", + "io.reactivex.rxjava3.internal.operators.parallel", + "io.reactivex.rxjava3.internal.operators.single", + "io.reactivex.rxjava3.internal.queue", + "io.reactivex.rxjava3.internal.schedulers", + "io.reactivex.rxjava3.internal.subscribers", + "io.reactivex.rxjava3.internal.subscriptions", + "io.reactivex.rxjava3.internal.util", + "io.reactivex.rxjava3.observables", + "io.reactivex.rxjava3.observers", + "io.reactivex.rxjava3.operators", + "io.reactivex.rxjava3.parallel", + "io.reactivex.rxjava3.plugins", + "io.reactivex.rxjava3.processors", + "io.reactivex.rxjava3.schedulers", + "io.reactivex.rxjava3.subjects", + "io.reactivex.rxjava3.subscribers" + ], + "jakarta.activation:jakarta.activation-api": [ + "javax.activation" + ], + "jakarta.annotation:jakarta.annotation-api": [ + "javax.annotation", + "javax.annotation.security", + "javax.annotation.sql" + ], + "jakarta.ws.rs:jakarta.ws.rs-api": [ + "javax.ws.rs", + "javax.ws.rs.client", + "javax.ws.rs.container", + "javax.ws.rs.core", + "javax.ws.rs.ext", + "javax.ws.rs.sse" + ], + "jakarta.xml.bind:jakarta.xml.bind-api": [ + "javax.xml.bind", + "javax.xml.bind.annotation", + "javax.xml.bind.annotation.adapters", + "javax.xml.bind.attachment", + "javax.xml.bind.helpers", + "javax.xml.bind.util" + ], + "javax.annotation:javax.annotation-api": [ + "javax.annotation", + "javax.annotation.security", + "javax.annotation.sql" + ], + "javax.cache:cache-api": [ + "javax.cache", + "javax.cache.annotation", + "javax.cache.configuration", + "javax.cache.event", + "javax.cache.expiry", + "javax.cache.integration", + "javax.cache.management", + "javax.cache.processor", + "javax.cache.spi" + ], + "javax.inject:javax.inject": [ + "javax.inject" + ], + "joda-time:joda-time": [ + "org.joda.time", + "org.joda.time.base", + "org.joda.time.chrono", + "org.joda.time.convert", + "org.joda.time.field", + "org.joda.time.format", + "org.joda.time.tz" + ], + "junit:junit": [ + "junit.extensions", + "junit.framework", + "junit.runner", + "junit.textui", + "org.junit", + "org.junit.experimental", + "org.junit.experimental.categories", + "org.junit.experimental.max", + "org.junit.experimental.results", + "org.junit.experimental.runners", + "org.junit.experimental.theories", + "org.junit.experimental.theories.internal", + "org.junit.experimental.theories.suppliers", + "org.junit.function", + "org.junit.internal", + "org.junit.internal.builders", + "org.junit.internal.management", + "org.junit.internal.matchers", + "org.junit.internal.requests", + "org.junit.internal.runners", + "org.junit.internal.runners.model", + "org.junit.internal.runners.rules", + "org.junit.internal.runners.statements", + "org.junit.matchers", + "org.junit.rules", + "org.junit.runner", + "org.junit.runner.manipulation", + "org.junit.runner.notification", + "org.junit.runners", + "org.junit.runners.model", + "org.junit.runners.parameterized", + "org.junit.validator" + ], + "me.dinowernli:java-grpc-prometheus": [ + "me.dinowernli.grpc.prometheus" + ], + "net.bytebuddy:byte-buddy": [ + "net.bytebuddy", + "net.bytebuddy.agent.builder", + "net.bytebuddy.asm", + "net.bytebuddy.build", + "net.bytebuddy.description", + "net.bytebuddy.description.annotation", + "net.bytebuddy.description.enumeration", + "net.bytebuddy.description.field", + "net.bytebuddy.description.method", + "net.bytebuddy.description.modifier", + "net.bytebuddy.description.type", + "net.bytebuddy.dynamic", + "net.bytebuddy.dynamic.loading", + "net.bytebuddy.dynamic.scaffold", + "net.bytebuddy.dynamic.scaffold.inline", + "net.bytebuddy.dynamic.scaffold.subclass", + "net.bytebuddy.implementation", + "net.bytebuddy.implementation.attribute", + "net.bytebuddy.implementation.auxiliary", + "net.bytebuddy.implementation.bind", + "net.bytebuddy.implementation.bind.annotation", + "net.bytebuddy.implementation.bytecode", + "net.bytebuddy.implementation.bytecode.assign", + "net.bytebuddy.implementation.bytecode.assign.primitive", + "net.bytebuddy.implementation.bytecode.assign.reference", + "net.bytebuddy.implementation.bytecode.collection", + "net.bytebuddy.implementation.bytecode.constant", + "net.bytebuddy.implementation.bytecode.member", + "net.bytebuddy.jar.asm", + "net.bytebuddy.jar.asm.commons", + "net.bytebuddy.jar.asm.signature", + "net.bytebuddy.matcher", + "net.bytebuddy.pool", + "net.bytebuddy.utility", + "net.bytebuddy.utility.dispatcher", + "net.bytebuddy.utility.nullability", + "net.bytebuddy.utility.privilege", + "net.bytebuddy.utility.visitor" + ], + "net.bytebuddy:byte-buddy-agent": [ + "net.bytebuddy.agent", + "net.bytebuddy.agent.utility.nullability" + ], + "net.java.dev.jna:jna": [ + "com.sun.jna", + "com.sun.jna.internal", + "com.sun.jna.ptr", + "com.sun.jna.win32" + ], + "net.java.dev.jna:jna-platform": [ + "com.sun.jna.platform", + "com.sun.jna.platform.dnd", + "com.sun.jna.platform.linux", + "com.sun.jna.platform.mac", + "com.sun.jna.platform.unix", + "com.sun.jna.platform.unix.aix", + "com.sun.jna.platform.unix.solaris", + "com.sun.jna.platform.win32", + "com.sun.jna.platform.win32.COM", + "com.sun.jna.platform.win32.COM.tlb", + "com.sun.jna.platform.win32.COM.tlb.imp", + "com.sun.jna.platform.win32.COM.util", + "com.sun.jna.platform.win32.COM.util.annotation", + "com.sun.jna.platform.wince" + ], + "net.javacrumbs.future-converter:future-converter-common": [ + "net.javacrumbs.futureconverter.common.internal" + ], + "net.javacrumbs.future-converter:future-converter-guava-common": [ + "net.javacrumbs.futureconverter.guavacommon" + ], + "net.javacrumbs.future-converter:future-converter-java8-common": [ + "net.javacrumbs.futureconverter.java8common" + ], + "net.javacrumbs.future-converter:future-converter-java8-guava": [ + "net.javacrumbs.futureconverter.java8guava" + ], + "net.jcip:jcip-annotations": [ + "net.jcip.annotations" + ], + "net.minidev:accessors-smart": [ + "net.minidev.asm", + "net.minidev.asm.ex" + ], + "net.minidev:json-smart": [ + "net.minidev.json", + "net.minidev.json.annotate", + "net.minidev.json.parser", + "net.minidev.json.reader", + "net.minidev.json.writer" + ], + "net.sf.jopt-simple:jopt-simple": [ + "joptsimple", + "joptsimple.internal", + "joptsimple.util" + ], + "org.apache.commons:commons-compress": [ + "org.apache.commons.compress", + "org.apache.commons.compress.archivers", + "org.apache.commons.compress.archivers.ar", + "org.apache.commons.compress.archivers.arj", + "org.apache.commons.compress.archivers.cpio", + "org.apache.commons.compress.archivers.dump", + "org.apache.commons.compress.archivers.examples", + "org.apache.commons.compress.archivers.jar", + "org.apache.commons.compress.archivers.sevenz", + "org.apache.commons.compress.archivers.tar", + "org.apache.commons.compress.archivers.zip", + "org.apache.commons.compress.changes", + "org.apache.commons.compress.compressors", + "org.apache.commons.compress.compressors.brotli", + "org.apache.commons.compress.compressors.bzip2", + "org.apache.commons.compress.compressors.deflate", + "org.apache.commons.compress.compressors.deflate64", + "org.apache.commons.compress.compressors.gzip", + "org.apache.commons.compress.compressors.lz4", + "org.apache.commons.compress.compressors.lz77support", + "org.apache.commons.compress.compressors.lzma", + "org.apache.commons.compress.compressors.lzw", + "org.apache.commons.compress.compressors.pack200", + "org.apache.commons.compress.compressors.snappy", + "org.apache.commons.compress.compressors.xz", + "org.apache.commons.compress.compressors.z", + "org.apache.commons.compress.compressors.zstandard", + "org.apache.commons.compress.harmony", + "org.apache.commons.compress.harmony.archive.internal.nls", + "org.apache.commons.compress.harmony.pack200", + "org.apache.commons.compress.harmony.unpack200", + "org.apache.commons.compress.harmony.unpack200.bytecode", + "org.apache.commons.compress.harmony.unpack200.bytecode.forms", + "org.apache.commons.compress.java.util.jar", + "org.apache.commons.compress.parallel", + "org.apache.commons.compress.utils" + ], + "org.apache.commons:commons-lang3": [ + "org.apache.commons.lang3", + "org.apache.commons.lang3.arch", + "org.apache.commons.lang3.builder", + "org.apache.commons.lang3.compare", + "org.apache.commons.lang3.concurrent", + "org.apache.commons.lang3.concurrent.locks", + "org.apache.commons.lang3.event", + "org.apache.commons.lang3.exception", + "org.apache.commons.lang3.function", + "org.apache.commons.lang3.math", + "org.apache.commons.lang3.mutable", + "org.apache.commons.lang3.reflect", + "org.apache.commons.lang3.stream", + "org.apache.commons.lang3.text", + "org.apache.commons.lang3.text.translate", + "org.apache.commons.lang3.time", + "org.apache.commons.lang3.tuple", + "org.apache.commons.lang3.util" + ], + "org.apache.commons:commons-math3": [ + "org.apache.commons.math3", + "org.apache.commons.math3.analysis", + "org.apache.commons.math3.analysis.differentiation", + "org.apache.commons.math3.analysis.function", + "org.apache.commons.math3.analysis.integration", + "org.apache.commons.math3.analysis.integration.gauss", + "org.apache.commons.math3.analysis.interpolation", + "org.apache.commons.math3.analysis.polynomials", + "org.apache.commons.math3.analysis.solvers", + "org.apache.commons.math3.complex", + "org.apache.commons.math3.dfp", + "org.apache.commons.math3.distribution", + "org.apache.commons.math3.distribution.fitting", + "org.apache.commons.math3.exception", + "org.apache.commons.math3.exception.util", + "org.apache.commons.math3.filter", + "org.apache.commons.math3.fitting", + "org.apache.commons.math3.fitting.leastsquares", + "org.apache.commons.math3.fraction", + "org.apache.commons.math3.genetics", + "org.apache.commons.math3.geometry", + "org.apache.commons.math3.geometry.enclosing", + "org.apache.commons.math3.geometry.euclidean.oned", + "org.apache.commons.math3.geometry.euclidean.threed", + "org.apache.commons.math3.geometry.euclidean.twod", + "org.apache.commons.math3.geometry.euclidean.twod.hull", + "org.apache.commons.math3.geometry.hull", + "org.apache.commons.math3.geometry.partitioning", + "org.apache.commons.math3.geometry.partitioning.utilities", + "org.apache.commons.math3.geometry.spherical.oned", + "org.apache.commons.math3.geometry.spherical.twod", + "org.apache.commons.math3.linear", + "org.apache.commons.math3.ml.clustering", + "org.apache.commons.math3.ml.clustering.evaluation", + "org.apache.commons.math3.ml.distance", + "org.apache.commons.math3.ml.neuralnet", + "org.apache.commons.math3.ml.neuralnet.oned", + "org.apache.commons.math3.ml.neuralnet.sofm", + "org.apache.commons.math3.ml.neuralnet.sofm.util", + "org.apache.commons.math3.ml.neuralnet.twod", + "org.apache.commons.math3.ml.neuralnet.twod.util", + "org.apache.commons.math3.ode", + "org.apache.commons.math3.ode.events", + "org.apache.commons.math3.ode.nonstiff", + "org.apache.commons.math3.ode.sampling", + "org.apache.commons.math3.optim", + "org.apache.commons.math3.optim.linear", + "org.apache.commons.math3.optim.nonlinear.scalar", + "org.apache.commons.math3.optim.nonlinear.scalar.gradient", + "org.apache.commons.math3.optim.nonlinear.scalar.noderiv", + "org.apache.commons.math3.optim.nonlinear.vector", + "org.apache.commons.math3.optim.nonlinear.vector.jacobian", + "org.apache.commons.math3.optim.univariate", + "org.apache.commons.math3.optimization", + "org.apache.commons.math3.optimization.direct", + "org.apache.commons.math3.optimization.fitting", + "org.apache.commons.math3.optimization.general", + "org.apache.commons.math3.optimization.linear", + "org.apache.commons.math3.optimization.univariate", + "org.apache.commons.math3.primes", + "org.apache.commons.math3.random", + "org.apache.commons.math3.special", + "org.apache.commons.math3.stat", + "org.apache.commons.math3.stat.clustering", + "org.apache.commons.math3.stat.correlation", + "org.apache.commons.math3.stat.descriptive", + "org.apache.commons.math3.stat.descriptive.moment", + "org.apache.commons.math3.stat.descriptive.rank", + "org.apache.commons.math3.stat.descriptive.summary", + "org.apache.commons.math3.stat.inference", + "org.apache.commons.math3.stat.interval", + "org.apache.commons.math3.stat.ranking", + "org.apache.commons.math3.stat.regression", + "org.apache.commons.math3.transform", + "org.apache.commons.math3.util" + ], + "org.apache.commons:commons-pool2": [ + "org.apache.commons.pool2", + "org.apache.commons.pool2.impl", + "org.apache.commons.pool2.proxy" + ], + "org.apache.httpcomponents:httpclient": [ + "org.apache.http.auth", + "org.apache.http.auth.params", + "org.apache.http.client", + "org.apache.http.client.config", + "org.apache.http.client.entity", + "org.apache.http.client.methods", + "org.apache.http.client.params", + "org.apache.http.client.protocol", + "org.apache.http.client.utils", + "org.apache.http.conn", + "org.apache.http.conn.params", + "org.apache.http.conn.routing", + "org.apache.http.conn.scheme", + "org.apache.http.conn.socket", + "org.apache.http.conn.ssl", + "org.apache.http.conn.util", + "org.apache.http.cookie", + "org.apache.http.cookie.params", + "org.apache.http.impl.auth", + "org.apache.http.impl.client", + "org.apache.http.impl.conn", + "org.apache.http.impl.conn.tsccm", + "org.apache.http.impl.cookie", + "org.apache.http.impl.execchain" + ], + "org.apache.httpcomponents:httpcore": [ + "org.apache.http", + "org.apache.http.annotation", + "org.apache.http.concurrent", + "org.apache.http.config", + "org.apache.http.entity", + "org.apache.http.impl", + "org.apache.http.impl.bootstrap", + "org.apache.http.impl.entity", + "org.apache.http.impl.io", + "org.apache.http.impl.pool", + "org.apache.http.io", + "org.apache.http.message", + "org.apache.http.params", + "org.apache.http.pool", + "org.apache.http.protocol", + "org.apache.http.ssl", + "org.apache.http.util" + ], + "org.apache.tomcat:annotations-api": [ + "javax.annotation", + "javax.annotation.security", + "javax.ejb", + "javax.persistence", + "javax.xml.ws" + ], + "org.bouncycastle:bcpkix-jdk18on": [ + "org.bouncycastle.cert", + "org.bouncycastle.cert.bc", + "org.bouncycastle.cert.cmp", + "org.bouncycastle.cert.crmf", + "org.bouncycastle.cert.crmf.bc", + "org.bouncycastle.cert.crmf.jcajce", + "org.bouncycastle.cert.dane", + "org.bouncycastle.cert.dane.fetcher", + "org.bouncycastle.cert.jcajce", + "org.bouncycastle.cert.ocsp", + "org.bouncycastle.cert.ocsp.jcajce", + "org.bouncycastle.cert.path", + "org.bouncycastle.cert.path.validations", + "org.bouncycastle.cert.selector", + "org.bouncycastle.cert.selector.jcajce", + "org.bouncycastle.cmc", + "org.bouncycastle.cms", + "org.bouncycastle.cms.bc", + "org.bouncycastle.cms.jcajce", + "org.bouncycastle.dvcs", + "org.bouncycastle.eac", + "org.bouncycastle.eac.jcajce", + "org.bouncycastle.eac.operator", + "org.bouncycastle.eac.operator.jcajce", + "org.bouncycastle.est", + "org.bouncycastle.est.jcajce", + "org.bouncycastle.its", + "org.bouncycastle.its.bc", + "org.bouncycastle.its.jcajce", + "org.bouncycastle.its.operator", + "org.bouncycastle.mime", + "org.bouncycastle.mime.encoding", + "org.bouncycastle.mime.smime", + "org.bouncycastle.mozilla", + "org.bouncycastle.mozilla.jcajce", + "org.bouncycastle.openssl", + "org.bouncycastle.openssl.bc", + "org.bouncycastle.openssl.jcajce", + "org.bouncycastle.operator", + "org.bouncycastle.operator.bc", + "org.bouncycastle.operator.jcajce", + "org.bouncycastle.pkcs", + "org.bouncycastle.pkcs.bc", + "org.bouncycastle.pkcs.jcajce", + "org.bouncycastle.pkix", + "org.bouncycastle.pkix.jcajce", + "org.bouncycastle.pkix.util", + "org.bouncycastle.pkix.util.filter", + "org.bouncycastle.tsp", + "org.bouncycastle.tsp.cms", + "org.bouncycastle.tsp.ers", + "org.bouncycastle.voms" + ], + "org.bouncycastle:bcprov-jdk15on": [ + "org.bouncycastle", + "org.bouncycastle.asn1", + "org.bouncycastle.asn1.anssi", + "org.bouncycastle.asn1.bc", + "org.bouncycastle.asn1.cryptlib", + "org.bouncycastle.asn1.cryptopro", + "org.bouncycastle.asn1.edec", + "org.bouncycastle.asn1.gm", + "org.bouncycastle.asn1.gnu", + "org.bouncycastle.asn1.iana", + "org.bouncycastle.asn1.isara", + "org.bouncycastle.asn1.iso", + "org.bouncycastle.asn1.kisa", + "org.bouncycastle.asn1.microsoft", + "org.bouncycastle.asn1.misc", + "org.bouncycastle.asn1.mozilla", + "org.bouncycastle.asn1.nist", + "org.bouncycastle.asn1.nsri", + "org.bouncycastle.asn1.ntt", + "org.bouncycastle.asn1.ocsp", + "org.bouncycastle.asn1.oiw", + "org.bouncycastle.asn1.pkcs", + "org.bouncycastle.asn1.rosstandart", + "org.bouncycastle.asn1.sec", + "org.bouncycastle.asn1.teletrust", + "org.bouncycastle.asn1.ua", + "org.bouncycastle.asn1.util", + "org.bouncycastle.asn1.x500", + "org.bouncycastle.asn1.x500.style", + "org.bouncycastle.asn1.x509", + "org.bouncycastle.asn1.x509.qualified", + "org.bouncycastle.asn1.x509.sigi", + "org.bouncycastle.asn1.x9", + "org.bouncycastle.crypto", + "org.bouncycastle.crypto.agreement", + "org.bouncycastle.crypto.agreement.jpake", + "org.bouncycastle.crypto.agreement.kdf", + "org.bouncycastle.crypto.agreement.srp", + "org.bouncycastle.crypto.commitments", + "org.bouncycastle.crypto.digests", + "org.bouncycastle.crypto.ec", + "org.bouncycastle.crypto.encodings", + "org.bouncycastle.crypto.engines", + "org.bouncycastle.crypto.examples", + "org.bouncycastle.crypto.fpe", + "org.bouncycastle.crypto.generators", + "org.bouncycastle.crypto.io", + "org.bouncycastle.crypto.kems", + "org.bouncycastle.crypto.macs", + "org.bouncycastle.crypto.modes", + "org.bouncycastle.crypto.modes.gcm", + "org.bouncycastle.crypto.modes.kgcm", + "org.bouncycastle.crypto.paddings", + "org.bouncycastle.crypto.params", + "org.bouncycastle.crypto.parsers", + "org.bouncycastle.crypto.prng", + "org.bouncycastle.crypto.prng.drbg", + "org.bouncycastle.crypto.signers", + "org.bouncycastle.crypto.util", + "org.bouncycastle.i18n", + "org.bouncycastle.i18n.filter", + "org.bouncycastle.iana", + "org.bouncycastle.internal.asn1.bsi", + "org.bouncycastle.internal.asn1.cms", + "org.bouncycastle.internal.asn1.eac", + "org.bouncycastle.internal.asn1.isismtt", + "org.bouncycastle.jcajce", + "org.bouncycastle.jcajce.interfaces", + "org.bouncycastle.jcajce.io", + "org.bouncycastle.jcajce.provider.asymmetric", + "org.bouncycastle.jcajce.provider.asymmetric.dh", + "org.bouncycastle.jcajce.provider.asymmetric.dsa", + "org.bouncycastle.jcajce.provider.asymmetric.dstu", + "org.bouncycastle.jcajce.provider.asymmetric.ec", + "org.bouncycastle.jcajce.provider.asymmetric.ecgost", + "org.bouncycastle.jcajce.provider.asymmetric.ecgost12", + "org.bouncycastle.jcajce.provider.asymmetric.edec", + "org.bouncycastle.jcajce.provider.asymmetric.elgamal", + "org.bouncycastle.jcajce.provider.asymmetric.gost", + "org.bouncycastle.jcajce.provider.asymmetric.ies", + "org.bouncycastle.jcajce.provider.asymmetric.rsa", + "org.bouncycastle.jcajce.provider.asymmetric.util", + "org.bouncycastle.jcajce.provider.asymmetric.x509", + "org.bouncycastle.jcajce.provider.config", + "org.bouncycastle.jcajce.provider.digest", + "org.bouncycastle.jcajce.provider.drbg", + "org.bouncycastle.jcajce.provider.keystore", + "org.bouncycastle.jcajce.provider.keystore.bc", + "org.bouncycastle.jcajce.provider.keystore.bcfks", + "org.bouncycastle.jcajce.provider.keystore.pkcs12", + "org.bouncycastle.jcajce.provider.keystore.util", + "org.bouncycastle.jcajce.provider.symmetric", + "org.bouncycastle.jcajce.provider.symmetric.util", + "org.bouncycastle.jcajce.provider.util", + "org.bouncycastle.jcajce.spec", + "org.bouncycastle.jcajce.util", + "org.bouncycastle.jce", + "org.bouncycastle.jce.exception", + "org.bouncycastle.jce.interfaces", + "org.bouncycastle.jce.netscape", + "org.bouncycastle.jce.provider", + "org.bouncycastle.jce.spec", + "org.bouncycastle.math", + "org.bouncycastle.math.ec", + "org.bouncycastle.math.ec.custom.djb", + "org.bouncycastle.math.ec.custom.gm", + "org.bouncycastle.math.ec.custom.sec", + "org.bouncycastle.math.ec.endo", + "org.bouncycastle.math.ec.rfc7748", + "org.bouncycastle.math.ec.rfc8032", + "org.bouncycastle.math.ec.tools", + "org.bouncycastle.math.field", + "org.bouncycastle.math.raw", + "org.bouncycastle.pqc.asn1", + "org.bouncycastle.pqc.crypto", + "org.bouncycastle.pqc.crypto.gmss", + "org.bouncycastle.pqc.crypto.gmss.util", + "org.bouncycastle.pqc.crypto.lms", + "org.bouncycastle.pqc.crypto.mceliece", + "org.bouncycastle.pqc.crypto.newhope", + "org.bouncycastle.pqc.crypto.qtesla", + "org.bouncycastle.pqc.crypto.rainbow", + "org.bouncycastle.pqc.crypto.rainbow.util", + "org.bouncycastle.pqc.crypto.sphincs", + "org.bouncycastle.pqc.crypto.sphincsplus", + "org.bouncycastle.pqc.crypto.util", + "org.bouncycastle.pqc.crypto.xmss", + "org.bouncycastle.pqc.jcajce.interfaces", + "org.bouncycastle.pqc.jcajce.provider", + "org.bouncycastle.pqc.jcajce.provider.gmss", + "org.bouncycastle.pqc.jcajce.provider.lms", + "org.bouncycastle.pqc.jcajce.provider.mceliece", + "org.bouncycastle.pqc.jcajce.provider.newhope", + "org.bouncycastle.pqc.jcajce.provider.qtesla", + "org.bouncycastle.pqc.jcajce.provider.rainbow", + "org.bouncycastle.pqc.jcajce.provider.sphincs", + "org.bouncycastle.pqc.jcajce.provider.util", + "org.bouncycastle.pqc.jcajce.provider.xmss", + "org.bouncycastle.pqc.jcajce.spec", + "org.bouncycastle.pqc.math.linearalgebra", + "org.bouncycastle.util", + "org.bouncycastle.util.encoders", + "org.bouncycastle.util.io", + "org.bouncycastle.util.io.pem", + "org.bouncycastle.util.test", + "org.bouncycastle.x509", + "org.bouncycastle.x509.extension", + "org.bouncycastle.x509.util" + ], + "org.bouncycastle:bcprov-jdk18on": [ + "org.bouncycastle", + "org.bouncycastle.asn1", + "org.bouncycastle.asn1.anssi", + "org.bouncycastle.asn1.bc", + "org.bouncycastle.asn1.cryptlib", + "org.bouncycastle.asn1.cryptopro", + "org.bouncycastle.asn1.edec", + "org.bouncycastle.asn1.gm", + "org.bouncycastle.asn1.gnu", + "org.bouncycastle.asn1.iana", + "org.bouncycastle.asn1.isara", + "org.bouncycastle.asn1.iso", + "org.bouncycastle.asn1.kisa", + "org.bouncycastle.asn1.microsoft", + "org.bouncycastle.asn1.misc", + "org.bouncycastle.asn1.mozilla", + "org.bouncycastle.asn1.nist", + "org.bouncycastle.asn1.nsri", + "org.bouncycastle.asn1.ntt", + "org.bouncycastle.asn1.ocsp", + "org.bouncycastle.asn1.oiw", + "org.bouncycastle.asn1.pkcs", + "org.bouncycastle.asn1.rosstandart", + "org.bouncycastle.asn1.sec", + "org.bouncycastle.asn1.teletrust", + "org.bouncycastle.asn1.ua", + "org.bouncycastle.asn1.util", + "org.bouncycastle.asn1.x500", + "org.bouncycastle.asn1.x500.style", + "org.bouncycastle.asn1.x509", + "org.bouncycastle.asn1.x509.qualified", + "org.bouncycastle.asn1.x509.sigi", + "org.bouncycastle.asn1.x9", + "org.bouncycastle.crypto", + "org.bouncycastle.crypto.agreement", + "org.bouncycastle.crypto.agreement.jpake", + "org.bouncycastle.crypto.agreement.kdf", + "org.bouncycastle.crypto.agreement.srp", + "org.bouncycastle.crypto.commitments", + "org.bouncycastle.crypto.constraints", + "org.bouncycastle.crypto.digests", + "org.bouncycastle.crypto.ec", + "org.bouncycastle.crypto.encodings", + "org.bouncycastle.crypto.engines", + "org.bouncycastle.crypto.examples", + "org.bouncycastle.crypto.fpe", + "org.bouncycastle.crypto.generators", + "org.bouncycastle.crypto.hpke", + "org.bouncycastle.crypto.io", + "org.bouncycastle.crypto.kems", + "org.bouncycastle.crypto.macs", + "org.bouncycastle.crypto.modes", + "org.bouncycastle.crypto.modes.gcm", + "org.bouncycastle.crypto.modes.kgcm", + "org.bouncycastle.crypto.paddings", + "org.bouncycastle.crypto.params", + "org.bouncycastle.crypto.parsers", + "org.bouncycastle.crypto.prng", + "org.bouncycastle.crypto.prng.drbg", + "org.bouncycastle.crypto.signers", + "org.bouncycastle.crypto.util", + "org.bouncycastle.i18n", + "org.bouncycastle.i18n.filter", + "org.bouncycastle.iana", + "org.bouncycastle.internal.asn1.bsi", + "org.bouncycastle.internal.asn1.cms", + "org.bouncycastle.internal.asn1.eac", + "org.bouncycastle.internal.asn1.isismtt", + "org.bouncycastle.jcajce", + "org.bouncycastle.jcajce.interfaces", + "org.bouncycastle.jcajce.io", + "org.bouncycastle.jcajce.provider.asymmetric", + "org.bouncycastle.jcajce.provider.asymmetric.dh", + "org.bouncycastle.jcajce.provider.asymmetric.dsa", + "org.bouncycastle.jcajce.provider.asymmetric.dstu", + "org.bouncycastle.jcajce.provider.asymmetric.ec", + "org.bouncycastle.jcajce.provider.asymmetric.ecgost", + "org.bouncycastle.jcajce.provider.asymmetric.ecgost12", + "org.bouncycastle.jcajce.provider.asymmetric.edec", + "org.bouncycastle.jcajce.provider.asymmetric.elgamal", + "org.bouncycastle.jcajce.provider.asymmetric.gost", + "org.bouncycastle.jcajce.provider.asymmetric.ies", + "org.bouncycastle.jcajce.provider.asymmetric.rsa", + "org.bouncycastle.jcajce.provider.asymmetric.util", + "org.bouncycastle.jcajce.provider.asymmetric.x509", + "org.bouncycastle.jcajce.provider.config", + "org.bouncycastle.jcajce.provider.digest", + "org.bouncycastle.jcajce.provider.drbg", + "org.bouncycastle.jcajce.provider.keystore", + "org.bouncycastle.jcajce.provider.keystore.bc", + "org.bouncycastle.jcajce.provider.keystore.bcfks", + "org.bouncycastle.jcajce.provider.keystore.pkcs12", + "org.bouncycastle.jcajce.provider.keystore.util", + "org.bouncycastle.jcajce.provider.symmetric", + "org.bouncycastle.jcajce.provider.symmetric.util", + "org.bouncycastle.jcajce.provider.util", + "org.bouncycastle.jcajce.spec", + "org.bouncycastle.jcajce.util", + "org.bouncycastle.jce", + "org.bouncycastle.jce.exception", + "org.bouncycastle.jce.interfaces", + "org.bouncycastle.jce.netscape", + "org.bouncycastle.jce.provider", + "org.bouncycastle.jce.spec", + "org.bouncycastle.math", + "org.bouncycastle.math.ec", + "org.bouncycastle.math.ec.custom.djb", + "org.bouncycastle.math.ec.custom.gm", + "org.bouncycastle.math.ec.custom.sec", + "org.bouncycastle.math.ec.endo", + "org.bouncycastle.math.ec.rfc7748", + "org.bouncycastle.math.ec.rfc8032", + "org.bouncycastle.math.ec.tools", + "org.bouncycastle.math.field", + "org.bouncycastle.math.raw", + "org.bouncycastle.pqc.asn1", + "org.bouncycastle.pqc.crypto", + "org.bouncycastle.pqc.crypto.bike", + "org.bouncycastle.pqc.crypto.cmce", + "org.bouncycastle.pqc.crypto.crystals.dilithium", + "org.bouncycastle.pqc.crypto.crystals.kyber", + "org.bouncycastle.pqc.crypto.falcon", + "org.bouncycastle.pqc.crypto.frodo", + "org.bouncycastle.pqc.crypto.gemss", + "org.bouncycastle.pqc.crypto.hqc", + "org.bouncycastle.pqc.crypto.lms", + "org.bouncycastle.pqc.crypto.newhope", + "org.bouncycastle.pqc.crypto.ntru", + "org.bouncycastle.pqc.crypto.ntruprime", + "org.bouncycastle.pqc.crypto.picnic", + "org.bouncycastle.pqc.crypto.rainbow", + "org.bouncycastle.pqc.crypto.saber", + "org.bouncycastle.pqc.crypto.sphincs", + "org.bouncycastle.pqc.crypto.sphincsplus", + "org.bouncycastle.pqc.crypto.util", + "org.bouncycastle.pqc.crypto.xmss", + "org.bouncycastle.pqc.jcajce.interfaces", + "org.bouncycastle.pqc.jcajce.provider", + "org.bouncycastle.pqc.jcajce.provider.bike", + "org.bouncycastle.pqc.jcajce.provider.cmce", + "org.bouncycastle.pqc.jcajce.provider.dilithium", + "org.bouncycastle.pqc.jcajce.provider.falcon", + "org.bouncycastle.pqc.jcajce.provider.frodo", + "org.bouncycastle.pqc.jcajce.provider.gmss", + "org.bouncycastle.pqc.jcajce.provider.hqc", + "org.bouncycastle.pqc.jcajce.provider.kyber", + "org.bouncycastle.pqc.jcajce.provider.lms", + "org.bouncycastle.pqc.jcajce.provider.mceliece", + "org.bouncycastle.pqc.jcajce.provider.newhope", + "org.bouncycastle.pqc.jcajce.provider.ntru", + "org.bouncycastle.pqc.jcajce.provider.ntruprime", + "org.bouncycastle.pqc.jcajce.provider.picnic", + "org.bouncycastle.pqc.jcajce.provider.rainbow", + "org.bouncycastle.pqc.jcajce.provider.saber", + "org.bouncycastle.pqc.jcajce.provider.sphincs", + "org.bouncycastle.pqc.jcajce.provider.sphincsplus", + "org.bouncycastle.pqc.jcajce.provider.util", + "org.bouncycastle.pqc.jcajce.provider.xmss", + "org.bouncycastle.pqc.jcajce.spec", + "org.bouncycastle.pqc.legacy.crypto.gmss", + "org.bouncycastle.pqc.legacy.crypto.gmss.util", + "org.bouncycastle.pqc.legacy.crypto.mceliece", + "org.bouncycastle.pqc.legacy.crypto.qtesla", + "org.bouncycastle.pqc.legacy.crypto.rainbow", + "org.bouncycastle.pqc.legacy.crypto.rainbow.util", + "org.bouncycastle.pqc.legacy.math.linearalgebra", + "org.bouncycastle.pqc.math.ntru", + "org.bouncycastle.pqc.math.ntru.parameters", + "org.bouncycastle.util", + "org.bouncycastle.util.encoders", + "org.bouncycastle.util.io", + "org.bouncycastle.util.io.pem", + "org.bouncycastle.util.test", + "org.bouncycastle.x509", + "org.bouncycastle.x509.extension", + "org.bouncycastle.x509.util" + ], + "org.bouncycastle:bcutil-jdk18on": [ + "org.bouncycastle.asn1.bsi", + "org.bouncycastle.asn1.cmc", + "org.bouncycastle.asn1.cmp", + "org.bouncycastle.asn1.cms", + "org.bouncycastle.asn1.cms.ecc", + "org.bouncycastle.asn1.crmf", + "org.bouncycastle.asn1.dvcs", + "org.bouncycastle.asn1.eac", + "org.bouncycastle.asn1.esf", + "org.bouncycastle.asn1.ess", + "org.bouncycastle.asn1.est", + "org.bouncycastle.asn1.icao", + "org.bouncycastle.asn1.isismtt", + "org.bouncycastle.asn1.isismtt.ocsp", + "org.bouncycastle.asn1.isismtt.x509", + "org.bouncycastle.asn1.smime", + "org.bouncycastle.asn1.tsp", + "org.bouncycastle.oer", + "org.bouncycastle.oer.its", + "org.bouncycastle.oer.its.etsi102941", + "org.bouncycastle.oer.its.etsi102941.basetypes", + "org.bouncycastle.oer.its.etsi103097", + "org.bouncycastle.oer.its.etsi103097.extension", + "org.bouncycastle.oer.its.ieee1609dot2", + "org.bouncycastle.oer.its.ieee1609dot2.basetypes", + "org.bouncycastle.oer.its.ieee1609dot2dot1", + "org.bouncycastle.oer.its.template.etsi102941", + "org.bouncycastle.oer.its.template.etsi102941.basetypes", + "org.bouncycastle.oer.its.template.etsi103097", + "org.bouncycastle.oer.its.template.etsi103097.extension", + "org.bouncycastle.oer.its.template.ieee1609dot2", + "org.bouncycastle.oer.its.template.ieee1609dot2.basetypes", + "org.bouncycastle.oer.its.template.ieee1609dot2dot1" + ], + "org.checkerframework:checker-qual": [ + "org.checkerframework.checker.builder.qual", + "org.checkerframework.checker.calledmethods.qual", + "org.checkerframework.checker.compilermsgs.qual", + "org.checkerframework.checker.fenum.qual", + "org.checkerframework.checker.formatter.qual", + "org.checkerframework.checker.guieffect.qual", + "org.checkerframework.checker.i18n.qual", + "org.checkerframework.checker.i18nformatter.qual", + "org.checkerframework.checker.index.qual", + "org.checkerframework.checker.initialization.qual", + "org.checkerframework.checker.interning.qual", + "org.checkerframework.checker.lock.qual", + "org.checkerframework.checker.mustcall.qual", + "org.checkerframework.checker.nullness.qual", + "org.checkerframework.checker.optional.qual", + "org.checkerframework.checker.propkey.qual", + "org.checkerframework.checker.regex.qual", + "org.checkerframework.checker.signature.qual", + "org.checkerframework.checker.signedness.qual", + "org.checkerframework.checker.tainting.qual", + "org.checkerframework.checker.units.qual", + "org.checkerframework.common.aliasing.qual", + "org.checkerframework.common.initializedfields.qual", + "org.checkerframework.common.reflection.qual", + "org.checkerframework.common.returnsreceiver.qual", + "org.checkerframework.common.subtyping.qual", + "org.checkerframework.common.util.report.qual", + "org.checkerframework.common.value.qual", + "org.checkerframework.dataflow.qual", + "org.checkerframework.framework.qual" + ], + "org.codehaus.mojo:animal-sniffer-annotations": [ + "org.codehaus.mojo.animal_sniffer" + ], + "org.glassfish.hk2.external:aopalliance-repackaged": [ + "org.aopalliance.aop", + "org.aopalliance.instrument", + "org.aopalliance.intercept", + "org.aopalliance.reflect" + ], + "org.glassfish.hk2.external:jakarta.inject": [ + "javax.inject" + ], + "org.glassfish.hk2:hk2-api": [ + "org.glassfish.hk2.api", + "org.glassfish.hk2.api.messaging", + "org.glassfish.hk2.extension", + "org.glassfish.hk2.internal", + "org.glassfish.hk2.utilities", + "org.glassfish.hk2.utilities.binding", + "org.jvnet.hk2.annotations" + ], + "org.glassfish.hk2:hk2-locator": [ + "org.jvnet.hk2.external.generator", + "org.jvnet.hk2.external.runtime", + "org.jvnet.hk2.internal" + ], + "org.glassfish.hk2:hk2-utils": [ + "org.glassfish.hk2.utilities.cache", + "org.glassfish.hk2.utilities.cache.internal", + "org.glassfish.hk2.utilities.general", + "org.glassfish.hk2.utilities.general.internal", + "org.glassfish.hk2.utilities.reflection", + "org.glassfish.hk2.utilities.reflection.internal", + "org.jvnet.hk2.component" + ], + "org.glassfish.hk2:osgi-resource-locator": [ + "org.glassfish.hk2.osgiresourcelocator" + ], + "org.glassfish.jersey.connectors:jersey-apache-connector": [ + "org.glassfish.jersey.apache.connector" + ], + "org.glassfish.jersey.core:jersey-client": [ + "org.glassfish.jersey.client", + "org.glassfish.jersey.client.authentication", + "org.glassfish.jersey.client.filter", + "org.glassfish.jersey.client.inject", + "org.glassfish.jersey.client.internal", + "org.glassfish.jersey.client.internal.inject", + "org.glassfish.jersey.client.internal.jdkconnector", + "org.glassfish.jersey.client.internal.routing", + "org.glassfish.jersey.client.spi" + ], + "org.glassfish.jersey.core:jersey-common": [ + "org.glassfish.jersey", + "org.glassfish.jersey.internal", + "org.glassfish.jersey.internal.config", + "org.glassfish.jersey.internal.guava", + "org.glassfish.jersey.internal.inject", + "org.glassfish.jersey.internal.jsr166", + "org.glassfish.jersey.internal.l10n", + "org.glassfish.jersey.internal.routing", + "org.glassfish.jersey.internal.sonar", + "org.glassfish.jersey.internal.spi", + "org.glassfish.jersey.internal.util", + "org.glassfish.jersey.internal.util.collection", + "org.glassfish.jersey.logging", + "org.glassfish.jersey.message", + "org.glassfish.jersey.message.internal", + "org.glassfish.jersey.model", + "org.glassfish.jersey.model.internal", + "org.glassfish.jersey.model.internal.spi", + "org.glassfish.jersey.process", + "org.glassfish.jersey.process.internal", + "org.glassfish.jersey.spi", + "org.glassfish.jersey.uri", + "org.glassfish.jersey.uri.internal" + ], + "org.glassfish.jersey.inject:jersey-hk2": [ + "org.glassfish.jersey.inject.hk2" + ], + "org.hamcrest:hamcrest-core": [ + "org.hamcrest", + "org.hamcrest.core", + "org.hamcrest.internal" + ], + "org.javassist:javassist": [ + "javassist", + "javassist.bytecode", + "javassist.bytecode.analysis", + "javassist.bytecode.annotation", + "javassist.bytecode.stackmap", + "javassist.compiler", + "javassist.compiler.ast", + "javassist.convert", + "javassist.expr", + "javassist.runtime", + "javassist.scopedpool", + "javassist.tools", + "javassist.tools.reflect", + "javassist.tools.rmi", + "javassist.tools.web", + "javassist.util", + "javassist.util.proxy" + ], + "org.jboss.marshalling:jboss-marshalling": [ + "org.jboss.marshalling", + "org.jboss.marshalling._private", + "org.jboss.marshalling.cloner", + "org.jboss.marshalling.reflect", + "org.jboss.marshalling.util" + ], + "org.jboss.marshalling:jboss-marshalling-river": [ + "org.jboss.marshalling.river" + ], + "org.jetbrains:annotations": [ + "org.intellij.lang.annotations", + "org.jetbrains.annotations" + ], + "org.jodd:jodd-bean": [ + "jodd.bean", + "jodd.introspector", + "jodd.typeconverter", + "jodd.typeconverter.impl" + ], + "org.jodd:jodd-core": [ + "jodd", + "jodd.buffer", + "jodd.cache", + "jodd.chalk", + "jodd.cli", + "jodd.core", + "jodd.exception", + "jodd.inex", + "jodd.io", + "jodd.io.findfile", + "jodd.io.upload", + "jodd.io.upload.impl", + "jodd.io.watch", + "jodd.mutable", + "jodd.net", + "jodd.system", + "jodd.template", + "jodd.time", + "jodd.util", + "jodd.util.annotation", + "jodd.util.cl", + "jodd.util.collection", + "jodd.util.concurrent" + ], + "org.json:json": [ + "org.json" + ], + "org.luaj:luaj-jse": [ + "", + "org.luaj.vm2", + "org.luaj.vm2.ast", + "org.luaj.vm2.compiler", + "org.luaj.vm2.lib", + "org.luaj.vm2.lib.jse", + "org.luaj.vm2.luajc", + "org.luaj.vm2.parser", + "org.luaj.vm2.script", + "org.luaj.vm2.server" + ], + "org.mockito:mockito-core": [ + "org.mockito", + "org.mockito.codegen", + "org.mockito.configuration", + "org.mockito.creation.instance", + "org.mockito.exceptions.base", + "org.mockito.exceptions.misusing", + "org.mockito.exceptions.stacktrace", + "org.mockito.exceptions.verification", + "org.mockito.exceptions.verification.junit", + "org.mockito.exceptions.verification.opentest4j", + "org.mockito.hamcrest", + "org.mockito.internal", + "org.mockito.internal.configuration", + "org.mockito.internal.configuration.injection", + "org.mockito.internal.configuration.injection.filter", + "org.mockito.internal.configuration.injection.scanner", + "org.mockito.internal.configuration.plugins", + "org.mockito.internal.creation", + "org.mockito.internal.creation.bytebuddy", + "org.mockito.internal.creation.instance", + "org.mockito.internal.creation.proxy", + "org.mockito.internal.creation.settings", + "org.mockito.internal.creation.util", + "org.mockito.internal.debugging", + "org.mockito.internal.exceptions", + "org.mockito.internal.exceptions.stacktrace", + "org.mockito.internal.exceptions.util", + "org.mockito.internal.framework", + "org.mockito.internal.hamcrest", + "org.mockito.internal.handler", + "org.mockito.internal.invocation", + "org.mockito.internal.invocation.finder", + "org.mockito.internal.invocation.mockref", + "org.mockito.internal.junit", + "org.mockito.internal.listeners", + "org.mockito.internal.matchers", + "org.mockito.internal.matchers.apachecommons", + "org.mockito.internal.matchers.text", + "org.mockito.internal.progress", + "org.mockito.internal.reporting", + "org.mockito.internal.runners", + "org.mockito.internal.runners.util", + "org.mockito.internal.session", + "org.mockito.internal.stubbing", + "org.mockito.internal.stubbing.answers", + "org.mockito.internal.stubbing.defaultanswers", + "org.mockito.internal.util", + "org.mockito.internal.util.collections", + "org.mockito.internal.util.concurrent", + "org.mockito.internal.util.io", + "org.mockito.internal.util.reflection", + "org.mockito.internal.verification", + "org.mockito.internal.verification.api", + "org.mockito.internal.verification.argumentmatching", + "org.mockito.internal.verification.checkers", + "org.mockito.invocation", + "org.mockito.junit", + "org.mockito.listeners", + "org.mockito.mock", + "org.mockito.plugins", + "org.mockito.quality", + "org.mockito.session", + "org.mockito.stubbing", + "org.mockito.verification" + ], + "org.objenesis:objenesis": [ + "org.objenesis", + "org.objenesis.instantiator", + "org.objenesis.instantiator.android", + "org.objenesis.instantiator.annotations", + "org.objenesis.instantiator.basic", + "org.objenesis.instantiator.gcj", + "org.objenesis.instantiator.perc", + "org.objenesis.instantiator.sun", + "org.objenesis.instantiator.util", + "org.objenesis.strategy" + ], + "org.openjdk.jmh:jmh-core": [ + "org.openjdk.jmh", + "org.openjdk.jmh.annotations", + "org.openjdk.jmh.generators.core", + "org.openjdk.jmh.infra", + "org.openjdk.jmh.profile", + "org.openjdk.jmh.results", + "org.openjdk.jmh.results.format", + "org.openjdk.jmh.runner", + "org.openjdk.jmh.runner.format", + "org.openjdk.jmh.runner.link", + "org.openjdk.jmh.runner.options", + "org.openjdk.jmh.util", + "org.openjdk.jmh.util.lines" + ], + "org.openjdk.jmh:jmh-generator-annprocess": [ + "org.openjdk.jmh.generators", + "org.openjdk.jmh.generators.annotations" + ], + "org.ow2.asm:asm": [ + "org.objectweb.asm", + "org.objectweb.asm.signature" + ], + "org.ow2.asm:asm-analysis": [ + "org.objectweb.asm.tree.analysis" + ], + "org.ow2.asm:asm-commons": [ + "org.objectweb.asm.commons" + ], + "org.ow2.asm:asm-tree": [ + "org.objectweb.asm.tree" + ], + "org.ow2.asm:asm-util": [ + "org.objectweb.asm.util" + ], + "org.pcollections:pcollections": [ + "org.pcollections" + ], + "org.projectlombok:lombok": [ + "lombok", + "lombok.delombok.ant", + "lombok.experimental", + "lombok.extern.apachecommons", + "lombok.extern.flogger", + "lombok.extern.jackson", + "lombok.extern.java", + "lombok.extern.jbosslog", + "lombok.extern.log4j", + "lombok.extern.slf4j", + "lombok.javac.apt", + "lombok.launch" + ], + "org.reactivestreams:reactive-streams": [ + "org.reactivestreams" + ], + "org.redisson:redisson": [ + "org.redisson", + "org.redisson.api", + "org.redisson.api.annotation", + "org.redisson.api.condition", + "org.redisson.api.executor", + "org.redisson.api.geo", + "org.redisson.api.listener", + "org.redisson.api.map", + "org.redisson.api.map.event", + "org.redisson.api.mapreduce", + "org.redisson.api.queue", + "org.redisson.api.redisnode", + "org.redisson.api.search", + "org.redisson.api.search.aggregate", + "org.redisson.api.search.index", + "org.redisson.api.search.query", + "org.redisson.api.stream", + "org.redisson.cache", + "org.redisson.client", + "org.redisson.client.codec", + "org.redisson.client.handler", + "org.redisson.client.protocol", + "org.redisson.client.protocol.convertor", + "org.redisson.client.protocol.decoder", + "org.redisson.client.protocol.pubsub", + "org.redisson.cluster", + "org.redisson.codec", + "org.redisson.command", + "org.redisson.config", + "org.redisson.connection", + "org.redisson.connection.balancer", + "org.redisson.connection.decoder", + "org.redisson.connection.pool", + "org.redisson.eviction", + "org.redisson.executor", + "org.redisson.executor.params", + "org.redisson.iterator", + "org.redisson.jcache", + "org.redisson.jcache.bean", + "org.redisson.jcache.configuration", + "org.redisson.liveobject", + "org.redisson.liveobject.condition", + "org.redisson.liveobject.core", + "org.redisson.liveobject.misc", + "org.redisson.liveobject.resolver", + "org.redisson.mapreduce", + "org.redisson.misc", + "org.redisson.pubsub", + "org.redisson.reactive", + "org.redisson.redisnode", + "org.redisson.remote", + "org.redisson.rx", + "org.redisson.spring.cache", + "org.redisson.spring.misc", + "org.redisson.spring.session", + "org.redisson.spring.session.config", + "org.redisson.spring.support", + "org.redisson.spring.transaction", + "org.redisson.transaction", + "org.redisson.transaction.operation", + "org.redisson.transaction.operation.bucket", + "org.redisson.transaction.operation.map", + "org.redisson.transaction.operation.set" + ], + "org.reflections:reflections": [ + "org.reflections", + "org.reflections.scanners", + "org.reflections.serializers", + "org.reflections.util", + "org.reflections.vfs" + ], + "org.slf4j:jcl-over-slf4j": [ + "org.apache.commons.logging", + "org.apache.commons.logging.impl" + ], + "org.slf4j:slf4j-api": [ + "org.slf4j", + "org.slf4j.event", + "org.slf4j.helpers", + "org.slf4j.spi" + ], + "org.slf4j:slf4j-simple": [ + "org.slf4j.simple" + ], + "org.threeten:threetenbp": [ + "org.threeten.bp", + "org.threeten.bp.chrono", + "org.threeten.bp.format", + "org.threeten.bp.jdk8", + "org.threeten.bp.temporal", + "org.threeten.bp.zone" + ], + "org.xerial:sqlite-jdbc": [ + "org.sqlite", + "org.sqlite.core", + "org.sqlite.date", + "org.sqlite.javax", + "org.sqlite.jdbc3", + "org.sqlite.jdbc4", + "org.sqlite.util" + ], + "org.yaml:snakeyaml": [ + "org.yaml.snakeyaml", + "org.yaml.snakeyaml.comments", + "org.yaml.snakeyaml.composer", + "org.yaml.snakeyaml.constructor", + "org.yaml.snakeyaml.emitter", + "org.yaml.snakeyaml.env", + "org.yaml.snakeyaml.error", + "org.yaml.snakeyaml.events", + "org.yaml.snakeyaml.extensions.compactnotation", + "org.yaml.snakeyaml.external.biz.base64Coder", + "org.yaml.snakeyaml.external.com.google.gdata.util.common.base", + "org.yaml.snakeyaml.inspector", + "org.yaml.snakeyaml.internal", + "org.yaml.snakeyaml.introspector", + "org.yaml.snakeyaml.nodes", + "org.yaml.snakeyaml.parser", + "org.yaml.snakeyaml.reader", + "org.yaml.snakeyaml.representer", + "org.yaml.snakeyaml.resolver", + "org.yaml.snakeyaml.scanner", + "org.yaml.snakeyaml.serializer", + "org.yaml.snakeyaml.tokens", + "org.yaml.snakeyaml.util" + ], + "redis.clients:jedis": [ + "redis.clients.jedis", + "redis.clients.jedis.args", + "redis.clients.jedis.bloom", + "redis.clients.jedis.bloom.commands", + "redis.clients.jedis.commands", + "redis.clients.jedis.exceptions", + "redis.clients.jedis.executors", + "redis.clients.jedis.gears", + "redis.clients.jedis.gears.resps", + "redis.clients.jedis.graph", + "redis.clients.jedis.graph.entities", + "redis.clients.jedis.json", + "redis.clients.jedis.json.commands", + "redis.clients.jedis.mcf", + "redis.clients.jedis.params", + "redis.clients.jedis.providers", + "redis.clients.jedis.resps", + "redis.clients.jedis.search", + "redis.clients.jedis.search.aggr", + "redis.clients.jedis.search.querybuilder", + "redis.clients.jedis.search.schemafields", + "redis.clients.jedis.timeseries", + "redis.clients.jedis.util" + ], + "software.amazon.ion:ion-java": [ + "software.amazon.ion", + "software.amazon.ion.apps", + "software.amazon.ion.facet", + "software.amazon.ion.impl", + "software.amazon.ion.impl.bin", + "software.amazon.ion.impl.lite", + "software.amazon.ion.system", + "software.amazon.ion.util" + ] + }, + "repositories": { + "https://repo.maven.apache.org/maven2/": [ + "aopalliance:aopalliance", + "com.amazonaws:aws-java-sdk-core", + "com.amazonaws:aws-java-sdk-kms", + "com.amazonaws:aws-java-sdk-s3", + "com.amazonaws:aws-java-sdk-secretsmanager", + "com.amazonaws:jmespath-java", + "com.esotericsoftware:kryo", + "com.esotericsoftware:minlog", + "com.esotericsoftware:reflectasm", + "com.fasterxml.jackson.core:jackson-annotations", + "com.fasterxml.jackson.core:jackson-core", + "com.fasterxml.jackson.core:jackson-databind", + "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor", + "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml", + "com.fasterxml.jackson.jaxrs:jackson-jaxrs-base", + "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider", + "com.fasterxml.jackson.module:jackson-module-jaxb-annotations", + "com.github.ben-manes.caffeine:caffeine", + "com.github.docker-java:docker-java", + "com.github.docker-java:docker-java-api", + "com.github.docker-java:docker-java-core", + "com.github.docker-java:docker-java-transport", + "com.github.docker-java:docker-java-transport-jersey", + "com.github.docker-java:docker-java-transport-netty", + "com.github.fppt:jedis-mock", + "com.github.jnr:jffi", + "com.github.jnr:jffi:jar:native", + "com.github.jnr:jnr-a64asm", + "com.github.jnr:jnr-constants", + "com.github.jnr:jnr-ffi", + "com.github.jnr:jnr-posix", + "com.github.jnr:jnr-x86asm", + "com.github.kevinstern:software-and-algorithms", + "com.github.luben:zstd-jni", + "com.github.oshi:oshi-core", + "com.github.pcj:google-options", + "com.github.serceman:jnr-fuse", + "com.google.android:annotations", + "com.google.api.grpc:proto-google-common-protos", + "com.google.auth:google-auth-library-credentials", + "com.google.auth:google-auth-library-oauth2-http", + "com.google.auto.service:auto-service-annotations", + "com.google.auto.value:auto-value-annotations", + "com.google.auto:auto-common", + "com.google.code.findbugs:jsr305", + "com.google.code.gson:gson", + "com.google.errorprone:error_prone_annotation", + "com.google.errorprone:error_prone_annotations", + "com.google.errorprone:error_prone_check_api", + "com.google.errorprone:error_prone_core", + "com.google.errorprone:error_prone_type_annotations", + "com.google.guava:failureaccess", + "com.google.guava:guava", + "com.google.guava:guava-testlib", + "com.google.guava:listenablefuture", + "com.google.http-client:google-http-client", + "com.google.http-client:google-http-client-gson", + "com.google.inject:guice", + "com.google.j2objc:j2objc-annotations", + "com.google.jimfs:jimfs", + "com.google.protobuf:protobuf-java", + "com.google.protobuf:protobuf-java-util", + "com.google.truth:truth", + "com.googlecode.json-simple:json-simple", + "com.jayway.jsonpath:json-path", + "com.kohlschutter.junixsocket:junixsocket-common", + "com.kohlschutter.junixsocket:junixsocket-native-common", + "com.sun.activation:jakarta.activation", + "commons-codec:commons-codec", + "commons-io:commons-io", + "commons-logging:commons-logging", + "io.github.eisop:dataflow-errorprone", + "io.github.java-diff-utils:java-diff-utils", + "io.grpc:grpc-api", + "io.grpc:grpc-auth", + "io.grpc:grpc-context", + "io.grpc:grpc-core", + "io.grpc:grpc-inprocess", + "io.grpc:grpc-netty", + "io.grpc:grpc-netty-shaded", + "io.grpc:grpc-protobuf", + "io.grpc:grpc-protobuf-lite", + "io.grpc:grpc-services", + "io.grpc:grpc-stub", + "io.grpc:grpc-testing", + "io.grpc:grpc-util", + "io.netty:netty-buffer", + "io.netty:netty-codec", + "io.netty:netty-codec-dns", + "io.netty:netty-codec-http", + "io.netty:netty-codec-http2", + "io.netty:netty-codec-socks", + "io.netty:netty-common", + "io.netty:netty-handler", + "io.netty:netty-handler-proxy", + "io.netty:netty-resolver", + "io.netty:netty-resolver-dns", + "io.netty:netty-transport", + "io.netty:netty-transport-classes-epoll", + "io.netty:netty-transport-classes-kqueue", + "io.netty:netty-transport-native-epoll", + "io.netty:netty-transport-native-epoll:jar:linux-x86_64", + "io.netty:netty-transport-native-kqueue", + "io.netty:netty-transport-native-kqueue:jar:osx-x86_64", + "io.netty:netty-transport-native-unix-common", + "io.opencensus:opencensus-api", + "io.opencensus:opencensus-contrib-http-util", + "io.perfmark:perfmark-api", + "io.projectreactor:reactor-core", + "io.prometheus:simpleclient", + "io.prometheus:simpleclient_common", + "io.prometheus:simpleclient_hotspot", + "io.prometheus:simpleclient_httpserver", + "io.prometheus:simpleclient_tracer_common", + "io.prometheus:simpleclient_tracer_otel", + "io.prometheus:simpleclient_tracer_otel_agent", + "io.reactivex.rxjava3:rxjava", + "jakarta.activation:jakarta.activation-api", + "jakarta.annotation:jakarta.annotation-api", + "jakarta.ws.rs:jakarta.ws.rs-api", + "jakarta.xml.bind:jakarta.xml.bind-api", + "javax.annotation:javax.annotation-api", + "javax.cache:cache-api", + "javax.inject:javax.inject", + "joda-time:joda-time", + "junit:junit", + "me.dinowernli:java-grpc-prometheus", + "net.bytebuddy:byte-buddy", + "net.bytebuddy:byte-buddy-agent", + "net.java.dev.jna:jna", + "net.java.dev.jna:jna-platform", + "net.javacrumbs.future-converter:future-converter-common", + "net.javacrumbs.future-converter:future-converter-guava-common", + "net.javacrumbs.future-converter:future-converter-java8-common", + "net.javacrumbs.future-converter:future-converter-java8-guava", + "net.jcip:jcip-annotations", + "net.minidev:accessors-smart", + "net.minidev:json-smart", + "net.sf.jopt-simple:jopt-simple", + "org.apache.commons:commons-compress", + "org.apache.commons:commons-lang3", + "org.apache.commons:commons-math3", + "org.apache.commons:commons-pool2", + "org.apache.httpcomponents:httpclient", + "org.apache.httpcomponents:httpcore", + "org.apache.tomcat:annotations-api", + "org.bouncycastle:bcpkix-jdk18on", + "org.bouncycastle:bcprov-jdk15on", + "org.bouncycastle:bcprov-jdk18on", + "org.bouncycastle:bcutil-jdk18on", + "org.checkerframework:checker-qual", + "org.codehaus.mojo:animal-sniffer-annotations", + "org.glassfish.hk2.external:aopalliance-repackaged", + "org.glassfish.hk2.external:jakarta.inject", + "org.glassfish.hk2:hk2-api", + "org.glassfish.hk2:hk2-locator", + "org.glassfish.hk2:hk2-utils", + "org.glassfish.hk2:osgi-resource-locator", + "org.glassfish.jersey.connectors:jersey-apache-connector", + "org.glassfish.jersey.core:jersey-client", + "org.glassfish.jersey.core:jersey-common", + "org.glassfish.jersey.inject:jersey-hk2", + "org.hamcrest:hamcrest-core", + "org.javassist:javassist", + "org.jboss.marshalling:jboss-marshalling", + "org.jboss.marshalling:jboss-marshalling-river", + "org.jetbrains:annotations", + "org.jodd:jodd-bean", + "org.jodd:jodd-core", + "org.json:json", + "org.luaj:luaj-jse", + "org.mockito:mockito-core", + "org.objenesis:objenesis", + "org.openjdk.jmh:jmh-core", + "org.openjdk.jmh:jmh-generator-annprocess", + "org.ow2.asm:asm", + "org.ow2.asm:asm-analysis", + "org.ow2.asm:asm-commons", + "org.ow2.asm:asm-tree", + "org.ow2.asm:asm-util", + "org.pcollections:pcollections", + "org.projectlombok:lombok", + "org.reactivestreams:reactive-streams", + "org.redisson:redisson", + "org.reflections:reflections", + "org.slf4j:jcl-over-slf4j", + "org.slf4j:slf4j-api", + "org.slf4j:slf4j-simple", + "org.threeten:threetenbp", + "org.xerial:sqlite-jdbc", + "org.yaml:snakeyaml", + "redis.clients:jedis", + "software.amazon.ion:ion-java" + ], + "https://repo1.maven.org/maven2/": [ + "aopalliance:aopalliance", + "com.amazonaws:aws-java-sdk-core", + "com.amazonaws:aws-java-sdk-kms", + "com.amazonaws:aws-java-sdk-s3", + "com.amazonaws:aws-java-sdk-secretsmanager", + "com.amazonaws:jmespath-java", + "com.esotericsoftware:kryo", + "com.esotericsoftware:minlog", + "com.esotericsoftware:reflectasm", + "com.fasterxml.jackson.core:jackson-annotations", + "com.fasterxml.jackson.core:jackson-core", + "com.fasterxml.jackson.core:jackson-databind", + "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor", + "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml", + "com.fasterxml.jackson.jaxrs:jackson-jaxrs-base", + "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider", + "com.fasterxml.jackson.module:jackson-module-jaxb-annotations", + "com.github.ben-manes.caffeine:caffeine", + "com.github.docker-java:docker-java", + "com.github.docker-java:docker-java-api", + "com.github.docker-java:docker-java-core", + "com.github.docker-java:docker-java-transport", + "com.github.docker-java:docker-java-transport-jersey", + "com.github.docker-java:docker-java-transport-netty", + "com.github.fppt:jedis-mock", + "com.github.jnr:jffi", + "com.github.jnr:jffi:jar:native", + "com.github.jnr:jnr-a64asm", + "com.github.jnr:jnr-constants", + "com.github.jnr:jnr-ffi", + "com.github.jnr:jnr-posix", + "com.github.jnr:jnr-x86asm", + "com.github.kevinstern:software-and-algorithms", + "com.github.luben:zstd-jni", + "com.github.oshi:oshi-core", + "com.github.pcj:google-options", + "com.github.serceman:jnr-fuse", + "com.google.android:annotations", + "com.google.api.grpc:proto-google-common-protos", + "com.google.auth:google-auth-library-credentials", + "com.google.auth:google-auth-library-oauth2-http", + "com.google.auto.service:auto-service-annotations", + "com.google.auto.value:auto-value-annotations", + "com.google.auto:auto-common", + "com.google.code.findbugs:jsr305", + "com.google.code.gson:gson", + "com.google.errorprone:error_prone_annotation", + "com.google.errorprone:error_prone_annotations", + "com.google.errorprone:error_prone_check_api", + "com.google.errorprone:error_prone_core", + "com.google.errorprone:error_prone_type_annotations", + "com.google.guava:failureaccess", + "com.google.guava:guava", + "com.google.guava:guava-testlib", + "com.google.guava:listenablefuture", + "com.google.http-client:google-http-client", + "com.google.http-client:google-http-client-gson", + "com.google.inject:guice", + "com.google.j2objc:j2objc-annotations", + "com.google.jimfs:jimfs", + "com.google.protobuf:protobuf-java", + "com.google.protobuf:protobuf-java-util", + "com.google.truth:truth", + "com.googlecode.json-simple:json-simple", + "com.jayway.jsonpath:json-path", + "com.kohlschutter.junixsocket:junixsocket-common", + "com.kohlschutter.junixsocket:junixsocket-native-common", + "com.sun.activation:jakarta.activation", + "commons-codec:commons-codec", + "commons-io:commons-io", + "commons-logging:commons-logging", + "io.github.eisop:dataflow-errorprone", + "io.github.java-diff-utils:java-diff-utils", + "io.grpc:grpc-api", + "io.grpc:grpc-auth", + "io.grpc:grpc-context", + "io.grpc:grpc-core", + "io.grpc:grpc-inprocess", + "io.grpc:grpc-netty", + "io.grpc:grpc-netty-shaded", + "io.grpc:grpc-protobuf", + "io.grpc:grpc-protobuf-lite", + "io.grpc:grpc-services", + "io.grpc:grpc-stub", + "io.grpc:grpc-testing", + "io.grpc:grpc-util", + "io.netty:netty-buffer", + "io.netty:netty-codec", + "io.netty:netty-codec-dns", + "io.netty:netty-codec-http", + "io.netty:netty-codec-http2", + "io.netty:netty-codec-socks", + "io.netty:netty-common", + "io.netty:netty-handler", + "io.netty:netty-handler-proxy", + "io.netty:netty-resolver", + "io.netty:netty-resolver-dns", + "io.netty:netty-transport", + "io.netty:netty-transport-classes-epoll", + "io.netty:netty-transport-classes-kqueue", + "io.netty:netty-transport-native-epoll", + "io.netty:netty-transport-native-epoll:jar:linux-x86_64", + "io.netty:netty-transport-native-kqueue", + "io.netty:netty-transport-native-kqueue:jar:osx-x86_64", + "io.netty:netty-transport-native-unix-common", + "io.opencensus:opencensus-api", + "io.opencensus:opencensus-contrib-http-util", + "io.perfmark:perfmark-api", + "io.projectreactor:reactor-core", + "io.prometheus:simpleclient", + "io.prometheus:simpleclient_common", + "io.prometheus:simpleclient_hotspot", + "io.prometheus:simpleclient_httpserver", + "io.prometheus:simpleclient_tracer_common", + "io.prometheus:simpleclient_tracer_otel", + "io.prometheus:simpleclient_tracer_otel_agent", + "io.reactivex.rxjava3:rxjava", + "jakarta.activation:jakarta.activation-api", + "jakarta.annotation:jakarta.annotation-api", + "jakarta.ws.rs:jakarta.ws.rs-api", + "jakarta.xml.bind:jakarta.xml.bind-api", + "javax.annotation:javax.annotation-api", + "javax.cache:cache-api", + "javax.inject:javax.inject", + "joda-time:joda-time", + "junit:junit", + "me.dinowernli:java-grpc-prometheus", + "net.bytebuddy:byte-buddy", + "net.bytebuddy:byte-buddy-agent", + "net.java.dev.jna:jna", + "net.java.dev.jna:jna-platform", + "net.javacrumbs.future-converter:future-converter-common", + "net.javacrumbs.future-converter:future-converter-guava-common", + "net.javacrumbs.future-converter:future-converter-java8-common", + "net.javacrumbs.future-converter:future-converter-java8-guava", + "net.jcip:jcip-annotations", + "net.minidev:accessors-smart", + "net.minidev:json-smart", + "net.sf.jopt-simple:jopt-simple", + "org.apache.commons:commons-compress", + "org.apache.commons:commons-lang3", + "org.apache.commons:commons-math3", + "org.apache.commons:commons-pool2", + "org.apache.httpcomponents:httpclient", + "org.apache.httpcomponents:httpcore", + "org.apache.tomcat:annotations-api", + "org.bouncycastle:bcpkix-jdk18on", + "org.bouncycastle:bcprov-jdk15on", + "org.bouncycastle:bcprov-jdk18on", + "org.bouncycastle:bcutil-jdk18on", + "org.checkerframework:checker-qual", + "org.codehaus.mojo:animal-sniffer-annotations", + "org.glassfish.hk2.external:aopalliance-repackaged", + "org.glassfish.hk2.external:jakarta.inject", + "org.glassfish.hk2:hk2-api", + "org.glassfish.hk2:hk2-locator", + "org.glassfish.hk2:hk2-utils", + "org.glassfish.hk2:osgi-resource-locator", + "org.glassfish.jersey.connectors:jersey-apache-connector", + "org.glassfish.jersey.core:jersey-client", + "org.glassfish.jersey.core:jersey-common", + "org.glassfish.jersey.inject:jersey-hk2", + "org.hamcrest:hamcrest-core", + "org.javassist:javassist", + "org.jboss.marshalling:jboss-marshalling", + "org.jboss.marshalling:jboss-marshalling-river", + "org.jetbrains:annotations", + "org.jodd:jodd-bean", + "org.jodd:jodd-core", + "org.json:json", + "org.luaj:luaj-jse", + "org.mockito:mockito-core", + "org.objenesis:objenesis", + "org.openjdk.jmh:jmh-core", + "org.openjdk.jmh:jmh-generator-annprocess", + "org.ow2.asm:asm", + "org.ow2.asm:asm-analysis", + "org.ow2.asm:asm-commons", + "org.ow2.asm:asm-tree", + "org.ow2.asm:asm-util", + "org.pcollections:pcollections", + "org.projectlombok:lombok", + "org.reactivestreams:reactive-streams", + "org.redisson:redisson", + "org.reflections:reflections", + "org.slf4j:jcl-over-slf4j", + "org.slf4j:slf4j-api", + "org.slf4j:slf4j-simple", + "org.threeten:threetenbp", + "org.xerial:sqlite-jdbc", + "org.yaml:snakeyaml", + "redis.clients:jedis", + "software.amazon.ion:ion-java" + ] + }, + "version": "2" +} From 2b3f0b2d98ebc5f49e2587df65dfe44263cc2ea9 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Sun, 31 Mar 2024 22:59:59 -0700 Subject: [PATCH 305/311] build: leave a comment about remoteapis --- MODULE.bazel | 1 + 1 file changed, 1 insertion(+) diff --git a/MODULE.bazel b/MODULE.bazel index 20f3ed1912..5365768c05 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -33,6 +33,7 @@ bazel_dep( dev_dependency = True, ) +# TODO: remove this after https://github.com/bazelbuild/remote-apis/pull/293 is merged bazel_dep(name = "remoteapis", version = "eb433accc6a666b782ea4b787eb598e5c3d27c93") archive_override( module_name = "remoteapis", From 91a7a7eccbad1a7e9fd39ee39a5adb67708d5b86 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Sun, 31 Mar 2024 23:03:07 -0700 Subject: [PATCH 306/311] fixup! chore: rewrite @bazel_remote_apis to @remoteapis --- src/main/java/build/buildfarm/common/services/BUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/build/buildfarm/common/services/BUILD b/src/main/java/build/buildfarm/common/services/BUILD index 59f962b320..d7afcd565a 100644 --- a/src/main/java/build/buildfarm/common/services/BUILD +++ b/src/main/java/build/buildfarm/common/services/BUILD @@ -14,7 +14,6 @@ java_library( "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", "//third_party/remote-apis:build_bazel_remote_asset_v1_remote_asset_java_grpc", "//third_party/remote-apis:build_bazel_remote_execution_v2_remote_execution_java_grpc", - "@remoteapis//build/bazel/remote/asset/v1:remote_asset_java_proto", "@com_google_googleapis//google/bytestream:bytestream_java_grpc", "@com_google_googleapis//google/bytestream:bytestream_java_proto", "@com_google_googleapis//google/devtools/build/v1:build_java_proto", @@ -30,6 +29,7 @@ java_library( "@maven//:io_grpc_grpc_stub", "@maven//:io_prometheus_simpleclient", "@maven//:org_projectlombok_lombok", + "@remoteapis//build/bazel/remote/asset/v1:remote_asset_java_proto", "@remoteapis//build/bazel/semver:semver_java_proto", ], ) From 910714ba0cfc4c44df0e94913033cac77daed8f0 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Tue, 2 Apr 2024 22:18:49 -0700 Subject: [PATCH 307/311] fixup! build: BUILD --- MODULE.bazel | 1 + extensions.bzl | 6 ++++++ src/main/java/build/buildfarm/server/BUILD | 2 +- src/main/java/build/buildfarm/worker/shard/BUILD | 2 +- 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 5365768c05..9750240e48 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -194,6 +194,7 @@ build_deps = use_extension("//:extensions.bzl", "build_deps") use_repo( build_deps, "bazel", + "io_grpc_grpc_proto", "opentelemetry", "skip_sleep", "tini", diff --git a/extensions.bzl b/extensions.bzl index 95a782eedf..e355bc6f76 100644 --- a/extensions.bzl +++ b/extensions.bzl @@ -59,6 +59,12 @@ def _buildfarm_extension_impl(_ctx): "https://github.com/grpc/grpc/archive/v1.46.0.tar.gz", ], ) + http_archive( + name = "io_grpc_grpc_proto", + sha256 = "729ac127a003836d539ed9da72a21e094aac4c4609e0481d6fc9e28a844e11af", + strip_prefix = "grpc-proto-4f245d272a28a680606c0739753506880cf33b5f", + urls = ["https://github.com/grpc/grpc-proto/archive/4f245d272a28a680606c0739753506880cf33b5f.zip"], + ) build_deps = module_extension( implementation = _buildfarm_extension_impl, diff --git a/src/main/java/build/buildfarm/server/BUILD b/src/main/java/build/buildfarm/server/BUILD index 9d332e9ebc..ba31d7a875 100644 --- a/src/main/java/build/buildfarm/server/BUILD +++ b/src/main/java/build/buildfarm/server/BUILD @@ -16,7 +16,7 @@ java_library( "//src/main/java/build/buildfarm/metrics/prometheus", "//src/main/java/build/buildfarm/server/services", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@@grpc-java~1.62.2~grpc_java_repositories_extension~io_grpc_grpc_proto//:health_java_proto", + "@io_grpc_grpc_proto//:health_java_proto", "@maven//:com_github_pcj_google_options", "@maven//:com_google_api_grpc_proto_google_common_protos", "@maven//:com_google_guava_guava", diff --git a/src/main/java/build/buildfarm/worker/shard/BUILD b/src/main/java/build/buildfarm/worker/shard/BUILD index c72d35245d..0f69b6fdff 100644 --- a/src/main/java/build/buildfarm/worker/shard/BUILD +++ b/src/main/java/build/buildfarm/worker/shard/BUILD @@ -21,8 +21,8 @@ java_library( "//src/main/java/build/buildfarm/worker/resources", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_grpc", "//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto", - "@@grpc-java~1.62.2~grpc_java_repositories_extension~io_grpc_grpc_proto//:health_java_proto", "@com_google_googleapis//google/rpc:rpc_java_proto", + "@io_grpc_grpc_proto//:health_java_proto", "@maven//:com_github_ben_manes_caffeine_caffeine", "@maven//:com_github_pcj_google_options", "@maven//:com_google_code_findbugs_jsr305", From 27e8d2edefc8ec29b76c6b4894ffdf8ba00e5715 Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Tue, 2 Apr 2024 22:19:34 -0700 Subject: [PATCH 308/311] build: don't make buildifier a dev dependency Since we declare a buildifier target in //BUILD, we can't make this a dev dependency. --- MODULE.bazel | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 9750240e48..094d71aa1a 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -7,6 +7,7 @@ module( bazel_dep(name = "bazel_skylib", version = "1.5.0") bazel_dep(name = "blake3", version = "1.3.3.bcr.1") +bazel_dep(name = "buildifier_prebuilt", version = "6.4.0") bazel_dep(name = "gazelle", version = "0.35.0", repo_name = "bazel_gazelle") bazel_dep(name = "grpc-java", version = "1.62.2") bazel_dep(name = "googleapis", version = "0.0.0-20240326-1c8d509c5", repo_name = "com_google_googleapis") @@ -27,11 +28,6 @@ bazel_dep( version = "1.16.0", dev_dependency = True, ) -bazel_dep( - name = "buildifier_prebuilt", - version = "6.4.0", - dev_dependency = True, -) # TODO: remove this after https://github.com/bazelbuild/remote-apis/pull/293 is merged bazel_dep(name = "remoteapis", version = "eb433accc6a666b782ea4b787eb598e5c3d27c93") From 481d627b849c79a78bbcb50cc36163db2290626b Mon Sep 17 00:00:00 2001 From: Jason Schroeder Date: Thu, 4 Apr 2024 16:16:04 -0700 Subject: [PATCH 309/311] build: re-add lost file from a merge --- third_party/remote-apis/BUILD.bazel | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 third_party/remote-apis/BUILD.bazel diff --git a/third_party/remote-apis/BUILD.bazel b/third_party/remote-apis/BUILD.bazel new file mode 100644 index 0000000000..40aba1531b --- /dev/null +++ b/third_party/remote-apis/BUILD.bazel @@ -0,0 +1,23 @@ +load("@grpc-java//:java_grpc_library.bzl", "java_grpc_library") + +package(default_visibility = ["//visibility:public"]) + +java_grpc_library( + name = "build_bazel_remote_asset_v1_remote_asset_java_grpc", + srcs = [ + "@remoteapis//build/bazel/remote/asset/v1:remote_asset_proto", + ], + deps = [ + "@remoteapis//build/bazel/remote/asset/v1:remote_asset_java_proto", + ], +) + +java_grpc_library( + name = "build_bazel_remote_execution_v2_remote_execution_java_grpc", + srcs = [ + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_proto", + ], + deps = [ + "@remoteapis//build/bazel/remote/execution/v2:remote_execution_java_proto", + ], +) From bb1f76697a5dd30131a75924d82b9ae2e14ef0e3 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Thu, 30 May 2024 12:36:56 -0400 Subject: [PATCH 310/311] Prevent write completion starvation for duplicates When a duplicate output stream is detected, we must signal the writeWinner (because the write exists) and onInsert (because it was inserted) for an output stream creation. If we're racing, we should be eventually convergent, but this absolutely fixes a hang which occurs on this sentinel stream's return into getOutput, where the future might never be triggered otherwise. --- src/main/java/build/buildfarm/cas/cfc/CASFileCache.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java index a0515d6b1b..38849642ca 100644 --- a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java +++ b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java @@ -2637,6 +2637,9 @@ private CancellableOutputStream putImpl( onInsert, isReset); if (out == DUPLICATE_OUTPUT_STREAM) { + log.log(Level.FINER, format("duplicate output stream, completing %s for %s", key, writeId)); + writeWinner.get(); + onInsert.run(); return null; } log.log(Level.FINER, format("entry %s is missing, downloading and populating", key)); From ece844a103eb0561a2bd1bf91129c12915a28ea8 Mon Sep 17 00:00:00 2001 From: George Gensure Date: Fri, 31 May 2024 17:35:30 -0400 Subject: [PATCH 311/311] Reduce DUPLICATE_OUTPUT_STREAM future to write Move future completion into the only scope it was actually missing from - getOutput for Write, rather than inducing all `put` calls into posts to backplane via onPut with duplicates. --- .../java/build/buildfarm/cas/cfc/CASFileCache.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java index 38849642ca..e9fadc9527 100644 --- a/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java +++ b/src/main/java/build/buildfarm/cas/cfc/CASFileCache.java @@ -885,7 +885,7 @@ public void cancel() throws IOException { } } - Write newWrite(BlobWriteKey key, ListenableFuture future) { + Write newWrite(BlobWriteKey key, SettableFuture future) { Write write = new Write() { CancellableOutputStream out = null; @@ -1004,11 +1004,12 @@ public synchronized FeedbackOutputStream getOutput( } } SettableFuture outClosedFuture = SettableFuture.create(); + Digest digest = key.getDigest(); UniqueWriteOutputStream uniqueOut = createUniqueWriteOutput( out, key.getCompressor(), - key.getDigest(), + digest, UUID.fromString(key.getIdentifier()), cancelled -> { if (cancelled) { @@ -1018,6 +1019,10 @@ public synchronized FeedbackOutputStream getOutput( }, this::isComplete, isReset); + if (uniqueOut.getPath() == null) { + // this is a duplicate output stream and the write is complete + future.set(key.getDigest().getSizeBytes()); + } commitOpenState(uniqueOut.delegate(), outClosedFuture); return uniqueOut; } @@ -2637,9 +2642,6 @@ private CancellableOutputStream putImpl( onInsert, isReset); if (out == DUPLICATE_OUTPUT_STREAM) { - log.log(Level.FINER, format("duplicate output stream, completing %s for %s", key, writeId)); - writeWinner.get(); - onInsert.run(); return null; } log.log(Level.FINER, format("entry %s is missing, downloading and populating", key));