Skip to content

Commit ec7be34

Browse files
coeuvrecopybara-github
authored andcommitted
Temporarily set parent directory of the input to writable if it is not.
PiperOrigin-RevId: 483615392 Change-Id: Ic8b301ef6fd004a88f9a563e04ba961f6dfb5708
1 parent 5cea7dd commit ec7be34

File tree

2 files changed

+78
-30
lines changed

2 files changed

+78
-30
lines changed

src/main/java/com/google/devtools/build/lib/remote/AbstractActionInputPrefetcher.java

+53-13
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,20 @@ public abstract class AbstractActionInputPrefetcher implements ActionInputPrefet
7070
protected final Path execRoot;
7171
protected final ImmutableList<Pattern> patternsToDownload;
7272

73+
private static class Context {
74+
private final Set<Path> nonWritableDirs = Sets.newConcurrentHashSet();
75+
76+
public void addNonWritableDir(Path dir) {
77+
nonWritableDirs.add(dir);
78+
}
79+
80+
public void finalizeContext() throws IOException {
81+
for (Path path : nonWritableDirs) {
82+
path.setWritable(false);
83+
}
84+
}
85+
}
86+
7387
/** Priority for the staging task. */
7488
protected enum Priority {
7589
/**
@@ -176,27 +190,37 @@ protected ListenableFuture<Void> prefetchFiles(
176190
files.add(input);
177191
}
178192

193+
Context context = new Context();
194+
179195
Flowable<TransferResult> treeDownloads =
180196
Flowable.fromIterable(trees.entrySet())
181197
.flatMapSingle(
182198
entry ->
183199
toTransferResult(
184200
prefetchInputTreeOrSymlink(
185-
metadataProvider, entry.getKey(), entry.getValue(), priority)));
201+
context,
202+
metadataProvider,
203+
entry.getKey(),
204+
entry.getValue(),
205+
priority)));
186206

187207
Flowable<TransferResult> fileDownloads =
188208
Flowable.fromIterable(files)
189209
.flatMapSingle(
190210
input ->
191211
toTransferResult(
192-
prefetchInputFileOrSymlink(metadataProvider, input, priority)));
212+
prefetchInputFileOrSymlink(context, metadataProvider, input, priority)));
193213

194214
Flowable<TransferResult> transfers = Flowable.merge(treeDownloads, fileDownloads);
195-
Completable prefetch = mergeBulkTransfer(transfers).onErrorResumeNext(this::onErrorResumeNext);
215+
Completable prefetch =
216+
Completable.using(
217+
() -> context, ctx -> mergeBulkTransfer(transfers), Context::finalizeContext)
218+
.onErrorResumeNext(this::onErrorResumeNext);
196219
return toListenableFuture(prefetch);
197220
}
198221

199222
private Completable prefetchInputTreeOrSymlink(
223+
Context context,
200224
MetadataProvider provider,
201225
SpecialArtifact tree,
202226
List<TreeFileArtifact> treeFiles,
@@ -216,7 +240,7 @@ private Completable prefetchInputTreeOrSymlink(
216240
PathFragment prefetchExecPath = treeMetadata.getMaterializationExecPath().orElse(execPath);
217241

218242
Completable prefetch =
219-
prefetchInputTree(provider, prefetchExecPath, treeFiles, treeMetadata, priority);
243+
prefetchInputTree(context, provider, prefetchExecPath, treeFiles, treeMetadata, priority);
220244

221245
// If prefetching to a different path, plant a symlink into it.
222246
if (!prefetchExecPath.equals(execPath)) {
@@ -249,6 +273,7 @@ private boolean shouldDownloadAnyTreeFiles(
249273
}
250274

251275
private Completable prefetchInputTree(
276+
Context context,
252277
MetadataProvider provider,
253278
PathFragment execPath,
254279
List<TreeFileArtifact> treeFiles,
@@ -303,7 +328,7 @@ private Completable prefetchInputTree(
303328
}
304329
}
305330
checkState(dir.equals(path));
306-
finalizeDownload(tempPath, path);
331+
finalizeDownload(context, tempPath, path);
307332
}
308333

309334
for (Path dir : dirs) {
@@ -337,7 +362,8 @@ private Completable prefetchInputTree(
337362
}
338363

339364
private Completable prefetchInputFileOrSymlink(
340-
MetadataProvider metadataProvider, ActionInput input, Priority priority) throws IOException {
365+
Context context, MetadataProvider metadataProvider, ActionInput input, Priority priority)
366+
throws IOException {
341367
if (input instanceof VirtualActionInput) {
342368
prefetchVirtualActionInput((VirtualActionInput) input);
343369
return Completable.complete();
@@ -353,7 +379,7 @@ private Completable prefetchInputFileOrSymlink(
353379
PathFragment prefetchExecPath = metadata.getMaterializationExecPath().orElse(execPath);
354380

355381
Completable prefetch =
356-
downloadFileNoCheckRx(execRoot.getRelative(prefetchExecPath), metadata, priority);
382+
downloadFileNoCheckRx(context, execRoot.getRelative(prefetchExecPath), metadata, priority);
357383

358384
// If prefetching to a different path, plant a symlink into it.
359385
if (!prefetchExecPath.equals(execPath)) {
@@ -371,15 +397,16 @@ private Completable prefetchInputFileOrSymlink(
371397
* <p>The file will be written into a temporary file and moved to the final destination after the
372398
* download finished.
373399
*/
374-
private Completable downloadFileRx(Path path, FileArtifactValue metadata, Priority priority) {
400+
private Completable downloadFileRx(
401+
Context context, Path path, FileArtifactValue metadata, Priority priority) {
375402
if (!canDownloadFile(path, metadata)) {
376403
return Completable.complete();
377404
}
378-
return downloadFileNoCheckRx(path, metadata, priority);
405+
return downloadFileNoCheckRx(context, path, metadata, priority);
379406
}
380407

381408
private Completable downloadFileNoCheckRx(
382-
Path path, FileArtifactValue metadata, Priority priority) {
409+
Context context, Path path, FileArtifactValue metadata, Priority priority) {
383410
if (path.isSymbolicLink()) {
384411
try {
385412
path = path.getRelative(path.readSymbolicLink());
@@ -402,7 +429,7 @@ private Completable downloadFileNoCheckRx(
402429
directExecutor())
403430
.doOnComplete(
404431
() -> {
405-
finalizeDownload(tempPath, finalPath);
432+
finalizeDownload(context, tempPath, finalPath);
406433
completed.set(true);
407434
}),
408435
tempPath -> {
@@ -439,11 +466,24 @@ public void downloadFile(Path path, FileArtifactValue metadata)
439466

440467
protected ListenableFuture<Void> downloadFileAsync(
441468
PathFragment path, FileArtifactValue metadata, Priority priority) {
469+
Context context = new Context();
442470
return toListenableFuture(
443-
downloadFileRx(execRoot.getFileSystem().getPath(path), metadata, priority));
471+
Completable.using(
472+
() -> context,
473+
ctx ->
474+
downloadFileRx(context, execRoot.getFileSystem().getPath(path), metadata, priority),
475+
Context::finalizeContext));
444476
}
445477

446-
private void finalizeDownload(Path tmpPath, Path path) throws IOException {
478+
private void finalizeDownload(Context context, Path tmpPath, Path path) throws IOException {
479+
Path parentDir = path.getParentDirectory();
480+
// In case the parent directory of the destination is not writable, temporarily change it to
481+
// writable. b/254844173.
482+
if (parentDir != null && !parentDir.isWritable()) {
483+
context.addNonWritableDir(parentDir);
484+
parentDir.setWritable(true);
485+
}
486+
447487
// The permission of output file is changed to 0555 after action execution. We manually change
448488
// the permission here for the downloaded file to keep this behaviour consistent.
449489
tmpPath.chmod(0555);

src/main/java/com/google/devtools/build/lib/skyframe/SkyframeActionExecutor.java

+25-17
Original file line numberDiff line numberDiff line change
@@ -727,8 +727,10 @@ void updateActionCache(
727727
// Skyframe has already done all the filesystem access needed for outputs and swallows
728728
// IOExceptions for inputs. So an IOException is impossible here.
729729
throw new IllegalStateException(
730-
"failed to update action cache for " + action.prettyPrint()
731-
+ ", but all outputs should already have been checked", e);
730+
"failed to update action cache for "
731+
+ action.prettyPrint()
732+
+ ", but all outputs should already have been checked",
733+
e);
732734
}
733735
}
734736

@@ -866,12 +868,12 @@ void recordExecutionError() {
866868
}
867869

868870
/**
869-
* Returns true if the Builder is winding down (i.e. cancelling outstanding
870-
* actions and preparing to abort.)
871-
* The builder is winding down iff:
871+
* Returns true if the Builder is winding down (i.e. cancelling outstanding actions and preparing
872+
* to abort.) The builder is winding down iff:
873+
*
872874
* <ul>
873-
* <li>we had an execution error
874-
* <li>we are not running with --keep_going
875+
* <li>we had an execution error
876+
* <li>we are not running with --keep_going
875877
* </ul>
876878
*/
877879
private boolean isBuilderAborting() {
@@ -1197,8 +1199,10 @@ private ActionExecutionValue actuallyCompleteAction(
11971199
Artifact primaryOutput = action.getPrimaryOutput();
11981200
Path primaryOutputPath = actionExecutionContext.getInputPath(primaryOutput);
11991201
try {
1200-
Preconditions.checkState(action.inputsDiscovered(),
1201-
"Action %s successfully executed, but inputs still not known", action);
1202+
Preconditions.checkState(
1203+
action.inputsDiscovered(),
1204+
"Action %s successfully executed, but inputs still not known",
1205+
action);
12021206

12031207
try {
12041208
flushActionFileSystem(actionExecutionContext.getActionFileSystem(), outputService);
@@ -1481,12 +1485,15 @@ private static void reportMissingOutputFile(
14811485
String msg = prefix + "is a dangling symbolic link";
14821486
reporter.handle(Event.error(action.getOwner().getLocation(), msg));
14831487
} else {
1484-
String suffix = genrule ? " by genrule. This is probably "
1485-
+ "because the genrule actually didn't create this output, or because the output was a "
1486-
+ "directory and the genrule was run remotely (note that only the contents of "
1487-
+ "declared file outputs are copied from genrules run remotely)" : "";
1488-
reporter.handle(Event.error(
1489-
action.getOwner().getLocation(), prefix + "was not created" + suffix));
1488+
String suffix =
1489+
genrule
1490+
? " by genrule. This is probably because the genrule actually didn't create this"
1491+
+ " output, or because the output was a directory and the genrule was run"
1492+
+ " remotely (note that only the contents of declared file outputs are copied"
1493+
+ " from genrules run remotely)"
1494+
: "";
1495+
reporter.handle(
1496+
Event.error(action.getOwner().getLocation(), prefix + "was not created" + suffix));
14901497
}
14911498
}
14921499

@@ -1496,8 +1503,9 @@ private static void reportOutputTreeArtifactErrors(
14961503
if (e instanceof FileNotFoundException) {
14971504
errorMessage = String.format("TreeArtifact %s was not created", output.prettyPrint());
14981505
} else {
1499-
errorMessage = String.format(
1500-
"Error while validating output TreeArtifact %s : %s", output, e.getMessage());
1506+
errorMessage =
1507+
String.format(
1508+
"Error while validating output TreeArtifact %s : %s", output, e.getMessage());
15011509
}
15021510

15031511
reporter.handle(Event.error(action.getOwner().getLocation(), errorMessage));

0 commit comments

Comments
 (0)