Skip to content

Commit

Permalink
Sort DirectoryNode children to ensure validity.
Browse files Browse the repository at this point in the history
InputTree will create DirectoryNodes with non-sequential additions of
directory children. These must be maintained in order for representation
within remote Directory messages (and to properly compute action keys).

Co-Author=buchgr

Closes #8008.

PiperOrigin-RevId: 243235156
  • Loading branch information
George Gensure authored and Copybara-Service committed Apr 12, 2019
1 parent 0e3db34 commit 4299b65
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import build.bazel.remote.execution.v2.Digest;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.Sets;
import com.google.devtools.build.lib.actions.ActionInput;
import com.google.devtools.build.lib.actions.ActionInputHelper;
import com.google.devtools.build.lib.actions.FileArtifactValue;
Expand All @@ -34,6 +35,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;

/**
Expand All @@ -46,7 +48,7 @@ interface Visitor {
void visitDirectory(PathFragment dirname, List<FileNode> files, List<DirectoryNode> dirs);
}

abstract static class Node {
abstract static class Node implements Comparable<Node> {
private final String pathSegment;

Node(String pathSegment) {
Expand All @@ -57,6 +59,11 @@ String getPathSegment() {
return pathSegment;
}

@Override
public int compareTo(Node other) {
return pathSegment.compareTo(other.pathSegment);
}

@Override
public int hashCode() {
return pathSegment.hashCode();
Expand Down Expand Up @@ -108,7 +115,7 @@ public boolean equals(Object o) {
}

static class DirectoryNode extends Node {
private final List<Node> children = new ArrayList<>();
private final SortedSet<Node> children = Sets.newTreeSet();

DirectoryNode(String pathSegment) {
super(pathSegment);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,30 @@ public void directoryInputShouldBeExpanded() throws Exception {
assertThat(fileNodesAtDepth(tree, 3)).containsExactly(expectedBuzzNode);
}

@Test
public void testLexicographicalOrder() throws Exception {
// Regression test for https://github.com/bazelbuild/bazel/pull/8008
//
// The issue was that before #8008 we wrongly assumed that a sorted full list of inputs would
// also lead to sorted tree nodes. Thereby not taking into account that the path separator '/'
// influences the sorting of the full list but not that of the tree nodes as its stripped there.
// For example, the below full list is lexicographically sorted
// srcs/system-root/bar.txt
// srcs/system/foo.txt
//
// However, the tree node [system-root, system] is not (note the missing / suffix).

SortedMap<PathFragment, ActionInput> sortedInputs = new TreeMap<>();
Map<ActionInput, FileArtifactValue> metadata = new HashMap<>();

addFile("srcs/system/foo.txt", "foo", sortedInputs, metadata);
addFile("srcs/system-root/bar.txt", "bar", sortedInputs, metadata);

InputTree tree =
InputTree.build(sortedInputs, new StaticMetadataProvider(metadata), execRoot, digestUtil);
assertLexicographicalOrder(tree);
}

private Artifact addFile(
String path,
String content,
Expand All @@ -193,28 +217,18 @@ private VirtualActionInput addVirtualFile(
}

private static void assertLexicographicalOrder(InputTree tree) {
int depth = 0;
while (true) {
// String::compareTo implements lexicographical order
List<String> files = filesAtDepth(depth, tree);
assertThat(files).isStrictlyOrdered();
List<String> directories = directoriesAtDepth(depth, tree);
assertThat(directories).isStrictlyOrdered();
if (directories.isEmpty()) {
break;
}
depth++;
}
// Assert the lexicographical order as defined by the remote execution protocol
tree.visit(
(PathFragment dirname, List<FileNode> files, List<DirectoryNode> dirs) -> {
assertThat(files).isStrictlyOrdered();
assertThat(dirs).isStrictlyOrdered();
});
}

private static List<String> directoriesAtDepth(int depth, InputTree tree) {
return asPathSegments(directoryNodesAtDepth(tree, depth));
}

private static List<String> filesAtDepth(int depth, InputTree tree) {
return asPathSegments(fileNodesAtDepth(tree, depth));
}

private static List<String> asPathSegments(List<? extends Node> nodes) {
return nodes.stream().map(Node::getPathSegment).collect(Collectors.toList());
}
Expand Down

0 comments on commit 4299b65

Please sign in to comment.