Return state information for index request on internal http server
This commit is contained in:
parent
d018164b37
commit
d4cd2ad607
@ -234,7 +234,7 @@ func main() {
|
|||||||
|
|
||||||
var httpServer *server.HTTPServer
|
var httpServer *server.HTTPServer
|
||||||
if *httpServerBinding != "" {
|
if *httpServerBinding != "" {
|
||||||
httpServer, err = server.NewHTTPServer(*httpServerBinding, *certFiles, index, chain, txCache)
|
httpServer, err = server.NewHTTPServer(*httpServerBinding, *certFiles, index, chain, txCache, internalState)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Error("https: ", err)
|
glog.Error("https: ", err)
|
||||||
return
|
return
|
||||||
@ -424,7 +424,7 @@ func storeInternalStateLoop() {
|
|||||||
lastCompute := time.Now()
|
lastCompute := time.Now()
|
||||||
// randomize the duration between ComputeInternalStateColumnStats to avoid peaks after reboot of machine with multiple blockbooks
|
// randomize the duration between ComputeInternalStateColumnStats to avoid peaks after reboot of machine with multiple blockbooks
|
||||||
computePeriod := 9*time.Hour + time.Duration(rand.Float64()*float64((2*time.Hour).Nanoseconds()))
|
computePeriod := 9*time.Hour + time.Duration(rand.Float64()*float64((2*time.Hour).Nanoseconds()))
|
||||||
glog.Info("storeInternalStateLoop starting with internal state compute period ", computePeriod)
|
glog.Info("storeInternalStateLoop starting with db stats recompute period ", computePeriod)
|
||||||
tickAndDebounce(storeInternalStatePeriodMs*time.Millisecond, (storeInternalStatePeriodMs-1)*time.Millisecond, chanStoreInternalState, func() {
|
tickAndDebounce(storeInternalStatePeriodMs*time.Millisecond, (storeInternalStatePeriodMs-1)*time.Millisecond, chanStoreInternalState, func() {
|
||||||
if !computeRunning && lastCompute.Add(computePeriod).Before(time.Now()) {
|
if !computeRunning && lastCompute.Add(computePeriod).Before(time.Now()) {
|
||||||
computeRunning = true
|
computeRunning = true
|
||||||
|
|||||||
@ -15,11 +15,12 @@ const (
|
|||||||
|
|
||||||
// InternalStateColumn contains the data of a db column
|
// InternalStateColumn contains the data of a db column
|
||||||
type InternalStateColumn struct {
|
type InternalStateColumn struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Version uint32 `json:"version"`
|
Version uint32 `json:"version"`
|
||||||
Rows int64 `json:"rows"`
|
Rows int64 `json:"rows"`
|
||||||
KeyBytes int64 `json:"keysSum"`
|
KeyBytes int64 `json:"keyBytes"`
|
||||||
ValueBytes int64 `json:"valuesSum"`
|
ValueBytes int64 `json:"valueBytes"`
|
||||||
|
Updated time.Time `json:"updated"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// InternalState contains the data of the internal state
|
// InternalState contains the data of the internal state
|
||||||
@ -91,29 +92,36 @@ func (is *InternalState) FinishedMempoolSync(mempoolSize int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetMempoolSyncState gets the state of mempool synchronization
|
// GetMempoolSyncState gets the state of mempool synchronization
|
||||||
func (is *InternalState) GetMempoolSyncState() (bool, time.Time) {
|
func (is *InternalState) GetMempoolSyncState() (bool, time.Time, int) {
|
||||||
is.mux.Lock()
|
is.mux.Lock()
|
||||||
defer is.mux.Unlock()
|
defer is.mux.Unlock()
|
||||||
return is.IsMempoolSynchronized, is.LastMempoolSync
|
return is.IsMempoolSynchronized, is.LastMempoolSync, is.MempoolSize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddDBColumnStats adds differences in column statistics to column stats
|
||||||
func (is *InternalState) AddDBColumnStats(c int, rowsDiff int64, keyBytesDiff int64, valueBytesDiff int64) {
|
func (is *InternalState) AddDBColumnStats(c int, rowsDiff int64, keyBytesDiff int64, valueBytesDiff int64) {
|
||||||
is.mux.Lock()
|
is.mux.Lock()
|
||||||
defer is.mux.Unlock()
|
defer is.mux.Unlock()
|
||||||
is.DbColumns[c].Rows += rowsDiff
|
dc := &is.DbColumns[c]
|
||||||
is.DbColumns[c].KeyBytes += keyBytesDiff
|
dc.Rows += rowsDiff
|
||||||
is.DbColumns[c].ValueBytes += valueBytesDiff
|
dc.KeyBytes += keyBytesDiff
|
||||||
|
dc.ValueBytes += valueBytesDiff
|
||||||
|
dc.Updated = time.Now()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetDBColumnStats sets new values of column stats
|
||||||
func (is *InternalState) SetDBColumnStats(c int, rows int64, keyBytes int64, valueBytes int64) {
|
func (is *InternalState) SetDBColumnStats(c int, rows int64, keyBytes int64, valueBytes int64) {
|
||||||
is.mux.Lock()
|
is.mux.Lock()
|
||||||
defer is.mux.Unlock()
|
defer is.mux.Unlock()
|
||||||
is.DbColumns[c].Rows = rows
|
dc := &is.DbColumns[c]
|
||||||
is.DbColumns[c].KeyBytes = keyBytes
|
dc.Rows = rows
|
||||||
is.DbColumns[c].ValueBytes = valueBytes
|
dc.KeyBytes = keyBytes
|
||||||
|
dc.ValueBytes = valueBytes
|
||||||
|
dc.Updated = time.Now()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (is *InternalState) GetDBColumnStats(c int) (int64, int64, int64) {
|
// GetDBColumnStatValues gets stat values for given column
|
||||||
|
func (is *InternalState) GetDBColumnStatValues(c int) (int64, int64, int64) {
|
||||||
is.mux.Lock()
|
is.mux.Lock()
|
||||||
defer is.mux.Unlock()
|
defer is.mux.Unlock()
|
||||||
if c < len(is.DbColumns) {
|
if c < len(is.DbColumns) {
|
||||||
@ -122,6 +130,16 @@ func (is *InternalState) GetDBColumnStats(c int) (int64, int64, int64) {
|
|||||||
return 0, 0, 0
|
return 0, 0, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAllDBColumnStats returns stats for all columns
|
||||||
|
func (is *InternalState) GetAllDBColumnStats() []InternalStateColumn {
|
||||||
|
is.mux.Lock()
|
||||||
|
defer is.mux.Unlock()
|
||||||
|
rv := make([]InternalStateColumn, len(is.DbColumns))
|
||||||
|
copy(rv, is.DbColumns)
|
||||||
|
return rv
|
||||||
|
}
|
||||||
|
|
||||||
|
// DBSizeTotal sums the computed sizes of all columns
|
||||||
func (is *InternalState) DBSizeTotal() int64 {
|
func (is *InternalState) DBSizeTotal() int64 {
|
||||||
is.mux.Lock()
|
is.mux.Lock()
|
||||||
defer is.mux.Unlock()
|
defer is.mux.Unlock()
|
||||||
@ -132,6 +150,7 @@ func (is *InternalState) DBSizeTotal() int64 {
|
|||||||
return total
|
return total
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pack marshals internal state to json
|
||||||
func (is *InternalState) Pack() ([]byte, error) {
|
func (is *InternalState) Pack() ([]byte, error) {
|
||||||
is.mux.Lock()
|
is.mux.Lock()
|
||||||
defer is.mux.Unlock()
|
defer is.mux.Unlock()
|
||||||
@ -139,6 +158,7 @@ func (is *InternalState) Pack() ([]byte, error) {
|
|||||||
return json.Marshal(is)
|
return json.Marshal(is)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnpackInternalState unmarshals internal state from json
|
||||||
func UnpackInternalState(buf []byte) (*InternalState, error) {
|
func UnpackInternalState(buf []byte) (*InternalState, error) {
|
||||||
var is InternalState
|
var is InternalState
|
||||||
if err := json.Unmarshal(buf, &is); err != nil {
|
if err := json.Unmarshal(buf, &is); err != nil {
|
||||||
|
|||||||
@ -934,6 +934,7 @@ func (d *RocksDB) LoadInternalState(rpcCoin string) (*common.InternalState, erro
|
|||||||
nc[i].Rows = sc[j].Rows
|
nc[i].Rows = sc[j].Rows
|
||||||
nc[i].KeyBytes = sc[j].KeyBytes
|
nc[i].KeyBytes = sc[j].KeyBytes
|
||||||
nc[i].ValueBytes = sc[j].ValueBytes
|
nc[i].ValueBytes = sc[j].ValueBytes
|
||||||
|
nc[i].Updated = sc[j].Updated
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -950,7 +951,7 @@ func (d *RocksDB) SetInternalState(is *common.InternalState) {
|
|||||||
// StoreInternalState stores the internal state to db
|
// StoreInternalState stores the internal state to db
|
||||||
func (d *RocksDB) StoreInternalState(is *common.InternalState) error {
|
func (d *RocksDB) StoreInternalState(is *common.InternalState) error {
|
||||||
for c := 0; c < len(cfNames); c++ {
|
for c := 0; c < len(cfNames); c++ {
|
||||||
rows, keyBytes, valueBytes := d.is.GetDBColumnStats(c)
|
rows, keyBytes, valueBytes := d.is.GetDBColumnStatValues(c)
|
||||||
d.metrics.DbColumnRows.With(common.Labels{"column": cfNames[c]}).Set(float64(rows))
|
d.metrics.DbColumnRows.With(common.Labels{"column": cfNames[c]}).Set(float64(rows))
|
||||||
d.metrics.DbColumnSize.With(common.Labels{"column": cfNames[c]}).Set(float64(keyBytes + valueBytes))
|
d.metrics.DbColumnSize.With(common.Labels{"column": cfNames[c]}).Set(float64(keyBytes + valueBytes))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"blockbook/bchain"
|
"blockbook/bchain"
|
||||||
|
"blockbook/common"
|
||||||
"blockbook/db"
|
"blockbook/db"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@ -9,6 +10,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
|
|
||||||
@ -24,10 +26,26 @@ type HTTPServer struct {
|
|||||||
txCache *db.TxCache
|
txCache *db.TxCache
|
||||||
chain bchain.BlockChain
|
chain bchain.BlockChain
|
||||||
chainParser bchain.BlockChainParser
|
chainParser bchain.BlockChainParser
|
||||||
|
is *common.InternalState
|
||||||
|
}
|
||||||
|
|
||||||
|
type resAboutBlockbookInternal struct {
|
||||||
|
Coin string `json:"coin"`
|
||||||
|
Host string `json:"host"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
GitCommit string `json:"gitcommit"`
|
||||||
|
BuildTime string `json:"buildtime"`
|
||||||
|
InSync bool `json:"inSync"`
|
||||||
|
BestHeight uint32 `json:"bestHeight"`
|
||||||
|
LastBlockTime time.Time `json:"lastBlockTime"`
|
||||||
|
InSyncMempool bool `json:"inSyncMempool"`
|
||||||
|
LastMempoolTime time.Time `json:"lastMempoolTime"`
|
||||||
|
MempoolSize int `json:"mempoolSize"`
|
||||||
|
DbColumns []common.InternalStateColumn `json:"dbColumns"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewHTTPServer creates new REST interface to blockbook and returns its handle
|
// NewHTTPServer creates new REST interface to blockbook and returns its handle
|
||||||
func NewHTTPServer(httpServerBinding string, certFiles string, db *db.RocksDB, chain bchain.BlockChain, txCache *db.TxCache) (*HTTPServer, error) {
|
func NewHTTPServer(httpServerBinding string, certFiles string, db *db.RocksDB, chain bchain.BlockChain, txCache *db.TxCache, is *common.InternalState) (*HTTPServer, error) {
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
https := &http.Server{
|
https := &http.Server{
|
||||||
Addr: httpServerBinding,
|
Addr: httpServerBinding,
|
||||||
@ -40,9 +58,10 @@ func NewHTTPServer(httpServerBinding string, certFiles string, db *db.RocksDB, c
|
|||||||
txCache: txCache,
|
txCache: txCache,
|
||||||
chain: chain,
|
chain: chain,
|
||||||
chainParser: chain.GetChainParser(),
|
chainParser: chain.GetChainParser(),
|
||||||
|
is: is,
|
||||||
}
|
}
|
||||||
|
|
||||||
r.HandleFunc("/", s.info)
|
r.HandleFunc("/", s.index)
|
||||||
r.HandleFunc("/bestBlockHash", s.bestBlockHash)
|
r.HandleFunc("/bestBlockHash", s.bestBlockHash)
|
||||||
r.HandleFunc("/blockHash/{height}", s.blockHash)
|
r.HandleFunc("/blockHash/{height}", s.blockHash)
|
||||||
r.HandleFunc("/transactions/{address}/{lower}/{higher}", s.transactions)
|
r.HandleFunc("/transactions/{address}/{lower}/{higher}", s.transactions)
|
||||||
@ -89,23 +108,29 @@ func respondHashData(w http.ResponseWriter, hash string) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *HTTPServer) info(w http.ResponseWriter, r *http.Request) {
|
func (s *HTTPServer) index(w http.ResponseWriter, r *http.Request) {
|
||||||
type info struct {
|
vi := common.GetVersionInfo()
|
||||||
Version string `json:"version"`
|
ss, bh, st := s.is.GetSyncState()
|
||||||
BestBlockHeight uint32 `json:"bestBlockHeight"`
|
ms, mt, msz := s.is.GetMempoolSyncState()
|
||||||
BestBlockHash string `json:"bestBlockHash"`
|
a := resAboutBlockbookInternal{
|
||||||
|
Coin: s.is.Coin,
|
||||||
|
Host: s.is.Host,
|
||||||
|
Version: vi.Version,
|
||||||
|
GitCommit: vi.GitCommit,
|
||||||
|
BuildTime: vi.BuildTime,
|
||||||
|
InSync: ss,
|
||||||
|
BestHeight: bh,
|
||||||
|
LastBlockTime: st,
|
||||||
|
InSyncMempool: ms,
|
||||||
|
LastMempoolTime: mt,
|
||||||
|
MempoolSize: msz,
|
||||||
|
DbColumns: s.is.GetAllDBColumnStats(),
|
||||||
}
|
}
|
||||||
|
buf, err := json.MarshalIndent(a, "", " ")
|
||||||
height, hash, err := s.db.GetBestBlock()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("https info: %v", err)
|
glog.Error(err)
|
||||||
}
|
}
|
||||||
|
w.Write(buf)
|
||||||
json.NewEncoder(w).Encode(info{
|
|
||||||
Version: "0.0.1",
|
|
||||||
BestBlockHeight: height,
|
|
||||||
BestBlockHash: hash,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *HTTPServer) bestBlockHash(w http.ResponseWriter, r *http.Request) {
|
func (s *HTTPServer) bestBlockHash(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user