Merge branch 'release/os/4.9' into shams-4.10-merge-c8135331

This commit is contained in:
Shams Asari 2023-08-22 11:24:38 +01:00
commit 46914a2b35
4 changed files with 79 additions and 33 deletions

View File

@ -272,7 +272,7 @@ class HibernateAttachmentQueryCriteriaParser<T,R>(override val criteriaBuilder:
class HibernateQueryCriteriaParser(val contractStateType: Class<out ContractState>,
val contractStateTypeMappings: Map<String, Set<String>>,
override val criteriaBuilder: CriteriaBuilder,
val criteriaQuery: CriteriaQuery<Tuple>,
val criteriaQuery: CriteriaQuery<*>,
val vaultStates: Root<VaultSchemaV1.VaultStates>) : AbstractQueryCriteriaParser<QueryCriteria, IQueryCriteriaParser, Sort>(), IQueryCriteriaParser {
private companion object {
private val log = contextLogger()

View File

@ -35,7 +35,6 @@ import net.corda.core.node.services.vault.PageSpecification
import net.corda.core.node.services.vault.QueryCriteria
import net.corda.core.node.services.vault.Sort
import net.corda.core.node.services.vault.SortAttribute
import net.corda.core.node.services.vault.builder
import net.corda.core.observable.internal.OnResilientSubscribe
import net.corda.core.schemas.PersistentStateRef
import net.corda.core.serialization.SingletonSerializeAsToken
@ -69,17 +68,21 @@ import java.security.PublicKey
import java.sql.SQLException
import java.time.Clock
import java.time.Instant
import java.util.Arrays
import java.util.UUID
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.CopyOnWriteArraySet
import java.util.stream.Stream
import javax.persistence.PersistenceException
import javax.persistence.Tuple
import javax.persistence.criteria.CriteriaBuilder
import javax.persistence.criteria.CriteriaQuery
import javax.persistence.criteria.CriteriaUpdate
import javax.persistence.criteria.Predicate
import javax.persistence.criteria.Root
import kotlin.collections.ArrayList
import kotlin.collections.LinkedHashSet
import kotlin.collections.component1
import kotlin.collections.component2
/**
* The vault service handles storage, retrieval and querying of states.
@ -706,10 +709,8 @@ class NodeVaultService(
paging: PageSpecification,
sorting: Sort,
contractStateType: Class<out T>): Vault.Page<T> {
// calculate total results where a page specification has been defined
val totalStatesAvailable = if (paging.isDefault) -1 else queryTotalStateCount(criteria, contractStateType)
val (query, stateTypes) = createQuery(criteria, contractStateType, sorting)
val (criteriaQuery, criteriaParser) = buildCriteriaQuery<Tuple>(criteria, contractStateType, sorting)
val query = getSession().createQuery(criteriaQuery)
query.setResultWindow(paging)
val statesMetadata: MutableList<Vault.StateMetadata> = mutableListOf()
@ -732,7 +733,14 @@ class NodeVaultService(
ArrayList()
)
return Vault.Page(states, statesMetadata, totalStatesAvailable, stateTypes, otherResults)
val totalStatesAvailable = when {
paging.isDefault -> -1L
// If the first page isn't full then we know that's all the states that are available
paging.pageNumber == DEFAULT_PAGE_NUM && states.size < paging.pageSize -> states.size.toLong()
else -> queryTotalStateCount(criteria, contractStateType)
}
return Vault.Page(states, statesMetadata, totalStatesAvailable, criteriaParser.stateTypes, otherResults)
}
private fun <R> Query<R>.resultStream(paging: PageSpecification): Stream<R> {
@ -761,19 +769,17 @@ class NodeVaultService(
}
}
private fun <T : ContractState> queryTotalStateCount(baseCriteria: QueryCriteria, contractStateType: Class<out T>): Long {
val count = builder { VaultSchemaV1.VaultStates::recordedTime.count() }
val countCriteria = QueryCriteria.VaultCustomQueryCriteria(count, Vault.StateStatus.ALL)
val criteria = baseCriteria.and(countCriteria)
val (query) = createQuery(criteria, contractStateType, null)
val results = query.resultList
return results.last().toArray().last() as Long
private fun <T : ContractState> queryTotalStateCount(criteria: QueryCriteria, contractStateType: Class<out T>): Long {
val (criteriaQuery, criteriaParser) = buildCriteriaQuery<Long>(criteria, contractStateType, null)
criteriaQuery.select(criteriaBuilder.countDistinct(criteriaParser.vaultStates))
val query = getSession().createQuery(criteriaQuery)
return query.singleResult
}
private fun <T : ContractState> createQuery(criteria: QueryCriteria,
contractStateType: Class<out T>,
sorting: Sort?): Pair<Query<Tuple>, Vault.StateStatus> {
val criteriaQuery = criteriaBuilder.createQuery(Tuple::class.java)
private inline fun <reified T> buildCriteriaQuery(criteria: QueryCriteria,
contractStateType: Class<out ContractState>,
sorting: Sort?): Pair<CriteriaQuery<T>, HibernateQueryCriteriaParser> {
val criteriaQuery = criteriaBuilder.createQuery(T::class.java)
val criteriaParser = HibernateQueryCriteriaParser(
contractStateType,
contractStateTypeMappings,
@ -782,8 +788,7 @@ class NodeVaultService(
criteriaQuery.from(VaultSchemaV1.VaultStates::class.java)
)
criteriaParser.parse(criteria, sorting)
val query = getSession().createQuery(criteriaQuery)
return Pair(query, criteriaParser.stateTypes)
return Pair(criteriaQuery, criteriaParser)
}
/**

View File

@ -22,7 +22,7 @@ class VaultQueryExceptionsTests : VaultQueryParties by rule {
@ClassRule
@JvmField
val rule = object : VaultQueryTestRule() {
val rule = object : VaultQueryTestRule(persistentServices = false) {
override val cordappPackages = listOf(
"net.corda.testing.contracts",
"net.corda.finance.contracts",

View File

@ -4,6 +4,7 @@ import com.nhaarman.mockito_kotlin.mock
import net.corda.core.contracts.*
import net.corda.core.crypto.*
import net.corda.core.identity.AbstractParty
import net.corda.core.identity.AnonymousParty
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.internal.packageName
@ -37,6 +38,7 @@ import net.corda.testing.internal.configureDatabase
import net.corda.testing.internal.vault.*
import net.corda.testing.node.MockServices
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseAndMockServices
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseAndPersistentServices
import net.corda.testing.node.makeTestIdentityService
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatCode
@ -102,7 +104,7 @@ interface VaultQueryParties {
val cordappPackages: List<String>
}
open class VaultQueryTestRule : ExternalResource(), VaultQueryParties {
open class VaultQueryTestRule(private val persistentServices: Boolean) : ExternalResource(), VaultQueryParties {
override val alice = TestIdentity(ALICE_NAME, 70)
override val bankOfCorda = TestIdentity(BOC_NAME)
override val bigCorp = TestIdentity(CordaX500Name("BigCorporation", "New York", "US"))
@ -135,12 +137,22 @@ open class VaultQueryTestRule : ExternalResource(), VaultQueryParties {
override fun before() {
// register additional identities
val databaseAndServices = makeTestDatabaseAndMockServices(
val databaseAndServices = if (persistentServices) {
makeTestDatabaseAndPersistentServices(
cordappPackages,
megaCorp,
moreKeys = setOf(DUMMY_NOTARY_KEY),
moreIdentities = setOf(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, dummyCashIssuer.identity, dummyNotary.identity)
)
} else {
@Suppress("SpreadOperator")
makeTestDatabaseAndMockServices(
cordappPackages,
makeTestIdentityService(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, dummyCashIssuer.identity, dummyNotary.identity),
megaCorp,
moreKeys = *arrayOf(DUMMY_NOTARY_KEY))
moreKeys = *arrayOf(DUMMY_NOTARY_KEY)
)
}
database = databaseAndServices.first
services = databaseAndServices.second
vaultFiller = VaultFiller(services, dummyNotary)
@ -2832,9 +2844,8 @@ abstract class VaultQueryTestsBase : VaultQueryParties {
}
class VaultQueryTests : VaultQueryTestsBase(), VaultQueryParties by delegate {
companion object {
val delegate = VaultQueryTestRule()
val delegate = VaultQueryTestRule(persistentServices = false)
}
@Rule
@ -3138,3 +3149,33 @@ class VaultQueryTests : VaultQueryTestsBase(), VaultQueryParties by delegate {
}
}
}
class PersistentServicesVaultQueryTests : VaultQueryParties by delegate {
companion object {
val delegate = VaultQueryTestRule(persistentServices = true)
@ClassRule
@JvmField
val testSerialization = SerializationEnvironmentRule()
}
@Rule
@JvmField
val vaultQueryTestRule = delegate
@Test(timeout = 300_000)
fun `query on externalId which maps to multiple keys`() {
val externalId = UUID.randomUUID()
val page = database.transaction {
val keys = Array(2) { services.keyManagementService.freshKey(externalId) }
vaultFiller.fillWithDummyState(participants = keys.map(::AnonymousParty))
services.vaultService.queryBy<ContractState>(
VaultQueryCriteria(externalIds = listOf(externalId)),
paging = PageSpecification(DEFAULT_PAGE_NUM, 10)
)
}
assertThat(page.states).hasSize(1)
assertThat(page.totalStatesAvailable).isEqualTo(1)
}
}