8259570: (macos) tools/jpackage tests fails with 'hdiutil: couldn't eject "disk2" - Resource busy'

Reviewed-by: herrick, asemenyuk
This commit is contained in:
Alexander Matveev 2021-02-03 00:29:08 +00:00
parent ffbcf1b0a7
commit bec60432ec
3 changed files with 73 additions and 20 deletions

View File

@ -437,7 +437,6 @@ public class MacDmgBundler extends MacBaseInstallerBundler {
pb = new ProcessBuilder( pb = new ProcessBuilder(
hdiutil, hdiutil,
"detach", "detach",
"-force",
hdiUtilVerbosityFlag, hdiUtilVerbosityFlag,
mountedRoot.toAbsolutePath().toString()); mountedRoot.toAbsolutePath().toString());
// "hdiutil detach" might not work right away due to resource busy error, so // "hdiutil detach" might not work right away due to resource busy error, so
@ -451,12 +450,21 @@ public class MacDmgBundler extends MacBaseInstallerBundler {
} }
}); });
try { try {
// 10 times with 3 second delays. // 10 times with 6 second delays.
retryExecutor.setMaxAttemptsCount(10).setAttemptTimeoutMillis(3000) retryExecutor.setMaxAttemptsCount(10).setAttemptTimeoutMillis(6000)
.execute(pb); .execute(pb);
} catch (IOException ex) { } catch (IOException ex) {
if (!retryExecutor.isAborted()) { if (!retryExecutor.isAborted()) {
throw ex; // Now force to detach if it still attached
if (Files.exists(mountedRoot)) {
pb = new ProcessBuilder(
hdiutil,
"detach",
"-force",
hdiUtilVerbosityFlag,
mountedRoot.toAbsolutePath().toString());
IOUtils.exec(pb);
}
} }
} }
} }
@ -469,10 +477,29 @@ public class MacDmgBundler extends MacBaseInstallerBundler {
hdiUtilVerbosityFlag, hdiUtilVerbosityFlag,
"-format", "UDZO", "-format", "UDZO",
"-o", finalDMG.toAbsolutePath().toString()); "-o", finalDMG.toAbsolutePath().toString());
new RetryExecutor() try {
new RetryExecutor()
.setMaxAttemptsCount(10) .setMaxAttemptsCount(10)
.setAttemptTimeoutMillis(3000) .setAttemptTimeoutMillis(3000)
.execute(pb); .execute(pb);
} catch (Exception ex) {
// Convert might failed if something holds file. Try to convert copy.
Path protoDMG2 = imagesRoot
.resolve(APP_NAME.fetchFrom(params) + "-tmp2.dmg");
Files.copy(protoDMG, protoDMG2);
try {
pb = new ProcessBuilder(
hdiutil,
"convert",
protoDMG2.toAbsolutePath().toString(),
hdiUtilVerbosityFlag,
"-format", "UDZO",
"-o", finalDMG.toAbsolutePath().toString());
IOUtils.exec(pb);
} finally {
Files.deleteIfExists(protoDMG2);
}
}
//add license if needed //add license if needed
if (Files.exists(getConfig_LicenseFile(params))) { if (Files.exists(getConfig_LicenseFile(params))) {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -29,31 +29,31 @@ import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
public final class RetryExecutor { public final class RetryExecutor {
RetryExecutor() { public RetryExecutor() {
setMaxAttemptsCount(5); setMaxAttemptsCount(5);
setAttemptTimeoutMillis(2 * 1000); setAttemptTimeoutMillis(2 * 1000);
} }
RetryExecutor setMaxAttemptsCount(int v) { public RetryExecutor setMaxAttemptsCount(int v) {
attempts = v; attempts = v;
return this; return this;
} }
RetryExecutor setAttemptTimeoutMillis(int v) { public RetryExecutor setAttemptTimeoutMillis(int v) {
timeoutMillis = v; timeoutMillis = v;
return this; return this;
} }
RetryExecutor setExecutorInitializer(Consumer<Executor> v) { public RetryExecutor setExecutorInitializer(Consumer<Executor> v) {
executorInitializer = v; executorInitializer = v;
return this; return this;
} }
void abort() { public void abort() {
aborted = true; aborted = true;
} }
boolean isAborted() { public boolean isAborted() {
return aborted; return aborted;
} }
@ -68,11 +68,11 @@ public final class RetryExecutor {
}); });
} }
void execute(String cmdline[]) throws IOException { public void execute(String cmdline[]) throws IOException {
executeLoop(() -> Executor.of(cmdline)); executeLoop(() -> Executor.of(cmdline));
} }
void execute(ProcessBuilder pb) throws IOException { public void execute(ProcessBuilder pb) throws IOException {
executeLoop(() -> Executor.of(pb)); executeLoop(() -> Executor.of(pb));
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -42,6 +42,7 @@ import javax.xml.xpath.XPathFactory;
import jdk.jpackage.test.Functional.ThrowingConsumer; import jdk.jpackage.test.Functional.ThrowingConsumer;
import jdk.jpackage.test.Functional.ThrowingSupplier; import jdk.jpackage.test.Functional.ThrowingSupplier;
import jdk.jpackage.test.PackageTest.PackageHandlers; import jdk.jpackage.test.PackageTest.PackageHandlers;
import jdk.jpackage.internal.RetryExecutor;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
@ -66,11 +67,36 @@ public class MacHelper {
cmd.outputBundle(), dmgImage)); cmd.outputBundle(), dmgImage));
ThrowingConsumer.toConsumer(consumer).accept(dmgImage); ThrowingConsumer.toConsumer(consumer).accept(dmgImage);
} finally { } finally {
// detach might not work right away due to resource busy error, so String cmdline[] = {
// repeat detach several times or fail. Try 10 times with 3 seconds "/usr/bin/hdiutil",
// delay. "detach",
Executor.of("/usr/bin/hdiutil", "detach").addArgument(mountPoint). "-verbose",
executeAndRepeatUntilExitCode(0, 10, 3); mountPoint.toAbsolutePath().toString()};
// "hdiutil detach" might not work right away due to resource busy error, so
// repeat detach several times.
RetryExecutor retryExecutor = new RetryExecutor();
// Image can get detach even if we got resource busy error, so stop
// trying to detach it if it is no longer attached.
retryExecutor.setExecutorInitializer(exec -> {
if (!Files.exists(mountPoint)) {
retryExecutor.abort();
}
});
try {
// 10 times with 6 second delays.
retryExecutor.setMaxAttemptsCount(10)
.setAttemptTimeoutMillis(6000)
.execute(cmdline);
} catch (IOException ex) {
if (!retryExecutor.isAborted()) {
// Now force to detach if it still attached
if (Files.exists(mountPoint)) {
Executor.of("/usr/bin/hdiutil", "detach",
"-force", "-verbose")
.addArgument(mountPoint).execute();
}
}
}
} }
} }