mirror of
https://github.com/corda/corda.git
synced 2024-12-24 07:06:44 +00:00
Unified the various StorageService implementations. Made getMap() private. Made the nested tables into instance variables. Moved StorageServiceImpl out into its own file to avoid merge conflicts in the future.
This commit is contained in:
parent
473e4e527e
commit
11d14001cd
8
.gitignore
vendored
8
.gitignore
vendored
@ -1,5 +1,13 @@
|
||||
TODO
|
||||
|
||||
# Eclipse, ctags, Mac metadata, log files
|
||||
.classpath
|
||||
.project
|
||||
.settings
|
||||
tags
|
||||
.DS_Store
|
||||
*.log
|
||||
|
||||
# Created by .ignore support plugin (hsz.mobi)
|
||||
|
||||
.gradle
|
||||
|
@ -61,7 +61,7 @@ import javax.annotation.concurrent.ThreadSafe
|
||||
class StateMachineManager(val serviceHub: ServiceHub, val runInThread: Executor) {
|
||||
// This map is backed by a database and will be used to store serialised state machines to disk, so we can resurrect
|
||||
// them across node restarts.
|
||||
private val checkpointsMap = serviceHub.storageService.getMap<SecureHash, ByteArray>("state machines")
|
||||
private val checkpointsMap = serviceHub.storageService.stateMachines
|
||||
// A list of all the state machines being managed by this class. We expose snapshots of it via the stateMachines
|
||||
// property.
|
||||
private val _stateMachines = Collections.synchronizedList(ArrayList<ProtocolLogic<*>>())
|
||||
|
@ -147,31 +147,12 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
|
||||
val attachments = makeAttachmentStorage(dir)
|
||||
_servicesThatAcceptUploads += attachments
|
||||
val (identity, keypair) = obtainKeyPair(dir)
|
||||
return constructStorageService(attachments, identity, keypair)
|
||||
return constructStorageService(attachments, keypair, identity, contractFactory)
|
||||
}
|
||||
|
||||
protected open fun constructStorageService(attachments: NodeAttachmentService, identity: Party, keypair: KeyPair) =
|
||||
StorageServiceImpl(attachments, identity, keypair)
|
||||
|
||||
open inner class StorageServiceImpl(attachments: NodeAttachmentService, identity: Party, keypair: KeyPair) : StorageService {
|
||||
protected val tables = HashMap<String, MutableMap<Any, Any>>()
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <K, V> getMap(tableName: String): MutableMap<K, V> {
|
||||
// TODO: This should become a database.
|
||||
synchronized(tables) {
|
||||
return tables.getOrPut(tableName) { Collections.synchronizedMap(HashMap<Any, Any>()) } as MutableMap<K, V>
|
||||
}
|
||||
}
|
||||
|
||||
override val validatedTransactions: MutableMap<SecureHash, SignedTransaction>
|
||||
get() = getMap("validated-transactions")
|
||||
|
||||
override val attachments: AttachmentStorage = attachments
|
||||
override val contractPrograms = contractFactory
|
||||
override val myLegalIdentity = identity
|
||||
override val myLegalIdentityKey = keypair
|
||||
}
|
||||
protected open fun constructStorageService(attachments: NodeAttachmentService, keypair: KeyPair, identity: Party,
|
||||
contractFactory: ContractFactory) =
|
||||
StorageServiceImpl(attachments, contractFactory, keypair, identity)
|
||||
|
||||
private fun obtainKeyPair(dir: Path): Pair<Party, KeyPair> {
|
||||
// Load the private identity key, creating it if necessary. The identity key is a long term well known key that
|
||||
@ -214,3 +195,4 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
|
||||
return NodeAttachmentService(attachmentsDir, services.monitoringService.metrics)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,9 +104,6 @@ interface KeyManagementService {
|
||||
* anything like that, this interface is only big enough to support the prototyping work.
|
||||
*/
|
||||
interface StorageService {
|
||||
/** TODO: Temp scaffolding that will go away eventually. */
|
||||
fun <K,V> getMap(tableName: String): MutableMap<K, V>
|
||||
|
||||
/**
|
||||
* A map of hash->tx where tx has been signature/contract validated and the states are known to be correct.
|
||||
* The signatures aren't technically needed after that point, but we keep them around so that we can relay
|
||||
@ -114,6 +111,8 @@ interface StorageService {
|
||||
*/
|
||||
val validatedTransactions: MutableMap<SecureHash, SignedTransaction>
|
||||
|
||||
val stateMachines: MutableMap<SecureHash, ByteArray>
|
||||
|
||||
/** Provides access to storage of arbitrary JAR files (which may contain only data, no code). */
|
||||
val attachments: AttachmentStorage
|
||||
|
||||
|
45
src/main/kotlin/core/node/services/StorageServiceImpl.kt
Normal file
45
src/main/kotlin/core/node/services/StorageServiceImpl.kt
Normal file
@ -0,0 +1,45 @@
|
||||
package core.node.services
|
||||
|
||||
import core.ContractFactory
|
||||
import core.Party
|
||||
import core.SignedTransaction
|
||||
import core.crypto.SecureHash
|
||||
import core.utilities.RecordingMap
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.security.KeyPair
|
||||
import java.util.*
|
||||
|
||||
open class StorageServiceImpl(attachments: AttachmentStorage,
|
||||
contractFactory: ContractFactory,
|
||||
keypair: KeyPair,
|
||||
identity: Party = Party("Unit test party", keypair.public),
|
||||
// This parameter is for unit tests that want to observe operation details.
|
||||
val recordingAs: (String) -> String = { tableName -> "" })
|
||||
: StorageService {
|
||||
protected val tables = HashMap<String, MutableMap<Any, Any>>()
|
||||
|
||||
private fun <K, V> getMapOriginal(tableName: String): MutableMap<K, V> {
|
||||
synchronized(tables) {
|
||||
return tables.getOrPut(tableName) {
|
||||
recorderWrap(Collections.synchronizedMap(HashMap<Any, Any>()), tableName);
|
||||
} as MutableMap<K, V>
|
||||
}
|
||||
}
|
||||
|
||||
private fun <K, V> recorderWrap(map: MutableMap<K, V>, tableName: String): MutableMap<K, V> {
|
||||
if (recordingAs(tableName) != "")
|
||||
return RecordingMap(map, LoggerFactory.getLogger("recordingmap.${recordingAs(tableName)}"))
|
||||
else
|
||||
return map
|
||||
}
|
||||
|
||||
override val validatedTransactions: MutableMap<SecureHash, SignedTransaction>
|
||||
get() = getMapOriginal("validated-transactions")
|
||||
override val stateMachines: MutableMap<SecureHash, ByteArray>
|
||||
get() = getMapOriginal("state-machines")
|
||||
|
||||
override val attachments: AttachmentStorage = attachments
|
||||
override val contractPrograms = contractFactory
|
||||
override val myLegalIdentity = identity
|
||||
override val myLegalIdentityKey = keypair
|
||||
}
|
@ -6,15 +6,7 @@
|
||||
* All other rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2015 Distributed Ledger Group LLC. Distributed as Licensed Company IP to DLG Group Members
|
||||
* pursuant to the August 7, 2015 Advisory Services Agreement and subject to the Company IP License terms
|
||||
* set forth therein.
|
||||
*
|
||||
* All other rights reserved.
|
||||
*/
|
||||
|
||||
package core.testutils
|
||||
package core.utilities
|
||||
|
||||
import core.utilities.loggerFor
|
||||
import org.slf4j.Logger
|
@ -14,9 +14,10 @@ import core.messaging.MessagingService
|
||||
import core.messaging.MockNetworkMapService
|
||||
import core.messaging.NetworkMapService
|
||||
import core.node.services.*
|
||||
import core.node.AbstractNode
|
||||
import core.node.services.StorageServiceImpl
|
||||
import core.serialization.SerializedBytes
|
||||
import core.serialization.deserialize
|
||||
import core.testutils.RecordingMap
|
||||
import core.testutils.TEST_KEYS_TO_CORP_MAP
|
||||
import core.testutils.TEST_PROGRAM_MAP
|
||||
import core.testutils.TEST_TX_TIME
|
||||
@ -114,31 +115,7 @@ class MockAttachmentStorage : AttachmentStorage {
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
class MockStorageService(val recordingAs: Map<String, String>? = null) : StorageService {
|
||||
override val myLegalIdentityKey: KeyPair = generateKeyPair()
|
||||
override val myLegalIdentity: Party = Party("Unit test party", myLegalIdentityKey.public)
|
||||
|
||||
private val tables = HashMap<String, MutableMap<Any, Any>>()
|
||||
|
||||
override val validatedTransactions: MutableMap<SecureHash, SignedTransaction>
|
||||
get() = getMap("validated-transactions")
|
||||
|
||||
override val contractPrograms = MockContractFactory
|
||||
|
||||
override val attachments: AttachmentStorage = MockAttachmentStorage()
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <K, V> getMap(tableName: String): MutableMap<K, V> {
|
||||
synchronized(tables) {
|
||||
return tables.getOrPut(tableName) {
|
||||
val map = Collections.synchronizedMap(HashMap<Any, Any>())
|
||||
if (recordingAs != null && recordingAs[tableName] != null)
|
||||
RecordingMap(map, LoggerFactory.getLogger("recordingmap.${recordingAs[tableName]}"))
|
||||
else
|
||||
map
|
||||
} as MutableMap<K, V>
|
||||
}
|
||||
}
|
||||
class MockStorageService : StorageServiceImpl(MockAttachmentStorage(), MockContractFactory, generateKeyPair()) {
|
||||
}
|
||||
|
||||
object MockContractFactory : ContractFactory {
|
||||
|
@ -14,8 +14,10 @@ import core.*
|
||||
import core.crypto.SecureHash
|
||||
import core.node.MockNetwork
|
||||
import core.node.services.*
|
||||
import core.node.services.StorageServiceImpl
|
||||
import core.testutils.*
|
||||
import core.utilities.BriefLogFormatter
|
||||
import core.utilities.RecordingMap
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
@ -151,7 +153,7 @@ class TwoPartyTradeProtocolTests : TestWithInMemoryNetwork() {
|
||||
|
||||
// OK, now Bob has sent the partial transaction back to Alice and is waiting for Alice's signature.
|
||||
// Save the state machine to "disk" (i.e. a variable, here)
|
||||
val savedCheckpoints = HashMap(bobNode.storage.getMap<Any, Any>("state machines"))
|
||||
val savedCheckpoints = HashMap(bobNode.storage.stateMachines)
|
||||
assertEquals(1, savedCheckpoints.size)
|
||||
|
||||
// .. and let's imagine that Bob's computer has a power cut. He now has nothing now beyond what was on disk.
|
||||
@ -167,7 +169,7 @@ class TwoPartyTradeProtocolTests : TestWithInMemoryNetwork() {
|
||||
object : MockNetwork.MockNode(path, nodeConfiguration, net, timestamper, bobAddr.id) {
|
||||
override fun initialiseStorageService(dir: Path): StorageService {
|
||||
val ss = super.initialiseStorageService(dir)
|
||||
val smMap = ss.getMap<Any, Any>("state machines")
|
||||
val smMap = ss.stateMachines
|
||||
smMap.putAll(savedCheckpoints)
|
||||
return ss
|
||||
}
|
||||
@ -195,20 +197,10 @@ class TwoPartyTradeProtocolTests : TestWithInMemoryNetwork() {
|
||||
return net.createNode(null) { path, config, net, tsNode ->
|
||||
object : MockNetwork.MockNode(path, config, net, tsNode) {
|
||||
// That constructs the storage service object in a customised way ...
|
||||
override fun constructStorageService(attachments: NodeAttachmentService, identity: Party, keypair: KeyPair): StorageServiceImpl {
|
||||
// By tweaking the standard StorageServiceImpl class ...
|
||||
return object : StorageServiceImpl(attachments, identity, keypair) {
|
||||
override fun constructStorageService(attachments: NodeAttachmentService, keypair: KeyPair, identity: Party,
|
||||
contractFactory: ContractFactory): StorageServiceImpl {
|
||||
// To use RecordingMaps instead of ordinary HashMaps.
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <K, V> getMap(tableName: String): MutableMap<K, V> {
|
||||
synchronized(tables) {
|
||||
return tables.getOrPut(tableName) {
|
||||
val map = Collections.synchronizedMap(HashMap<Any, Any>())
|
||||
RecordingMap(map, LoggerFactory.getLogger("recordingmap.$name"))
|
||||
} as MutableMap<K, V>
|
||||
}
|
||||
}
|
||||
}
|
||||
return StorageServiceImpl(attachments, contractFactory, keypair, identity, { tableName -> name })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user