// Copyright 2015 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.annotations.VisibleForTesting; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; import com.google.devtools.build.lib.util.GroupedList; import java.util.Collections; import java.util.Map; import javax.annotation.Nullable; /** * Basic implementation of {@link SkyFunction.Environment} in which all convenience methods delegate * to a single abstract method. */ @VisibleForTesting public abstract class AbstractSkyFunctionEnvironment implements SkyFunction.Environment { protected boolean valuesMissing = false; // Hack for the common case that there are no errors in the retrieved values. In that case, we // don't have to filter out any impermissible exceptions. Hack because we communicate this in an // out-of-band way from #getValueOrUntypedExceptions. It's out-of-band because we don't want to // incur the garbage overhead of returning a more complex data structure from // #getValueOrUntypedExceptions. protected boolean errorMightHaveBeenFound = false; @Nullable private final GroupedList temporaryDirectDeps; public AbstractSkyFunctionEnvironment(@Nullable GroupedList temporaryDirectDeps) { this.temporaryDirectDeps = temporaryDirectDeps; } public AbstractSkyFunctionEnvironment() { this(null); } @Override public GroupedList getTemporaryDirectDeps() { return temporaryDirectDeps; } /** Implementations should set {@link #valuesMissing} as necessary. */ protected abstract Map getValueOrUntypedExceptions( Iterable depKeys) throws InterruptedException; @Override @Nullable public SkyValue getValue(SkyKey depKey) throws InterruptedException { return getValues(ImmutableSet.of(depKey)).get(depKey); } @Override @Nullable public SkyValue getValueOrThrow(SkyKey depKey, Class exceptionClass) throws E, InterruptedException { return getValuesOrThrow(ImmutableSet.of(depKey), exceptionClass).get(depKey).get(); } @Override @Nullable public SkyValue getValueOrThrow( SkyKey depKey, Class exceptionClass1, Class exceptionClass2) throws E1, E2, InterruptedException { return getValuesOrThrow(ImmutableSet.of(depKey), exceptionClass1, exceptionClass2) .get(depKey) .get(); } @Override @Nullable public SkyValue getValueOrThrow( SkyKey depKey, Class exceptionClass1, Class exceptionClass2, Class exceptionClass3) throws E1, E2, E3, InterruptedException { return getValuesOrThrow( ImmutableSet.of(depKey), exceptionClass1, exceptionClass2, exceptionClass3) .get(depKey) .get(); } @Override public SkyValue getValueOrThrow( SkyKey depKey, Class exceptionClass1, Class exceptionClass2, Class exceptionClass3, Class exceptionClass4) throws E1, E2, E3, E4, InterruptedException { return getValuesOrThrow( ImmutableSet.of(depKey), exceptionClass1, exceptionClass2, exceptionClass3, exceptionClass4) .get(depKey) .get(); } @Override public < E1 extends Exception, E2 extends Exception, E3 extends Exception, E4 extends Exception, E5 extends Exception> SkyValue getValueOrThrow( SkyKey depKey, Class exceptionClass1, Class exceptionClass2, Class exceptionClass3, Class exceptionClass4, Class exceptionClass5) throws E1, E2, E3, E4, E5, InterruptedException { return getValuesOrThrow( ImmutableSet.of(depKey), exceptionClass1, exceptionClass2, exceptionClass3, exceptionClass4, exceptionClass5) .get(depKey) .get(); } @Override public Map getValues(Iterable depKeys) throws InterruptedException { Map valuesOrExceptions = getValueOrUntypedExceptions(depKeys); checkValuesMissingBecauseOfFilteredError(valuesOrExceptions, null, null, null, null, null); return Collections.unmodifiableMap( Maps.transformValues(valuesOrExceptions, ValueOrUntypedException::getValue)); } @Override public Map> getValuesOrThrow( Iterable depKeys, Class exceptionClass) throws InterruptedException { SkyFunctionException.validateExceptionType(exceptionClass); Map valuesOrExceptions = getValueOrUntypedExceptions(depKeys); checkValuesMissingBecauseOfFilteredError( valuesOrExceptions, exceptionClass, null, null, null, null); return Collections.unmodifiableMap( Maps.transformValues( valuesOrExceptions, voe -> ValueOrException.fromUntypedException(voe, exceptionClass))); } @Override public Map> getValuesOrThrow( Iterable depKeys, Class exceptionClass1, Class exceptionClass2) throws InterruptedException { SkyFunctionException.validateExceptionType(exceptionClass1); SkyFunctionException.validateExceptionType(exceptionClass2); Map valuesOrExceptions = getValueOrUntypedExceptions(depKeys); checkValuesMissingBecauseOfFilteredError( valuesOrExceptions, exceptionClass1, exceptionClass2, null, null, null); return Collections.unmodifiableMap( Maps.transformValues( valuesOrExceptions, voe -> ValueOrException2.fromUntypedException(voe, exceptionClass1, exceptionClass2))); } @Override public Map> getValuesOrThrow( Iterable depKeys, Class exceptionClass1, Class exceptionClass2, Class exceptionClass3) throws InterruptedException { SkyFunctionException.validateExceptionType(exceptionClass1); SkyFunctionException.validateExceptionType(exceptionClass2); SkyFunctionException.validateExceptionType(exceptionClass3); Map valuesOrExceptions = getValueOrUntypedExceptions(depKeys); checkValuesMissingBecauseOfFilteredError( valuesOrExceptions, exceptionClass1, exceptionClass2, exceptionClass3, null, null); return Collections.unmodifiableMap( Maps.transformValues( valuesOrExceptions, voe -> ValueOrException3.fromUntypedException( voe, exceptionClass1, exceptionClass2, exceptionClass3))); } @Override public Map> getValuesOrThrow( Iterable depKeys, Class exceptionClass1, Class exceptionClass2, Class exceptionClass3, Class exceptionClass4) throws InterruptedException { SkyFunctionException.validateExceptionType(exceptionClass1); SkyFunctionException.validateExceptionType(exceptionClass2); SkyFunctionException.validateExceptionType(exceptionClass3); SkyFunctionException.validateExceptionType(exceptionClass4); Map valuesOrExceptions = getValueOrUntypedExceptions(depKeys); checkValuesMissingBecauseOfFilteredError( valuesOrExceptions, exceptionClass1, exceptionClass2, exceptionClass3, exceptionClass4, null); return Collections.unmodifiableMap( Maps.transformValues( valuesOrExceptions, voe -> ValueOrException4.fromUntypedException( voe, exceptionClass1, exceptionClass2, exceptionClass3, exceptionClass4))); } @Override public < E1 extends Exception, E2 extends Exception, E3 extends Exception, E4 extends Exception, E5 extends Exception> Map> getValuesOrThrow( Iterable depKeys, Class exceptionClass1, Class exceptionClass2, Class exceptionClass3, Class exceptionClass4, Class exceptionClass5) throws InterruptedException { SkyFunctionException.validateExceptionType(exceptionClass1); SkyFunctionException.validateExceptionType(exceptionClass2); SkyFunctionException.validateExceptionType(exceptionClass3); SkyFunctionException.validateExceptionType(exceptionClass4); SkyFunctionException.validateExceptionType(exceptionClass5); Map valuesOrExceptions = getValueOrUntypedExceptions(depKeys); checkValuesMissingBecauseOfFilteredError( valuesOrExceptions, exceptionClass1, exceptionClass2, exceptionClass3, exceptionClass4, exceptionClass5); return Collections.unmodifiableMap( Maps.transformValues( valuesOrExceptions, voe -> ValueOrException5.fromUntypedException( voe, exceptionClass1, exceptionClass2, exceptionClass3, exceptionClass4, exceptionClass5))); } private < E1 extends Exception, E2 extends Exception, E3 extends Exception, E4 extends Exception, E5 extends Exception> void checkValuesMissingBecauseOfFilteredError( Map voes, @Nullable Class exceptionClass1, @Nullable Class exceptionClass2, @Nullable Class exceptionClass3, @Nullable Class exceptionClass4, @Nullable Class exceptionClass5) { if (!errorMightHaveBeenFound) { // Short-circuit in the common case of no errors. return; } for (ValueOrUntypedException voe : voes.values()) { SkyValue value = voe.getValue(); if (value == null) { Exception e = voe.getException(); if (e == null || ((exceptionClass1 == null || !exceptionClass1.isInstance(e)) && (exceptionClass2 == null || !exceptionClass2.isInstance(e)) && (exceptionClass3 == null || !exceptionClass3.isInstance(e)) && (exceptionClass4 == null || !exceptionClass4.isInstance(e)) && (exceptionClass5 == null || !exceptionClass5.isInstance(e)))) { valuesMissing = true; return; } } } } @Override public boolean valuesMissing() { return valuesMissing; } }