-
Notifications
You must be signed in to change notification settings - Fork 13
/
get.go
110 lines (89 loc) · 2.35 KB
/
get.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// SPDX-License-Identifier: ISC
// Copyright (c) 2014-2020 Bitmark Inc.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package blockheader
import (
"encoding/binary"
"sync"
"github.com/bitmark-inc/bitmarkd/blockdigest"
"github.com/bitmark-inc/bitmarkd/blockrecord"
"github.com/bitmark-inc/bitmarkd/fault"
"github.com/bitmark-inc/bitmarkd/genesis"
"github.com/bitmark-inc/bitmarkd/mode"
"github.com/bitmark-inc/bitmarkd/storage"
)
const (
cacheSize = 10
)
type cachedBlockDigest struct {
blockNumber uint64
digest blockdigest.Digest
}
var cached [cacheSize]cachedBlockDigest
var cacheIndex int
var cacheLock sync.RWMutex
// DigestForBlock - return the digest for a specific block number
func DigestForBlock(number uint64) (blockdigest.Digest, error) {
// valid block number
if number <= genesis.BlockNumber {
if mode.IsTesting() {
return genesis.TestGenesisDigest, nil
}
return genesis.LiveGenesisDigest, nil
}
digest := digestFromCache(number)
if !digest.IsEmpty() {
return digest, nil
}
// fetch block and compute digest
n := make([]byte, 8)
binary.BigEndian.PutUint64(n, number)
digest = blockrecord.DigestFromHashPool(storage.Pool.BlockHeaderHash, n)
if !digest.IsEmpty() {
addToCache(number, digest)
return digest, nil
}
digest, err := genDigestFromPool(storage.Pool.Blocks, n)
if nil != err {
return blockdigest.Digest{}, err
}
addToCache(number, digest)
return digest, err
}
func ClearCache() {
cacheLock.Lock()
cached = *new([cacheSize]cachedBlockDigest)
cacheLock.Unlock()
}
func digestFromCache(blockNumber uint64) blockdigest.Digest {
cacheLock.RLock()
defer cacheLock.RUnlock()
for _, c := range cached {
if c.blockNumber == blockNumber {
return c.digest
}
}
return blockdigest.Digest{}
}
func addToCache(blockNumber uint64, digest blockdigest.Digest) {
cacheLock.Lock()
cached[cacheIndex] = cachedBlockDigest{
blockNumber: blockNumber,
digest: digest,
}
if cacheSize-1 == cacheIndex {
cacheIndex = 0
} else {
cacheIndex++
}
cacheLock.Unlock()
}
func genDigestFromPool(pool storage.Handle, blockNumber []byte) (blockdigest.Digest, error) {
packed := pool.Get(blockNumber)
if nil == packed {
return blockdigest.Digest{}, fault.BlockNotFound
}
_, digest, _, err := blockrecord.ExtractHeader(packed, 0, false)
return digest, err
}