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:
Vibhu Mohindra 2016-03-15 17:08:28 +00:00
parent 473e4e527e
commit 11d14001cd
8 changed files with 75 additions and 80 deletions

8
.gitignore vendored
View File

@ -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

View File

@ -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<*>>())

View File

@ -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)
}
}

View File

@ -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

View 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
}

View File

@ -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

View File

@ -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 {

View File

@ -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 })
}
}
}