Improve xpub cache
This commit is contained in:
parent
1df8f8eb69
commit
1d55a66fab
@ -29,10 +29,11 @@ type Worker struct {
|
|||||||
chainType bchain.ChainType
|
chainType bchain.ChainType
|
||||||
mempool bchain.Mempool
|
mempool bchain.Mempool
|
||||||
is *common.InternalState
|
is *common.InternalState
|
||||||
|
metrics *common.Metrics
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWorker creates new api worker
|
// NewWorker creates new api worker
|
||||||
func NewWorker(db *db.RocksDB, chain bchain.BlockChain, mempool bchain.Mempool, txCache *db.TxCache, is *common.InternalState) (*Worker, error) {
|
func NewWorker(db *db.RocksDB, chain bchain.BlockChain, mempool bchain.Mempool, txCache *db.TxCache, metrics *common.Metrics, is *common.InternalState) (*Worker, error) {
|
||||||
w := &Worker{
|
w := &Worker{
|
||||||
db: db,
|
db: db,
|
||||||
txCache: txCache,
|
txCache: txCache,
|
||||||
@ -41,6 +42,10 @@ func NewWorker(db *db.RocksDB, chain bchain.BlockChain, mempool bchain.Mempool,
|
|||||||
chainType: chain.GetChainParser().GetChainType(),
|
chainType: chain.GetChainParser().GetChainType(),
|
||||||
mempool: mempool,
|
mempool: mempool,
|
||||||
is: is,
|
is: is,
|
||||||
|
metrics: metrics,
|
||||||
|
}
|
||||||
|
if w.chainType == bchain.ChainBitcoinType {
|
||||||
|
w.initXpubCache()
|
||||||
}
|
}
|
||||||
return w, nil
|
return w, nil
|
||||||
}
|
}
|
||||||
|
|||||||
57
api/xpub.go
57
api/xpub.go
@ -19,10 +19,9 @@ const maxAddressesGap = 10000
|
|||||||
const txInput = 1
|
const txInput = 1
|
||||||
const txOutput = 2
|
const txOutput = 2
|
||||||
|
|
||||||
const xpubCacheSize = 4096
|
|
||||||
const xpubCacheExpirationSeconds = 3600
|
const xpubCacheExpirationSeconds = 3600
|
||||||
|
|
||||||
var cachedXpubs = make(map[string]xpubData)
|
var cachedXpubs map[string]xpubData
|
||||||
var cachedXpubsMux sync.Mutex
|
var cachedXpubsMux sync.Mutex
|
||||||
|
|
||||||
type xpubTxid struct {
|
type xpubTxid struct {
|
||||||
@ -67,6 +66,35 @@ type xpubData struct {
|
|||||||
changeAddresses []xpubAddress
|
changeAddresses []xpubAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *Worker) initXpubCache() {
|
||||||
|
cachedXpubsMux.Lock()
|
||||||
|
if cachedXpubs == nil {
|
||||||
|
cachedXpubs = make(map[string]xpubData)
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
time.Sleep(20 * time.Second)
|
||||||
|
w.evictXpubCacheItems()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
cachedXpubsMux.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Worker) evictXpubCacheItems() {
|
||||||
|
cachedXpubsMux.Lock()
|
||||||
|
defer cachedXpubsMux.Unlock()
|
||||||
|
threshold := time.Now().Unix() - xpubCacheExpirationSeconds
|
||||||
|
count := 0
|
||||||
|
for k, v := range cachedXpubs {
|
||||||
|
if v.accessed < threshold {
|
||||||
|
delete(cachedXpubs, k)
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.metrics.XPubCacheSize.Set(float64(len(cachedXpubs)))
|
||||||
|
glog.Info("Evicted ", count, " items from xpub cache, cache size ", len(cachedXpubs))
|
||||||
|
}
|
||||||
|
|
||||||
func (w *Worker) xpubGetAddressTxids(addrDesc bchain.AddressDescriptor, mempool bool, fromHeight, toHeight uint32, maxResults int) ([]xpubTxid, bool, error) {
|
func (w *Worker) xpubGetAddressTxids(addrDesc bchain.AddressDescriptor, mempool bool, fromHeight, toHeight uint32, maxResults int) ([]xpubTxid, bool, error) {
|
||||||
var err error
|
var err error
|
||||||
complete := true
|
complete := true
|
||||||
@ -247,28 +275,6 @@ func (w *Worker) tokenFromXpubAddress(data *xpubData, ad *xpubAddress, changeInd
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func evictXpubCacheItems() {
|
|
||||||
var oldestKey string
|
|
||||||
oldest := maxInt64
|
|
||||||
now := time.Now().Unix()
|
|
||||||
count := 0
|
|
||||||
for k, v := range cachedXpubs {
|
|
||||||
if v.accessed+xpubCacheExpirationSeconds < now {
|
|
||||||
delete(cachedXpubs, k)
|
|
||||||
count++
|
|
||||||
}
|
|
||||||
if v.accessed < oldest {
|
|
||||||
oldestKey = k
|
|
||||||
oldest = v.accessed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if oldestKey != "" && oldest+xpubCacheExpirationSeconds >= now {
|
|
||||||
delete(cachedXpubs, oldestKey)
|
|
||||||
count++
|
|
||||||
}
|
|
||||||
glog.V(1).Info("Evicted ", count, " items from xpub cache, oldest item accessed at ", time.Unix(oldest, 0), ", cache size ", len(cachedXpubs))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *Worker) getXpubData(xpub string, page int, txsOnPage int, option AccountDetails, filter *AddressFilter, gap int) (*xpubData, uint32, bool, error) {
|
func (w *Worker) getXpubData(xpub string, page int, txsOnPage int, option AccountDetails, filter *AddressFilter, gap int) (*xpubData, uint32, bool, error) {
|
||||||
if w.chainType != bchain.ChainBitcoinType {
|
if w.chainType != bchain.ChainBitcoinType {
|
||||||
return nil, 0, false, ErrUnsupportedXpub
|
return nil, 0, false, ErrUnsupportedXpub
|
||||||
@ -345,9 +351,6 @@ func (w *Worker) getXpubData(xpub string, page int, txsOnPage int, option Accoun
|
|||||||
}
|
}
|
||||||
data.accessed = time.Now().Unix()
|
data.accessed = time.Now().Unix()
|
||||||
cachedXpubsMux.Lock()
|
cachedXpubsMux.Lock()
|
||||||
if len(cachedXpubs) >= xpubCacheSize {
|
|
||||||
evictXpubCacheItems()
|
|
||||||
}
|
|
||||||
cachedXpubs[xpub] = data
|
cachedXpubs[xpub] = data
|
||||||
cachedXpubsMux.Unlock()
|
cachedXpubsMux.Unlock()
|
||||||
return &data, bestheight, inCache, nil
|
return &data, bestheight, inCache, nil
|
||||||
|
|||||||
@ -387,7 +387,7 @@ func getBlockChainWithRetry(coin string, configfile string, pushHandler func(bch
|
|||||||
}
|
}
|
||||||
|
|
||||||
func startInternalServer() (*server.InternalServer, error) {
|
func startInternalServer() (*server.InternalServer, error) {
|
||||||
internalServer, err := server.NewInternalServer(*internalBinding, *certFiles, index, chain, mempool, txCache, internalState)
|
internalServer, err := server.NewInternalServer(*internalBinding, *certFiles, index, chain, mempool, txCache, metrics, internalState)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -453,7 +453,7 @@ func performRollback() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func blockbookAppInfoMetric(db *db.RocksDB, chain bchain.BlockChain, txCache *db.TxCache, is *common.InternalState, metrics *common.Metrics) error {
|
func blockbookAppInfoMetric(db *db.RocksDB, chain bchain.BlockChain, txCache *db.TxCache, is *common.InternalState, metrics *common.Metrics) error {
|
||||||
api, err := api.NewWorker(db, chain, mempool, txCache, is)
|
api, err := api.NewWorker(db, chain, mempool, txCache, metrics, is)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -708,7 +708,7 @@ func normalizeName(s string) string {
|
|||||||
func computeFeeStats(stopCompute chan os.Signal, blockFrom, blockTo int, db *db.RocksDB, chain bchain.BlockChain, txCache *db.TxCache, is *common.InternalState, metrics *common.Metrics) error {
|
func computeFeeStats(stopCompute chan os.Signal, blockFrom, blockTo int, db *db.RocksDB, chain bchain.BlockChain, txCache *db.TxCache, is *common.InternalState, metrics *common.Metrics) error {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
glog.Info("computeFeeStats start")
|
glog.Info("computeFeeStats start")
|
||||||
api, err := api.NewWorker(db, chain, mempool, txCache, is)
|
api, err := api.NewWorker(db, chain, mempool, txCache, metrics, is)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,6 +32,7 @@ type Metrics struct {
|
|||||||
ExplorerPendingRequests *prometheus.GaugeVec
|
ExplorerPendingRequests *prometheus.GaugeVec
|
||||||
WebsocketPendingRequests *prometheus.GaugeVec
|
WebsocketPendingRequests *prometheus.GaugeVec
|
||||||
SocketIOPendingRequests *prometheus.GaugeVec
|
SocketIOPendingRequests *prometheus.GaugeVec
|
||||||
|
XPubCacheSize prometheus.Gauge
|
||||||
}
|
}
|
||||||
|
|
||||||
// Labels represents a collection of label name -> value mappings.
|
// Labels represents a collection of label name -> value mappings.
|
||||||
@ -230,6 +231,13 @@ func GetMetrics(coin string) (*Metrics, error) {
|
|||||||
},
|
},
|
||||||
[]string{"method"},
|
[]string{"method"},
|
||||||
)
|
)
|
||||||
|
metrics.XPubCacheSize = prometheus.NewGauge(
|
||||||
|
prometheus.GaugeOpts{
|
||||||
|
Name: "blockbook_xpub_cache_size",
|
||||||
|
Help: "Number of cached xpubs",
|
||||||
|
ConstLabels: Labels{"coin": coin},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
v := reflect.ValueOf(metrics)
|
v := reflect.ValueOf(metrics)
|
||||||
for i := 0; i < v.NumField(); i++ {
|
for i := 0; i < v.NumField(); i++ {
|
||||||
|
|||||||
@ -28,8 +28,8 @@ type InternalServer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewInternalServer creates new internal http interface to blockbook and returns its handle
|
// NewInternalServer creates new internal http interface to blockbook and returns its handle
|
||||||
func NewInternalServer(binding, certFiles string, db *db.RocksDB, chain bchain.BlockChain, mempool bchain.Mempool, txCache *db.TxCache, is *common.InternalState) (*InternalServer, error) {
|
func NewInternalServer(binding, certFiles string, db *db.RocksDB, chain bchain.BlockChain, mempool bchain.Mempool, txCache *db.TxCache, metrics *common.Metrics, is *common.InternalState) (*InternalServer, error) {
|
||||||
api, err := api.NewWorker(db, chain, mempool, txCache, is)
|
api, err := api.NewWorker(db, chain, mempool, txCache, metrics, is)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,7 +60,7 @@ type PublicServer struct {
|
|||||||
// only basic functionality is mapped, to map all functions, call
|
// only basic functionality is mapped, to map all functions, call
|
||||||
func NewPublicServer(binding string, certFiles string, db *db.RocksDB, chain bchain.BlockChain, mempool bchain.Mempool, txCache *db.TxCache, explorerURL string, metrics *common.Metrics, is *common.InternalState, debugMode bool, enableSubNewTx bool) (*PublicServer, error) {
|
func NewPublicServer(binding string, certFiles string, db *db.RocksDB, chain bchain.BlockChain, mempool bchain.Mempool, txCache *db.TxCache, explorerURL string, metrics *common.Metrics, is *common.InternalState, debugMode bool, enableSubNewTx bool) (*PublicServer, error) {
|
||||||
|
|
||||||
api, err := api.NewWorker(db, chain, mempool, txCache, is)
|
api, err := api.NewWorker(db, chain, mempool, txCache, metrics, is)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,7 +34,7 @@ type SocketIoServer struct {
|
|||||||
|
|
||||||
// NewSocketIoServer creates new SocketIo interface to blockbook and returns its handle
|
// NewSocketIoServer creates new SocketIo interface to blockbook and returns its handle
|
||||||
func NewSocketIoServer(db *db.RocksDB, chain bchain.BlockChain, mempool bchain.Mempool, txCache *db.TxCache, metrics *common.Metrics, is *common.InternalState) (*SocketIoServer, error) {
|
func NewSocketIoServer(db *db.RocksDB, chain bchain.BlockChain, mempool bchain.Mempool, txCache *db.TxCache, metrics *common.Metrics, is *common.InternalState) (*SocketIoServer, error) {
|
||||||
api, err := api.NewWorker(db, chain, mempool, txCache, is)
|
api, err := api.NewWorker(db, chain, mempool, txCache, metrics, is)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -81,7 +81,7 @@ type WebsocketServer struct {
|
|||||||
|
|
||||||
// NewWebsocketServer creates new websocket interface to blockbook and returns its handle
|
// NewWebsocketServer creates new websocket interface to blockbook and returns its handle
|
||||||
func NewWebsocketServer(db *db.RocksDB, chain bchain.BlockChain, mempool bchain.Mempool, txCache *db.TxCache, metrics *common.Metrics, is *common.InternalState, enableSubNewTx bool) (*WebsocketServer, error) {
|
func NewWebsocketServer(db *db.RocksDB, chain bchain.BlockChain, mempool bchain.Mempool, txCache *db.TxCache, metrics *common.Metrics, is *common.InternalState, enableSubNewTx bool) (*WebsocketServer, error) {
|
||||||
api, err := api.NewWorker(db, chain, mempool, txCache, is)
|
api, err := api.NewWorker(db, chain, mempool, txCache, metrics, is)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user