github.com/bchainhub/blockbook@v0.3.2/common/internalstate.go (about)

     1  package common
     2  
     3  import (
     4  	"encoding/json"
     5  	"sort"
     6  	"sync"
     7  	"time"
     8  )
     9  
    10  const (
    11  	// DbStateClosed means db was closed gracefully
    12  	DbStateClosed = uint32(iota)
    13  	// DbStateOpen means db is open or application died without closing the db
    14  	DbStateOpen
    15  	// DbStateInconsistent means db is in inconsistent state and cannot be used
    16  	DbStateInconsistent
    17  )
    18  
    19  // InternalStateColumn contains the data of a db column
    20  type InternalStateColumn struct {
    21  	Name       string    `json:"name"`
    22  	Version    uint32    `json:"version"`
    23  	Rows       int64     `json:"rows"`
    24  	KeyBytes   int64     `json:"keyBytes"`
    25  	ValueBytes int64     `json:"valueBytes"`
    26  	Updated    time.Time `json:"updated"`
    27  }
    28  
    29  // InternalState contains the data of the internal state
    30  type InternalState struct {
    31  	mux sync.Mutex
    32  
    33  	Coin         string `json:"coin"`
    34  	CoinShortcut string `json:"coinShortcut"`
    35  	CoinLabel    string `json:"coinLabel"`
    36  	Host         string `json:"host"`
    37  
    38  	DbState uint32 `json:"dbState"`
    39  
    40  	LastStore time.Time `json:"lastStore"`
    41  
    42  	// true if application is with flag --sync
    43  	SyncMode bool `json:"syncMode"`
    44  
    45  	InitialSync    bool      `json:"initialSync"`
    46  	IsSynchronized bool      `json:"isSynchronized"`
    47  	BestHeight     uint32    `json:"bestHeight"`
    48  	LastSync       time.Time `json:"lastSync"`
    49  	BlockTimes     []uint32  `json:"-"`
    50  
    51  	IsMempoolSynchronized bool      `json:"isMempoolSynchronized"`
    52  	MempoolSize           int       `json:"mempoolSize"`
    53  	LastMempoolSync       time.Time `json:"lastMempoolSync"`
    54  
    55  	DbColumns []InternalStateColumn `json:"dbColumns"`
    56  
    57  	UtxoChecked bool `json:"utxoChecked"`
    58  }
    59  
    60  // StartedSync signals start of synchronization
    61  func (is *InternalState) StartedSync() {
    62  	is.mux.Lock()
    63  	defer is.mux.Unlock()
    64  	is.IsSynchronized = false
    65  }
    66  
    67  // FinishedSync marks end of synchronization, bestHeight specifies new best block height
    68  func (is *InternalState) FinishedSync(bestHeight uint32) {
    69  	is.mux.Lock()
    70  	defer is.mux.Unlock()
    71  	is.IsSynchronized = true
    72  	is.BestHeight = bestHeight
    73  	is.LastSync = time.Now()
    74  }
    75  
    76  // UpdateBestHeight sets new best height, without changing IsSynchronized flag
    77  func (is *InternalState) UpdateBestHeight(bestHeight uint32) {
    78  	is.mux.Lock()
    79  	defer is.mux.Unlock()
    80  	is.BestHeight = bestHeight
    81  	is.LastSync = time.Now()
    82  }
    83  
    84  // FinishedSyncNoChange marks end of synchronization in case no index update was necessary, it does not update lastSync time
    85  func (is *InternalState) FinishedSyncNoChange() {
    86  	is.mux.Lock()
    87  	defer is.mux.Unlock()
    88  	is.IsSynchronized = true
    89  }
    90  
    91  // GetSyncState gets the state of synchronization
    92  func (is *InternalState) GetSyncState() (bool, uint32, time.Time) {
    93  	is.mux.Lock()
    94  	defer is.mux.Unlock()
    95  	return is.IsSynchronized, is.BestHeight, is.LastSync
    96  }
    97  
    98  // StartedMempoolSync signals start of mempool synchronization
    99  func (is *InternalState) StartedMempoolSync() {
   100  	is.mux.Lock()
   101  	defer is.mux.Unlock()
   102  	is.IsMempoolSynchronized = false
   103  }
   104  
   105  // FinishedMempoolSync marks end of mempool synchronization
   106  func (is *InternalState) FinishedMempoolSync(mempoolSize int) {
   107  	is.mux.Lock()
   108  	defer is.mux.Unlock()
   109  	is.IsMempoolSynchronized = true
   110  	is.MempoolSize = mempoolSize
   111  	is.LastMempoolSync = time.Now()
   112  }
   113  
   114  // GetMempoolSyncState gets the state of mempool synchronization
   115  func (is *InternalState) GetMempoolSyncState() (bool, time.Time, int) {
   116  	is.mux.Lock()
   117  	defer is.mux.Unlock()
   118  	return is.IsMempoolSynchronized, is.LastMempoolSync, is.MempoolSize
   119  }
   120  
   121  // AddDBColumnStats adds differences in column statistics to column stats
   122  func (is *InternalState) AddDBColumnStats(c int, rowsDiff int64, keyBytesDiff int64, valueBytesDiff int64) {
   123  	is.mux.Lock()
   124  	defer is.mux.Unlock()
   125  	dc := &is.DbColumns[c]
   126  	dc.Rows += rowsDiff
   127  	dc.KeyBytes += keyBytesDiff
   128  	dc.ValueBytes += valueBytesDiff
   129  	dc.Updated = time.Now()
   130  }
   131  
   132  // SetDBColumnStats sets new values of column stats
   133  func (is *InternalState) SetDBColumnStats(c int, rows int64, keyBytes int64, valueBytes int64) {
   134  	is.mux.Lock()
   135  	defer is.mux.Unlock()
   136  	dc := &is.DbColumns[c]
   137  	dc.Rows = rows
   138  	dc.KeyBytes = keyBytes
   139  	dc.ValueBytes = valueBytes
   140  	dc.Updated = time.Now()
   141  }
   142  
   143  // GetDBColumnStatValues gets stat values for given column
   144  func (is *InternalState) GetDBColumnStatValues(c int) (int64, int64, int64) {
   145  	is.mux.Lock()
   146  	defer is.mux.Unlock()
   147  	if c < len(is.DbColumns) {
   148  		return is.DbColumns[c].Rows, is.DbColumns[c].KeyBytes, is.DbColumns[c].ValueBytes
   149  	}
   150  	return 0, 0, 0
   151  }
   152  
   153  // GetAllDBColumnStats returns stats for all columns
   154  func (is *InternalState) GetAllDBColumnStats() []InternalStateColumn {
   155  	is.mux.Lock()
   156  	defer is.mux.Unlock()
   157  	return append(is.DbColumns[:0:0], is.DbColumns...)
   158  }
   159  
   160  // DBSizeTotal sums the computed sizes of all columns
   161  func (is *InternalState) DBSizeTotal() int64 {
   162  	is.mux.Lock()
   163  	defer is.mux.Unlock()
   164  	total := int64(0)
   165  	for _, c := range is.DbColumns {
   166  		total += c.KeyBytes + c.ValueBytes
   167  	}
   168  	return total
   169  }
   170  
   171  // GetBlockTime returns block time if block found or 0
   172  func (is *InternalState) GetBlockTime(height uint32) uint32 {
   173  	is.mux.Lock()
   174  	defer is.mux.Unlock()
   175  	if int(height) < len(is.BlockTimes) {
   176  		return is.BlockTimes[height]
   177  	}
   178  	return 0
   179  }
   180  
   181  // AppendBlockTime appends block time to BlockTimes
   182  func (is *InternalState) AppendBlockTime(time uint32) {
   183  	is.mux.Lock()
   184  	defer is.mux.Unlock()
   185  	is.BlockTimes = append(is.BlockTimes, time)
   186  }
   187  
   188  // RemoveLastBlockTimes removes last times from BlockTimes
   189  func (is *InternalState) RemoveLastBlockTimes(count int) {
   190  	is.mux.Lock()
   191  	defer is.mux.Unlock()
   192  	if len(is.BlockTimes) < count {
   193  		count = len(is.BlockTimes)
   194  	}
   195  	is.BlockTimes = is.BlockTimes[:len(is.BlockTimes)-count]
   196  }
   197  
   198  // GetBlockHeightOfTime returns block height of the first block with time greater or equal to the given time or MaxUint32 if no such block
   199  func (is *InternalState) GetBlockHeightOfTime(time uint32) uint32 {
   200  	is.mux.Lock()
   201  	defer is.mux.Unlock()
   202  	height := sort.Search(len(is.BlockTimes), func(i int) bool { return time <= is.BlockTimes[i] })
   203  	if height == len(is.BlockTimes) {
   204  		return ^uint32(0)
   205  	}
   206  	// as the block times can sometimes be out of order try 20 blocks lower to locate a block with the time greater or equal to the given time
   207  	max, height := height, height-20
   208  	if height < 0 {
   209  		height = 0
   210  	}
   211  	for ; height <= max; height++ {
   212  		if time <= is.BlockTimes[height] {
   213  			break
   214  		}
   215  	}
   216  	return uint32(height)
   217  }
   218  
   219  // Pack marshals internal state to json
   220  func (is *InternalState) Pack() ([]byte, error) {
   221  	is.mux.Lock()
   222  	defer is.mux.Unlock()
   223  	is.LastStore = time.Now()
   224  	return json.Marshal(is)
   225  }
   226  
   227  // UnpackInternalState unmarshals internal state from json
   228  func UnpackInternalState(buf []byte) (*InternalState, error) {
   229  	var is InternalState
   230  	if err := json.Unmarshal(buf, &is); err != nil {
   231  		return nil, err
   232  	}
   233  	return &is, nil
   234  }