2023-10-12 12:29:21 -07:00
|
|
|
package ccq
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/hex"
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
gossipv1 "github.com/certusone/wormhole/node/pkg/proto/gossip/v1"
|
2024-03-14 07:39:07 -07:00
|
|
|
"github.com/certusone/wormhole/node/pkg/query"
|
|
|
|
"github.com/wormhole-foundation/wormhole/sdk/vaa"
|
|
|
|
"go.uber.org/zap"
|
2023-10-12 12:29:21 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
type PendingResponse struct {
|
2024-03-14 07:39:07 -07:00
|
|
|
req *gossipv1.SignedQueryRequest
|
|
|
|
userName string
|
|
|
|
queryRequest *query.QueryRequest
|
|
|
|
ch chan *SignedResponse
|
|
|
|
errCh chan *ErrorEntry
|
2023-10-12 12:29:21 -07:00
|
|
|
}
|
|
|
|
|
2024-02-02 12:10:51 -08:00
|
|
|
type ErrorEntry struct {
|
|
|
|
err error
|
|
|
|
status int
|
|
|
|
}
|
|
|
|
|
2024-03-14 07:39:07 -07:00
|
|
|
func NewPendingResponse(req *gossipv1.SignedQueryRequest, userName string, queryRequest *query.QueryRequest) *PendingResponse {
|
2023-10-12 12:29:21 -07:00
|
|
|
return &PendingResponse{
|
2024-03-14 07:39:07 -07:00
|
|
|
req: req,
|
|
|
|
userName: userName,
|
|
|
|
queryRequest: queryRequest,
|
|
|
|
ch: make(chan *SignedResponse),
|
|
|
|
errCh: make(chan *ErrorEntry),
|
2023-10-12 12:29:21 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type PendingResponses struct {
|
|
|
|
pendingResponses map[string]*PendingResponse
|
|
|
|
mu sync.RWMutex
|
2024-03-14 07:39:07 -07:00
|
|
|
logger *zap.Logger
|
2023-10-12 12:29:21 -07:00
|
|
|
}
|
|
|
|
|
2024-03-14 07:39:07 -07:00
|
|
|
func NewPendingResponses(logger *zap.Logger) *PendingResponses {
|
2023-10-12 12:29:21 -07:00
|
|
|
return &PendingResponses{
|
2023-11-06 12:16:43 -08:00
|
|
|
// Make this channel bigger than the number of responses we ever expect to get for a query.
|
|
|
|
pendingResponses: make(map[string]*PendingResponse, 100),
|
2024-03-14 07:39:07 -07:00
|
|
|
logger: logger,
|
2023-10-12 12:29:21 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *PendingResponses) Add(r *PendingResponse) bool {
|
|
|
|
signature := hex.EncodeToString(r.req.Signature)
|
|
|
|
p.mu.Lock()
|
|
|
|
defer p.mu.Unlock()
|
|
|
|
if _, ok := p.pendingResponses[signature]; ok {
|
|
|
|
// the request w/ this signature is already being handled
|
|
|
|
// don't overwrite
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
p.pendingResponses[signature] = r
|
2024-03-26 11:02:41 -07:00
|
|
|
p.updateMetricsAlreadyLocked(nil)
|
2023-10-12 12:29:21 -07:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *PendingResponses) Get(signature string) *PendingResponse {
|
|
|
|
p.mu.RLock()
|
|
|
|
defer p.mu.RUnlock()
|
|
|
|
if r, ok := p.pendingResponses[signature]; ok {
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *PendingResponses) Remove(r *PendingResponse) {
|
|
|
|
signature := hex.EncodeToString(r.req.Signature)
|
|
|
|
p.mu.Lock()
|
|
|
|
defer p.mu.Unlock()
|
|
|
|
delete(p.pendingResponses, signature)
|
2024-03-26 11:02:41 -07:00
|
|
|
p.updateMetricsAlreadyLocked(r)
|
2023-10-12 12:29:21 -07:00
|
|
|
}
|
2023-12-11 14:00:46 -08:00
|
|
|
|
|
|
|
func (p *PendingResponses) NumPending() int {
|
|
|
|
p.mu.Lock()
|
|
|
|
defer p.mu.Unlock()
|
|
|
|
return len(p.pendingResponses)
|
|
|
|
}
|
2024-03-14 07:39:07 -07:00
|
|
|
|
2024-03-26 11:02:41 -07:00
|
|
|
func (p *PendingResponses) updateMetricsAlreadyLocked(reqRemoved *PendingResponse) {
|
2024-03-14 07:39:07 -07:00
|
|
|
counts := make(map[vaa.ChainID]float64)
|
2024-03-26 11:02:41 -07:00
|
|
|
if reqRemoved != nil {
|
|
|
|
// We may have removed the last request for a chain. Make sure we always update that chain.
|
|
|
|
for _, pcr := range reqRemoved.queryRequest.PerChainQueries {
|
|
|
|
counts[pcr.ChainId] = 0
|
|
|
|
}
|
|
|
|
}
|
2024-03-14 07:39:07 -07:00
|
|
|
for _, pr := range p.pendingResponses {
|
|
|
|
for _, pcr := range pr.queryRequest.PerChainQueries {
|
|
|
|
counts[pcr.ChainId] = counts[pcr.ChainId] + 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for chainId, count := range counts {
|
|
|
|
currentNumConcurrentQueriesByChain.WithLabelValues(chainId.String()).Set(count)
|
|
|
|
currVal, err := getGaugeValue(maxConcurrentQueriesByChain.WithLabelValues(chainId.String()))
|
|
|
|
if err != nil {
|
|
|
|
p.logger.Error("failed to read current value of max concurrent queries metric", zap.String("chainId", chainId.String()), zap.Error(err))
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if count > currVal {
|
|
|
|
p.logger.Info("updating max concurrent queries metric", zap.String("chain", chainId.String()), zap.Float64("oldMax", currVal), zap.Float64("newMax", count))
|
|
|
|
maxConcurrentQueriesByChain.WithLabelValues(chainId.String()).Set(count)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|