@@ -6,12 +6,54 @@ import (
6
6
7
7
"github.com/iotexproject/go-pkgs/hash"
8
8
"github.com/pkg/errors"
9
+ "github.com/prometheus/client_golang/prometheus"
9
10
"go.uber.org/zap"
10
11
11
12
"github.com/iotexproject/iotex-core/v2/blockchain/block"
12
13
"github.com/iotexproject/iotex-core/v2/pkg/log"
14
+ "github.com/iotexproject/iotex-core/v2/pkg/prometheustimer"
13
15
)
14
16
17
+ var (
18
+ // _proposalPoolMtc tracks proposal pool operations
19
+ _proposalPoolMtc = prometheus .NewCounterVec (prometheus.CounterOpts {
20
+ Name : "iotex_consensus_proposalpool_operations_total" ,
21
+ Help : "Total number of proposal pool operations" ,
22
+ }, []string {"operation" , "result" })
23
+
24
+ // _proposalPoolSizeGauge tracks the current size of the proposal pool
25
+ _proposalPoolSizeGauge = prometheus .NewGauge (prometheus.GaugeOpts {
26
+ Name : "iotex_consensus_proposalpool_size" ,
27
+ Help : "Current number of blocks in the proposal pool" ,
28
+ })
29
+
30
+ // _proposalPoolForksGauge tracks the current number of forks
31
+ _proposalPoolForksGauge = prometheus .NewGauge (prometheus.GaugeOpts {
32
+ Name : "iotex_consensus_proposalpool_forks" ,
33
+ Help : "Current number of forks in the proposal pool" ,
34
+ })
35
+
36
+ // _proposalPoolLatencyTimer tracks operation latency
37
+ _proposalPoolLatencyTimer * prometheustimer.TimerFactory
38
+ )
39
+
40
+ func init () {
41
+ prometheus .MustRegister (_proposalPoolMtc )
42
+ prometheus .MustRegister (_proposalPoolSizeGauge )
43
+ prometheus .MustRegister (_proposalPoolForksGauge )
44
+
45
+ var err error
46
+ _proposalPoolLatencyTimer , err = prometheustimer .New (
47
+ "iotex_consensus_proposalpool_latency_nanoseconds" ,
48
+ "Latency of proposal pool operations in nanoseconds" ,
49
+ []string {"operation" },
50
+ []string {"unknown" },
51
+ )
52
+ if err != nil {
53
+ log .L ().Error ("Failed to create proposal pool latency timer" , zap .Error (err ))
54
+ }
55
+ }
56
+
15
57
// proposalPool is a pool of draft blocks
16
58
type proposalPool struct {
17
59
// nodes is a map of draft proposal blocks
@@ -27,43 +69,65 @@ type proposalPool struct {
27
69
}
28
70
29
71
func newProposalPool () * proposalPool {
30
- return & proposalPool {
72
+ pool := & proposalPool {
31
73
nodes : make (map [hash.Hash256 ]* block.Block ),
32
74
leaves : make (map [hash.Hash256 ]time.Time ),
33
75
}
76
+ // Initialize metrics
77
+ _proposalPoolSizeGauge .Set (0 )
78
+ _proposalPoolForksGauge .Set (0 )
79
+ return pool
34
80
}
35
81
36
82
func (d * proposalPool ) Init (root hash.Hash256 ) {
37
83
d .mu .Lock ()
38
84
defer d .mu .Unlock ()
39
85
d .root = root
86
+
87
+ // Update metrics after initialization
88
+ d .updateMetrics ()
89
+
40
90
log .L ().Debug ("proposal pool initialized" , log .Hex ("root" , root [:]))
41
91
}
42
92
43
93
// AddBlock adds a block to the draft pool
44
94
func (d * proposalPool ) AddBlock (blk * block.Block ) error {
95
+ timer := _proposalPoolLatencyTimer .NewTimer ("add_block" )
96
+ defer timer .End ()
97
+
45
98
d .mu .Lock ()
46
99
defer d .mu .Unlock ()
100
+
47
101
// nothing to do if the block already exists
48
102
hash := blk .HashBlock ()
49
103
if _ , ok := d .nodes [hash ]; ok {
104
+ _proposalPoolMtc .WithLabelValues ("add_block" , "duplicate" ).Inc ()
50
105
return nil
51
106
}
52
107
// it must be a new tip of any fork, or make a new fork
53
108
prevHash := blk .PrevHash ()
54
109
if _ , ok := d .leaves [prevHash ]; ok {
55
110
delete (d .leaves , prevHash )
56
111
} else if prevHash != d .root && d .nodes [prevHash ] == nil {
112
+ _proposalPoolMtc .WithLabelValues ("add_block" , "invalid_prev" ).Inc ()
57
113
return errors .Errorf ("block %x is not a tip of any fork" , prevHash [:])
58
114
}
59
115
d .leaves [hash ] = blk .Timestamp ()
60
116
d .nodes [hash ] = blk
117
+
118
+ // Update metrics after successful addition
119
+ d .updateMetrics ()
120
+ _proposalPoolMtc .WithLabelValues ("add_block" , "success" ).Inc ()
121
+
61
122
log .L ().Debug ("added block to draft pool" , log .Hex ("hash" , hash [:]), zap .Uint64 ("height" , blk .Height ()), zap .Time ("timestamp" , blk .Timestamp ()))
62
123
return nil
63
124
}
64
125
65
126
// ReceiveBlock a block has been confirmed and remove all the blocks that is previous to it, or other forks
66
127
func (d * proposalPool ) ReceiveBlock (blk * block.Block ) error {
128
+ timer := _proposalPoolLatencyTimer .NewTimer ("receive_block" )
129
+ defer timer .End ()
130
+
67
131
d .mu .Lock ()
68
132
defer d .mu .Unlock ()
69
133
@@ -102,12 +166,33 @@ func (d *proposalPool) ReceiveBlock(blk *block.Block) error {
102
166
delete (d .leaves , f )
103
167
}
104
168
d .root = blk .HashBlock ()
169
+
170
+ // Update metrics after successful operation
171
+ d .updateMetrics ()
172
+ _proposalPoolMtc .WithLabelValues ("receive_block" , "success" ).Inc ()
173
+
105
174
return nil
106
175
}
107
176
108
177
// BlockByHash returns the block by hash
109
178
func (d * proposalPool ) BlockByHash (hash hash.Hash256 ) * block.Block {
179
+ timer := _proposalPoolLatencyTimer .NewTimer ("block_by_hash" )
180
+ defer timer .End ()
181
+
110
182
d .mu .Lock ()
111
183
defer d .mu .Unlock ()
112
- return d .nodes [hash ]
184
+
185
+ block := d .nodes [hash ]
186
+ if block != nil {
187
+ _proposalPoolMtc .WithLabelValues ("block_by_hash" , "hit" ).Inc ()
188
+ } else {
189
+ _proposalPoolMtc .WithLabelValues ("block_by_hash" , "miss" ).Inc ()
190
+ }
191
+ return block
192
+ }
193
+
194
+ // updateMetrics updates the gauge metrics with current pool state
195
+ func (d * proposalPool ) updateMetrics () {
196
+ _proposalPoolSizeGauge .Set (float64 (len (d .nodes )))
197
+ _proposalPoolForksGauge .Set (float64 (len (d .leaves )))
113
198
}
0 commit comments