diff --git a/node/src/integration-test/kotlin/net/corda/node/BootTests.kt b/node/src/integration-test/kotlin/net/corda/node/BootTests.kt index 16010a755d..6f67459650 100644 --- a/node/src/integration-test/kotlin/net/corda/node/BootTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/BootTests.kt @@ -42,7 +42,7 @@ class BootTests { startNode(ALICE.name).getOrThrow() } // We count the number of nodes that wrote into the logfile by counting "Logs can be found in" - val numberOfNodesThatLogged = Files.lines(logFile.toPath()).filter { it.contains("Logs can be found in") }.count() + val numberOfNodesThatLogged = Files.lines(logFile.toPath()).filter { it.contains(LOGS_CAN_BE_FOUND_IN_STRING) }.count() assertEquals(1, numberOfNodesThatLogged) } } diff --git a/node/src/main/kotlin/net/corda/node/Corda.kt b/node/src/main/kotlin/net/corda/node/Corda.kt index ba222d6ca5..36a6f45d2b 100644 --- a/node/src/main/kotlin/net/corda/node/Corda.kt +++ b/node/src/main/kotlin/net/corda/node/Corda.kt @@ -9,8 +9,8 @@ import net.corda.core.* import net.corda.core.node.VersionInfo import net.corda.core.utilities.Emoji import net.corda.core.utilities.LogHelper.withLevel -import net.corda.node.internal.EnforceSingleNodeIsRunning import net.corda.node.internal.Node +import net.corda.node.internal.enforceSingleNodeIsRunning import net.corda.node.services.config.FullNodeConfiguration import net.corda.node.shell.InteractiveShell import net.corda.node.utilities.registration.HTTPNetworkRegistrationService @@ -36,6 +36,7 @@ fun printBasicNodeInfo(description: String, info: String? = null) { } val LOGS_DIRECTORY_NAME = "logs" +val LOGS_CAN_BE_FOUND_IN_STRING = "Logs can be found in" private val log by lazy { LoggerFactory.getLogger("Main") } private fun initLogging(cmdlineOptions: CmdLineOptions) { @@ -64,10 +65,9 @@ fun main(args: Array) { exitProcess(1) } - val enforceSingleNodeIsRunning = EnforceSingleNodeIsRunning(cmdlineOptions.baseDirectory) // We do the single node check before we initialise logging so that in case of a double-node start it doesn't mess // with the running node's logs. - enforceSingleNodeIsRunning.start() + enforceSingleNodeIsRunning(cmdlineOptions.baseDirectory) initLogging(cmdlineOptions) disableJavaDeserialization() // Should be after initLogging to avoid TMI. @@ -97,7 +97,7 @@ fun main(args: Array) { drawBanner(versionInfo) - printBasicNodeInfo("Logs can be found in", System.getProperty("log-path")) + printBasicNodeInfo(LOGS_CAN_BE_FOUND_IN_STRING, System.getProperty("log-path")) val conf = try { cmdlineOptions.loadConfig() diff --git a/node/src/main/kotlin/net/corda/node/driver/Driver.kt b/node/src/main/kotlin/net/corda/node/driver/Driver.kt index 68925e3a6e..a77835649c 100644 --- a/node/src/main/kotlin/net/corda/node/driver/Driver.kt +++ b/node/src/main/kotlin/net/corda/node/driver/Driver.kt @@ -340,15 +340,18 @@ class ShutdownManager(private val executorService: ExecutorService) { } val shutdowns = shutdownFutures.map { ErrorOr.catch { it.get(1, SECONDS) } } shutdowns.reversed().forEach { errorOrShutdown -> - try { - if (errorOrShutdown.error == null) { - errorOrShutdown.value?.invoke() - } else { - log.error("Exception while getting shutdown method, disregarding", errorOrShutdown.error) - } - } catch (throwable: Throwable) { - log.error("Exception while shutting down", throwable) - } + errorOrShutdown.match( + onValue = { shutdown -> + try { + shutdown() + } catch (throwable: Throwable) { + log.error("Exception while shutting down", throwable) + } + }, + onError = { error -> + log.error("Exception while getting shutdown method, disregarding", error) + } + ) } } diff --git a/node/src/main/kotlin/net/corda/node/internal/EnforceSingleNodeIsRunning.kt b/node/src/main/kotlin/net/corda/node/internal/EnforceSingleNodeIsRunning.kt index cd52b52958..0b09e2953c 100644 --- a/node/src/main/kotlin/net/corda/node/internal/EnforceSingleNodeIsRunning.kt +++ b/node/src/main/kotlin/net/corda/node/internal/EnforceSingleNodeIsRunning.kt @@ -7,38 +7,29 @@ import java.lang.management.ManagementFactory import java.nio.file.Path /** - * This class enforces that only a single node is running using the given [baseDirectory] by using a file lock. + * This function enforces that only a single node is running using the given [baseDirectory] by using a file lock. */ -class EnforceSingleNodeIsRunning(val baseDirectory: Path) { - private companion object { - val log = loggerFor() - } - - fun start() { - // Write out our process ID (which may or may not resemble a UNIX process id - to us it's just a string) to a - // file that we'll do our best to delete on exit. But if we don't, it'll be overwritten next time. If it already - // exists, we try to take the file lock first before replacing it and if that fails it means we're being started - // twice with the same directory: that's a user error and we should bail out. - val pidPath = baseDirectory / "process-id" - val pidFile = pidPath.toFile() - if (!pidFile.exists()) { - pidFile.createNewFile() - } - pidFile.deleteOnExit() - val pidFileRw = RandomAccessFile(pidFile, "rw") - val pidFileLock = pidFileRw.channel.tryLock() - if (pidFileLock == null) { - log.error("It appears there is already a node running with the specified data directory $baseDirectory") - log.error("Shut that other node down and try again. It may have process ID ${pidFile.readText()}") - System.exit(1) - } - // Avoid the lock being garbage collected. We don't really need to release it as the OS will do so for us - // when our process shuts down, but we try in stop() anyway just to be nice. - Runtime.getRuntime().addShutdownHook(Thread { - pidFileLock.release() - }) - val ourProcessID: String = ManagementFactory.getRuntimeMXBean().name.split("@")[0] - pidFileRw.setLength(0) - pidFileRw.write(ourProcessID.toByteArray()) +fun enforceSingleNodeIsRunning(baseDirectory: Path) { + // Write out our process ID (which may or may not resemble a UNIX process id - to us it's just a string) to a + // file that we'll do our best to delete on exit. But if we don't, it'll be overwritten next time. If it already + // exists, we try to take the file lock first before replacing it and if that fails it means we're being started + // twice with the same directory: that's a user error and we should bail out. + val pidFile = (baseDirectory / "process-id").toFile() + pidFile.createNewFile() + pidFile.deleteOnExit() + val pidFileRw = RandomAccessFile(pidFile, "rw") + val pidFileLock = pidFileRw.channel.tryLock() + if (pidFileLock == null) { + println("It appears there is already a node running with the specified data directory $baseDirectory") + println("Shut that other node down and try again. It may have process ID ${pidFile.readText()}") + System.exit(1) } + // Avoid the lock being garbage collected. We don't really need to release it as the OS will do so for us + // when our process shuts down, but we try in stop() anyway just to be nice. + Runtime.getRuntime().addShutdownHook(Thread { + pidFileLock.release() + }) + val ourProcessID: String = ManagementFactory.getRuntimeMXBean().name.split("@")[0] + pidFileRw.setLength(0) + pidFileRw.write(ourProcessID.toByteArray()) }