Add bulk package lookup for use during target pattern resolution.
--
MOS_MIGRATED_REVID=111130363
diff --git a/src/main/java/com/google/devtools/build/lib/pkgcache/RecursivePackageProvider.java b/src/main/java/com/google/devtools/build/lib/pkgcache/RecursivePackageProvider.java
index 24866b6..808085b 100644
--- a/src/main/java/com/google/devtools/build/lib/pkgcache/RecursivePackageProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/pkgcache/RecursivePackageProvider.java
@@ -14,10 +14,16 @@
package com.google.devtools.build.lib.pkgcache;
import com.google.common.collect.ImmutableSet;
+import com.google.devtools.build.lib.cmdline.PackageIdentifier;
import com.google.devtools.build.lib.cmdline.PackageIdentifier.RepositoryName;
+import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.packages.NoSuchPackageException;
+import com.google.devtools.build.lib.packages.Package;
import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.lib.vfs.RootedPath;
+import java.util.Map;
+
/**
* Support for resolving {@code package/...} target patterns.
*/
@@ -31,4 +37,23 @@
*/
Iterable<PathFragment> getPackagesUnderDirectory(RepositoryName repository,
PathFragment directory, ImmutableSet<PathFragment> excludedSubdirectories);
+
+
+ /**
+ * Returns the {@link Package} corresponding to each Package in "pkgIds". If any of the packages
+ * does not exist (e.g. {@code isPackage(pkgIds)} returns false), throws a
+ * {@link NoSuchPackageException}.
+ *
+ * <p>The returned package may contain lexical/grammatical errors, in which case
+ * <code>pkg.containsErrors() == true</code>. Such packages may be missing some rules. Any rules
+ * that are present may soundly be used for builds, though.
+ *
+ * @param eventHandler the eventHandler on which to report warning and errors; if the package
+ * has been loaded by another thread, this eventHandler won't see any warnings or errors
+ * @param pkgIds an Iterable of PackageIdentifier objects.
+ * @throws NoSuchPackageException if any package could not be found.
+ * @throws InterruptedException if the package loading was interrupted.
+ */
+ Map<PackageIdentifier, Package> bulkGetPackages(EventHandler eventHandler,
+ Iterable<PackageIdentifier> pkgIds) throws NoSuchPackageException, InterruptedException;
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/EnvironmentBackedRecursivePackageProvider.java b/src/main/java/com/google/devtools/build/lib/skyframe/EnvironmentBackedRecursivePackageProvider.java
index 115a0f5..db6639d 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/EnvironmentBackedRecursivePackageProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/EnvironmentBackedRecursivePackageProvider.java
@@ -13,6 +13,7 @@
// limitations under the License.
package com.google.devtools.build.lib.skyframe;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.cmdline.Label;
@@ -37,6 +38,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
/**
* A {@link RecursivePackageProvider} backed by an {@link Environment}. Its methods
@@ -78,6 +80,17 @@
}
@Override
+ public Map<PackageIdentifier, Package> bulkGetPackages(EventHandler eventHandler,
+ Iterable<PackageIdentifier> pkgIds)
+ throws NoSuchPackageException, InterruptedException {
+ ImmutableMap.Builder<PackageIdentifier, Package> builder = ImmutableMap.builder();
+ for (PackageIdentifier pkgId : pkgIds) {
+ builder.put(pkgId, getPackage(eventHandler, pkgId));
+ }
+ return builder.build();
+ }
+
+ @Override
public boolean isPackage(EventHandler eventHandler, PackageIdentifier packageId)
throws MissingDepException {
SkyKey packageLookupKey = PackageLookupValue.key(packageId);
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/GraphBackedRecursivePackageProvider.java b/src/main/java/com/google/devtools/build/lib/skyframe/GraphBackedRecursivePackageProvider.java
index 2768c31..f8761ba 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/GraphBackedRecursivePackageProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/GraphBackedRecursivePackageProvider.java
@@ -15,11 +15,13 @@
import com.google.common.base.Function;
import com.google.common.base.Objects;
+import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.google.common.collect.Sets.SetView;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.PackageIdentifier;
import com.google.devtools.build.lib.cmdline.PackageIdentifier.RepositoryName;
@@ -90,6 +92,36 @@
}
@Override
+ public Map<PackageIdentifier, Package> bulkGetPackages(EventHandler eventHandler,
+ Iterable<PackageIdentifier> pkgIds) throws NoSuchPackageException {
+ Set<SkyKey> pkgKeys = ImmutableSet.copyOf(PackageValue.keys(pkgIds));
+
+ ImmutableMap.Builder<PackageIdentifier, Package> pkgResults = ImmutableMap.builder();
+ Map<SkyKey, SkyValue> packages = graph.getSuccessfulValues(pkgKeys);
+ for (PackageIdentifier pkgId : pkgIds) {
+ PackageValue pkgValue = (PackageValue) packages.get(PackageValue.key(pkgId));
+ pkgResults.put(pkgId, Preconditions.checkNotNull(pkgValue.getPackage(), pkgId));
+ }
+
+ SetView<SkyKey> unknownKeys = Sets.difference(pkgKeys, packages.keySet());
+ for (Map.Entry<SkyKey, Exception> missingOrExceptionEntry :
+ graph.getMissingAndExceptions(unknownKeys).entrySet()) {
+ PackageIdentifier pkgIdentifier =
+ (PackageIdentifier) missingOrExceptionEntry.getKey().argument();
+ Exception exception = missingOrExceptionEntry.getValue();
+ if (exception == null) {
+ // If the package key does not exist in the graph, then it must not correspond to any
+ // package, because the SkyQuery environment has already loaded the universe.
+ throw new BuildFileNotFoundException(pkgIdentifier, "BUILD file not found on package path");
+ }
+ Throwables.propagateIfInstanceOf(exception, NoSuchPackageException.class);
+ Throwables.propagate(exception);
+ }
+ return pkgResults.build();
+ }
+
+
+ @Override
public boolean isPackage(EventHandler eventHandler, PackageIdentifier packageName) {
SkyKey packageLookupKey = PackageLookupValue.key(packageName);
if (!graph.exists(packageLookupKey)) {
@@ -162,21 +194,6 @@
return builder.build();
}
- private final void preloadPackages(final RepositoryName repositoryName,
- Iterable<TraversalInfo> traversals) {
- // Note that the return value is intentionally unused - we call this to elicit the side effect
- // that the packages end up warm in the graph.
- graph.getSuccessfulValues(Iterables.transform(traversals,
- new Function<TraversalInfo, SkyKey>() {
- @Override
- public SkyKey apply(TraversalInfo traversalInfo) {
- return PackageValue.key(
- PackageIdentifier.create(repositoryName,
- traversalInfo.rootedDir.getRelativePath()));
- }
- }));
- }
-
private void collectPackagesUnder(final RepositoryName repository,
Set<TraversalInfo> traversals, ImmutableList.Builder<PathFragment> builder,
final FilteringPolicy policy) {
@@ -189,9 +206,6 @@
}
});
Map<SkyKey, SkyValue> values = graph.getSuccessfulValues(traversalToKeyMap.values());
- // Preload the packages so subsequent lookups are faster. A better approach might be forego this
- // here, and instead load the needed package in batch on demand.
- preloadPackages(repository, traversals);
ImmutableSet.Builder<TraversalInfo> subdirTraversalBuilder = ImmutableSet.builder();
for (Map.Entry<TraversalInfo, SkyKey> entry : traversalToKeyMap.entrySet()) {
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/RecursivePackageProviderBackedTargetPatternResolver.java b/src/main/java/com/google/devtools/build/lib/skyframe/RecursivePackageProviderBackedTargetPatternResolver.java
index 3f5f76e..d3f758f 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/RecursivePackageProviderBackedTargetPatternResolver.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/RecursivePackageProviderBackedTargetPatternResolver.java
@@ -13,7 +13,10 @@
// limitations under the License.
package com.google.devtools.build.lib.skyframe;
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.PackageIdentifier;
import com.google.devtools.build.lib.cmdline.PackageIdentifier.RepositoryName;
@@ -32,6 +35,8 @@
import com.google.devtools.build.lib.pkgcache.TargetPatternResolverUtil;
import com.google.devtools.build.lib.vfs.PathFragment;
+import java.util.Map;
+
/**
* A {@link TargetPatternResolver} backed by a {@link RecursivePackageProvider}.
*/
@@ -65,6 +70,11 @@
return recursivePackageProvider.getPackage(eventHandler, pkgIdentifier);
}
+ private Map<PackageIdentifier, Package> bulkGetPackages(Iterable<PackageIdentifier> pkgIds)
+ throws NoSuchPackageException, InterruptedException {
+ return recursivePackageProvider.bulkGetPackages(eventHandler, pkgIds);
+ }
+
@Override
public Target getTargetOrNull(Label label) throws InterruptedException {
try {
@@ -113,6 +123,26 @@
}
}
+ private Map<PackageIdentifier, ResolvedTargets<Target>> bulkGetTargetsInPackage(
+ String originalPattern,
+ Iterable<PackageIdentifier> pkgIds, FilteringPolicy policy)
+ throws TargetParsingException, InterruptedException {
+ try {
+ Map<PackageIdentifier, Package> pkgs = bulkGetPackages(pkgIds);
+ ImmutableMap.Builder<PackageIdentifier, ResolvedTargets<Target>> result =
+ ImmutableMap.builder();
+ for (PackageIdentifier pkgId : pkgIds) {
+ Package pkg = pkgs.get(pkgId);
+ result.put(pkgId, TargetPatternResolverUtil.resolvePackageTargets(pkg, policy));
+ }
+ return result.build();
+ } catch (NoSuchThingException e) {
+ String message = TargetPatternResolverUtil.getParsingErrorMessage(
+ e.getMessage(), originalPattern);
+ throw new TargetParsingException(message, e);
+ }
+ }
+
@Override
public boolean isPackage(PackageIdentifier packageIdentifier) {
return recursivePackageProvider.isPackage(eventHandler, packageIdentifier);
@@ -124,7 +154,7 @@
}
@Override
- public ResolvedTargets<Target> findTargetsBeneathDirectory(RepositoryName repository,
+ public ResolvedTargets<Target> findTargetsBeneathDirectory(final RepositoryName repository,
String originalPattern, String directory, boolean rulesOnly,
ImmutableSet<String> excludedSubdirectories)
throws TargetParsingException, InterruptedException {
@@ -138,10 +168,17 @@
Iterable<PathFragment> packagesUnderDirectory =
recursivePackageProvider.getPackagesUnderDirectory(
repository, pathFragment, excludedPathFragments);
- for (PathFragment pkg : packagesUnderDirectory) {
- targetBuilder.merge(getTargetsInPackage(originalPattern,
- PackageIdentifier.create(repository, pkg),
- FilteringPolicies.NO_FILTER));
+
+ Iterable<PackageIdentifier> pkgIds = Iterables.transform(packagesUnderDirectory,
+ new Function<PathFragment, PackageIdentifier>() {
+ @Override
+ public PackageIdentifier apply(PathFragment path) {
+ return PackageIdentifier.create(repository, path);
+ }
+ });
+ for (ResolvedTargets<Target> targets : bulkGetTargetsInPackage(originalPattern, pkgIds,
+ FilteringPolicies.NO_FILTER).values()) {
+ targetBuilder.merge(targets);
}
// Perform the no-targets-found check before applying the filtering policy so we only return the