Use List instead of Map in Skyframe's intermediate eval results.
This CL is a no-op and only provides the necessary methods for Skyframe
evaluation with Lists instead of Maps. Actual application will be done in
subsequent CLs.
Constructing a Map<SkyKey, SkyValue> to store intermediate Skyframe evaluation result is wasteful since we don't make use of the look up capabilities of Maps, but rather just iterate over the key-value pairs. As an alternative, we can present the Skyframe evaluation result with a more space-efficient List<SkyValue>, then rely on the given order of the requested SkyKeys to iterate over it in various SkyFunctions.
Our benchmarks/profiles showed some reduction in GC and CPU time as a result of this switch.
RELNOTES: None
PiperOrigin-RevId: 342917514
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ProgressEventSuppressingEnvironment.java b/src/main/java/com/google/devtools/build/lib/skyframe/ProgressEventSuppressingEnvironment.java
index 4d23fee..093fd4e 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ProgressEventSuppressingEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ProgressEventSuppressingEnvironment.java
@@ -26,6 +26,7 @@
import com.google.devtools.build.skyframe.ValueOrException4;
import com.google.devtools.build.skyframe.ValueOrException5;
import com.google.devtools.build.skyframe.Version;
+import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
@@ -197,6 +198,75 @@
}
@Override
+ public List<SkyValue> getOrderedValues(Iterable<? extends SkyKey> depKeys)
+ throws InterruptedException {
+ return delegate.getOrderedValues(depKeys);
+ }
+
+ @Override
+ public <E extends Exception> List<ValueOrException<E>> getOrderedValuesOrThrow(
+ Iterable<? extends SkyKey> depKeys, Class<E> exceptionClass) throws InterruptedException {
+ return delegate.getOrderedValuesOrThrow(depKeys, exceptionClass);
+ }
+
+ @Override
+ public <E1 extends Exception, E2 extends Exception>
+ List<ValueOrException2<E1, E2>> getOrderedValuesOrThrow(
+ Iterable<? extends SkyKey> depKeys, Class<E1> exceptionClass1, Class<E2> exceptionClass2)
+ throws InterruptedException {
+ return delegate.getOrderedValuesOrThrow(depKeys, exceptionClass1, exceptionClass2);
+ }
+
+ @Override
+ public <E1 extends Exception, E2 extends Exception, E3 extends Exception>
+ List<ValueOrException3<E1, E2, E3>> getOrderedValuesOrThrow(
+ Iterable<? extends SkyKey> depKeys,
+ Class<E1> exceptionClass1,
+ Class<E2> exceptionClass2,
+ Class<E3> exceptionClass3)
+ throws InterruptedException {
+ return delegate.getOrderedValuesOrThrow(
+ depKeys, exceptionClass1, exceptionClass2, exceptionClass3);
+ }
+
+ @Override
+ public <E1 extends Exception, E2 extends Exception, E3 extends Exception, E4 extends Exception>
+ List<ValueOrException4<E1, E2, E3, E4>> getOrderedValuesOrThrow(
+ Iterable<? extends SkyKey> depKeys,
+ Class<E1> exceptionClass1,
+ Class<E2> exceptionClass2,
+ Class<E3> exceptionClass3,
+ Class<E4> exceptionClass4)
+ throws InterruptedException {
+ return delegate.getOrderedValuesOrThrow(
+ depKeys, exceptionClass1, exceptionClass2, exceptionClass3, exceptionClass4);
+ }
+
+ @Override
+ public <
+ E1 extends Exception,
+ E2 extends Exception,
+ E3 extends Exception,
+ E4 extends Exception,
+ E5 extends Exception>
+ List<ValueOrException5<E1, E2, E3, E4, E5>> getOrderedValuesOrThrow(
+ Iterable<? extends SkyKey> depKeys,
+ Class<E1> exceptionClass1,
+ Class<E2> exceptionClass2,
+ Class<E3> exceptionClass3,
+ Class<E4> exceptionClass4,
+ Class<E5> exceptionClass5)
+ throws InterruptedException {
+ return delegate.getOrderedValuesOrThrow(
+ depKeys,
+ exceptionClass1,
+ exceptionClass2,
+ exceptionClass3,
+ exceptionClass4,
+ exceptionClass5);
+ }
+
+ @Override
@Nullable
public GroupedList<SkyKey> getTemporaryDirectDeps() {
return delegate.getTemporaryDirectDeps();
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctionEnvironmentForTesting.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctionEnvironmentForTesting.java
index 894c544..1f2fc19 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctionEnvironmentForTesting.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctionEnvironmentForTesting.java
@@ -25,6 +25,7 @@
import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyValue;
import com.google.devtools.build.skyframe.ValueOrUntypedException;
+import java.util.List;
import java.util.Map;
/**
@@ -62,6 +63,12 @@
}
@Override
+ protected List<ValueOrUntypedException> getOrderedValueOrUntypedExceptions(
+ Iterable<? extends SkyKey> depKeys) throws InterruptedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public boolean inErrorBubblingForTesting() {
return false;
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/StateInformingSkyFunctionEnvironment.java b/src/main/java/com/google/devtools/build/lib/skyframe/StateInformingSkyFunctionEnvironment.java
index 59d8182..a1c8ce7 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/StateInformingSkyFunctionEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/StateInformingSkyFunctionEnvironment.java
@@ -25,6 +25,7 @@
import com.google.devtools.build.skyframe.ValueOrException4;
import com.google.devtools.build.skyframe.ValueOrException5;
import com.google.devtools.build.skyframe.Version;
+import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
@@ -247,6 +248,105 @@
}
@Override
+ public List<SkyValue> getOrderedValues(Iterable<? extends SkyKey> depKeys)
+ throws InterruptedException {
+ preFetch.inform();
+ try {
+ return delegate.getOrderedValues(depKeys);
+ } finally {
+ postFetch.inform();
+ }
+ }
+
+ @Override
+ public <E extends Exception> List<ValueOrException<E>> getOrderedValuesOrThrow(
+ Iterable<? extends SkyKey> depKeys, Class<E> exceptionClass) throws InterruptedException {
+ preFetch.inform();
+ try {
+ return delegate.getOrderedValuesOrThrow(depKeys, exceptionClass);
+ } finally {
+ postFetch.inform();
+ }
+ }
+
+ @Override
+ public <E1 extends Exception, E2 extends Exception>
+ List<ValueOrException2<E1, E2>> getOrderedValuesOrThrow(
+ Iterable<? extends SkyKey> depKeys, Class<E1> exceptionClass1, Class<E2> exceptionClass2)
+ throws InterruptedException {
+ preFetch.inform();
+ try {
+ return delegate.getOrderedValuesOrThrow(depKeys, exceptionClass1, exceptionClass2);
+ } finally {
+ postFetch.inform();
+ }
+ }
+
+ @Override
+ public <E1 extends Exception, E2 extends Exception, E3 extends Exception>
+ List<ValueOrException3<E1, E2, E3>> getOrderedValuesOrThrow(
+ Iterable<? extends SkyKey> depKeys,
+ Class<E1> exceptionClass1,
+ Class<E2> exceptionClass2,
+ Class<E3> exceptionClass3)
+ throws InterruptedException {
+ preFetch.inform();
+ try {
+ return delegate.getOrderedValuesOrThrow(
+ depKeys, exceptionClass1, exceptionClass2, exceptionClass3);
+ } finally {
+ postFetch.inform();
+ }
+ }
+
+ @Override
+ public <E1 extends Exception, E2 extends Exception, E3 extends Exception, E4 extends Exception>
+ List<ValueOrException4<E1, E2, E3, E4>> getOrderedValuesOrThrow(
+ Iterable<? extends SkyKey> depKeys,
+ Class<E1> exceptionClass1,
+ Class<E2> exceptionClass2,
+ Class<E3> exceptionClass3,
+ Class<E4> exceptionClass4)
+ throws InterruptedException {
+ preFetch.inform();
+ try {
+ return delegate.getOrderedValuesOrThrow(
+ depKeys, exceptionClass1, exceptionClass2, exceptionClass3, exceptionClass4);
+ } finally {
+ postFetch.inform();
+ }
+ }
+
+ @Override
+ public <
+ E1 extends Exception,
+ E2 extends Exception,
+ E3 extends Exception,
+ E4 extends Exception,
+ E5 extends Exception>
+ List<ValueOrException5<E1, E2, E3, E4, E5>> getOrderedValuesOrThrow(
+ Iterable<? extends SkyKey> depKeys,
+ Class<E1> exceptionClass1,
+ Class<E2> exceptionClass2,
+ Class<E3> exceptionClass3,
+ Class<E4> exceptionClass4,
+ Class<E5> exceptionClass5)
+ throws InterruptedException {
+ preFetch.inform();
+ try {
+ return delegate.getOrderedValuesOrThrow(
+ depKeys,
+ exceptionClass1,
+ exceptionClass2,
+ exceptionClass3,
+ exceptionClass4,
+ exceptionClass5);
+ } finally {
+ postFetch.inform();
+ }
+ }
+
+ @Override
public ExtendedEventHandler getListener() {
return delegate.getListener();
}
diff --git a/src/main/java/com/google/devtools/build/skyframe/AbstractSkyFunctionEnvironment.java b/src/main/java/com/google/devtools/build/skyframe/AbstractSkyFunctionEnvironment.java
index 4ec831a..3a29f71 100644
--- a/src/main/java/com/google/devtools/build/skyframe/AbstractSkyFunctionEnvironment.java
+++ b/src/main/java/com/google/devtools/build/skyframe/AbstractSkyFunctionEnvironment.java
@@ -15,10 +15,12 @@
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.devtools.build.lib.util.GroupedList;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -57,6 +59,10 @@
protected abstract Map<SkyKey, ValueOrUntypedException> getValueOrUntypedExceptions(
Iterable<? extends SkyKey> depKeys) throws InterruptedException;
+ /** Implementations should set {@link #valuesMissing} as necessary. */
+ protected abstract List<ValueOrUntypedException> getOrderedValueOrUntypedExceptions(
+ Iterable<? extends SkyKey> depKeys) throws InterruptedException;
+
@Override
@Nullable
public SkyValue getValue(SkyKey depKey) throws InterruptedException {
@@ -282,11 +288,33 @@
@Nullable Class<E3> exceptionClass3,
@Nullable Class<E4> exceptionClass4,
@Nullable Class<E5> exceptionClass5) {
+ checkValuesMissingBecauseOfFilteredError(
+ voes.values(),
+ exceptionClass1,
+ exceptionClass2,
+ exceptionClass3,
+ exceptionClass4,
+ exceptionClass5);
+ }
+
+ private <
+ E1 extends Exception,
+ E2 extends Exception,
+ E3 extends Exception,
+ E4 extends Exception,
+ E5 extends Exception>
+ void checkValuesMissingBecauseOfFilteredError(
+ Collection<ValueOrUntypedException> voes,
+ @Nullable Class<E1> exceptionClass1,
+ @Nullable Class<E2> exceptionClass2,
+ @Nullable Class<E3> exceptionClass3,
+ @Nullable Class<E4> exceptionClass4,
+ @Nullable Class<E5> exceptionClass5) {
if (!errorMightHaveBeenFound) {
// Short-circuit in the common case of no errors.
return;
}
- for (ValueOrUntypedException voe : voes.values()) {
+ for (ValueOrUntypedException voe : voes) {
SkyValue value = voe.getValue();
if (value == null) {
Exception e = voe.getException();
@@ -304,6 +332,135 @@
}
@Override
+ public List<SkyValue> getOrderedValues(Iterable<? extends SkyKey> depKeys)
+ throws InterruptedException {
+ List<ValueOrUntypedException> valuesOrExceptions = getOrderedValueOrUntypedExceptions(depKeys);
+ checkValuesMissingBecauseOfFilteredError(valuesOrExceptions, null, null, null, null, null);
+ return Collections.unmodifiableList(
+ Lists.transform(valuesOrExceptions, ValueOrUntypedException::getValue));
+ }
+
+ @Override
+ public <E extends Exception> List<ValueOrException<E>> getOrderedValuesOrThrow(
+ Iterable<? extends SkyKey> depKeys, Class<E> exceptionClass) throws InterruptedException {
+ SkyFunctionException.validateExceptionType(exceptionClass);
+ List<ValueOrUntypedException> valuesOrExceptions = getOrderedValueOrUntypedExceptions(depKeys);
+ checkValuesMissingBecauseOfFilteredError(
+ valuesOrExceptions, exceptionClass, null, null, null, null);
+ return Collections.unmodifiableList(
+ Lists.transform(
+ valuesOrExceptions, voe -> ValueOrException.fromUntypedException(voe, exceptionClass)));
+ }
+
+ @Override
+ public <E1 extends Exception, E2 extends Exception>
+ List<ValueOrException2<E1, E2>> getOrderedValuesOrThrow(
+ Iterable<? extends SkyKey> depKeys, Class<E1> exceptionClass1, Class<E2> exceptionClass2)
+ throws InterruptedException {
+ SkyFunctionException.validateExceptionType(exceptionClass1);
+ SkyFunctionException.validateExceptionType(exceptionClass2);
+ List<ValueOrUntypedException> valuesOrExceptions = getOrderedValueOrUntypedExceptions(depKeys);
+ checkValuesMissingBecauseOfFilteredError(
+ valuesOrExceptions, exceptionClass1, exceptionClass2, null, null, null);
+ return Collections.unmodifiableList(
+ Lists.transform(
+ valuesOrExceptions,
+ voe -> ValueOrException2.fromUntypedException(voe, exceptionClass1, exceptionClass2)));
+ }
+
+ @Override
+ public <E1 extends Exception, E2 extends Exception, E3 extends Exception>
+ List<ValueOrException3<E1, E2, E3>> getOrderedValuesOrThrow(
+ Iterable<? extends SkyKey> depKeys,
+ Class<E1> exceptionClass1,
+ Class<E2> exceptionClass2,
+ Class<E3> exceptionClass3)
+ throws InterruptedException {
+ SkyFunctionException.validateExceptionType(exceptionClass1);
+ SkyFunctionException.validateExceptionType(exceptionClass2);
+ SkyFunctionException.validateExceptionType(exceptionClass3);
+ List<ValueOrUntypedException> valuesOrExceptions = getOrderedValueOrUntypedExceptions(depKeys);
+ checkValuesMissingBecauseOfFilteredError(
+ valuesOrExceptions, exceptionClass1, exceptionClass2, exceptionClass3, null, null);
+ return Collections.unmodifiableList(
+ Lists.transform(
+ valuesOrExceptions,
+ voe ->
+ ValueOrException3.fromUntypedException(
+ voe, exceptionClass1, exceptionClass2, exceptionClass3)));
+ }
+
+ @Override
+ public <E1 extends Exception, E2 extends Exception, E3 extends Exception, E4 extends Exception>
+ List<ValueOrException4<E1, E2, E3, E4>> getOrderedValuesOrThrow(
+ Iterable<? extends SkyKey> depKeys,
+ Class<E1> exceptionClass1,
+ Class<E2> exceptionClass2,
+ Class<E3> exceptionClass3,
+ Class<E4> exceptionClass4)
+ throws InterruptedException {
+ SkyFunctionException.validateExceptionType(exceptionClass1);
+ SkyFunctionException.validateExceptionType(exceptionClass2);
+ SkyFunctionException.validateExceptionType(exceptionClass3);
+ SkyFunctionException.validateExceptionType(exceptionClass4);
+ List<ValueOrUntypedException> valuesOrExceptions = getOrderedValueOrUntypedExceptions(depKeys);
+ checkValuesMissingBecauseOfFilteredError(
+ valuesOrExceptions,
+ exceptionClass1,
+ exceptionClass2,
+ exceptionClass3,
+ exceptionClass4,
+ null);
+ return Collections.unmodifiableList(
+ Lists.transform(
+ 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>
+ List<ValueOrException5<E1, E2, E3, E4, E5>> getOrderedValuesOrThrow(
+ Iterable<? extends SkyKey> depKeys,
+ Class<E1> exceptionClass1,
+ Class<E2> exceptionClass2,
+ Class<E3> exceptionClass3,
+ Class<E4> exceptionClass4,
+ Class<E5> exceptionClass5)
+ throws InterruptedException {
+ SkyFunctionException.validateExceptionType(exceptionClass1);
+ SkyFunctionException.validateExceptionType(exceptionClass2);
+ SkyFunctionException.validateExceptionType(exceptionClass3);
+ SkyFunctionException.validateExceptionType(exceptionClass4);
+ SkyFunctionException.validateExceptionType(exceptionClass5);
+ List<ValueOrUntypedException> valuesOrExceptions = getOrderedValueOrUntypedExceptions(depKeys);
+ checkValuesMissingBecauseOfFilteredError(
+ valuesOrExceptions,
+ exceptionClass1,
+ exceptionClass2,
+ exceptionClass3,
+ exceptionClass4,
+ exceptionClass5);
+ return Collections.unmodifiableList(
+ Lists.transform(
+ valuesOrExceptions,
+ voe ->
+ ValueOrException5.fromUntypedException(
+ voe,
+ exceptionClass1,
+ exceptionClass2,
+ exceptionClass3,
+ exceptionClass4,
+ exceptionClass5)));
+ }
+
+ @Override
public boolean valuesMissing() {
return valuesMissing || (externalDeps != null);
}
diff --git a/src/main/java/com/google/devtools/build/skyframe/QueryableGraphBackedSkyFunctionEnvironment.java b/src/main/java/com/google/devtools/build/skyframe/QueryableGraphBackedSkyFunctionEnvironment.java
index c07e510..d4bd5bd 100644
--- a/src/main/java/com/google/devtools/build/skyframe/QueryableGraphBackedSkyFunctionEnvironment.java
+++ b/src/main/java/com/google/devtools/build/skyframe/QueryableGraphBackedSkyFunctionEnvironment.java
@@ -17,6 +17,7 @@
import com.google.common.collect.Maps;
import com.google.devtools.build.lib.events.ExtendedEventHandler;
import com.google.devtools.build.skyframe.QueryableGraph.Reason;
+import java.util.List;
import java.util.Map;
/**
@@ -75,6 +76,12 @@
}
@Override
+ protected List<ValueOrUntypedException> getOrderedValueOrUntypedExceptions(
+ Iterable<? extends SkyKey> depKeys) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public ExtendedEventHandler getListener() {
return eventHandler;
}
diff --git a/src/main/java/com/google/devtools/build/skyframe/RecordingSkyFunctionEnvironment.java b/src/main/java/com/google/devtools/build/skyframe/RecordingSkyFunctionEnvironment.java
index 4b55081..52e64f8 100644
--- a/src/main/java/com/google/devtools/build/skyframe/RecordingSkyFunctionEnvironment.java
+++ b/src/main/java/com/google/devtools/build/skyframe/RecordingSkyFunctionEnvironment.java
@@ -17,6 +17,7 @@
import com.google.devtools.build.lib.events.ExtendedEventHandler;
import com.google.devtools.build.lib.util.GroupedList;
import com.google.devtools.build.skyframe.SkyFunction.Environment;
+import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import javax.annotation.Nullable;
@@ -265,6 +266,115 @@
}
@Override
+ public List<SkyValue> getOrderedValues(Iterable<? extends SkyKey> depKeys)
+ throws InterruptedException {
+ return delegate.getOrderedValues(depKeys);
+ }
+
+ @Override
+ public <E extends Exception> List<ValueOrException<E>> getOrderedValuesOrThrow(
+ Iterable<? extends SkyKey> depKeys, Class<E> exceptionClass) throws InterruptedException {
+ recordDeps(depKeys);
+ try {
+ return delegate.getOrderedValuesOrThrow(depKeys, exceptionClass);
+ } catch (
+ @SuppressWarnings("InterruptedExceptionSwallowed")
+ Exception e) {
+ noteException(e);
+ throw e;
+ }
+ }
+
+ @Override
+ public <E1 extends Exception, E2 extends Exception>
+ List<ValueOrException2<E1, E2>> getOrderedValuesOrThrow(
+ Iterable<? extends SkyKey> depKeys, Class<E1> exceptionClass1, Class<E2> exceptionClass2)
+ throws InterruptedException {
+ recordDeps(depKeys);
+ try {
+ return delegate.getOrderedValuesOrThrow(depKeys, exceptionClass1, exceptionClass2);
+ } catch (
+ @SuppressWarnings("InterruptedExceptionSwallowed")
+ Exception e) {
+ noteException(e);
+ throw e;
+ }
+ }
+
+ @Override
+ public <E1 extends Exception, E2 extends Exception, E3 extends Exception>
+ List<ValueOrException3<E1, E2, E3>> getOrderedValuesOrThrow(
+ Iterable<? extends SkyKey> depKeys,
+ Class<E1> exceptionClass1,
+ Class<E2> exceptionClass2,
+ Class<E3> exceptionClass3)
+ throws InterruptedException {
+ recordDeps(depKeys);
+ try {
+ return delegate.getOrderedValuesOrThrow(
+ depKeys, exceptionClass1, exceptionClass2, exceptionClass3);
+ } catch (
+ @SuppressWarnings("InterruptedExceptionSwallowed")
+ Exception e) {
+ noteException(e);
+ throw e;
+ }
+ }
+
+ @Override
+ public <E1 extends Exception, E2 extends Exception, E3 extends Exception, E4 extends Exception>
+ List<ValueOrException4<E1, E2, E3, E4>> getOrderedValuesOrThrow(
+ Iterable<? extends SkyKey> depKeys,
+ Class<E1> exceptionClass1,
+ Class<E2> exceptionClass2,
+ Class<E3> exceptionClass3,
+ Class<E4> exceptionClass4)
+ throws InterruptedException {
+ recordDeps(depKeys);
+ try {
+ return delegate.getOrderedValuesOrThrow(
+ depKeys, exceptionClass1, exceptionClass2, exceptionClass3, exceptionClass4);
+ } catch (
+ @SuppressWarnings("InterruptedExceptionSwallowed")
+ Exception e) {
+ noteException(e);
+ throw e;
+ }
+ }
+
+ @Override
+ public <
+ E1 extends Exception,
+ E2 extends Exception,
+ E3 extends Exception,
+ E4 extends Exception,
+ E5 extends Exception>
+ List<ValueOrException5<E1, E2, E3, E4, E5>> getOrderedValuesOrThrow(
+ Iterable<? extends SkyKey> depKeys,
+ Class<E1> exceptionClass1,
+ Class<E2> exceptionClass2,
+ Class<E3> exceptionClass3,
+ Class<E4> exceptionClass4,
+ Class<E5> exceptionClass5)
+ throws InterruptedException {
+ recordDeps(depKeys);
+ try {
+ return delegate.getOrderedValuesOrThrow(
+ depKeys,
+ exceptionClass1,
+ exceptionClass2,
+ exceptionClass3,
+ exceptionClass4,
+ exceptionClass5);
+ } catch (
+ @SuppressWarnings("InterruptedExceptionSwallowed")
+ Exception e) {
+ noteException(e);
+ throw e;
+ }
+ }
+
+ @Override
public ExtendedEventHandler getListener() {
return delegate.getListener();
}
diff --git a/src/main/java/com/google/devtools/build/skyframe/SkyFunction.java b/src/main/java/com/google/devtools/build/skyframe/SkyFunction.java
index 1117bc8..0ba2590 100644
--- a/src/main/java/com/google/devtools/build/skyframe/SkyFunction.java
+++ b/src/main/java/com/google/devtools/build/skyframe/SkyFunction.java
@@ -21,6 +21,7 @@
import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
import com.google.devtools.build.lib.events.ExtendedEventHandler;
import com.google.devtools.build.lib.util.GroupedList;
+import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
@@ -245,6 +246,12 @@
Map<SkyKey, SkyValue> getValues(Iterable<? extends SkyKey> depKeys) throws InterruptedException;
/**
+ * Similar to getValues, but instead of returning a {@code Map<SkyKey, SkyValue>}, returns a
+ * {@code List<SkyValue>} in the order of the input {@code Iterable<SkyKey>}. b/172462551
+ */
+ List<SkyValue> getOrderedValues(Iterable<? extends SkyKey> depKeys) throws InterruptedException;
+
+ /**
* Similar to {@link #getValues} but allows the caller to specify a set of types that are proper
* subtypes of Exception (see {@link SkyFunctionException} for more details) to find out whether
* any of the dependencies' evaluations resulted in exceptions of those types. The returned
@@ -304,6 +311,53 @@
throws InterruptedException;
/**
+ * Similar to getValuesOrThrow, but instead of returning a {@code Map<SkyKey,
+ * ValueOrException>}, returns a {@code List<SkyValue>} in the order of the input {@code
+ * Iterable<SkyKey>}.
+ */
+ <E extends Exception> List<ValueOrException<E>> getOrderedValuesOrThrow(
+ Iterable<? extends SkyKey> depKeys, Class<E> exceptionClass) throws InterruptedException;
+
+ <E1 extends Exception, E2 extends Exception>
+ List<ValueOrException2<E1, E2>> getOrderedValuesOrThrow(
+ Iterable<? extends SkyKey> depKeys,
+ Class<E1> exceptionClass1,
+ Class<E2> exceptionClass2)
+ throws InterruptedException;
+
+ <E1 extends Exception, E2 extends Exception, E3 extends Exception>
+ List<ValueOrException3<E1, E2, E3>> getOrderedValuesOrThrow(
+ Iterable<? extends SkyKey> depKeys,
+ Class<E1> exceptionClass1,
+ Class<E2> exceptionClass2,
+ Class<E3> exceptionClass3)
+ throws InterruptedException;
+
+ <E1 extends Exception, E2 extends Exception, E3 extends Exception, E4 extends Exception>
+ List<ValueOrException4<E1, E2, E3, E4>> getOrderedValuesOrThrow(
+ Iterable<? extends SkyKey> depKeys,
+ Class<E1> exceptionClass1,
+ Class<E2> exceptionClass2,
+ Class<E3> exceptionClass3,
+ Class<E4> exceptionClass4)
+ throws InterruptedException;
+
+ <
+ E1 extends Exception,
+ E2 extends Exception,
+ E3 extends Exception,
+ E4 extends Exception,
+ E5 extends Exception>
+ List<ValueOrException5<E1, E2, E3, E4, E5>> getOrderedValuesOrThrow(
+ Iterable<? extends SkyKey> depKeys,
+ Class<E1> exceptionClass1,
+ Class<E2> exceptionClass2,
+ Class<E3> exceptionClass3,
+ Class<E4> exceptionClass4,
+ Class<E5> exceptionClass5)
+ throws InterruptedException;
+
+ /**
* Returns whether there was a previous getValue[s][OrThrow] that indicated a missing
* dependency. Formally, returns true iff at least one of the following occurred:
*
diff --git a/src/main/java/com/google/devtools/build/skyframe/SkyFunctionEnvironment.java b/src/main/java/com/google/devtools/build/skyframe/SkyFunctionEnvironment.java
index afe1492..ea24d9a 100644
--- a/src/main/java/com/google/devtools/build/skyframe/SkyFunctionEnvironment.java
+++ b/src/main/java/com/google/devtools/build/skyframe/SkyFunctionEnvironment.java
@@ -20,6 +20,7 @@
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.devtools.build.lib.collect.compacthashmap.CompactHashMap;
@@ -401,6 +402,58 @@
}
/**
+ * Similar to {@link #getValuesFromErrorOrDepsOrGraph}, but instead of a Map, return a List of
+ * SkyValue ordered by the given order of SkyKeys.
+ */
+ private List<SkyValue> getOrderedValuesFromErrorOrDepsOrGraph(Iterable<? extends SkyKey> keys)
+ throws InterruptedException {
+ int capacity = keys instanceof Collection ? ((Collection<?>) keys).size() : 16;
+ List<SkyValue> result = new ArrayList<>(capacity);
+
+ // Ignoring duplication check here since it's done in GroupedList.
+ List<SkyKey> missingKeys = new ArrayList<>();
+ newlyRequestedDeps.startGroup();
+ for (SkyKey key : keys) {
+ Preconditions.checkState(
+ !key.equals(ErrorTransienceValue.KEY),
+ "Error transience key cannot be in requested deps of %s",
+ skyKey);
+ SkyValue value = maybeGetValueFromErrorOrDeps(key);
+ if (value == null) {
+ missingKeys.add(key);
+ }
+ // To maintain the ordering.
+ result.add(value);
+ if (!previouslyRequestedDepsValues.containsKey(key)) {
+ newlyRequestedDeps.add(key);
+ }
+ }
+ newlyRequestedDeps.endGroup();
+
+ if (missingKeys.isEmpty()) {
+ return result;
+ }
+
+ Map<SkyKey, ? extends NodeEntry> missingEntries =
+ evaluatorContext.getBatchValues(skyKey, Reason.DEP_REQUESTED, missingKeys);
+ int i = 0;
+ for (SkyKey key : keys) {
+ if (result.get(i) != null) {
+ continue;
+ }
+ NodeEntry depEntry = missingEntries.get(key);
+ SkyValue valueOrNullMarker = getValueOrNullMarker(depEntry);
+ result.set(i, valueOrNullMarker);
+ newlyRequestedDepsValues.put(key, valueOrNullMarker);
+ if (valueOrNullMarker != NULL_MARKER) {
+ maybeUpdateMaxChildVersion(depEntry);
+ }
+ i++;
+ }
+ return result;
+ }
+
+ /**
* Returns the values of done deps in {@code depKeys}, by looking in order at:
*
* <ol>
@@ -571,46 +624,90 @@
}
}
- return Maps.transformValues(
- values,
- maybeWrappedValue -> {
- if (maybeWrappedValue == NULL_MARKER) {
- return ValueOrUntypedException.ofNull();
- }
- SkyValue justValue = ValueWithMetadata.justValue(maybeWrappedValue);
- ErrorInfo errorInfo = ValueWithMetadata.getMaybeErrorInfo(maybeWrappedValue);
+ return Maps.transformValues(values, this::transformToValueOrUntypedException);
+ }
- if (justValue != null && (evaluatorContext.keepGoing() || errorInfo == null)) {
- // If the dep did compute a value, it is given to the caller if we are in
- // keepGoing mode or if we are in noKeepGoingMode and there were no errors computing
- // it.
- return ValueOrUntypedException.ofValueUntyped(justValue);
- }
+ @Override
+ protected List<ValueOrUntypedException> getOrderedValueOrUntypedExceptions(
+ Iterable<? extends SkyKey> depKeys) throws InterruptedException {
+ checkActive();
+ List<SkyValue> values = getOrderedValuesFromErrorOrDepsOrGraph(depKeys);
+ int i = 0;
+ for (SkyKey depKey : depKeys) {
+ SkyValue depValue = values.get(i++);
- // There was an error building the value, which we will either report by throwing an
- // exception or insulate the caller from by returning null.
- Preconditions.checkNotNull(errorInfo, "%s %s", skyKey, maybeWrappedValue);
- Exception exception = errorInfo.getException();
-
- if (!evaluatorContext.keepGoing() && exception != null && bubbleErrorInfo == null) {
- // Child errors should not be propagated in noKeepGoing mode (except during error
- // bubbling). Instead we should fail fast.
- return ValueOrUntypedException.ofNull();
- }
-
- if (exception != null) {
- // Give builder a chance to handle this exception.
- return ValueOrUntypedException.ofExn(exception);
- }
- // In a cycle.
+ if (depValue == NULL_MARKER) {
+ valuesMissing = true;
+ if (previouslyRequestedDepsValues.containsKey(depKey)) {
Preconditions.checkState(
- !errorInfo.getCycleInfo().isEmpty(),
- "%s %s %s",
+ bubbleErrorInfo != null,
+ "Undone key %s was already in deps of %s( dep: %s, parent: %s )",
+ depKey,
skyKey,
- errorInfo,
- maybeWrappedValue);
- return ValueOrUntypedException.ofNull();
- });
+ evaluatorContext.getGraph().get(skyKey, Reason.OTHER, depKey),
+ evaluatorContext.getGraph().get(null, Reason.OTHER, skyKey));
+ }
+ continue;
+ }
+
+ ErrorInfo errorInfo = ValueWithMetadata.getMaybeErrorInfo(depValue);
+ if (errorInfo != null) {
+ errorMightHaveBeenFound = true;
+ childErrorInfos.add(errorInfo);
+ if (bubbleErrorInfo != null) {
+ // Set interrupted status, to try to prevent the calling SkyFunction from doing anything
+ // fancy after this. SkyFunctions executed during error bubbling are supposed to
+ // (quickly) rethrow errors or return a value/null (but there's currently no way to
+ // enforce this).
+ Thread.currentThread().interrupt();
+ }
+ if ((!evaluatorContext.keepGoing() && bubbleErrorInfo == null)
+ || errorInfo.getException() == null) {
+ valuesMissing = true;
+ // We arbitrarily record the first child error if we are about to abort.
+ if (!evaluatorContext.keepGoing() && depErrorKey == null) {
+ depErrorKey = depKey;
+ }
+ }
+ }
+ }
+
+ return Lists.transform(values, this::transformToValueOrUntypedException);
+ }
+
+ private ValueOrUntypedException transformToValueOrUntypedException(SkyValue maybeWrappedValue) {
+ if (maybeWrappedValue == NULL_MARKER) {
+ return ValueOrUntypedException.ofNull();
+ }
+ SkyValue justValue = ValueWithMetadata.justValue(maybeWrappedValue);
+ ErrorInfo errorInfo = ValueWithMetadata.getMaybeErrorInfo(maybeWrappedValue);
+
+ if (justValue != null && (evaluatorContext.keepGoing() || errorInfo == null)) {
+ // If the dep did compute a value, it is given to the caller if we are in
+ // keepGoing mode or if we are in noKeepGoingMode and there were no errors computing
+ // it.
+ return ValueOrUntypedException.ofValueUntyped(justValue);
+ }
+
+ // There was an error building the value, which we will either report by throwing an
+ // exception or insulate the caller from by returning null.
+ Preconditions.checkNotNull(errorInfo, "%s %s", skyKey, maybeWrappedValue);
+ Exception exception = errorInfo.getException();
+
+ if (!evaluatorContext.keepGoing() && exception != null && bubbleErrorInfo == null) {
+ // Child errors should not be propagated in noKeepGoing mode (except during error
+ // bubbling). Instead we should fail fast.
+ return ValueOrUntypedException.ofNull();
+ }
+
+ if (exception != null) {
+ // Give builder a chance to handle this exception.
+ return ValueOrUntypedException.ofExn(exception);
+ }
+ // In a cycle.
+ Preconditions.checkState(
+ !errorInfo.getCycleInfo().isEmpty(), "%s %s %s", skyKey, errorInfo, maybeWrappedValue);
+ return ValueOrUntypedException.ofNull();
}
/**
diff --git a/src/test/java/com/google/devtools/build/lib/actions/util/ActionsTestUtil.java b/src/test/java/com/google/devtools/build/lib/actions/util/ActionsTestUtil.java
index 39b4389..fda987b 100644
--- a/src/test/java/com/google/devtools/build/lib/actions/util/ActionsTestUtil.java
+++ b/src/test/java/com/google/devtools/build/lib/actions/util/ActionsTestUtil.java
@@ -355,6 +355,12 @@
}
@Override
+ protected List<ValueOrUntypedException> getOrderedValueOrUntypedExceptions(
+ Iterable<? extends SkyKey> depKeys) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public ExtendedEventHandler getListener() {
return null;
}