mirror of
https://github.com/corda/corda.git
synced 2025-01-18 10:46:38 +00:00
CORDA-1493: add --clear-network-map-cache command line option (#3272)
CORDA-1493: add --clear-network-map-cache command
This commit is contained in:
parent
5d1cc0bd54
commit
3758dbea34
@ -55,6 +55,7 @@ class NodeArgsParser : AbstractArgsParser<CmdLineOptions>() {
|
|||||||
private val justGenerateNodeInfoArg = optionParser.accepts("just-generate-node-info",
|
private val justGenerateNodeInfoArg = optionParser.accepts("just-generate-node-info",
|
||||||
"Perform the node start-up task necessary to generate its nodeInfo, save it to disk, then quit")
|
"Perform the node start-up task necessary to generate its nodeInfo, save it to disk, then quit")
|
||||||
private val bootstrapRaftClusterArg = optionParser.accepts("bootstrap-raft-cluster", "Bootstraps Raft cluster. The node forms a single node cluster (ignoring otherwise configured peer addresses), acting as a seed for other nodes to join the cluster.")
|
private val bootstrapRaftClusterArg = optionParser.accepts("bootstrap-raft-cluster", "Bootstraps Raft cluster. The node forms a single node cluster (ignoring otherwise configured peer addresses), acting as a seed for other nodes to join the cluster.")
|
||||||
|
private val clearNetworkMapCache = optionParser.accepts("clear-network-map-cache", "Clears local copy of network map, on node startup it will be restored from server or file system.")
|
||||||
|
|
||||||
override fun doParse(optionSet: OptionSet): CmdLineOptions {
|
override fun doParse(optionSet: OptionSet): CmdLineOptions {
|
||||||
require(!optionSet.has(baseDirectoryArg) || !optionSet.has(configFileArg)) {
|
require(!optionSet.has(baseDirectoryArg) || !optionSet.has(configFileArg)) {
|
||||||
@ -74,6 +75,7 @@ class NodeArgsParser : AbstractArgsParser<CmdLineOptions>() {
|
|||||||
val networkRootTrustStorePassword = optionSet.valueOf(networkRootTrustStorePasswordArg)
|
val networkRootTrustStorePassword = optionSet.valueOf(networkRootTrustStorePasswordArg)
|
||||||
val unknownConfigKeysPolicy = optionSet.valueOf(unknownConfigKeysPolicy)
|
val unknownConfigKeysPolicy = optionSet.valueOf(unknownConfigKeysPolicy)
|
||||||
val devMode = optionSet.has(devModeArg)
|
val devMode = optionSet.has(devModeArg)
|
||||||
|
val clearNetworkMapCache = optionSet.has(clearNetworkMapCache)
|
||||||
|
|
||||||
val registrationConfig = if (isRegistration) {
|
val registrationConfig = if (isRegistration) {
|
||||||
requireNotNull(networkRootTrustStorePassword) { "Network root trust store password must be provided in registration mode using --network-root-truststore-password." }
|
requireNotNull(networkRootTrustStorePassword) { "Network root trust store password must be provided in registration mode using --network-root-truststore-password." }
|
||||||
@ -94,7 +96,8 @@ class NodeArgsParser : AbstractArgsParser<CmdLineOptions>() {
|
|||||||
justGenerateNodeInfo,
|
justGenerateNodeInfo,
|
||||||
bootstrapRaftCluster,
|
bootstrapRaftCluster,
|
||||||
unknownConfigKeysPolicy,
|
unknownConfigKeysPolicy,
|
||||||
devMode)
|
devMode,
|
||||||
|
clearNetworkMapCache)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,7 +114,8 @@ data class CmdLineOptions(val baseDirectory: Path,
|
|||||||
val justGenerateNodeInfo: Boolean,
|
val justGenerateNodeInfo: Boolean,
|
||||||
val bootstrapRaftCluster: Boolean,
|
val bootstrapRaftCluster: Boolean,
|
||||||
val unknownConfigKeysPolicy: UnknownConfigKeysPolicy,
|
val unknownConfigKeysPolicy: UnknownConfigKeysPolicy,
|
||||||
val devMode: Boolean) {
|
val devMode: Boolean,
|
||||||
|
val clearNetworkMapCache: Boolean) {
|
||||||
fun loadConfig(): Pair<Config, Try<NodeConfiguration>> {
|
fun loadConfig(): Pair<Config, Try<NodeConfiguration>> {
|
||||||
val rawConfig = ConfigHelper.loadConfig(
|
val rawConfig = ConfigHelper.loadConfig(
|
||||||
baseDirectory,
|
baseDirectory,
|
||||||
|
@ -274,6 +274,15 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun clearNetworkMapCache() {
|
||||||
|
Node.printBasicNodeInfo("Clearing network map cache entries")
|
||||||
|
log.info("Starting clearing of network map cache entries...")
|
||||||
|
configureDatabase(configuration.dataSourceProperties, configuration.database, { null }, { null }).use {
|
||||||
|
val networkMapCache = PersistentNetworkMapCache(it, emptyList())
|
||||||
|
networkMapCache.clearNetworkMapCache()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
open fun start(): StartedNode<AbstractNode> {
|
open fun start(): StartedNode<AbstractNode> {
|
||||||
check(started == null) { "Node has already been started" }
|
check(started == null) { "Node has already been started" }
|
||||||
if (configuration.devMode) {
|
if (configuration.devMode) {
|
||||||
|
@ -58,7 +58,6 @@ open class NodeStartup(val args: Array<String>) {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
val cmdlineOptions = NodeArgsParser().parseOrExit(*args)
|
val cmdlineOptions = NodeArgsParser().parseOrExit(*args)
|
||||||
|
|
||||||
// We do the single node check before we initialise logging so that in case of a double-node start it
|
// 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.
|
// doesn't mess with the running node's logs.
|
||||||
enforceSingleNodeIsRunning(cmdlineOptions.baseDirectory)
|
enforceSingleNodeIsRunning(cmdlineOptions.baseDirectory)
|
||||||
@ -153,6 +152,10 @@ open class NodeStartup(val args: Array<String>) {
|
|||||||
|
|
||||||
protected open fun startNode(conf: NodeConfiguration, versionInfo: VersionInfo, startTime: Long, cmdlineOptions: CmdLineOptions) {
|
protected open fun startNode(conf: NodeConfiguration, versionInfo: VersionInfo, startTime: Long, cmdlineOptions: CmdLineOptions) {
|
||||||
val node = createNode(conf, versionInfo)
|
val node = createNode(conf, versionInfo)
|
||||||
|
if (cmdlineOptions.clearNetworkMapCache) {
|
||||||
|
node.clearNetworkMapCache()
|
||||||
|
return
|
||||||
|
}
|
||||||
if (cmdlineOptions.justGenerateNodeInfo) {
|
if (cmdlineOptions.justGenerateNodeInfo) {
|
||||||
// Perform the minimum required start-up logic to be able to write a nodeInfo to disk
|
// Perform the minimum required start-up logic to be able to write a nodeInfo to disk
|
||||||
node.generateAndSaveNodeInfo()
|
node.generateAndSaveNodeInfo()
|
||||||
|
@ -19,6 +19,7 @@ import net.corda.core.serialization.SingletonSerializeAsToken
|
|||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
import net.corda.core.utilities.contextLogger
|
import net.corda.core.utilities.contextLogger
|
||||||
|
import net.corda.core.utilities.debug
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
import net.corda.node.internal.schemas.NodeInfoSchemaV1
|
import net.corda.node.internal.schemas.NodeInfoSchemaV1
|
||||||
import net.corda.node.services.api.NetworkMapCacheBaseInternal
|
import net.corda.node.services.api.NetworkMapCacheBaseInternal
|
||||||
@ -339,9 +340,11 @@ open class PersistentNetworkMapCache(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun clearNetworkMapCache() {
|
override fun clearNetworkMapCache() {
|
||||||
|
logger.info("Clearing Network Map Cache entries")
|
||||||
invalidateCaches()
|
invalidateCaches()
|
||||||
database.transaction {
|
database.transaction {
|
||||||
val result = getAllInfos(session)
|
val result = getAllInfos(session)
|
||||||
|
logger.debug { "Number of node infos to be cleared: ${result.size}" }
|
||||||
for (nodeInfo in result) session.remove(nodeInfo)
|
for (nodeInfo in result) session.remove(nodeInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,8 @@ class NodeArgsParserTest {
|
|||||||
justGenerateNodeInfo = false,
|
justGenerateNodeInfo = false,
|
||||||
bootstrapRaftCluster = false,
|
bootstrapRaftCluster = false,
|
||||||
unknownConfigKeysPolicy = UnknownConfigKeysPolicy.FAIL,
|
unknownConfigKeysPolicy = UnknownConfigKeysPolicy.FAIL,
|
||||||
devMode = false))
|
devMode = false,
|
||||||
|
clearNetworkMapCache = false))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -158,6 +159,12 @@ class NodeArgsParserTest {
|
|||||||
assertThat(cmdLineOptions.justGenerateNodeInfo).isTrue()
|
assertThat(cmdLineOptions.justGenerateNodeInfo).isTrue()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `clear network map cache`() {
|
||||||
|
val cmdLineOptions = parser.parse("--clear-network-map-cache")
|
||||||
|
assertThat(cmdLineOptions.clearNetworkMapCache).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `bootstrap raft cluster`() {
|
fun `bootstrap raft cluster`() {
|
||||||
val cmdLineOptions = parser.parse("--bootstrap-raft-cluster")
|
val cmdLineOptions = parser.parse("--bootstrap-raft-cluster")
|
||||||
|
@ -7,15 +7,21 @@ import net.corda.core.internal.delete
|
|||||||
import net.corda.core.internal.list
|
import net.corda.core.internal.list
|
||||||
import net.corda.core.internal.readObject
|
import net.corda.core.internal.readObject
|
||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
import net.corda.node.VersionInfo
|
import net.corda.node.VersionInfo
|
||||||
|
import net.corda.node.internal.schemas.NodeInfoSchemaV1
|
||||||
import net.corda.node.services.config.NodeConfiguration
|
import net.corda.node.services.config.NodeConfiguration
|
||||||
import net.corda.nodeapi.internal.SignedNodeInfo
|
import net.corda.nodeapi.internal.SignedNodeInfo
|
||||||
import net.corda.nodeapi.internal.network.NodeInfoFilesCopier.Companion.NODE_INFO_FILE_NAME_PREFIX
|
import net.corda.nodeapi.internal.network.NodeInfoFilesCopier.Companion.NODE_INFO_FILE_NAME_PREFIX
|
||||||
|
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||||
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
||||||
|
import net.corda.testing.core.ALICE_NAME
|
||||||
import net.corda.testing.core.SerializationEnvironmentRule
|
import net.corda.testing.core.SerializationEnvironmentRule
|
||||||
|
import net.corda.testing.internal.createNodeInfoAndSigned
|
||||||
import net.corda.testing.internal.rigorousMock
|
import net.corda.testing.internal.rigorousMock
|
||||||
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
|
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
|
||||||
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.rules.TemporaryFolder
|
import org.junit.rules.TemporaryFolder
|
||||||
@ -52,12 +58,58 @@ class NodeTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `generateAndSaveNodeInfo works`() {
|
fun `generateAndSaveNodeInfo works`() {
|
||||||
val nodeAddress = NetworkHostAndPort("0.1.2.3", 456)
|
val configuration = createConfig()
|
||||||
val nodeName = CordaX500Name("Manx Blockchain Corp", "Douglas", "IM")
|
|
||||||
val platformVersion = 789
|
val platformVersion = 789
|
||||||
|
configureDatabase(configuration.dataSourceProperties, configuration.database, { null }, { null }).use { database ->
|
||||||
|
val node = Node(configuration, rigorousMock<VersionInfo>().also {
|
||||||
|
doReturn(platformVersion).whenever(it).platformVersion
|
||||||
|
}, initialiseSerialization = false)
|
||||||
|
assertEquals(node.generateNodeInfo(), node.generateNodeInfo()) // Node info doesn't change (including the serial)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `clear network map cache works`() {
|
||||||
|
val configuration = createConfig()
|
||||||
|
val (nodeInfo, _) = createNodeInfoAndSigned(ALICE_NAME)
|
||||||
|
configureDatabase(configuration.dataSourceProperties, configuration.database, { null }, { null }).use {
|
||||||
|
it.transaction {
|
||||||
|
val persistentNodeInfo = NodeInfoSchemaV1.PersistentNodeInfo(
|
||||||
|
id = 0,
|
||||||
|
hash = nodeInfo.serialize().hash.toString(),
|
||||||
|
addresses = nodeInfo.addresses.map { NodeInfoSchemaV1.DBHostAndPort.fromHostAndPort(it) },
|
||||||
|
legalIdentitiesAndCerts = nodeInfo.legalIdentitiesAndCerts.mapIndexed { idx, elem ->
|
||||||
|
NodeInfoSchemaV1.DBPartyAndCertificate(elem, isMain = idx == 0)
|
||||||
|
},
|
||||||
|
platformVersion = nodeInfo.platformVersion,
|
||||||
|
serial = nodeInfo.serial
|
||||||
|
)
|
||||||
|
// Save some NodeInfo
|
||||||
|
session.save(persistentNodeInfo)
|
||||||
|
}
|
||||||
|
val node = Node(configuration, rigorousMock<VersionInfo>().also {
|
||||||
|
doReturn(10).whenever(it).platformVersion
|
||||||
|
}, initialiseSerialization = false)
|
||||||
|
assertThat(getAllInfos(it)).isNotEmpty
|
||||||
|
node.clearNetworkMapCache()
|
||||||
|
assertThat(getAllInfos(it)).isEmpty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getAllInfos(database: CordaPersistence): List<NodeInfoSchemaV1.PersistentNodeInfo> {
|
||||||
|
return database.transaction {
|
||||||
|
val criteria = session.criteriaBuilder.createQuery(NodeInfoSchemaV1.PersistentNodeInfo::class.java)
|
||||||
|
criteria.select(criteria.from(NodeInfoSchemaV1.PersistentNodeInfo::class.java))
|
||||||
|
session.createQuery(criteria).resultList
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createConfig(): NodeConfiguration {
|
||||||
val dataSourceProperties = makeTestDataSourceProperties()
|
val dataSourceProperties = makeTestDataSourceProperties()
|
||||||
val databaseConfig = DatabaseConfig()
|
val databaseConfig = DatabaseConfig()
|
||||||
val configuration = rigorousMock<AbstractNodeConfiguration>().also {
|
val nodeAddress = NetworkHostAndPort("0.1.2.3", 456)
|
||||||
|
val nodeName = CordaX500Name("Manx Blockchain Corp", "Douglas", "IM")
|
||||||
|
return rigorousMock<AbstractNodeConfiguration>().also {
|
||||||
doReturn(nodeAddress).whenever(it).p2pAddress
|
doReturn(nodeAddress).whenever(it).p2pAddress
|
||||||
doReturn(nodeName).whenever(it).myLegalName
|
doReturn(nodeName).whenever(it).myLegalName
|
||||||
doReturn(null).whenever(it).notary // Don't add notary identity.
|
doReturn(null).whenever(it).notary // Don't add notary identity.
|
||||||
@ -68,11 +120,5 @@ class NodeTest {
|
|||||||
doReturn("tsp").whenever(it).trustStorePassword
|
doReturn("tsp").whenever(it).trustStorePassword
|
||||||
doReturn("ksp").whenever(it).keyStorePassword
|
doReturn("ksp").whenever(it).keyStorePassword
|
||||||
}
|
}
|
||||||
configureDatabase(dataSourceProperties, databaseConfig, { null }, { null }).use { database ->
|
|
||||||
val node = Node(configuration, rigorousMock<VersionInfo>().also {
|
|
||||||
doReturn(platformVersion).whenever(it).platformVersion
|
|
||||||
}, initialiseSerialization = false)
|
|
||||||
assertEquals(node.generateNodeInfo(), node.generateNodeInfo()) // Node info doesn't change (including the serial)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user