| // Copyright 2014 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.skyframe; | |
| import com.google.common.base.MoreObjects; | |
| import com.google.common.base.Preconditions; | |
| import com.google.common.collect.ImmutableMap; | |
| import com.google.common.collect.Iterables; | |
| import com.google.common.collect.Lists; | |
| import java.util.Collection; | |
| import java.util.Collections; | |
| import java.util.HashMap; | |
| import java.util.Map; | |
| import javax.annotation.Nullable; | |
| /** | |
| * The result of a Skyframe {@link ParallelEvaluator#eval} call. Will contain all the successfully | |
| * evaluated values, retrievable through {@link #get}. As well, the {@link ErrorInfo} for the first | |
| * value that failed to evaluate (in the non-keep-going case), or any remaining values that failed | |
| * to evaluate (in the keep-going case) will be retrievable. | |
| * | |
| * <p>A node can never be successfully evaluated and fail to evaluate. Thus, if {@link #get} returns | |
| * non-null for some key, there is no stored error for that key, and vice versa. | |
| * | |
| * @param <T> The type of the values that the caller has requested. | |
| */ | |
| public class EvaluationResult<T extends SkyValue> { | |
| @Nullable private final Exception catastrophe; | |
| private final Map<SkyKey, T> resultMap; | |
| private final Map<SkyKey, ErrorInfo> errorMap; | |
| private final WalkableGraph walkableGraph; | |
| /** | |
| * Constructor for the "completed" case. Used only by {@link Builder}. | |
| */ | |
| private EvaluationResult( | |
| Map<SkyKey, T> result, | |
| Map<SkyKey, ErrorInfo> errorMap, | |
| @Nullable Exception catastrophe, | |
| @Nullable WalkableGraph walkableGraph) { | |
| this.resultMap = Preconditions.checkNotNull(result); | |
| this.errorMap = Preconditions.checkNotNull(errorMap); | |
| this.catastrophe = catastrophe; | |
| this.walkableGraph = walkableGraph; | |
| } | |
| /** | |
| * Get a successfully evaluated value. | |
| */ | |
| public T get(SkyKey key) { | |
| Preconditions.checkNotNull(resultMap, key); | |
| return resultMap.get(key); | |
| } | |
| /** | |
| * @return Whether or not the eval successfully evaluated all requested values. True iff | |
| * {@link #getCatastrophe} or {@link #getError} returns non-null. | |
| */ | |
| public boolean hasError() { | |
| return catastrophe != null || !errorMap.isEmpty(); | |
| } | |
| /** @return catastrophic error encountered during evaluation, if any */ | |
| @Nullable | |
| public Exception getCatastrophe() { | |
| return catastrophe; | |
| } | |
| /** | |
| * @return All successfully evaluated {@link SkyValue}s. | |
| */ | |
| public Collection<T> values() { | |
| return Collections.unmodifiableCollection(resultMap.values()); | |
| } | |
| /** | |
| * Returns {@link Map} of {@link SkyKey}s to {@link ErrorInfo}. Note that currently some | |
| * of the returned SkyKeys may not be the ones requested by the user. Moreover, the SkyKey | |
| * is not necessarily the cause of the error -- it is just the value that was being evaluated | |
| * when the error was discovered. For the cause of the error, use | |
| * {@link ErrorInfo#getRootCauses()} on each ErrorInfo. | |
| */ | |
| public Map<SkyKey, ErrorInfo> errorMap() { | |
| return ImmutableMap.copyOf(errorMap); | |
| } | |
| /** | |
| * @param key {@link SkyKey} to get {@link ErrorInfo} for. | |
| */ | |
| public ErrorInfo getError(SkyKey key) { | |
| return Preconditions.checkNotNull(errorMap, key).get(key); | |
| } | |
| /** | |
| * Returns some error info. Convenience method equivalent to Iterables.getFirst({@link | |
| * #errorMap()}, null).getValue(). | |
| */ | |
| public ErrorInfo getError() { | |
| return Iterables.getFirst(errorMap.entrySet(), null).getValue(); | |
| } | |
| /** | |
| * @return Names of all values that were successfully evaluated. This collection is disjoint from | |
| * the keys in {@link #errorMap}. | |
| */ | |
| public <S> Collection<? extends S> keyNames() { | |
| return EvaluationResult.<S>getNames(resultMap.keySet()); | |
| } | |
| @SuppressWarnings("unchecked") | |
| private static <S> Collection<? extends S> getNames(Collection<SkyKey> keys) { | |
| Collection<S> names = Lists.newArrayListWithCapacity(keys.size()); | |
| for (SkyKey key : keys) { | |
| names.add((S) key.argument()); | |
| } | |
| return names; | |
| } | |
| @Nullable | |
| public WalkableGraph getWalkableGraph() { | |
| return walkableGraph; | |
| } | |
| @Override | |
| public String toString() { | |
| return MoreObjects.toStringHelper(this) | |
| .add("catastrophe", catastrophe) | |
| .add("errorMap", errorMap) | |
| .add("resultMap", resultMap) | |
| .toString(); | |
| } | |
| public static <T extends SkyValue> Builder<T> builder() { | |
| return new Builder<>(); | |
| } | |
| /** | |
| * Builder for {@link EvaluationResult}. | |
| * | |
| * <p>This is intended only for use in alternative {@code MemoizingEvaluator} implementations. | |
| */ | |
| public static class Builder<T extends SkyValue> { | |
| private final Map<SkyKey, T> result = new HashMap<>(); | |
| private final Map<SkyKey, ErrorInfo> errors = new HashMap<>(); | |
| @Nullable private Exception catastrophe = null; | |
| private WalkableGraph walkableGraph = null; | |
| /** Adds a value to the result. An error for this key must not already be present. */ | |
| @SuppressWarnings("unchecked") | |
| public Builder<T> addResult(SkyKey key, SkyValue value) { | |
| result.put(key, Preconditions.checkNotNull((T) value, key)); | |
| Preconditions.checkState( | |
| !errors.containsKey(key), "%s in both result and errors: %s %s", value, errors); | |
| return this; | |
| } | |
| /** Adds an error to the result. A successful value for this key must not already be present. */ | |
| public Builder<T> addError(SkyKey key, ErrorInfo error) { | |
| errors.put(key, Preconditions.checkNotNull(error, key)); | |
| Preconditions.checkState( | |
| !result.containsKey(key), "%s in both result and errors: %s %s", error, result); | |
| return this; | |
| } | |
| public Builder<T> setWalkableGraph(WalkableGraph walkableGraph) { | |
| this.walkableGraph = walkableGraph; | |
| return this; | |
| } | |
| public Builder<T> mergeFrom(EvaluationResult<T> otherResult) { | |
| result.putAll(otherResult.resultMap); | |
| errors.putAll(otherResult.errorMap); | |
| catastrophe = otherResult.catastrophe; | |
| return this; | |
| } | |
| public EvaluationResult<T> build() { | |
| return new EvaluationResult<>(result, errors, catastrophe, walkableGraph); | |
| } | |
| public Builder<T> setCatastrophe(Exception catastrophe) { | |
| this.catastrophe = catastrophe; | |
| return this; | |
| } | |
| } | |
| } |