mirror of
https://github.com/corda/corda.git
synced 2024-12-30 09:48:59 +00:00
Node: if the node is started twice, abort and tell the sysadmin the PID of the other instance.
This commit is contained in:
parent
7a70cdd4de
commit
5d0d926568
@ -14,8 +14,12 @@ import core.messaging.*
|
|||||||
import core.serialization.deserialize
|
import core.serialization.deserialize
|
||||||
import core.serialization.serialize
|
import core.serialization.serialize
|
||||||
import core.utilities.loggerFor
|
import core.utilities.loggerFor
|
||||||
|
import java.io.RandomAccessFile
|
||||||
|
import java.lang.management.ManagementFactory
|
||||||
|
import java.nio.channels.FileLock
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
import java.nio.file.StandardOpenOption
|
||||||
import java.security.KeyPair
|
import java.security.KeyPair
|
||||||
import java.security.KeyPairGenerator
|
import java.security.KeyPairGenerator
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -65,17 +69,27 @@ class Node(val dir: Path, val myNetAddr: HostAndPort, val configuration: NodeCon
|
|||||||
override val identityService: IdentityService get() = identity
|
override val identityService: IdentityService get() = identity
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Implement mutual exclusion so we can't start the node twice by accident.
|
val storage: StorageService
|
||||||
|
val smm: StateMachineManager
|
||||||
val storage = makeStorageService(dir)
|
val net: ArtemisMessagingService
|
||||||
val smm = StateMachineManager(services, serverThread)
|
val wallet: WalletService
|
||||||
val net = ArtemisMessagingService(dir, myNetAddr)
|
val keyManagement: E2ETestKeyManagementService
|
||||||
val wallet: WalletService = E2ETestWalletService(services)
|
|
||||||
val keyManagement = E2ETestKeyManagementService()
|
|
||||||
val inNodeTimestampingService: TimestamperNodeService?
|
val inNodeTimestampingService: TimestamperNodeService?
|
||||||
val identity: IdentityService
|
val identity: IdentityService
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
private var nodeFileLock: FileLock? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
alreadyRunningNodeCheck()
|
||||||
|
|
||||||
|
storage = makeStorageService(dir)
|
||||||
|
smm = StateMachineManager(services, serverThread)
|
||||||
|
net = ArtemisMessagingService(dir, myNetAddr)
|
||||||
|
wallet = E2ETestWalletService(services)
|
||||||
|
keyManagement = E2ETestKeyManagementService()
|
||||||
|
|
||||||
// Insert a network map entry for the timestamper: this is all temp scaffolding and will go away. If we are
|
// Insert a network map entry for the timestamper: this is all temp scaffolding and will go away. If we are
|
||||||
// given the details, the timestamping node is somewhere else. Otherwise, we do our own timestamping.
|
// given the details, the timestamping node is somewhere else. Otherwise, we do our own timestamping.
|
||||||
val tsid = if (timestamperAddress != null) {
|
val tsid = if (timestamperAddress != null) {
|
||||||
@ -101,6 +115,7 @@ class Node(val dir: Path, val myNetAddr: HostAndPort, val configuration: NodeCon
|
|||||||
fun stop() {
|
fun stop() {
|
||||||
net.stop()
|
net.stop()
|
||||||
serverThread.shutdownNow()
|
serverThread.shutdownNow()
|
||||||
|
nodeFileLock!!.release()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun makeStorageService(dir: Path): StorageService {
|
fun makeStorageService(dir: Path): StorageService {
|
||||||
@ -152,6 +167,30 @@ class Node(val dir: Path, val myNetAddr: HostAndPort, val configuration: NodeCon
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun alreadyRunningNodeCheck() {
|
||||||
|
// 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 = dir.resolve("process-id")
|
||||||
|
val file = pidPath.toFile()
|
||||||
|
if (file.exists()) {
|
||||||
|
val f = RandomAccessFile(file, "rw")
|
||||||
|
val l = f.channel.tryLock()
|
||||||
|
if (l == null) {
|
||||||
|
println("It appears there is already a node running with the specified data directory $dir")
|
||||||
|
println("Shut that other node down and try again. It may have process ID ${file.readText()}")
|
||||||
|
System.exit(1)
|
||||||
|
}
|
||||||
|
nodeFileLock = l
|
||||||
|
}
|
||||||
|
val ourProcessID: String = ManagementFactory.getRuntimeMXBean().name.split("@")[0]
|
||||||
|
Files.write(pidPath, ourProcessID.toByteArray(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)
|
||||||
|
pidPath.toFile().deleteOnExit()
|
||||||
|
if (nodeFileLock == null)
|
||||||
|
nodeFileLock = RandomAccessFile(file, "rw").channel.lock()
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val PRIVATE_KEY_FILE_NAME = "identity-private-key"
|
val PRIVATE_KEY_FILE_NAME = "identity-private-key"
|
||||||
val PUBLIC_IDENTITY_FILE_NAME = "identity-public"
|
val PUBLIC_IDENTITY_FILE_NAME = "identity-public"
|
||||||
|
Loading…
Reference in New Issue
Block a user