com.google.devtools.build.skyframe.EvaluationResult.java Source code

Java tutorial

Introduction

Here is the source code for com.google.devtools.build.skyframe.EvaluationResult.java

Source

// 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.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.devtools.build.lib.util.Preconditions;

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 void setCatastrophe(Exception catastrophe) {
            this.catastrophe = catastrophe;
        }
    }
}