Filter and sort upstreams if latest (#476)
This commit is contained in:
@@ -68,16 +68,16 @@ interface RequestReaderFactory {
|
||||
class Default : RequestReaderFactory {
|
||||
override fun create(data: ReaderData): RequestReader {
|
||||
if (data.quorum is MaximumValueQuorum || data.quorum is BroadcastQuorum) {
|
||||
return BroadcastReader(data.multistream.getAll(), data.matcher, data.signer, data.quorum, data.tracer)
|
||||
return BroadcastReader(data.multistream.getAll(), data.upstreamFilter.matcher, data.signer, data.quorum, data.tracer)
|
||||
}
|
||||
val apis = data.multistream.getApiSource(data.matcher)
|
||||
val apis = data.multistream.getApiSource(data.upstreamFilter)
|
||||
return QuorumRequestReader(apis, data.quorum, data.signer, data.tracer)
|
||||
}
|
||||
}
|
||||
|
||||
data class ReaderData(
|
||||
val multistream: Multistream,
|
||||
val matcher: Selector.Matcher,
|
||||
val upstreamFilter: Selector.UpstreamFilter,
|
||||
val quorum: CallQuorum,
|
||||
val signer: ResponseSigner?,
|
||||
val tracer: Tracer,
|
||||
|
||||
@@ -331,12 +331,12 @@ open class NativeCall(
|
||||
),
|
||||
)
|
||||
}
|
||||
val requestMatcher = requestItem.selectorsList
|
||||
val upstreamFilter = requestItem.selectorsList
|
||||
.takeIf { it.isNotEmpty() }
|
||||
?.run { Mono.just(Selector.convertToMatcher(this, upstream.getHead())) }
|
||||
?.run { Selector.convertToUpstreamFilter(this) }
|
||||
// for ethereum the actual block needed for the call may be specified in the call parameters
|
||||
val callSpecificMatcher: Mono<Selector.Matcher> =
|
||||
requestMatcher ?: upstream.callSelector?.getMatcher(method, params, upstream.getHead(), passthrough) ?: Mono.empty()
|
||||
upstreamFilter?.matcher?.let { Mono.just(it) } ?: upstream.callSelector?.getMatcher(method, params, upstream.getHead(), passthrough) ?: Mono.empty()
|
||||
return callSpecificMatcher.defaultIfEmpty(Selector.empty).map { csm ->
|
||||
val matcher = Selector.Builder()
|
||||
.withMatcher(csm)
|
||||
@@ -363,7 +363,7 @@ open class NativeCall(
|
||||
requestItem.id,
|
||||
nonce,
|
||||
upstream,
|
||||
matcher.build(),
|
||||
Selector.UpstreamFilter(upstreamFilter?.sort ?: Selector.Sort.default, matcher.build()),
|
||||
callQuorum,
|
||||
parsedCallDetails(requestItem),
|
||||
requestDecorator,
|
||||
@@ -433,7 +433,7 @@ open class NativeCall(
|
||||
return Mono.error(RpcException(RpcResponseError.CODE_METHOD_NOT_EXIST, "Unsupported method"))
|
||||
}
|
||||
val reader = requestReaderFactory.create(
|
||||
ReaderData(ctx.upstream, ctx.matcher, ctx.callQuorum, signer, tracer),
|
||||
ReaderData(ctx.upstream, ctx.upstreamFilter, ctx.callQuorum, signer, tracer),
|
||||
)
|
||||
val counter = reader.attempts()
|
||||
|
||||
@@ -572,7 +572,7 @@ open class NativeCall(
|
||||
val id: Int,
|
||||
val nonce: Long?,
|
||||
val upstream: Multistream,
|
||||
val matcher: Selector.Matcher,
|
||||
val upstreamFilter: Selector.UpstreamFilter,
|
||||
val callQuorum: CallQuorum,
|
||||
val payload: T,
|
||||
val requestDecorator: RequestDecorator,
|
||||
@@ -587,13 +587,13 @@ open class NativeCall(
|
||||
id: Int,
|
||||
nonce: Long?,
|
||||
upstream: Multistream,
|
||||
matcher: Selector.Matcher,
|
||||
upstreamFilter: Selector.UpstreamFilter,
|
||||
callQuorum: CallQuorum,
|
||||
payload: T,
|
||||
requestId: String,
|
||||
requestCount: Int,
|
||||
) : this(
|
||||
id, nonce, upstream, matcher, callQuorum, payload,
|
||||
id, nonce, upstream, upstreamFilter, callQuorum, payload,
|
||||
NoneRequestDecorator(), NoneResultDecorator(), null, false, requestId, requestCount,
|
||||
)
|
||||
|
||||
@@ -613,13 +613,13 @@ open class NativeCall(
|
||||
|
||||
fun <X> withPayload(payload: X): ValidCallContext<X> {
|
||||
return ValidCallContext(
|
||||
id, nonce, upstream, matcher, callQuorum, payload,
|
||||
id, nonce, upstream, upstreamFilter, callQuorum, payload,
|
||||
requestDecorator, resultDecorator, forwardedSelector, streamRequest, requestId, requestCount,
|
||||
)
|
||||
}
|
||||
|
||||
fun getApis(): ApiSource {
|
||||
return upstream.getApiSource(matcher)
|
||||
return upstream.getApiSource(upstreamFilter)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ class FilteredApis(
|
||||
matcher: Selector.Matcher,
|
||||
private val pos: Int,
|
||||
private val retries: Int,
|
||||
sort: Selector.Sort = Selector.Sort.default,
|
||||
) : ApiSource {
|
||||
private val internalMatcher: Selector.Matcher
|
||||
|
||||
@@ -69,6 +70,13 @@ class FilteredApis(
|
||||
pos: Int,
|
||||
) : this(chain, allUpstreams, matcher, pos, DEFAULT_RETRY_LIMIT)
|
||||
|
||||
constructor(
|
||||
chain: Chain,
|
||||
allUpstreams: List<Upstream>,
|
||||
upstreamFilter: Selector.UpstreamFilter,
|
||||
pos: Int,
|
||||
) : this(chain, allUpstreams, upstreamFilter.matcher, pos, DEFAULT_RETRY_LIMIT, upstreamFilter.sort)
|
||||
|
||||
constructor(
|
||||
chain: Chain,
|
||||
allUpstreams: List<Upstream>,
|
||||
@@ -79,12 +87,12 @@ class FilteredApis(
|
||||
it.getRole() == UpstreamsConfig.UpstreamRole.PRIMARY
|
||||
}.let {
|
||||
startFrom(it, pos)
|
||||
}
|
||||
}.sortedWith(sort.comparator)
|
||||
private val secondaryUpstreams: List<Upstream> = allUpstreams.filter {
|
||||
it.getRole() == UpstreamsConfig.UpstreamRole.SECONDARY
|
||||
}.let {
|
||||
startFrom(it, pos)
|
||||
}
|
||||
}.sortedWith(sort.comparator)
|
||||
private val standardWithFallback: List<Upstream>
|
||||
|
||||
private val counter: AtomicInteger = AtomicInteger(0)
|
||||
@@ -98,7 +106,7 @@ class FilteredApis(
|
||||
it.getRole() == UpstreamsConfig.UpstreamRole.FALLBACK
|
||||
}.let {
|
||||
startFrom(it, pos)
|
||||
}
|
||||
}.sortedWith(sort.comparator)
|
||||
standardWithFallback = emptyList<Upstream>()
|
||||
.plus(primaryUpstreams)
|
||||
.plus(secondaryUpstreams)
|
||||
|
||||
@@ -206,12 +206,12 @@ abstract class Multistream(
|
||||
/**
|
||||
* Get a source for direct APIs
|
||||
*/
|
||||
open fun getApiSource(matcher: Selector.Matcher): ApiSource {
|
||||
open fun getApiSource(upstreamFilter: Selector.UpstreamFilter): ApiSource {
|
||||
val i = seq++
|
||||
if (seq >= Int.MAX_VALUE / 2) {
|
||||
seq = 0
|
||||
}
|
||||
return FilteredApis(chain, getUpstreams(), matcher, i)
|
||||
return FilteredApis(chain, getUpstreams(), upstreamFilter, i)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -41,15 +41,19 @@ class Selector {
|
||||
val anyLabel = AnyLabelMatcher()
|
||||
|
||||
@JvmStatic
|
||||
fun convertToMatcher(selectors: List<BlockchainOuterClass.Selector>, head: Head): Matcher {
|
||||
return selectors
|
||||
fun convertToUpstreamFilter(selectors: List<BlockchainOuterClass.Selector>): UpstreamFilter {
|
||||
val matcher = selectors
|
||||
.map {
|
||||
when {
|
||||
it.hasSlotHeightSelector() -> {
|
||||
SlotMatcher(it.slotHeightSelector.slotHeight)
|
||||
}
|
||||
it.hasHeightSelector() -> {
|
||||
val height = if (it.heightSelector.height == -1L) head.getCurrentHeight() else it.heightSelector.height
|
||||
val height = if (it.heightSelector.height == -1L) {
|
||||
null
|
||||
} else {
|
||||
it.heightSelector.height
|
||||
}
|
||||
if (height == null) {
|
||||
empty
|
||||
} else {
|
||||
@@ -61,6 +65,10 @@ class Selector {
|
||||
}.run {
|
||||
MultiMatcher(this)
|
||||
}
|
||||
val sort = selectors.firstOrNull { it.hasHeightSelector() && it.heightSelector.height == -1L }
|
||||
?.let { Sort(compareByDescending { it.getHead().getCurrentHeight() }) }
|
||||
?: Sort.default
|
||||
return UpstreamFilter(sort, matcher)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@@ -153,6 +161,15 @@ class Selector {
|
||||
}
|
||||
}
|
||||
|
||||
data class Sort(
|
||||
val comparator: Comparator<Upstream>,
|
||||
) {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
val default = Sort(compareBy { null })
|
||||
}
|
||||
}
|
||||
|
||||
abstract class Matcher {
|
||||
fun matches(up: Upstream): Boolean = matchesWithCause(up).matched()
|
||||
|
||||
@@ -161,6 +178,13 @@ class Selector {
|
||||
abstract fun describeInternal(): String
|
||||
}
|
||||
|
||||
data class UpstreamFilter(
|
||||
val sort: Sort,
|
||||
val matcher: Matcher,
|
||||
) {
|
||||
constructor(matcher: Matcher) : this(Sort.default, matcher)
|
||||
}
|
||||
|
||||
data class MultiMatcher(
|
||||
private val matchers: Collection<Matcher>,
|
||||
) : Matcher() {
|
||||
|
||||
@@ -92,7 +92,7 @@ open class BitcoinMultistream(
|
||||
* Finds an API that executed directly on a remote.
|
||||
*/
|
||||
open fun getDirectApi(matcher: Selector.Matcher): Mono<ChainReader> {
|
||||
val apis = getApiSource(matcher)
|
||||
val apis = getApiSource(Selector.UpstreamFilter(matcher))
|
||||
apis.request(1)
|
||||
return Mono.from(apis)
|
||||
.map(Upstream::getIngressReader)
|
||||
|
||||
@@ -18,7 +18,7 @@ class RemoteUnspentReader(
|
||||
)
|
||||
|
||||
override fun read(key: Address): Mono<List<SimpleUnspent>> {
|
||||
val apis = upstreams.getApiSource(selector)
|
||||
val apis = upstreams.getApiSource(Selector.UpstreamFilter(selector))
|
||||
apis.request(1)
|
||||
return Mono.empty()
|
||||
}
|
||||
|
||||
@@ -237,7 +237,7 @@ class EthereumDirectReader(
|
||||
it.create(
|
||||
RequestReaderFactory.ReaderData(
|
||||
up,
|
||||
requestMatcher,
|
||||
Selector.UpstreamFilter(requestMatcher),
|
||||
callMethodsFactory.create().createQuorumFor(request.method),
|
||||
null,
|
||||
tracer,
|
||||
|
||||
Reference in New Issue
Block a user