|  | // Copyright 2017 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 com.google.devtools.build.lib.exec; | 
|  |  | 
|  | import com.google.devtools.build.lib.actions.ActionContext; | 
|  | import com.google.devtools.build.lib.actions.ExecException; | 
|  | import com.google.devtools.build.lib.actions.ForbiddenActionInputException; | 
|  | import com.google.devtools.build.lib.actions.Spawn; | 
|  | import com.google.devtools.build.lib.actions.SpawnResult; | 
|  | import com.google.devtools.build.lib.exec.SpawnRunner.SpawnExecutionContext; | 
|  | import java.io.Closeable; | 
|  | import java.io.IOException; | 
|  | import java.util.NoSuchElementException; | 
|  |  | 
|  | /** | 
|  | * A cache that can lookup a {@link SpawnResult} given a {@link Spawn}, and can also upload the | 
|  | * results of an executed spawn to the cache. | 
|  | * | 
|  | * <p>This is an experimental interface to implement caching with sandboxed local execution. | 
|  | */ | 
|  | public interface SpawnCache extends ActionContext { | 
|  | /** A no-op implementation that has no result, and performs no upload. */ | 
|  | public static CacheHandle NO_RESULT_NO_STORE = | 
|  | new CacheHandle() { | 
|  | @Override | 
|  | public boolean hasResult() { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public SpawnResult getResult() { | 
|  | throw new NoSuchElementException(); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public boolean willStore() { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void store(SpawnResult result) throws InterruptedException, IOException { | 
|  | // Do nothing. | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void close() {} | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * Helper method to create a {@link CacheHandle} from a successful {@link SpawnResult} instance. | 
|  | */ | 
|  | public static CacheHandle success(final SpawnResult result) { | 
|  | return new CacheHandle() { | 
|  | @Override | 
|  | public boolean hasResult() { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public SpawnResult getResult() { | 
|  | return result; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public boolean willStore() { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void store(SpawnResult result) throws InterruptedException, IOException { | 
|  | throw new IllegalStateException(); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void close() {} | 
|  | }; | 
|  | } | 
|  |  | 
|  | /** A no-op spawn cache. */ | 
|  | public static class NoSpawnCache implements SpawnCache { | 
|  | @Override | 
|  | public CacheHandle lookup(Spawn spawn, SpawnExecutionContext context) { | 
|  | return SpawnCache.NO_RESULT_NO_STORE; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** A no-op implementation that has no results and performs no stores. */ | 
|  | public static SpawnCache NO_CACHE = new NoSpawnCache(); | 
|  |  | 
|  | /** | 
|  | * This object represents both a successful and an unsuccessful cache lookup. If | 
|  | * {@link #hasResult} returns true, then {@link #getResult} must successfully return a non-null | 
|  | * instance (use the {@link #success} helper method). Otherwise {@link #getResult} should throw an | 
|  | * {@link IllegalStateException}. | 
|  | * | 
|  | * <p>If {@link #hasResult} returns false, then {@link #store} may upload the result to the cache | 
|  | * after successful execution. | 
|  | * | 
|  | * <p>Note that this interface extends {@link Closeable}, and callers must guarantee that | 
|  | * {@link #close} is called on this entry (e.g., by using try-with-resources) to free up any | 
|  | * acquired resources. | 
|  | */ | 
|  | interface CacheHandle extends Closeable { | 
|  | /** Returns whether the cache lookup was successful. */ | 
|  | boolean hasResult(); | 
|  |  | 
|  | /** | 
|  | * Returns the cached result. | 
|  | * | 
|  | * @throws NoSuchElementException if there is no result in this cache entry | 
|  | */ | 
|  | SpawnResult getResult(); | 
|  |  | 
|  | /** | 
|  | * Returns true if the store call will actually do work. Use this to avoid unnecessary work | 
|  | * before store if it won't do anything. | 
|  | */ | 
|  | boolean willStore(); | 
|  |  | 
|  | /** | 
|  | * Called after successful {@link Spawn} execution, which may or may not store the result in the | 
|  | * cache. | 
|  | * | 
|  | * <p>A cache may silently return from a failed store operation. We recommend to err on the side | 
|  | * of raising an exception rather than returning silently, and to offer command-line flags to | 
|  | * tweak this default policy as needed. | 
|  | * | 
|  | * <p>If the current thread is interrupted, then this method should return as quickly as | 
|  | * possible with an {@link InterruptedException}. | 
|  | */ | 
|  | void store(SpawnResult result) throws ExecException, InterruptedException, IOException; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Perform a spawn lookup. This method is similar to {@link SpawnRunner#exec}, taking the same | 
|  | * parameters and being allowed to throw the same exceptions. The intent for this method is to | 
|  | * compute a cache lookup key for the given spawn, looking it up in an implementation-dependent | 
|  | * cache (can be either on the local or remote machine), and returning a non-null {@link | 
|  | * CacheHandle} instance. | 
|  | * | 
|  | * <p>If the lookup was successful, this method should write the cached outputs to their | 
|  | * corresponding output locations in the output tree, as well as stdout and stderr, after | 
|  | * notifying {@link SpawnExecutionContext#lockOutputFiles}. | 
|  | * | 
|  | * <p>If the lookup was unsuccessful, this method can return a {@link CacheHandle} instance that | 
|  | * has no result, but uploads the results of the execution to the cache. The reason for a callback | 
|  | * object is for the cache to store expensive intermediate values (such as the cache key) that are | 
|  | * needed both for the lookup and the subsequent store operation. | 
|  | * | 
|  | * <p>The lookup must not succeed for non-cachable spawns. See {@link Spawns#mayBeCached()} and | 
|  | * {@link Spawns#mayBeCachedRemotely}. | 
|  | * | 
|  | * <p>Note that cache stores may be disabled, in which case the returned {@link CacheHandle} | 
|  | * instance's {@link CacheHandle#store} is a no-op. | 
|  | */ | 
|  | CacheHandle lookup(Spawn spawn, SpawnExecutionContext context) | 
|  | throws ExecException, IOException, InterruptedException, ForbiddenActionInputException; | 
|  |  | 
|  | /** | 
|  | * Returns whether this cache implementation makes sense to use together with dynamic execution. | 
|  | * | 
|  | * <p>A cache that's part of the remote system used for dynamic execution should not also be used | 
|  | * for the local speculative execution. However, a local cache or a separate remote cache-only | 
|  | * system would be. | 
|  | */ | 
|  | default boolean usefulInDynamicExecution() { | 
|  | return true; | 
|  | } | 
|  | } |