Skip to content

Commit a88f62b

Browse files
wiwaShaneDelmore
andcommitted
wip: Add test utils and tests for ProtoCoordinator
Co-authored-by: Shane Delmore <shane@delmore.io>
1 parent 59d3a60 commit a88f62b

File tree

14 files changed

+405
-96
lines changed

14 files changed

+405
-96
lines changed

src/main/java/build/buildfarm/worker/Executor.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -452,12 +452,7 @@ private Code executeCommand(
452452
Tree execTree = workerContext.getQueuedOperation(operationContext.queueEntry).getTree();
453453

454454
WorkFilesContext filesContext =
455-
new WorkFilesContext(
456-
execDir,
457-
execTree,
458-
ImmutableList.copyOf(operationContext.command.getOutputPathsList()),
459-
ImmutableList.copyOf(operationContext.command.getOutputFilesList()),
460-
ImmutableList.copyOf(operationContext.command.getOutputDirectoriesList()));
455+
WorkFilesContext.fromContext(execDir, execTree, operationContext.command);
461456

462457
return PersistentExecutor.runOnPersistentWorker(
463458
limits.persistentWorkerCommand,
@@ -467,6 +462,7 @@ private Code executeCommand(
467462
ImmutableMap.copyOf(environment),
468463
limits,
469464
timeout,
465+
PersistentExecutor.defaultWorkRootsDir,
470466
resultBuilder);
471467
}
472468

src/main/java/build/buildfarm/worker/OperationContext.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import com.google.longrunning.Operation;
2323
import java.nio.file.Path;
2424

25-
final class OperationContext {
25+
public final class OperationContext {
2626
final ExecuteResponse.Builder executeResponse;
2727
final Operation operation;
2828
final Poller poller;

src/main/java/build/buildfarm/worker/persistent/FileAccessUtils.java

Lines changed: 24 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,41 @@
33
import static java.nio.file.StandardCopyOption.COPY_ATTRIBUTES;
44
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
55

6+
import com.google.common.collect.ImmutableSet;
67
import java.io.IOException;
78
import java.nio.file.Files;
89
import java.nio.file.Path;
10+
import java.nio.file.attribute.PosixFilePermission;
11+
import java.util.Set;
912
import java.util.concurrent.ConcurrentHashMap;
1013
import java.util.function.Supplier;
1114
import java.util.logging.Logger;
1215

13-
// Utility for concurrent move/copy/link of files
16+
/**
17+
* Utility for concurrent move/copy of files Can be extended in the future to (sym)linking if we
18+
* need performance
19+
*/
1420
public final class FileAccessUtils {
1521
// singleton class with only static methods
1622
private FileAccessUtils() {}
1723

1824
private static final Logger logger = Logger.getLogger(FileAccessUtils.class.getName());
1925

26+
public static Path addPosixOwnerWrite(Path absPath) throws IOException {
27+
Set<PosixFilePermission> perms = Files.getPosixFilePermissions(absPath);
28+
29+
ImmutableSet<PosixFilePermission> permsWithWrite =
30+
ImmutableSet.<PosixFilePermission>builder()
31+
.addAll(perms)
32+
.add(PosixFilePermission.OWNER_WRITE)
33+
.build();
34+
35+
return Files.setAttribute(absPath, "posix:permissions", permsWithWrite);
36+
}
37+
2038
private static final ConcurrentHashMap<Path, PathLock> fileLocks = new ConcurrentHashMap<>();
2139

22-
// Used here for locking "files"
40+
// Used here as a simple lock for locking "files" (paths)
2341
private static class PathLock {
2442
// Not used elsewhere
2543
private PathLock() {}
@@ -46,13 +64,10 @@ public static void copyFile(Path from, Path to) throws IOException {
4664
() -> {
4765
try {
4866
Files.copy(from, absTo, REPLACE_EXISTING, COPY_ATTRIBUTES);
49-
boolean writeable = absTo.toFile().setWritable(true);
50-
if (!writeable) {
51-
return new IOException("copyFile() could not set writeable: " + absTo);
52-
}
67+
addPosixOwnerWrite(absTo);
5368
return null;
5469
} catch (IOException e) {
55-
return e;
70+
return new IOException("copyFile() could not set writeable: " + absTo, e);
5671
}
5772
});
5873
if (ioException != null) {
@@ -81,44 +96,10 @@ public static void moveFile(Path from, Path to) throws IOException {
8196
() -> {
8297
try {
8398
Files.move(from, absTo, REPLACE_EXISTING);
84-
boolean writeable = absTo.toFile().setWritable(true);
85-
if (!writeable) {
86-
return new IOException("moveFile() could not set writeable: " + absTo);
87-
}
88-
return null;
89-
} catch (IOException e) {
90-
return e;
91-
}
92-
});
93-
if (ioException != null) {
94-
throw ioException;
95-
}
96-
}
97-
98-
/**
99-
* Creates a symlink, creating necessary directories. Deletes pre-existing files/links which have
100-
* the same path as the specified link, effectively overwriting any existing files/links.
101-
*
102-
* @param from
103-
* @param to
104-
* @throws IOException
105-
*/
106-
public static void linkFile(Path from, Path to) throws IOException {
107-
Path absTo = to.toAbsolutePath();
108-
logger.finer("linkFile: " + from + " to " + absTo);
109-
if (!Files.exists(from)) {
110-
throw new IOException("linkFile: source file doesn't exist: " + from);
111-
}
112-
IOException ioException =
113-
writeFileSafe(
114-
absTo,
115-
() -> {
116-
try {
117-
Files.deleteIfExists(absTo);
118-
Files.createSymbolicLink(absTo, from);
99+
addPosixOwnerWrite(absTo);
119100
return null;
120101
} catch (IOException e) {
121-
return e;
102+
return new IOException("copyFile() could not set writeable: " + absTo, e);
122103
}
123104
});
124105
if (ioException != null) {

src/main/java/build/buildfarm/worker/persistent/Keymaker.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@
1313
import persistent.bazel.client.PersistentWorker;
1414
import persistent.bazel.client.WorkerKey;
1515

16+
/** Much of the logic (hashing) is from Bazel itself (private library/methods, i.e. WorkerKey). */
1617
public class Keymaker {
1718
// Constructs a key with its worker tool input files being relative paths
1819
public static WorkerKey make(
1920
Path opRoot,
21+
Path workRootsDir,
2022
ImmutableList<String> workerInitCmd,
2123
ImmutableList<String> workerInitArgs,
2224
ImmutableMap<String, String> workerEnv,
@@ -29,7 +31,13 @@ public static WorkerKey make(
2931

3032
Path workRoot =
3133
calculateWorkRoot(
32-
workerInitCmd, workerInitArgs, workerEnv, executionName, sandboxed, cancellable);
34+
workRootsDir,
35+
workerInitCmd,
36+
workerInitArgs,
37+
workerEnv,
38+
executionName,
39+
sandboxed,
40+
cancellable);
3341
Path toolsRoot = workRoot.resolve(PersistentWorker.TOOL_INPUT_SUBDIR);
3442

3543
SortedMap<Path, HashCode> hashedTools = workerFilesWithHashes(workerFiles);
@@ -49,6 +57,7 @@ public static WorkerKey make(
4957

5058
// Hash of a subset of the WorkerKey
5159
private static Path calculateWorkRoot(
60+
Path workRootsDir,
5261
ImmutableList<String> workerInitCmd,
5362
ImmutableList<String> workerInitArgs,
5463
ImmutableMap<String, String> workerEnv,
@@ -57,7 +66,7 @@ private static Path calculateWorkRoot(
5766
boolean cancellable) {
5867
int workRootId = Objects.hash(workerInitCmd, workerInitArgs, workerEnv, sandboxed, cancellable);
5968
String workRootDirName = "work-root_" + executionName + "_" + workRootId;
60-
return PersistentExecutor.workRootsDir.resolve(workRootDirName);
69+
return workRootsDir.resolve(workRootDirName);
6170
}
6271

6372
private static ImmutableSortedMap<Path, HashCode> workerFilesWithHashes(

src/main/java/build/buildfarm/worker/persistent/PersistentExecutor.java

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,13 @@
2929
public class PersistentExecutor {
3030
private static final Logger logger = Logger.getLogger(PersistentExecutor.class.getName());
3131

32-
// How many workers can exist at once for a given WorkerKey
33-
// There may be multiple WorkerKeys per mnemonic,
34-
// e.g. if builds are run with different tool fingerprints
35-
private static final int defaultMaxWorkersPerKey = 6;
36-
3732
private static final ProtoCoordinator coordinator =
3833
ProtoCoordinator.ofCommonsPool(getMaxWorkersPerKey());
3934

4035
// TODO load from config (i.e. {worker_root}/persistent)
41-
static final Path workRootsDir = Paths.get("/tmp/worker/persistent/");
36+
public static final Path defaultWorkRootsDir = Paths.get("/tmp/worker/persistent/");
4237

43-
static final String PERSISTENT_WORKER_FLAG = "--persistent_worker";
38+
public static final String PERSISTENT_WORKER_FLAG = "--persistent_worker";
4439

4540
// TODO Revisit hardcoded actions
4641
static final String JAVABUILDER_JAR =
@@ -49,6 +44,11 @@ public class PersistentExecutor {
4944
private static final String SCALAC_EXEC_NAME = "Scalac";
5045
private static final String JAVAC_EXEC_NAME = "JavaBuilder";
5146

47+
// How many workers can exist at once for a given WorkerKey
48+
// There may be multiple WorkerKeys per mnemonic,
49+
// e.g. if builds are run with different tool fingerprints
50+
private static final int defaultMaxWorkersPerKey = 6;
51+
5252
private static int getMaxWorkersPerKey() {
5353
try {
5454
return Integer.parseInt(System.getenv("BUILDFARM_MAX_WORKERS_PER_KEY"));
@@ -73,6 +73,7 @@ public static Code runOnPersistentWorker(
7373
ImmutableMap<String, String> envVars,
7474
ResourceLimits limits,
7575
Duration timeout,
76+
Path workRootsDir,
7677
ActionResult.Builder resultBuilder)
7778
throws IOException {
7879
//// Pull out persistent worker start command from the overall action request
@@ -112,7 +113,13 @@ public static Code runOnPersistentWorker(
112113

113114
WorkerKey key =
114115
Keymaker.make(
115-
context.opRoot, workerExecCmd, workerInitArgs, env, executionName, workerFiles);
116+
context.opRoot,
117+
workRootsDir,
118+
workerExecCmd,
119+
workerInitArgs,
120+
env,
121+
executionName,
122+
workerFiles);
116123

117124
coordinator.copyToolInputsIntoWorkerToolRoot(key, workerFiles);
118125

src/main/java/build/buildfarm/worker/persistent/WorkFilesContext.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package build.buildfarm.worker.persistent;
22

3+
import build.bazel.remote.execution.v2.Command;
34
import build.buildfarm.v1test.Tree;
45
import build.buildfarm.worker.util.InputsIndexer;
56
import com.google.common.collect.ImmutableList;
@@ -37,14 +38,23 @@ public WorkFilesContext(
3738
this.outputFiles = outputFiles;
3839
this.outputDirectories = outputDirectories;
3940

40-
this.inputsIndexer = new InputsIndexer(execTree);
41+
this.inputsIndexer = new InputsIndexer(execTree, this.opRoot);
42+
}
43+
44+
public static WorkFilesContext fromContext(Path opRoot, Tree inputsTree, Command opCommand) {
45+
return new WorkFilesContext(
46+
opRoot,
47+
inputsTree,
48+
ImmutableList.copyOf(opCommand.getOutputPathsList()),
49+
ImmutableList.copyOf(opCommand.getOutputFilesList()),
50+
ImmutableList.copyOf(opCommand.getOutputDirectoriesList()));
4151
}
4252

4353
// Paths are absolute paths from the opRoot; same as the Input.getPath();
4454
public ImmutableMap<Path, Input> getPathInputs() {
4555
synchronized (this) {
4656
if (pathInputs == null) {
47-
pathInputs = inputsIndexer.getAllInputs(opRoot);
57+
pathInputs = inputsIndexer.getAllInputs();
4858
}
4959
}
5060
return pathInputs;
@@ -53,7 +63,7 @@ public ImmutableMap<Path, Input> getPathInputs() {
5363
public ImmutableMap<Path, Input> getToolInputs() {
5464
synchronized (this) {
5565
if (toolInputs == null) {
56-
toolInputs = inputsIndexer.getToolInputs(opRoot);
66+
toolInputs = inputsIndexer.getToolInputs();
5767
}
5868
}
5969
return toolInputs;

src/main/java/build/buildfarm/worker/persistent/WorkerInputs.java

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,16 +57,6 @@ public void copyInputFile(Path from, Path to) throws IOException {
5757
FileAccessUtils.copyFile(from, to);
5858
}
5959

60-
public void moveInputFile(Path from, Path to) throws IOException {
61-
checkFileIsInput("moveInputFile()", from);
62-
FileAccessUtils.moveFile(from, to);
63-
}
64-
65-
public void linkInputFile(Path from, Path to) throws IOException {
66-
checkFileIsInput("linkInputFile()", from);
67-
FileAccessUtils.linkFile(from, to);
68-
}
69-
7060
public void deleteInputFileIfExists(Path workerExecRoot, Path opPathInput) throws IOException {
7161
checkFileIsInput("deleteInputFile()", opPathInput);
7262
Path execPathInput = relativizeInput(workerExecRoot, opPathInput);

src/main/java/build/buildfarm/worker/util/InputsIndexer.java

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
import build.buildfarm.v1test.Tree;
99
import com.google.common.collect.ImmutableMap;
1010
import com.google.devtools.build.lib.worker.WorkerProtocol.Input;
11+
import java.nio.file.FileSystem;
1112
import java.nio.file.Path;
12-
import java.nio.file.Paths;
1313
import java.util.Map;
1414

1515
/**
@@ -25,38 +25,51 @@ public class InputsIndexer {
2525
final Tree tree;
2626
final Map<Digest, Directory> proxyDirs;
2727

28+
final FileSystem fs;
29+
30+
final Path opRoot;
31+
2832
ImmutableMap<Path, FileNode> files = null;
2933
ImmutableMap<Path, Input> absPathInputs = null;
3034
ImmutableMap<Path, Input> toolInputs = null;
3135

32-
public InputsIndexer(Tree tree) {
36+
public InputsIndexer(Tree tree, Path opRoot) {
3337
this.tree = tree;
3438
this.proxyDirs = new ProxyDirectoriesIndex(tree.getDirectoriesMap());
39+
this.opRoot = opRoot;
40+
this.fs = opRoot.getFileSystem();
3541
}
3642

37-
public ImmutableMap<Path, Input> getAllInputs(Path opRoot) {
43+
// https://stackoverflow.com/questions/22611919/why-do-i-get-providermismatchexception-when-i-try-to-relativize-a-path-agains
44+
public Path pathTransform(final Path path) {
45+
Path ret = fs.getPath(path.isAbsolute() ? fs.getSeparator() : "");
46+
for (final Path component : path) ret = ret.resolve(component.getFileName().toString());
47+
return ret;
48+
}
49+
50+
public ImmutableMap<Path, Input> getAllInputs() {
3851
if (absPathInputs == null) {
3952
ImmutableMap<Path, FileNode> relFiles = getAllFiles();
4053
ImmutableMap.Builder<Path, Input> inputs = ImmutableMap.builder();
4154

4255
for (Map.Entry<Path, FileNode> pf : relFiles.entrySet()) {
43-
Path absPath = opRoot.resolve(pf.getKey());
56+
Path absPath = this.opRoot.resolve(pf.getKey()).normalize();
4457
inputs.put(absPath, inputFromFile(absPath, pf.getValue()));
4558
}
4659
absPathInputs = inputs.build();
4760
}
4861
return absPathInputs;
4962
}
5063

51-
public ImmutableMap<Path, Input> getToolInputs(Path opRoot) {
64+
public ImmutableMap<Path, Input> getToolInputs() {
5265
if (toolInputs == null) {
5366
ImmutableMap<Path, FileNode> relFiles = getAllFiles();
5467
ImmutableMap.Builder<Path, Input> inputs = ImmutableMap.builder();
5568

5669
for (Map.Entry<Path, FileNode> pf : relFiles.entrySet()) {
5770
FileNode fn = pf.getValue();
5871
if (isToolInput(fn)) {
59-
Path absPath = opRoot.resolve(pf.getKey());
72+
Path absPath = this.opRoot.resolve(pf.getKey());
6073
inputs.put(absPath, inputFromFile(absPath, fn));
6174
}
6275
}
@@ -69,7 +82,9 @@ private ImmutableMap<Path, FileNode> getAllFiles() {
6982
if (files == null) {
7083
ImmutableMap.Builder<Path, FileNode> accumulator = ImmutableMap.builder();
7184
Directory rootDir = proxyDirs.get(tree.getRootDigest());
72-
files = getFilesFromDir(Paths.get("."), rootDir, accumulator).build();
85+
86+
Path fsRelative = fs.getPath(".");
87+
files = getFilesFromDir(fsRelative, rootDir, accumulator).build();
7388
}
7489
return files;
7590
}

src/test/java/build/buildfarm/worker/persistent/BUILD

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,18 @@ java_test(
44
srcs = glob(["*.java"]),
55
test_class = "build.buildfarm.AllTests",
66
deps = [
7+
"//persistentworkers/src/main/java/persistent/bazel:bazel-persistent-workers",
8+
"//persistentworkers/src/main/java/persistent/common:persistent-common",
9+
"//persistentworkers/src/main/java/persistent/common/util",
710
"//src/main/java/build/buildfarm/common",
811
"//src/main/java/build/buildfarm/common/config",
912
"//src/main/java/build/buildfarm/instance",
1013
"//src/main/java/build/buildfarm/worker",
14+
"//src/main/java/build/buildfarm/worker/persistent",
1115
"//src/main/java/build/buildfarm/worker/resources",
1216
"//src/main/protobuf:build_buildfarm_v1test_buildfarm_java_proto",
1317
"//src/test/java/build/buildfarm:test_runner",
18+
"//src/test/java/build/buildfarm/worker/util:worker_test_utils",
1419
"@bazel_tools//src/main/protobuf:worker_protocol_java_proto",
1520
"@googleapis//:google_rpc_code_java_proto",
1621
"@maven//:com_github_jnr_jnr_constants",

0 commit comments

Comments
 (0)