Update labels (#302)
This commit is contained in:
@@ -19,9 +19,7 @@ package io.emeraldpay.dshackle.rpc
|
|||||||
import io.emeraldpay.api.proto.BlockchainOuterClass
|
import io.emeraldpay.api.proto.BlockchainOuterClass
|
||||||
import io.emeraldpay.api.proto.Common
|
import io.emeraldpay.api.proto.Common
|
||||||
import io.emeraldpay.dshackle.Global
|
import io.emeraldpay.dshackle.Global
|
||||||
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
|
||||||
import io.emeraldpay.dshackle.upstream.Capability
|
import io.emeraldpay.dshackle.upstream.Capability
|
||||||
import io.emeraldpay.dshackle.upstream.DefaultUpstream
|
|
||||||
import io.emeraldpay.dshackle.upstream.MultistreamHolder
|
import io.emeraldpay.dshackle.upstream.MultistreamHolder
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
@@ -48,28 +46,21 @@ class Describe(
|
|||||||
.addAllSupportedSubscriptions(chainUpstreams.getEgressSubscription().getAvailableTopics())
|
.addAllSupportedSubscriptions(chainUpstreams.getEgressSubscription().getAvailableTopics())
|
||||||
.setStatus(status)
|
.setStatus(status)
|
||||||
.setCurrentHeight(chainUpstreams.getHead().getCurrentHeight() ?: 0)
|
.setCurrentHeight(chainUpstreams.getHead().getCurrentHeight() ?: 0)
|
||||||
chainUpstreams.getAll().let { ups ->
|
chainUpstreams.getQuorumLabels()
|
||||||
ups.forEach { up ->
|
.forEach { node ->
|
||||||
val nodes = QuorumForLabels()
|
val nodeDetails = BlockchainOuterClass.NodeDetails.newBuilder()
|
||||||
if (up is DefaultUpstream) {
|
.setQuorum(node.quorum)
|
||||||
nodes.add(up.getQuorumByLabel())
|
.addAllLabels(
|
||||||
}
|
node.labels.entries.map { label ->
|
||||||
nodes.getAll().forEach { node ->
|
BlockchainOuterClass.Label.newBuilder()
|
||||||
val nodeDetails = BlockchainOuterClass.NodeDetails.newBuilder()
|
.setName(label.key)
|
||||||
.setQuorum(node.quorum)
|
.setValue(label.value)
|
||||||
.addAllLabels(
|
.build()
|
||||||
node.labels.entries.map { label ->
|
}
|
||||||
BlockchainOuterClass.Label.newBuilder()
|
)
|
||||||
.setName(label.key)
|
chainDescription.addNodes(nodeDetails)
|
||||||
.setValue(label.value)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
chainDescription.addNodes(nodeDetails)
|
|
||||||
}
|
|
||||||
capabilities.addAll(up.getCapabilities())
|
|
||||||
}
|
}
|
||||||
}
|
capabilities.addAll(chainUpstreams.getCapabilities())
|
||||||
chainDescription.addAllCapabilities(
|
chainDescription.addAllCapabilities(
|
||||||
capabilities.map {
|
capabilities.map {
|
||||||
when (it) {
|
when (it) {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import io.emeraldpay.dshackle.cache.Caches
|
|||||||
import io.emeraldpay.dshackle.cache.CachesEnabled
|
import io.emeraldpay.dshackle.cache.CachesEnabled
|
||||||
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
import io.emeraldpay.dshackle.config.UpstreamsConfig
|
||||||
import io.emeraldpay.dshackle.reader.JsonRpcReader
|
import io.emeraldpay.dshackle.reader.JsonRpcReader
|
||||||
|
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
||||||
import io.emeraldpay.dshackle.startup.UpstreamChangeEvent
|
import io.emeraldpay.dshackle.startup.UpstreamChangeEvent
|
||||||
import io.emeraldpay.dshackle.upstream.calls.AggregatedCallMethods
|
import io.emeraldpay.dshackle.upstream.calls.AggregatedCallMethods
|
||||||
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
||||||
@@ -63,6 +64,7 @@ abstract class Multistream(
|
|||||||
private var cacheSubscription: Disposable? = null
|
private var cacheSubscription: Disposable? = null
|
||||||
private val reconfigLock = ReentrantLock()
|
private val reconfigLock = ReentrantLock()
|
||||||
private val eventLock = ReentrantLock()
|
private val eventLock = ReentrantLock()
|
||||||
|
@Volatile
|
||||||
private var callMethods: CallMethods? = null
|
private var callMethods: CallMethods? = null
|
||||||
private var callMethodsFactory: Factory<CallMethods> = Factory {
|
private var callMethodsFactory: Factory<CallMethods> = Factory {
|
||||||
return@Factory callMethods ?: throw FunctorException("Not initialized yet")
|
return@Factory callMethods ?: throw FunctorException("Not initialized yet")
|
||||||
@@ -70,7 +72,10 @@ abstract class Multistream(
|
|||||||
private var seq = 0
|
private var seq = 0
|
||||||
protected var lagObserver: HeadLagObserver? = null
|
protected var lagObserver: HeadLagObserver? = null
|
||||||
private var subscription: Disposable? = null
|
private var subscription: Disposable? = null
|
||||||
|
@Volatile
|
||||||
private var capabilities: Set<Capability> = emptySet()
|
private var capabilities: Set<Capability> = emptySet()
|
||||||
|
@Volatile
|
||||||
|
private var quorumLabels: List<QuorumForLabels.QuorumItem>? = null
|
||||||
private val removed: MutableMap<String, Upstream> = HashMap()
|
private val removed: MutableMap<String, Upstream> = HashMap()
|
||||||
private val meters: MutableMap<String, List<Meter.Id>> = HashMap()
|
private val meters: MutableMap<String, List<Meter.Id>> = HashMap()
|
||||||
private val addedUpstreams = Sinks.many()
|
private val addedUpstreams = Sinks.many()
|
||||||
@@ -203,13 +208,14 @@ abstract class Multistream(
|
|||||||
open fun onUpstreamsUpdated() {
|
open fun onUpstreamsUpdated() {
|
||||||
reconfigLock.withLock {
|
reconfigLock.withLock {
|
||||||
val upstreams = getAll()
|
val upstreams = getAll()
|
||||||
upstreams.filter { it.isAvailable() }.map { it.getMethods() }.let {
|
val availableUpstreams = upstreams.filter { it.isAvailable() }
|
||||||
|
availableUpstreams.map { it.getMethods() }.let {
|
||||||
callMethods = AggregatedCallMethods(it)
|
callMethods = AggregatedCallMethods(it)
|
||||||
}
|
}
|
||||||
capabilities = if (upstreams.isEmpty()) {
|
capabilities = if (upstreams.isEmpty()) {
|
||||||
emptySet()
|
emptySet()
|
||||||
} else {
|
} else {
|
||||||
upstreams.filter { it.isAvailable() }.map { up ->
|
availableUpstreams.map { up ->
|
||||||
up.getCapabilities()
|
up.getCapabilities()
|
||||||
}.let {
|
}.let {
|
||||||
if (it.isNotEmpty()) {
|
if (it.isNotEmpty()) {
|
||||||
@@ -219,6 +225,7 @@ abstract class Multistream(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
quorumLabels = getQuorumLabels(availableUpstreams)
|
||||||
when {
|
when {
|
||||||
upstreams.size == 1 -> {
|
upstreams.size == 1 -> {
|
||||||
lagObserver?.stop()
|
lagObserver?.stop()
|
||||||
@@ -230,6 +237,18 @@ abstract class Multistream(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getQuorumLabels(ups: List<Upstream>): List<QuorumForLabels.QuorumItem> {
|
||||||
|
val nodes = QuorumForLabels()
|
||||||
|
ups.forEach { up ->
|
||||||
|
if (up is DefaultUpstream) {
|
||||||
|
nodes.add(up.getQuorumByLabel())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nodes.getAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getQuorumLabels(): List<QuorumForLabels.QuorumItem> = quorumLabels ?: emptyList()
|
||||||
|
|
||||||
override fun observeStatus(): Flux<UpstreamAvailability> {
|
override fun observeStatus(): Flux<UpstreamAvailability> {
|
||||||
val upstreamsFluxes = getAll().map { up ->
|
val upstreamsFluxes = getAll().map { up ->
|
||||||
Flux.concat(
|
Flux.concat(
|
||||||
@@ -457,9 +476,4 @@ abstract class Multistream(
|
|||||||
return map.values.min()
|
return map.values.min()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class UpstreamChangeState(
|
|
||||||
val upId: String,
|
|
||||||
val status: UpstreamAvailability
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,10 +54,11 @@ class GrpcUpstreamStatus(
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.nodes.set(updateNodes)
|
this.nodes.set(updateNodes)
|
||||||
|
val labelsChanged = updateLabels != this.allLabels.get().toList()
|
||||||
this.allLabels.set(Collections.unmodifiableCollection(updateLabels))
|
this.allLabels.set(Collections.unmodifiableCollection(updateLabels))
|
||||||
val changed = conf.supportedMethodsList.toSet() != this.targets?.getSupportedMethods()
|
val changed = conf.supportedMethodsList.toSet() != this.targets?.getSupportedMethods()
|
||||||
this.targets = DirectCallMethods(conf.supportedMethodsList.toSet())
|
this.targets = DirectCallMethods(conf.supportedMethodsList.toSet())
|
||||||
return changed
|
return changed || labelsChanged
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getLabels(): Collection<UpstreamsConfig.Labels> {
|
fun getLabels(): Collection<UpstreamsConfig.Labels> {
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ class GrpcUpstreamStatusSpec extends Specification {
|
|||||||
)
|
)
|
||||||
act = status.getLabels()
|
act = status.getLabels()
|
||||||
then:
|
then:
|
||||||
!result
|
result
|
||||||
act.toList() == [
|
act.toList() == [
|
||||||
UpstreamsConfig.Labels.fromMap([test1: "bar", test2: "baz"])
|
UpstreamsConfig.Labels.fromMap([test1: "bar", test2: "baz"])
|
||||||
]
|
]
|
||||||
@@ -125,7 +125,7 @@ class GrpcUpstreamStatusSpec extends Specification {
|
|||||||
)
|
)
|
||||||
act = status.getLabels()
|
act = status.getLabels()
|
||||||
then:
|
then:
|
||||||
!result
|
result
|
||||||
act.toList() == [
|
act.toList() == [
|
||||||
UpstreamsConfig.Labels.fromMap([test: "bar", fix: "value"])
|
UpstreamsConfig.Labels.fromMap([test: "bar", fix: "value"])
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -72,7 +72,6 @@ class IntegrationTest {
|
|||||||
val result = stub.describe(BlockchainOuterClass.DescribeRequest.newBuilder().build())
|
val result = stub.describe(BlockchainOuterClass.DescribeRequest.newBuilder().build())
|
||||||
Assertions.assertThat(result.chainsCount).isEqualTo(1)
|
Assertions.assertThat(result.chainsCount).isEqualTo(1)
|
||||||
Assertions.assertThat(result.chainsList[0].chain).isEqualTo(ChainRef.CHAIN_ETHEREUM__MAINNET)
|
Assertions.assertThat(result.chainsList[0].chain).isEqualTo(ChainRef.CHAIN_ETHEREUM__MAINNET)
|
||||||
Assertions.assertThat(result.chainsList[0].nodesCount).isEqualTo(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestConfiguration
|
@TestConfiguration
|
||||||
|
|||||||
Reference in New Issue
Block a user