Add WorkerKey to the ResourceSet.

This field will be used in next cls in functions `areResourcesAvailable` and `acquire` from `ResourceManager`. This is the part of worker-as-resource plan.

PiperOrigin-RevId: 448934201
diff --git a/src/main/java/com/google/devtools/build/lib/actions/BUILD b/src/main/java/com/google/devtools/build/lib/actions/BUILD
index 0fe4c4f..042a9e35 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/actions/BUILD
@@ -305,9 +305,11 @@
         "//src/main/java/com/google/devtools/build/lib/unix",
         "//src/main/java/com/google/devtools/build/lib/unix:procmeminfo_parser",
         "//src/main/java/com/google/devtools/build/lib/util:os",
+        "//src/main/java/com/google/devtools/build/lib/worker:worker_key",
         "//src/main/java/com/google/devtools/common/options",
         "//third_party:flogger",
         "//third_party:guava",
+        "//third_party:jsr305",
     ],
 )
 
@@ -369,5 +371,6 @@
         "//src/main/java/com/google/devtools/build/lib/util:os",
         "//src/main/java/com/google/devtools/build/lib/worker",
         "//third_party:guava",
+        "//third_party:jsr305",
     ],
 )
diff --git a/src/main/java/com/google/devtools/build/lib/actions/ResourceManager.java b/src/main/java/com/google/devtools/build/lib/actions/ResourceManager.java
index 145fd8c..7674bff 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/ResourceManager.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/ResourceManager.java
@@ -25,13 +25,13 @@
 import com.google.devtools.build.lib.util.OS;
 import com.google.devtools.build.lib.util.Pair;
 import com.google.devtools.build.lib.worker.Worker;
-import com.google.devtools.build.lib.worker.WorkerKey;
 import com.google.devtools.build.lib.worker.WorkerPool;
 import java.io.IOException;
 import java.util.Deque;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.concurrent.CountDownLatch;
