blob: be5385eb577a78a27c258b619cb6885d450d2d55 [file] [log] [blame]
// 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.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.
}
};
/**
* Helper method to create a {@link CacheHandle} from a successful {@link SpawnResult} instance.
*/
public static CacheHandle success(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();
}
};
}
/** 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.
*
* <p>If {@link #hasResult} returns true, then {@link #getResult} returns a non-null instance.
* Otherwise, if {@link #hasResult} returns false, then {@link #getResult} throws an {@link
* IllegalStateException}.
*
* <p>If {@link #willStore} returns true, then {@link #store} may be called to upload the result
* to the cache after successful execution. Otherwise, if {@link #willStore} returns false, then
* {@link #store} throws an {@link IllegalStateException}.
*/
interface CacheHandle {
/** 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;
}
}