CORDA-599 Remove unnecessary laziness (#1517)

This commit is contained in:
Andrzej Cichocki
2017-10-03 16:30:17 +01:00
committed by GitHub
parent eb0e2535ed
commit ab7507db69
10 changed files with 30 additions and 37 deletions

View File

@ -185,8 +185,9 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
check(started == null) { "Node has already been started" } check(started == null) { "Node has already been started" }
initCertificate() initCertificate()
log.info("Generating nodeInfo ...") log.info("Generating nodeInfo ...")
initialiseDatabasePersistence { val schemaService = NodeSchemaService()
makeServices() initialiseDatabasePersistence(schemaService) {
makeServices(schemaService)
saveOwnNodeInfo() saveOwnNodeInfo()
} }
} }
@ -195,9 +196,10 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
check(started == null) { "Node has already been started" } check(started == null) { "Node has already been started" }
initCertificate() initCertificate()
log.info("Node starting up ...") log.info("Node starting up ...")
val schemaService = NodeSchemaService()
// Do all of this in a database transaction so anything that might need a connection has one. // Do all of this in a database transaction so anything that might need a connection has one.
val startedImpl = initialiseDatabasePersistence { val startedImpl = initialiseDatabasePersistence(schemaService) {
val tokenizableServices = makeServices() val tokenizableServices = makeServices(schemaService)
saveOwnNodeInfo() saveOwnNodeInfo()
smm = StateMachineManager(services, smm = StateMachineManager(services,
checkpointStorage, checkpointStorage,
@ -391,10 +393,10 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
* Builds node internal, advertised, and plugin services. * Builds node internal, advertised, and plugin services.
* Returns a list of tokenizable services to be added to the serialisation context. * Returns a list of tokenizable services to be added to the serialisation context.
*/ */
private fun makeServices(): MutableList<Any> { private fun makeServices(schemaService: SchemaService): MutableList<Any> {
checkpointStorage = DBCheckpointStorage() checkpointStorage = DBCheckpointStorage()
cordappProvider = CordappProviderImpl(cordappLoader) cordappProvider = CordappProviderImpl(cordappLoader)
_services = ServiceHubInternalImpl() _services = ServiceHubInternalImpl(schemaService)
attachments = NodeAttachmentService(services.monitoringService.metrics) attachments = NodeAttachmentService(services.monitoringService.metrics)
cordappProvider.start(attachments) cordappProvider.start(attachments)
legalIdentity = obtainIdentity() legalIdentity = obtainIdentity()
@ -482,10 +484,10 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
// Specific class so that MockNode can catch it. // Specific class so that MockNode can catch it.
class DatabaseConfigurationException(msg: String) : CordaException(msg) class DatabaseConfigurationException(msg: String) : CordaException(msg)
protected open fun <T> initialiseDatabasePersistence(insideTransaction: () -> T): T { protected open fun <T> initialiseDatabasePersistence(schemaService: SchemaService, insideTransaction: () -> T): T {
val props = configuration.dataSourceProperties val props = configuration.dataSourceProperties
if (props.isNotEmpty()) { if (props.isNotEmpty()) {
this.database = configureDatabase(props, configuration.database, { _services.schemaService }, createIdentityService = { _services.identityService }) this.database = configureDatabase(props, configuration.database, schemaService, { _services.identityService })
// Now log the vendor string as this will also cause a connection to be tested eagerly. // Now log the vendor string as this will also cause a connection to be tested eagerly.
database.transaction { database.transaction {
log.info("Connected to ${database.dataSource.connection.metaData.databaseProductName} database.") log.info("Connected to ${database.dataSource.connection.metaData.databaseProductName} database.")
@ -689,15 +691,13 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
protected open fun generateKeyPair() = cryptoGenerateKeyPair() protected open fun generateKeyPair() = cryptoGenerateKeyPair()
private inner class ServiceHubInternalImpl : ServiceHubInternal, SingletonSerializeAsToken() { private inner class ServiceHubInternalImpl(override val schemaService: SchemaService) : ServiceHubInternal, SingletonSerializeAsToken() {
override val rpcFlows = ArrayList<Class<out FlowLogic<*>>>() override val rpcFlows = ArrayList<Class<out FlowLogic<*>>>()
override val stateMachineRecordedTransactionMapping = DBTransactionMappingStorage() override val stateMachineRecordedTransactionMapping = DBTransactionMappingStorage()
override val auditService = DummyAuditService() override val auditService = DummyAuditService()
override val monitoringService = MonitoringService(MetricRegistry()) override val monitoringService = MonitoringService(MetricRegistry())
override val validatedTransactions = makeTransactionStorage() override val validatedTransactions = makeTransactionStorage()
override val transactionVerifierService by lazy { makeTransactionVerifierService() } override val transactionVerifierService by lazy { makeTransactionVerifierService() }
override val schemaService by lazy { NodeSchemaService() }
override val networkMapCache by lazy { PersistentNetworkMapCache(this) } override val networkMapCache by lazy { PersistentNetworkMapCache(this) }
override val vaultService by lazy { NodeVaultService(this, database.hibernateConfig) } override val vaultService by lazy { NodeVaultService(this, database.hibernateConfig) }
override val contractUpgradeService by lazy { ContractUpgradeServiceImpl() } override val contractUpgradeService by lazy { ContractUpgradeServiceImpl() }

View File

@ -15,11 +15,11 @@ import net.corda.core.node.ServiceHub
import net.corda.core.serialization.SerializationDefaults import net.corda.core.serialization.SerializationDefaults
import net.corda.core.utilities.* import net.corda.core.utilities.*
import net.corda.node.VersionInfo import net.corda.node.VersionInfo
import net.corda.node.internal.cordapp.CordappProviderImpl
import net.corda.node.serialization.KryoServerSerializationScheme import net.corda.node.serialization.KryoServerSerializationScheme
import net.corda.node.serialization.NodeClock import net.corda.node.serialization.NodeClock
import net.corda.node.services.RPCUserService import net.corda.node.services.RPCUserService
import net.corda.node.services.RPCUserServiceImpl import net.corda.node.services.RPCUserServiceImpl
import net.corda.node.services.api.SchemaService
import net.corda.nodeapi.internal.ServiceInfo import net.corda.nodeapi.internal.ServiceInfo
import net.corda.node.services.config.FullNodeConfiguration import net.corda.node.services.config.FullNodeConfiguration
import net.corda.node.services.messaging.ArtemisMessagingServer import net.corda.node.services.messaging.ArtemisMessagingServer
@ -287,7 +287,7 @@ open class Node(override val configuration: FullNodeConfiguration,
* This is not using the H2 "automatic mixed mode" directly but leans on many of the underpinnings. For more details * This is not using the H2 "automatic mixed mode" directly but leans on many of the underpinnings. For more details
* on H2 URLs and configuration see: http://www.h2database.com/html/features.html#database_url * on H2 URLs and configuration see: http://www.h2database.com/html/features.html#database_url
*/ */
override fun <T> initialiseDatabasePersistence(insideTransaction: () -> T): T { override fun <T> initialiseDatabasePersistence(schemaService: SchemaService, insideTransaction: () -> T): T {
val databaseUrl = configuration.dataSourceProperties.getProperty("dataSource.url") val databaseUrl = configuration.dataSourceProperties.getProperty("dataSource.url")
val h2Prefix = "jdbc:h2:file:" val h2Prefix = "jdbc:h2:file:"
if (databaseUrl != null && databaseUrl.startsWith(h2Prefix)) { if (databaseUrl != null && databaseUrl.startsWith(h2Prefix)) {
@ -304,7 +304,7 @@ open class Node(override val configuration: FullNodeConfiguration,
printBasicNodeInfo("Database connection url is", "jdbc:h2:$url/node") printBasicNodeInfo("Database connection url is", "jdbc:h2:$url/node")
} }
} }
return super.initialiseDatabasePersistence(insideTransaction) return super.initialiseDatabasePersistence(schemaService, insideTransaction)
} }
private val _startupComplete = openFuture<Unit>() private val _startupComplete = openFuture<Unit>()

View File

@ -24,7 +24,7 @@ import java.sql.Connection
import java.util.* import java.util.*
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
class HibernateConfiguration(createSchemaService: () -> SchemaService, private val databaseProperties: Properties, private val createIdentityScervice: () -> IdentityService) { class HibernateConfiguration(val schemaService: SchemaService, private val databaseProperties: Properties, private val createIdentityService: () -> IdentityService) {
companion object { companion object {
val logger = loggerFor<HibernateConfiguration>() val logger = loggerFor<HibernateConfiguration>()
} }
@ -33,7 +33,6 @@ class HibernateConfiguration(createSchemaService: () -> SchemaService, private v
private val sessionFactories = ConcurrentHashMap<Set<MappedSchema>, SessionFactory>() private val sessionFactories = ConcurrentHashMap<Set<MappedSchema>, SessionFactory>()
private val transactionIsolationLevel = parserTransactionIsolationLevel(databaseProperties.getProperty("transactionIsolationLevel") ?:"") private val transactionIsolationLevel = parserTransactionIsolationLevel(databaseProperties.getProperty("transactionIsolationLevel") ?:"")
var schemaService = createSchemaService()
init { init {
logger.info("Init HibernateConfiguration for schemas: ${schemaService.schemaOptions.keys}") logger.info("Init HibernateConfiguration for schemas: ${schemaService.schemaOptions.keys}")
@ -86,7 +85,7 @@ class HibernateConfiguration(createSchemaService: () -> SchemaService, private v
} }
}) })
// register custom converters // register custom converters
applyAttributeConverter(AbstractPartyToX500NameAsStringConverter(createIdentityScervice)) applyAttributeConverter(AbstractPartyToX500NameAsStringConverter(createIdentityService))
// Register a tweaked version of `org.hibernate.type.MaterializedBlobType` that truncates logged messages. // Register a tweaked version of `org.hibernate.type.MaterializedBlobType` that truncates logged messages.
// to avoid OOM when large blobs might get logged. // to avoid OOM when large blobs might get logged.
applyBasicType(CordaMaterializedBlobType, CordaMaterializedBlobType.name) applyBasicType(CordaMaterializedBlobType, CordaMaterializedBlobType.name)

View File

@ -23,13 +23,13 @@ import java.util.concurrent.CopyOnWriteArrayList
const val NODE_DATABASE_PREFIX = "node_" const val NODE_DATABASE_PREFIX = "node_"
//HikariDataSource implements Closeable which allows CordaPersistence to be Closeable //HikariDataSource implements Closeable which allows CordaPersistence to be Closeable
class CordaPersistence(var dataSource: HikariDataSource, private var createSchemaService: () -> SchemaService, class CordaPersistence(var dataSource: HikariDataSource, private val schemaService: SchemaService,
private val createIdentityService: ()-> IdentityService, databaseProperties: Properties): Closeable { private val createIdentityService: ()-> IdentityService, databaseProperties: Properties): Closeable {
var transactionIsolationLevel = parserTransactionIsolationLevel(databaseProperties.getProperty("transactionIsolationLevel")) var transactionIsolationLevel = parserTransactionIsolationLevel(databaseProperties.getProperty("transactionIsolationLevel"))
val hibernateConfig: HibernateConfiguration by lazy { val hibernateConfig: HibernateConfiguration by lazy {
transaction { transaction {
HibernateConfiguration(createSchemaService, databaseProperties, createIdentityService) HibernateConfiguration(schemaService, databaseProperties, createIdentityService)
} }
} }
@ -40,8 +40,8 @@ class CordaPersistence(var dataSource: HikariDataSource, private var createSchem
} }
companion object { companion object {
fun connect(dataSource: HikariDataSource, createSchemaService: () -> SchemaService, createIdentityService: () -> IdentityService, databaseProperties: Properties): CordaPersistence { fun connect(dataSource: HikariDataSource, schemaService: SchemaService, createIdentityService: () -> IdentityService, databaseProperties: Properties): CordaPersistence {
return CordaPersistence(dataSource, createSchemaService, createIdentityService, databaseProperties).apply { return CordaPersistence(dataSource, schemaService, createIdentityService, databaseProperties).apply {
DatabaseTransactionManager(this) DatabaseTransactionManager(this)
} }
} }
@ -107,10 +107,10 @@ class CordaPersistence(var dataSource: HikariDataSource, private var createSchem
} }
} }
fun configureDatabase(dataSourceProperties: Properties, databaseProperties: Properties?, createSchemaService: () -> SchemaService = { NodeSchemaService() }, createIdentityService: () -> IdentityService): CordaPersistence { fun configureDatabase(dataSourceProperties: Properties, databaseProperties: Properties?, schemaService: SchemaService = NodeSchemaService(), createIdentityService: () -> IdentityService): CordaPersistence {
val config = HikariConfig(dataSourceProperties) val config = HikariConfig(dataSourceProperties)
val dataSource = HikariDataSource(config) val dataSource = HikariDataSource(config)
val persistence = CordaPersistence.connect(dataSource, createSchemaService, createIdentityService, databaseProperties ?: Properties()) val persistence = CordaPersistence.connect(dataSource, schemaService, createIdentityService, databaseProperties ?: Properties())
// Check not in read-only mode. // Check not in read-only mode.
persistence.transaction { persistence.transaction {

View File

@ -42,11 +42,7 @@ class DBTransactionStorageTests : TestDependencyInjectionBase() {
fun setUp() { fun setUp() {
LogHelper.setLevel(PersistentUniquenessProvider::class) LogHelper.setLevel(PersistentUniquenessProvider::class)
val dataSourceProps = makeTestDataSourceProperties() val dataSourceProps = makeTestDataSourceProperties()
database = configureDatabase(dataSourceProps, makeTestDatabaseProperties(), NodeSchemaService(), ::makeTestIdentityService)
val createSchemaService = { NodeSchemaService() }
database = configureDatabase(dataSourceProps, makeTestDatabaseProperties(), createSchemaService, ::makeTestIdentityService)
database.transaction { database.transaction {
services = object : MockServices(BOB_KEY) { services = object : MockServices(BOB_KEY) {

View File

@ -77,8 +77,7 @@ class HibernateConfigurationTest : TestDependencyInjectionBase() {
issuerServices = MockServices(DUMMY_CASH_ISSUER_KEY, BOB_KEY, BOC_KEY) issuerServices = MockServices(DUMMY_CASH_ISSUER_KEY, BOB_KEY, BOC_KEY)
val dataSourceProps = makeTestDataSourceProperties() val dataSourceProps = makeTestDataSourceProperties()
val defaultDatabaseProperties = makeTestDatabaseProperties() val defaultDatabaseProperties = makeTestDatabaseProperties()
val createSchemaService = { NodeSchemaService() } database = configureDatabase(dataSourceProps, defaultDatabaseProperties, NodeSchemaService(), ::makeTestIdentityService)
database = configureDatabase(dataSourceProps, defaultDatabaseProperties, createSchemaService, ::makeTestIdentityService)
database.transaction { database.transaction {
hibernateConfig = database.hibernateConfig hibernateConfig = database.hibernateConfig
services = object : MockServices(BOB_KEY, BOC_KEY, DUMMY_NOTARY_KEY) { services = object : MockServices(BOB_KEY, BOC_KEY, DUMMY_NOTARY_KEY) {

View File

@ -70,8 +70,7 @@ class HibernateObserverTests {
return parent return parent
} }
} }
val database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), { schemaService }, createIdentityService = ::makeTestIdentityService) val database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), schemaService, createIdentityService = ::makeTestIdentityService)
@Suppress("UNUSED_VARIABLE") @Suppress("UNUSED_VARIABLE")
val observer = HibernateObserver(rawUpdatesPublisher, database.hibernateConfig) val observer = HibernateObserver(rawUpdatesPublisher, database.hibernateConfig)
database.transaction { database.transaction {

View File

@ -26,6 +26,7 @@ import net.corda.core.utilities.loggerFor
import net.corda.finance.utils.WorldMapLocation import net.corda.finance.utils.WorldMapLocation
import net.corda.node.internal.AbstractNode import net.corda.node.internal.AbstractNode
import net.corda.node.internal.StartedNode import net.corda.node.internal.StartedNode
import net.corda.node.services.api.SchemaService
import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.identity.PersistentIdentityService import net.corda.node.services.identity.PersistentIdentityService
import net.corda.node.services.keys.E2ETestKeyManagementService import net.corda.node.services.keys.E2ETestKeyManagementService
@ -248,7 +249,7 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
@Suppress("unused") val place: WorldMapLocation get() = findMyLocation()!! @Suppress("unused") val place: WorldMapLocation get() = findMyLocation()!!
private var dbCloser: (() -> Any?)? = null private var dbCloser: (() -> Any?)? = null
override fun <T> initialiseDatabasePersistence(insideTransaction: () -> T) = super.initialiseDatabasePersistence { override fun <T> initialiseDatabasePersistence(schemaService: SchemaService, insideTransaction: () -> T) = super.initialiseDatabasePersistence(schemaService) {
dbCloser = database::close dbCloser = database::close
insideTransaction() insideTransaction()
} }

View File

@ -100,9 +100,8 @@ open class MockServices(cordappPackages: List<String> = emptyList(), vararg val
cordappPackages: List<String> = emptyList()): Pair<CordaPersistence, MockServices> { cordappPackages: List<String> = emptyList()): Pair<CordaPersistence, MockServices> {
val dataSourceProps = makeTestDataSourceProperties() val dataSourceProps = makeTestDataSourceProperties()
val databaseProperties = makeTestDatabaseProperties() val databaseProperties = makeTestDatabaseProperties()
val createSchemaService = { NodeSchemaService(customSchemas) }
val identityServiceRef: IdentityService by lazy { createIdentityService() } val identityServiceRef: IdentityService by lazy { createIdentityService() }
val database = configureDatabase(dataSourceProps, databaseProperties, createSchemaService, { identityServiceRef }) val database = configureDatabase(dataSourceProps, databaseProperties, NodeSchemaService(customSchemas), { identityServiceRef })
val mockService = database.transaction { val mockService = database.transaction {
object : MockServices(cordappPackages, *(keys.toTypedArray())) { object : MockServices(cordappPackages, *(keys.toTypedArray())) {
override val identityService: IdentityService = database.transaction { identityServiceRef } override val identityService: IdentityService = database.transaction { identityServiceRef }
@ -158,7 +157,7 @@ open class MockServices(cordappPackages: List<String> = emptyList(), vararg val
lateinit var hibernatePersister: HibernateObserver lateinit var hibernatePersister: HibernateObserver
fun makeVaultService(hibernateConfig: HibernateConfiguration = HibernateConfiguration( { NodeSchemaService() }, makeTestDatabaseProperties(), { identityService })): VaultService { fun makeVaultService(hibernateConfig: HibernateConfiguration = HibernateConfiguration(NodeSchemaService(), makeTestDatabaseProperties(), { identityService })): VaultService {
val vaultService = NodeVaultService(this, hibernateConfig) val vaultService = NodeVaultService(this, hibernateConfig)
hibernatePersister = HibernateObserver(vaultService.rawUpdates, hibernateConfig) hibernatePersister = HibernateObserver(vaultService.rawUpdates, hibernateConfig)
return vaultService return vaultService

View File

@ -37,7 +37,7 @@ class SimpleNode(val config: NodeConfiguration, val address: NetworkHostAndPort
val monitoringService = MonitoringService(MetricRegistry()) val monitoringService = MonitoringService(MetricRegistry())
val identity: KeyPair = generateKeyPair() val identity: KeyPair = generateKeyPair()
val identityService: IdentityService = InMemoryIdentityService(trustRoot = trustRoot) val identityService: IdentityService = InMemoryIdentityService(trustRoot = trustRoot)
val database: CordaPersistence = configureDatabase(config.dataSourceProperties, config.database, { NodeSchemaService() }, { InMemoryIdentityService(trustRoot = trustRoot) }) val database: CordaPersistence = configureDatabase(config.dataSourceProperties, config.database, NodeSchemaService(), { InMemoryIdentityService(trustRoot = trustRoot) })
val keyService: KeyManagementService = E2ETestKeyManagementService(identityService, setOf(identity)) val keyService: KeyManagementService = E2ETestKeyManagementService(identityService, setOf(identity))
val executor = ServiceAffinityExecutor(config.myLegalName.organisation, 1) val executor = ServiceAffinityExecutor(config.myLegalName.organisation, 1)
// TODO: We should have a dummy service hub rather than change behaviour in tests // TODO: We should have a dummy service hub rather than change behaviour in tests