+import javax.annotation.Nullable;
 
 /**
  * Used to keep track of resources consumed by the Blaze action execution threads and throttle them
@@ -69,39 +69,28 @@
    * ResourcePriority)} that must be closed in order to free the resources again.
    */
   public static class ResourceHandle implements AutoCloseable {
-    final ResourceManager rm;
-    final ActionExecutionMetadata actionMetadata;
-    final ResourceSet resourceSet;
+    private final ResourceManager rm;
+    private final ActionExecutionMetadata actionMetadata;
+    private final ResourceSet resourceSet;
+    private final Worker worker;
 
-    public ResourceHandle(ResourceManager rm, ActionExecutionMetadata actionMetadata,
-        ResourceSet resources) {
+    private ResourceHandle(
+        ResourceManager rm,
+        ActionExecutionMetadata actionMetadata,
+        ResourceSet resources,
+        Worker worker) {
       this.rm = rm;
       this.actionMetadata = actionMetadata;
       this.resourceSet = resources;
-    }
-
-    /**
-     * Closing the ResourceHandle releases the resources associated with it.
-     */
-    @Override
-    public void close() {
-      rm.releaseResources(actionMetadata, resourceSet);
-    }
-  }
-
-  /**
-   * A handle returned by {@link #acquireWorkerResources(ActionExecutionMetadata, ResourceSet,
-   * WorkerKey, ResourcePriority)} that must be closed in order to free the resources again.
-   */
-  public static class ResourceHandleWithWorker implements AutoCloseable {
-    final ResourceHandle resourceHandle;
-    final Worker worker;
-
-    public ResourceHandleWithWorker(ResourceHandle resourceHandle, Worker worker) {
-      this.resourceHandle = resourceHandle;
       this.worker = worker;
     }
 
+    private ResourceHandle(
+        ResourceManager rm, ActionExecutionMetadata actionMetadata, ResourceSet resources) {
+      this(rm, actionMetadata, resources, /* worker= */ null);
+    }
+
+    @Nullable
     public Worker getWorker() {
       return worker;
     }
@@ -109,16 +98,17 @@
     /** Closing the ResourceHandle releases the resources associated with it. */
     @Override
     public void close() {
-      this.resourceHandle.close();
+      rm.releaseResources(actionMetadata, resourceSet);
     }
   }
 
-  private final ThreadLocal<Boolean> threadLocked = new ThreadLocal<Boolean>() {
-    @Override
-    protected Boolean initialValue() {
-      return false;
-    }
-  };
+  private final ThreadLocal<Boolean> threadLocked =
+      new ThreadLocal<Boolean>() {
+        @Override
+        protected Boolean initialValue() {
+          return false;
+        }
+      };
 
   /**
    * Defines the possible priorities of resources. The earlier elements in this enum will get first
@@ -135,9 +125,7 @@
     static ResourceManager instance = new ResourceManager();
   }
 
-  /**
-   * Returns singleton instance of the resource manager.
-   */
+  /** Returns singleton instance of the resource manager. */
   public static ResourceManager instance() {
     return Singleton.instance;
   }
@@ -192,16 +180,17 @@
   /** If set, local-only actions are given priority over dynamically run actions. */
   private boolean prioritizeLocalActions;
 
-  private ResourceManager() {
-  }
+  private ResourceManager() {}
 
-  @VisibleForTesting public static ResourceManager instanceForTestingOnly() {
+  @VisibleForTesting
+  public static ResourceManager instanceForTestingOnly() {
     return new ResourceManager();
   }
 
   /**
    * Resets resource manager state and releases all thread locks.
-   * Note - it does not reset available resources. Use separate call to setAvailableResources().
+   *
+   * <p>Note - it does not reset available resources. Use separate call to setAvailableResources().
    */
   public synchronized void resetResourceUsage() {
     usedCpu = 0;
@@ -222,8 +211,9 @@
   }
 
   /**
-   * Sets available resources using given resource set. Must be called
-   * at least once before using resource manager.
+   * Sets available resources using given resource set.
+   *
+   * <p>Must be called at least once before using resource manager.
    */
   public synchronized void setAvailableResources(ResourceSet resources) {
     Preconditions.checkNotNull(resources);
@@ -257,32 +247,22 @@
   }
 
   /**
-   * Acuqires requested resource set and worker. Will block if resource is not available. The worker
-   * isn't released as part of the AutoCloseable.
-   */
-  public ResourceHandleWithWorker acquireWorkerResources(
-      ActionExecutionMetadata owner,
-      ResourceSet resources,
-      WorkerKey workerKey,
-      ResourcePriority priority)
-      throws InterruptedException, IOException {
-    Worker worker = this.workerPool.borrowObject(workerKey);
-    ResourceHandle handle = acquireResources(owner, resources, priority);
-    return new ResourceHandleWithWorker(handle, worker);
-  }
-
-  /**
    * Acquires requested resource set. Will block if resource is not available. NB! This method must
    * be thread-safe!
    */
   public ResourceHandle acquireResources(
       ActionExecutionMetadata owner, ResourceSet resources, ResourcePriority priority)
-      throws InterruptedException {
+      throws InterruptedException, IOException {
     Preconditions.checkNotNull(
         resources, "acquireResources called with resources == NULL during %s", owner);
     Preconditions.checkState(
         !threadHasResources(), "acquireResources with existing resource lock during %s", owner);
 
+    Worker worker = null;
+    if (resources.getWorkerKey() != null) {
+      worker = this.workerPool.borrowObject(resources.getWorkerKey());
+    }
+
     AutoProfiler p =
         profiled("Acquiring resources for: " + owner.describe(), ProfilerTask.ACTION_LOCK);
     CountDownLatch latch = null;
@@ -313,7 +293,7 @@
       p.complete();
     }
 
-    return new ResourceHandle(this, owner, resources);
+    return new ResourceHandle(this, owner, resources, worker);
   }
 
   /**
@@ -499,7 +479,7 @@
     if (localMemoryEstimate && OS.getCurrent() == OS.LINUX) {
       try {
         ProcMeminfoParser memInfo = new ProcMeminfoParser();
-        double totalFreeRam = memInfo.getFreeRamKb() / 1024;
+        double totalFreeRam = memInfo.getFreeRamKb() / 1024.0;
         double reserveMemory = staticResources.getMemoryMb();
         remainingRam = totalFreeRam - reserveMemory;
       } catch (IOException e) {
diff --git a/src/main/java/com/google/devtools/build/lib/actions/ResourceSet.java b/src/main/java/com/google/devtools/build/lib/actions/ResourceSet.java
index 053a810..7bdfa2d 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/ResourceSet.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/ResourceSet.java
@@ -18,10 +18,12 @@
 import com.google.common.primitives.Doubles;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
 import com.google.devtools.build.lib.util.OS;
+import com.google.devtools.build.lib.worker.WorkerKey;
 import com.google.devtools.common.options.Converter;
 import com.google.devtools.common.options.OptionsParsingException;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
+import javax.annotation.Nullable;
 
 /**
  * Instances of this class represent an estimate of the resource consumption for a particular
@@ -44,10 +46,19 @@
   /** The number of local tests. */
   private final int localTestCount;
 
-  private ResourceSet(double memoryMb, double cpuUsage, int localTestCount) {
+  /** The workerKey of used worker. Null if no worker is used. */
+  @Nullable private final WorkerKey workerKey;
+
+  private ResourceSet(
+      double memoryMb, double cpuUsage, int localTestCount, @Nullable WorkerKey workerKey) {
     this.memoryMb = memoryMb;
     this.cpuUsage = cpuUsage;
     this.localTestCount = localTestCount;
+    this.workerKey = workerKey;
+  }
+
+  private ResourceSet(double memoryMb, double cpuUsage, int localTestCount) {
+    this(memoryMb, cpuUsage, localTestCount, /* workerKey= */ null);
   }
 
   /**
@@ -78,10 +89,15 @@
    * represent available resources.
    */
   public static ResourceSet create(double memoryMb, double cpuUsage, int localTestCount) {
-    if (memoryMb == 0 && cpuUsage == 0 && localTestCount == 0) {
+    return createWithWorkerKey(memoryMb, cpuUsage, localTestCount, /* workerKey= */ null);
+  }
+
+  public static ResourceSet createWithWorkerKey(
+      double memoryMb, double cpuUsage, int localTestCount, WorkerKey workerKey) {
+    if (memoryMb == 0 && cpuUsage == 0 && localTestCount == 0 && workerKey == null) {
       return ZERO;
     }
-    return new ResourceSet(memoryMb, cpuUsage, localTestCount);
+    return new ResourceSet(memoryMb, cpuUsage, localTestCount, workerKey);
   }
 
   /** Returns the amount of real memory (resident set size) used in MB. */
@@ -90,6 +106,15 @@
   }
 
   /**
+   * Returns the workerKey of worker.
+   *
+   * <p>If there is no worker requested, then returns null
+   */
+  public WorkerKey getWorkerKey() {
+    return workerKey;
+  }
+
+  /**
    * Returns the number of CPUs (or fractions thereof) used. For a CPU-bound single-threaded
    * process, this will be 1.0. For a single-threaded process which spends part of its time waiting
    * for I/O, this will be somewhere between 0.0 and 1.0. For a multi-threaded or multi-process
diff --git a/src/main/java/com/google/devtools/build/lib/worker/BUILD b/src/main/java/com/google/devtools/build/lib/worker/BUILD
index b312e76..ab395d4 100644
--- a/src/main/java/com/google/devtools/build/lib/worker/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/worker/BUILD
@@ -18,20 +18,16 @@
             "WorkerModule.java",
             "WorkerParser.java",
             "WorkerSpawnStrategy.java",
+            "WorkerKey.java",
         ],
     ),
     deps = [
-        # ":worker_spawn_runner",
-        "//third_party:guava",
-        "//third_party/protobuf:protobuf_java",
-        "//third_party/protobuf:protobuf_java_util",
+        ":worker_key",
         "//src/main/java/com/google/devtools/build/lib/actions",
-        "//src/main/java/com/google/devtools/build/lib/actions:execution_requirements",
         "//src/main/java/com/google/devtools/build/lib/buildeventstream/proto:build_event_stream_java_proto",
         "//src/main/java/com/google/devtools/build/lib/events",
         "//src/main/java/com/google/devtools/build/lib/sandbox:sandbox_helpers",
         "//src/main/java/com/google/devtools/build/lib/shell",
-        "//src/main/java/com/google/devtools/build/lib/util:command",
         "//src/main/java/com/google/devtools/build/lib/util:resource_converter",
         "//src/main/java/com/google/devtools/build/lib/vfs",
         "//src/main/java/com/google/devtools/build/lib/vfs:pathfragment",
@@ -42,7 +38,10 @@
         "//third_party:auto_value",
         "//third_party:flogger",
         "//third_party:gson",
+        "//third_party:guava",
         "//third_party:jsr305",
+        "//third_party/protobuf:protobuf_java",
+        "//third_party/protobuf:protobuf_java_util",
     ],
 )
 
@@ -69,11 +68,13 @@
     deps = [
         ":worker",
         ":worker_files_hash",
+        ":worker_key",
         "//src/main/java/com/google/devtools/build/lib:runtime",
         "//src/main/java/com/google/devtools/build/lib/actions",
         "//src/main/java/com/google/devtools/build/lib/actions:action_input_helper",
         "//src/main/java/com/google/devtools/build/lib/actions:artifacts",
         "//src/main/java/com/google/devtools/build/lib/actions:execution_requirements",
+        "//src/main/java/com/google/devtools/build/lib/actions:localhost_capacity",
         "//src/main/java/com/google/devtools/build/lib/actions:resource_manager",
         "//src/main/java/com/google/devtools/build/lib/events",
         "//src/main/java/com/google/devtools/build/lib/exec:bin_tools",
@@ -134,3 +135,17 @@
         "//third_party/protobuf:protobuf_java_util",
     ],
 )
+
+java_library(
+    name = "worker_key",
+    srcs = [
+        "WorkerKey.java",
+    ],
+    deps = [
+        "//src/main/java/com/google/devtools/build/lib/actions:execution_requirements",
+        "//src/main/java/com/google/devtools/build/lib/util:command",
+        "//src/main/java/com/google/devtools/build/lib/vfs",
+        "//src/main/java/com/google/devtools/build/lib/vfs:pathfragment",
+        "//third_party:guava",
+    ],
+)
diff --git a/src/main/java/com/google/devtools/build/lib/worker/WorkerFactory.java b/src/main/java/com/google/devtools/build/lib/worker/WorkerFactory.java
index 81ef251..487e0a3 100644
--- a/src/main/java/com/google/devtools/build/lib/worker/WorkerFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/worker/WorkerFactory.java
@@ -31,7 +31,7 @@
 import org.apache.commons.pool2.impl.DefaultPooledObject;
 
 /** Factory used by the pool to create / destroy / validate worker processes. */
-class WorkerFactory extends BaseKeyedPooledObjectFactory<WorkerKey, Worker> {
+public class WorkerFactory extends BaseKeyedPooledObjectFactory<WorkerKey, Worker> {
 
   // It's fine to use an AtomicInteger here (which is 32-bit), because it is only incremented when
   // spawning a new worker, thus even under worst-case circumstances and buggy workers quitting
diff --git a/src/main/java/com/google/devtools/build/lib/worker/WorkerKey.java b/src/main/java/com/google/devtools/build/lib/worker/WorkerKey.java
index 6d55a54..2ffacc9 100644
--- a/src/main/java/com/google/devtools/build/lib/worker/WorkerKey.java
+++ b/src/main/java/com/google/devtools/build/lib/worker/WorkerKey.java
@@ -64,7 +64,7 @@
   /** The format of the worker protocol sent to and read from the worker. */
   private final WorkerProtocolFormat protocolFormat;
 
-  WorkerKey(
+  public WorkerKey(
       ImmutableList<String> args,
       ImmutableMap<String, String> env,
       Path execRoot,
diff --git a/src/main/java/com/google/devtools/build/lib/worker/WorkerPool.java b/src/main/java/com/google/devtools/build/lib/worker/WorkerPool.java
index c8d0b83..eda05ac 100644
--- a/src/main/java/com/google/devtools/build/lib/worker/WorkerPool.java
+++ b/src/main/java/com/google/devtools/build/lib/worker/WorkerPool.java
@@ -200,13 +200,17 @@
     multiplexPools.values().forEach(GenericKeyedObjectPool::close);
   }
 
-  static class WorkerPoolConfig {
+  /**
+   * Describes the configuration of worker pool, e.g. number of maximal instances and priority of
+   * the workers.
+   */
+  public static class WorkerPoolConfig {
     private final WorkerFactory workerFactory;
     private final List<Entry<String, Integer>> workerMaxInstances;
     private final List<Entry<String, Integer>> workerMaxMultiplexInstances;
     private final List<String> highPriorityWorkers;
 
-    WorkerPoolConfig(
+    public WorkerPoolConfig(
         WorkerFactory workerFactory,
         List<Entry<String, Integer>> workerMaxInstances,
         List<Entry<String, Integer>> workerMaxMultiplexInstances,
diff --git a/src/main/java/com/google/devtools/build/lib/worker/WorkerSpawnRunner.java b/src/main/java/com/google/devtools/build/lib/worker/WorkerSpawnRunner.java
index a7e0015..3fc169f 100644
--- a/src/main/java/com/google/devtools/build/lib/worker/WorkerSpawnRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/worker/WorkerSpawnRunner.java
@@ -33,8 +33,8 @@
 import com.google.devtools.build.lib.actions.MetadataProvider;
 import com.google.devtools.build.lib.actions.ResourceManager;
 import com.google.devtools.build.lib.actions.ResourceManager.ResourceHandle;
-import com.google.devtools.build.lib.actions.ResourceManager.ResourceHandleWithWorker;
 import com.google.devtools.build.lib.actions.ResourceManager.ResourcePriority;
+import com.google.devtools.build.lib.actions.ResourceSet;
 import com.google.devtools.build.lib.actions.Spawn;
 import com.google.devtools.build.lib.actions.SpawnMetrics;
 import com.google.devtools.build.lib.actions.SpawnResult;
@@ -387,12 +387,18 @@
 
       Stopwatch queueStopwatch = Stopwatch.createStarted();
       if (workerOptions.workerAsResource) {
+        ResourceSet resourceSet =
+            ResourceSet.createWithWorkerKey(
+                spawn.getLocalResources().getMemoryMb(),
+                spawn.getLocalResources().getCpuUsage(),
+                spawn.getLocalResources().getLocalTestCount(),
+                key);
+
         // Worker doesn't automatically return to pool after closing of the handle.
-        try (ResourceHandleWithWorker handle =
-            resourceManager.acquireWorkerResources(
+        try (ResourceHandle handle =
+            resourceManager.acquireResources(
                 owner,
-                spawn.getLocalResources(),
-                key,
+                resourceSet,
                 context.speculating() ? ResourcePriority.DYNAMIC_WORKER : ResourcePriority.LOCAL)) {
           workerOwner.setWorker(handle.getWorker());
           workerOwner.getWorker().setReporter(workerOptions.workerVerbose ? reporter : null);
@@ -430,6 +436,12 @@
           response =
               executeRequest(
                   spawn, context, inputFiles, outputs, workerOwner, key, request, spawnMetrics);
+        } catch (IOException e) {
+          restoreInterrupt(e);
+          String message =
+              "The IOException is thrown from worker allocation, but"
+                  + " there is no worker allocation here.";
+          throw createUserExecException(e, message, Code.BORROW_FAILURE);
         }
       }
 
diff --git a/src/test/java/com/google/devtools/build/lib/actions/BUILD b/src/test/java/com/google/devtools/build/lib/actions/BUILD
index bbb6374..0cabee7 100644
--- a/src/test/java/com/google/devtools/build/lib/actions/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/actions/BUILD
@@ -36,6 +36,7 @@
         "//src/main/java/com/google/devtools/build/lib/actions:artifact_owner",
         "//src/main/java/com/google/devtools/build/lib/actions:artifacts",
         "//src/main/java/com/google/devtools/build/lib/actions:commandline_item",
+        "//src/main/java/com/google/devtools/build/lib/actions:execution_requirements",
         "//src/main/java/com/google/devtools/build/lib/actions:file_metadata",
         "//src/main/java/com/google/devtools/build/lib/actions:fileset_output_symlink",
         "//src/main/java/com/google/devtools/build/lib/actions:localhost_capacity",
@@ -67,6 +68,8 @@
         "//src/main/java/com/google/devtools/build/lib/vfs",
         "//src/main/java/com/google/devtools/build/lib/vfs:pathfragment",
         "//src/main/java/com/google/devtools/build/lib/vfs/inmemoryfs",
+        "//src/main/java/com/google/devtools/build/lib/worker",
+        "//src/main/java/com/google/devtools/build/lib/worker:worker_key",
         "//src/main/java/com/google/devtools/build/skyframe:skyframe-objects",
         "//src/main/java/com/google/devtools/common/options",
         "//src/main/java/net/starlark/java/eval",
@@ -79,6 +82,7 @@
         "//src/test/java/com/google/devtools/build/lib/testutil:TestThread",
         "//src/test/java/com/google/devtools/build/lib/testutil:TestUtils",
         "//src/test/java/com/google/devtools/build/lib/vfs/util",
+        "//third_party:apache_commons_pool2",
         "//third_party:auto_value",
         "//third_party:guava",
         "//third_party:guava-testlib",
diff --git a/src/test/java/com/google/devtools/build/lib/actions/ResourceManagerTest.java b/src/test/java/com/google/devtools/build/lib/actions/ResourceManagerTest.java
index 0de6d7e..0dee9f2 100644
--- a/src/test/java/com/google/devtools/build/lib/actions/ResourceManagerTest.java
+++ b/src/test/java/com/google/devtools/build/lib/actions/ResourceManagerTest.java
@@ -16,8 +16,12 @@
 import static com.google.common.truth.Truth.assertThat;
 import static org.junit.Assert.assertThrows;
 
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSortedMap;
+import com.google.common.hash.HashCode;
+import com.google.devtools.build.lib.actions.ExecutionRequirements.WorkerProtocolFormat;
 import com.google.devtools.build.lib.actions.ResourceManager.ResourceHandle;
 import com.google.devtools.build.lib.actions.ResourceManager.ResourcePriority;
 import com.google.devtools.build.lib.analysis.platform.PlatformInfo;
@@ -26,28 +30,40 @@
 import com.google.devtools.build.lib.collect.nestedset.Order;
 import com.google.devtools.build.lib.testutil.TestThread;
 import com.google.devtools.build.lib.testutil.TestUtils;
+import com.google.devtools.build.lib.vfs.DigestHashFunction;
+import com.google.devtools.build.lib.vfs.FileSystem;
+import com.google.devtools.build.lib.vfs.inmemoryfs.InMemoryFileSystem;
+import com.google.devtools.build.lib.worker.Worker;
+import com.google.devtools.build.lib.worker.WorkerFactory;
+import com.google.devtools.build.lib.worker.WorkerKey;
+import com.google.devtools.build.lib.worker.WorkerPool;
+import java.io.IOException;
 import java.util.Collection;
 import java.util.concurrent.CyclicBarrier;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 import javax.annotation.Nullable;
+import org.apache.commons.pool2.PooledObject;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
+import org.mockito.Mock;
 
 /** Tests for {@link ResourceManager}. */
 @RunWith(JUnit4.class)
-public class ResourceManagerTest {
+public final class ResourceManagerTest {
 
+  private final FileSystem fs = new InMemoryFileSystem(DigestHashFunction.SHA256);
   private final ActionExecutionMetadata resourceOwner = new ResourceOwnerStub();
   private final ResourceManager rm = ResourceManager.instanceForTestingOnly();
+  @Mock private Worker worker;
   private AtomicInteger counter;
   CyclicBarrier sync;
   CyclicBarrier sync2;
 
   @Before
-  public final void configureResourceManager() throws Exception  {
+  public void configureResourceManager() throws Exception {
     rm.setAvailableResources(
         ResourceSet.create(/*memoryMb=*/ 1000, /*cpuUsage=*/ 1, /* localTestCount= */ 2));
     counter = new AtomicInteger(0);
@@ -55,18 +71,47 @@
     sync2 = new CyclicBarrier(2);
     rm.resetResourceUsage();
     rm.setPrioritizeLocalActions(true);
+    rm.setWorkerPool(createWorkerPool());
+  }
+
+  private WorkerPool createWorkerPool() {
+    return new WorkerPool(
+        new WorkerPool.WorkerPoolConfig(
+            new WorkerFactory(fs.getPath("/workerBase")) {
+              @Override
+              public Worker create(WorkerKey key) {
+                return worker;
+              }
+
+              @Override
+              public boolean validateObject(WorkerKey key, PooledObject<Worker> p) {
+                return true;
+              }
+            },
+            ImmutableList.of(),
+            ImmutableList.of(),
+            ImmutableList.of()));
   }
 
   private ResourceHandle acquire(double ram, double cpu, int tests, ResourcePriority priority)
-      throws InterruptedException {
+      throws InterruptedException, IOException {
     return rm.acquireResources(resourceOwner, ResourceSet.create(ram, cpu, tests), priority);
   }
 
   private ResourceHandle acquire(double ram, double cpu, int tests)
-      throws InterruptedException {
+      throws InterruptedException, IOException {
     return acquire(ram, cpu, tests, ResourcePriority.LOCAL);
   }
 
+  private ResourceHandle acquire(double ram, double cpu, int tests, String mnemonic)
+      throws InterruptedException, IOException {
+
+    return rm.acquireResources(
+        resourceOwner,
+        ResourceSet.createWithWorkerKey(ram, cpu, tests, createWorkerKey(mnemonic)),
+        ResourcePriority.LOCAL);
+  }
+
   private ResourceHandle acquireNonblocking(double ram, double cpu, int tests) {
     return rm.tryAcquire(resourceOwner, ResourceSet.create(ram, cpu, tests));
   }
@@ -79,6 +124,20 @@
     assertThat(counter.incrementAndGet()).isEqualTo(count);
   }
 
+  private WorkerKey createWorkerKey(String mnemonic) {
+    return new WorkerKey(
+        /* args= */ ImmutableList.of(),
+        /* env= */ ImmutableMap.of(),
+        /* execRoot= */ fs.getPath("/outputbase/execroot/workspace"),
+        /* mnemonic= */ mnemonic,
+        /* workerFilesCombinedHash= */ HashCode.fromInt(0),
+        /* workerFilesWithDigests= */ ImmutableSortedMap.of(),
+        /* sandboxed= */ false,
+        /* multiplex= */ false,
+        /* cancellable= */ false,
+        WorkerProtocolFormat.PROTO);
+  }
+
   @Test
   public void testOverBudgetRequests() throws Exception {
     assertThat(rm.inUse()).isFalse();
@@ -607,6 +666,19 @@
     return sync;
   }
 
+  @Test
+  public void testAcquireWithWorker_acquireAndRelease() throws Exception {
+    int memory = 100;
+
+    assertThat(rm.inUse()).isFalse();
+    acquire(memory, 1, 0, "dummy");
+    assertThat(rm.inUse()).isTrue();
+    release(memory, 1, 0);
+    // When that RAM is released,
+    // Then Resource Manager will not be "in use":
+    assertThat(rm.inUse()).isFalse();
+  }
+
   private static class ResourceOwnerStub implements ActionExecutionMetadata {
 
     @Override
diff --git a/src/test/java/com/google/devtools/build/lib/worker/BUILD b/src/test/java/com/google/devtools/build/lib/worker/BUILD
index d2efeab..c868ab1 100644
--- a/src/test/java/com/google/devtools/build/lib/worker/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/worker/BUILD
@@ -48,6 +48,7 @@
         "//src/main/java/com/google/devtools/build/lib/vfs",
         "//src/main/java/com/google/devtools/build/lib/vfs:pathfragment",
         "//src/main/java/com/google/devtools/build/lib/worker",
+        "//src/main/java/com/google/devtools/build/lib/worker:worker_key",
         "//src/main/java/com/google/devtools/build/lib/worker:worker_spawn_runner",
         "//src/test/java/com/google/devtools/build/lib/actions/util",
         "//third_party:guava",
@@ -97,6 +98,7 @@
         "//src/main/java/com/google/devtools/build/lib/vfs/inmemoryfs",
         "//src/main/java/com/google/devtools/build/lib/worker",
         "//src/main/java/com/google/devtools/build/lib/worker:worker_files_hash",
+        "//src/main/java/com/google/devtools/build/lib/worker:worker_key",
         "//src/main/java/com/google/devtools/build/lib/worker:worker_module",
         "//src/main/java/com/google/devtools/build/lib/worker:worker_spawn_runner",
         "//src/main/java/com/google/devtools/common/options",