Transaction notes now stored individually per row.

This commit is contained in:
Jose Coll 2016-11-17 17:57:07 +00:00
commit 876b17bb12
4 changed files with 24 additions and 26 deletions

View File

@ -38,8 +38,7 @@ val DEFAULT_SESSION_ID = 0L
* Active means they haven't been consumed yet (or we don't know about it).
* Relevant means they contain at least one of our pubkeys.
*/
class Vault(val states: Iterable<StateAndRef<ContractState>>,
val transactionNotes: Map<SecureHash, Set<String>> = emptyMap()) {
class Vault(val states: Iterable<StateAndRef<ContractState>>) {
@Suppress("UNCHECKED_CAST")
inline fun <reified T : ContractState> statesOfType() = states.filter { it.state.data is T } as List<StateAndRef<T>>

View File

@ -18,6 +18,7 @@ import net.corda.core.utilities.loggerFor
import net.corda.core.utilities.trace
import net.corda.node.utilities.*
import org.jetbrains.exposed.sql.ResultRow
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.statements.InsertStatement
import rx.Observable
import rx.subjects.PublishSubject
@ -45,9 +46,13 @@ class NodeVaultService(private val services: ServiceHub) : SingletonSerializeAsT
val stateRef = stateRef("transaction_id", "output_index")
}
private data class TxnNote(val txnId: SecureHash, val note: String) {
override fun toString() = "$txnId: $note"
}
private object TransactionNotesTable : JDBCHashedTable("${NODE_DATABASE_PREFIX}vault_txn_notes") {
val txnId = secureHash("txnId")
val notes = text("notes")
val txnId = secureHash("txnId").index()
val note = text("note")
}
private val mutex = ThreadBox(content = object {
@ -60,21 +65,17 @@ class NodeVaultService(private val services: ServiceHub) : SingletonSerializeAsT
}
}
val transactionNotes = object : AbstractJDBCHashMap<SecureHash, Set<String>, TransactionNotesTable>(TransactionNotesTable, loadOnInit = false) {
override fun keyFromRow(row: ResultRow): SecureHash {
return row[table.txnId]
val transactionNotes = object : AbstractJDBCHashSet<TxnNote, TransactionNotesTable>(TransactionNotesTable) {
override fun elementFromRow(row: ResultRow): TxnNote = TxnNote(row[table.txnId], row[table.note])
override fun addElementToInsert(insert: InsertStatement, entry: TxnNote, finalizables: MutableList<() -> Unit>) {
insert[table.txnId] = entry.txnId
insert[table.note] = entry.note
}
override fun valueFromRow(row: ResultRow): Set<String> {
return row[table.notes].split(delimiters = ";").toSet()
}
override fun addKeyToInsert(insert: InsertStatement, entry: Map.Entry<SecureHash, Set<String>>, finalizables: MutableList<() -> Unit>) {
insert[table.txnId] = entry.key
}
override fun addValueToInsert(insert: InsertStatement, entry: Map.Entry<SecureHash, Set<String>>, finalizables: MutableList<() -> Unit>) {
insert[table.notes] = entry.value.joinToString(separator = ";")
// TODO: caching (2nd tier db cache) and db results filtering (max records, date, other)
fun select(txnId: SecureHash) : Iterable<String> {
return table.select { table.txnId.eq(txnId) }.map { row -> row[table.note] }.toSet().asIterable()
}
}
@ -101,14 +102,14 @@ class NodeVaultService(private val services: ServiceHub) : SingletonSerializeAsT
}
})
override val currentVault: Vault get() = mutex.locked { Vault(allUnconsumedStates(), transactionNotes) }
override val currentVault: Vault get() = mutex.locked { Vault(allUnconsumedStates()) }
override val updates: Observable<Vault.Update>
get() = mutex.locked { _updatesPublisher }
override fun track(): Pair<Vault, Observable<Vault.Update>> {
return mutex.locked {
Pair(Vault(allUnconsumedStates(), transactionNotes), _updatesPublisher.bufferUntilSubscribed())
Pair(Vault(allUnconsumedStates()), _updatesPublisher.bufferUntilSubscribed())
}
}
@ -134,16 +135,13 @@ class NodeVaultService(private val services: ServiceHub) : SingletonSerializeAsT
override fun addNoteToTransaction(txnId: SecureHash, noteText: String) {
mutex.locked {
val notes = transactionNotes.getOrPut(key = txnId, defaultValue = {
setOf(noteText)
})
transactionNotes.put(txnId, notes.plus(noteText))
transactionNotes.add(TxnNote(txnId, noteText))
}
}
override fun getTransactionNotes(txnId: SecureHash): Iterable<String> {
mutex.locked {
return transactionNotes.get(txnId)!!.asIterable()
return transactionNotes.select(txnId)
}
}

View File

@ -140,6 +140,7 @@ class StrandLocalTransactionManager(initWithDatabase: Database) : TransactionMan
// Composite columns for use with below Exposed helpers.
data class PartyColumns(val name: Column<String>, val owningKey: Column<PublicKeyTree>)
data class StateRefColumns(val txId: Column<SecureHash>, val index: Column<Int>)
data class TxnNoteColumns(val txId: Column<SecureHash>, val note: Column<String>)
/**
* [Table] column helpers for use with Exposed, as per [varchar] etc.
@ -154,6 +155,7 @@ fun Table.localDate(name: String) = this.registerColumn<LocalDate>(name, LocalDa
fun Table.localDateTime(name: String) = this.registerColumn<LocalDateTime>(name, LocalDateTimeColumnType)
fun Table.instant(name: String) = this.registerColumn<Instant>(name, InstantColumnType)
fun Table.stateRef(txIdColumnName: String, indexColumnName: String) = StateRefColumns(this.secureHash(txIdColumnName), this.integer(indexColumnName))
fun Table.txnNote(txIdColumnName: String, txnNoteColumnName: String) = TxnNoteColumns(this.secureHash(txIdColumnName), this.text(txnNoteColumnName))
/**
* [ColumnType] for marshalling to/from database on behalf of [PublicKey].

View File

@ -112,7 +112,7 @@ class NodeVaultServiceTest {
services.vaultService.addNoteToTransaction(usefulTX.id, "USD Sample Note 1")
services.vaultService.addNoteToTransaction(usefulTX.id, "USD Sample Note 2")
services.vaultService.addNoteToTransaction(usefulTX.id, "USD Sample Note 3")
assertEquals(1, services.vaultService.currentVault.transactionNotes.toList().size)
val results = services.vaultService.getTransactionNotes(usefulTX.id)
assertEquals(3, services.vaultService.getTransactionNotes(usefulTX.id).count())
// Issue more Money (GBP)
@ -124,7 +124,6 @@ class NodeVaultServiceTest {
services.recordTransactions(listOf(anotherTX))
services.vaultService.addNoteToTransaction(anotherTX.id, "GPB Sample Note 1")
assertEquals(2, services.vaultService.currentVault.transactionNotes.toList().size)
assertEquals(1, services.vaultService.getTransactionNotes(anotherTX.id).count())
}
}