|  | // 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 Evaluator#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); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @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 this.<S>getNames(resultMap.keySet()); | 
|  | } | 
|  |  | 
|  | @SuppressWarnings("unchecked") | 
|  | private <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; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns some error info. Convenience method equivalent to | 
|  | * Iterables.getFirst({@link #errorMap()}, null).getValue(). | 
|  | */ | 
|  | public ErrorInfo getError() { | 
|  | return Iterables.getFirst(errorMap.entrySet(), null).getValue(); | 
|  | } | 
|  |  | 
|  | @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; | 
|  | } | 
|  | } | 
|  | } |