Skip to content

Commit 2293972

Browse files
dustinxieYutong Pei
authored and
Yutong Pei
committed
use separate channel for blockSyncMsg (iotexproject#2411)
* use separate channel for blockSyncMsg
1 parent b523a73 commit 2293972

File tree

8 files changed

+211
-71
lines changed

8 files changed

+211
-71
lines changed

action/protocol/poll/blockmeta.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func (bm *BlockMeta) Proto() (*blockmetapb.BlockMeta, error) {
5858
func (bm *BlockMeta) Deserialize(buf []byte) error {
5959
epochMetapb := &blockmetapb.BlockMeta{}
6060
if err := proto.Unmarshal(buf, epochMetapb); err != nil {
61-
return errors.Wrap(err, "failed to unmarshal blacklist")
61+
return errors.Wrap(err, "failed to unmarshal blocklist")
6262
}
6363
return bm.LoadProto(epochMetapb)
6464
}

blocksync/blocksync.go

+19-16
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package blocksync
88

99
import (
1010
"context"
11+
"time"
1112

1213
"github.com/golang/protobuf/proto"
1314
peerstore "github.com/libp2p/go-libp2p-peerstore"
@@ -71,13 +72,14 @@ type BlockSync interface {
7172

7273
// blockSyncer implements BlockSync interface
7374
type blockSyncer struct {
74-
commitHeight uint64 // last commit block height
75-
buf *blockBuffer
76-
worker *syncWorker
77-
bc blockchain.Blockchain
78-
dao BlockDAO
79-
unicastHandler UnicastOutbound
80-
neighborsHandler Neighbors
75+
commitHeight uint64 // last commit block height
76+
processSyncRequestTTL time.Duration
77+
buf *blockBuffer
78+
worker *syncWorker
79+
bc blockchain.Blockchain
80+
dao BlockDAO
81+
unicastHandler UnicastOutbound
82+
neighborsHandler Neighbors
8183
}
8284

8385
// NewBlockSyncer returns a new block syncer instance
@@ -102,12 +104,13 @@ func NewBlockSyncer(
102104
}
103105
}
104106
bs := &blockSyncer{
105-
bc: chain,
106-
dao: dao,
107-
buf: buf,
108-
unicastHandler: bsCfg.unicastHandler,
109-
neighborsHandler: bsCfg.neighborsHandler,
110-
worker: newSyncWorker(chain.ChainID(), cfg, bsCfg.unicastHandler, bsCfg.neighborsHandler, buf),
107+
bc: chain,
108+
dao: dao,
109+
buf: buf,
110+
unicastHandler: bsCfg.unicastHandler,
111+
neighborsHandler: bsCfg.neighborsHandler,
112+
worker: newSyncWorker(chain.ChainID(), cfg, bsCfg.unicastHandler, bsCfg.neighborsHandler, buf),
113+
processSyncRequestTTL: cfg.BlockSync.ProcessSyncRequestTTL,
111114
}
112115
return bs, nil
113116
}
@@ -184,9 +187,9 @@ func (bs *blockSyncer) ProcessSyncRequest(ctx context.Context, peer peerstore.Pe
184187
return err
185188
}
186189
// TODO: send back multiple blocks in one shot
187-
if err := bs.unicastHandler(context.Background(), peer,
188-
blk.ConvertToBlockPb(),
189-
); err != nil {
190+
syncCtx, cancel := context.WithTimeout(ctx, bs.processSyncRequestTTL)
191+
defer cancel()
192+
if err := bs.unicastHandler(syncCtx, peer, blk.ConvertToBlockPb()); err != nil {
190193
log.L().Debug("Failed to response to ProcessSyncRequest.", zap.Error(err))
191194
}
192195
}

config/config.go

+10-8
Original file line numberDiff line numberDiff line change
@@ -155,11 +155,12 @@ var (
155155
},
156156
},
157157
BlockSync: BlockSync{
158-
Interval: 10 * time.Second,
159-
BufferSize: 200,
160-
IntervalSize: 20,
161-
MaxRepeat: 3,
162-
RepeatDecayStep: 1,
158+
Interval: 10 * time.Second,
159+
ProcessSyncRequestTTL: 10 * time.Second,
160+
BufferSize: 200,
161+
IntervalSize: 20,
162+
MaxRepeat: 3,
163+
RepeatDecayStep: 1,
163164
},
164165
Dispatcher: Dispatcher{
165166
EventChanSize: 10000,
@@ -274,9 +275,10 @@ type (
274275

275276
// BlockSync is the config struct for the BlockSync
276277
BlockSync struct {
277-
Interval time.Duration `yaml:"interval"` // update duration
278-
BufferSize uint64 `yaml:"bufferSize"`
279-
IntervalSize uint64 `yaml:"intervalSize"`
278+
Interval time.Duration `yaml:"interval"` // update duration
279+
ProcessSyncRequestTTL time.Duration `yaml:"processSyncRequestTTL"`
280+
BufferSize uint64 `yaml:"bufferSize"`
281+
IntervalSize uint64 `yaml:"intervalSize"`
280282
// MaxRepeat is the maximal number of repeat of a block sync request
281283
MaxRepeat int `yaml:"maxRepeat"`
282284
// RepeatDecayStep is the step for repeat number decreasing by 1

dispatcher/dispatcher.go

+56-28
Original file line numberDiff line numberDiff line change
@@ -100,19 +100,20 @@ type IotxDispatcher struct {
100100
started int32
101101
shutdown int32
102102
eventChan chan interface{}
103+
syncChan chan *blockSyncMsg
103104
eventAudit map[iotexrpc.MessageType]int
104105
eventAuditLock sync.RWMutex
105106
wg sync.WaitGroup
106107
quit chan struct{}
107-
108-
subscribers map[uint32]Subscriber
109-
subscribersMU sync.RWMutex
108+
subscribers map[uint32]Subscriber
109+
subscribersMU sync.RWMutex
110110
}
111111

112112
// NewDispatcher creates a new Dispatcher
113113
func NewDispatcher(cfg config.Config) (Dispatcher, error) {
114114
d := &IotxDispatcher{
115115
eventChan: make(chan interface{}, cfg.Dispatcher.EventChanSize),
116+
syncChan: make(chan *blockSyncMsg, cfg.Dispatcher.EventChanSize),
116117
eventAudit: make(map[iotexrpc.MessageType]int),
117118
quit: make(chan struct{}),
118119
subscribers: make(map[uint32]Subscriber),
@@ -136,8 +137,10 @@ func (d *IotxDispatcher) Start(ctx context.Context) error {
136137
return errors.New("Dispatcher already started")
137138
}
138139
log.L().Info("Starting dispatcher.")
139-
d.wg.Add(1)
140+
d.wg.Add(2)
140141
go d.newsHandler()
142+
go d.syncHandler()
143+
141144
return nil
142145
}
143146

@@ -153,9 +156,11 @@ func (d *IotxDispatcher) Stop(ctx context.Context) error {
153156
return nil
154157
}
155158

156-
// EventChan returns the event chan
157-
func (d *IotxDispatcher) EventChan() *chan interface{} {
158-
return &d.eventChan
159+
// EventQueueSize returns the event queue size
160+
func (d *IotxDispatcher) EventQueueSize() int {
161+
d.eventAuditLock.RLock()
162+
defer d.eventAuditLock.RUnlock()
163+
return len(d.eventChan) + len(d.syncChan)
159164
}
160165

161166
// EventAudit returns the event audit map
@@ -180,26 +185,43 @@ loop:
180185
d.handleActionMsg(msg)
181186
case *blockMsg:
182187
d.handleBlockMsg(msg)
183-
case *blockSyncMsg:
184-
d.handleBlockSyncMsg(msg)
185-
186188
default:
187189
log.L().Warn("Invalid message type in block handler.", zap.Any("msg", msg))
188190
}
191+
case <-d.quit:
192+
break loop
193+
}
194+
}
195+
196+
d.wg.Done()
197+
log.L().Info("news handler done.")
198+
}
189199

200+
// syncHandler handles incoming block sync requests
201+
func (d *IotxDispatcher) syncHandler() {
202+
loop:
203+
for {
204+
select {
205+
case m := <-d.syncChan:
206+
d.handleBlockSyncMsg(m)
190207
case <-d.quit:
191208
break loop
192209
}
193210
}
194211

195212
d.wg.Done()
196-
log.L().Info("News handler done.")
213+
log.L().Info("block sync handler done.")
197214
}
198215

199216
// handleActionMsg handles actionMsg from all peers.
200217
func (d *IotxDispatcher) handleActionMsg(m *actionMsg) {
201-
d.updateEventAudit(iotexrpc.MessageType_ACTION)
202-
if subscriber, ok := d.subscribers[m.ChainID()]; ok {
218+
log.L().Debug("receive actionMsg.")
219+
220+
d.subscribersMU.RLock()
221+
subscriber, ok := d.subscribers[m.ChainID()]
222+
d.subscribersMU.RUnlock()
223+
if ok {
224+
d.updateEventAudit(iotexrpc.MessageType_ACTION)
203225
if err := subscriber.HandleAction(m.ctx, m.action); err != nil {
204226
requestMtc.WithLabelValues("AddAction", "false").Inc()
205227
log.L().Debug("Handle action request error.", zap.Error(err))
@@ -214,8 +236,9 @@ func (d *IotxDispatcher) handleBlockMsg(m *blockMsg) {
214236
log.L().Debug("receive blockMsg.", zap.Uint64("height", m.block.GetHeader().GetCore().GetHeight()))
215237

216238
d.subscribersMU.RLock()
217-
defer d.subscribersMU.RUnlock()
218-
if subscriber, ok := d.subscribers[m.ChainID()]; ok {
239+
subscriber, ok := d.subscribers[m.ChainID()]
240+
d.subscribersMU.RUnlock()
241+
if ok {
219242
d.updateEventAudit(iotexrpc.MessageType_BLOCK)
220243
if err := subscriber.HandleBlock(m.ctx, m.block); err != nil {
221244
log.L().Error("Fail to handle the block.", zap.Error(err))
@@ -232,8 +255,11 @@ func (d *IotxDispatcher) handleBlockSyncMsg(m *blockSyncMsg) {
232255
zap.Uint64("start", m.sync.Start),
233256
zap.Uint64("end", m.sync.End))
234257

235-
d.updateEventAudit(iotexrpc.MessageType_BLOCK_REQUEST)
236-
if subscriber, ok := d.subscribers[m.ChainID()]; ok {
258+
d.subscribersMU.RLock()
259+
subscriber, ok := d.subscribers[m.ChainID()]
260+
d.subscribersMU.RUnlock()
261+
if ok {
262+
d.updateEventAudit(iotexrpc.MessageType_BLOCK_REQUEST)
237263
// dispatch to block sync
238264
if err := subscriber.HandleSyncRequest(m.ctx, m.peer, m.sync); err != nil {
239265
log.L().Error("Failed to handle sync request.", zap.Error(err))
@@ -272,12 +298,17 @@ func (d *IotxDispatcher) dispatchBlockSyncReq(ctx context.Context, chainID uint3
272298
if atomic.LoadInt32(&d.shutdown) != 0 {
273299
return
274300
}
275-
d.enqueueEvent(&blockSyncMsg{
301+
302+
if len(d.syncChan) == cap(d.syncChan) {
303+
log.L().Warn("dispatcher sync chan is full, drop an event.")
304+
return
305+
}
306+
d.syncChan <- &blockSyncMsg{
276307
ctx: ctx,
277308
chainID: chainID,
278309
peer: peer,
279310
sync: (msg).(*iotexrpc.BlockSync),
280-
})
311+
}
281312
}
282313

283314
// HandleBroadcast handles incoming broadcast message
@@ -288,12 +319,11 @@ func (d *IotxDispatcher) HandleBroadcast(ctx context.Context, chainID uint32, me
288319
}
289320
d.subscribersMU.RLock()
290321
subscriber, ok := d.subscribers[chainID]
322+
d.subscribersMU.RUnlock()
291323
if !ok {
292324
log.L().Warn("chainID has not been registered in dispatcher.", zap.Uint32("chainID", chainID))
293-
d.subscribersMU.RUnlock()
294325
return
295326
}
296-
d.subscribersMU.RUnlock()
297327

298328
switch msgType {
299329
case iotexrpc.MessageType_CONSENSUS:
@@ -326,13 +356,11 @@ func (d *IotxDispatcher) HandleTell(ctx context.Context, chainID uint32, peer pe
326356
}
327357

328358
func (d *IotxDispatcher) enqueueEvent(event interface{}) {
329-
go func() {
330-
if len(d.eventChan) == cap(d.eventChan) {
331-
log.L().Debug("dispatcher event chan is full, drop an event.")
332-
return
333-
}
334-
d.eventChan <- event
335-
}()
359+
if len(d.eventChan) == cap(d.eventChan) {
360+
log.L().Warn("dispatcher event chan is full, drop an event.")
361+
return
362+
}
363+
d.eventChan <- event
336364
}
337365

338366
func (d *IotxDispatcher) updateEventAudit(t iotexrpc.MessageType) {

p2p/agent.go

+22-17
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import (
2626
"go.uber.org/zap"
2727

2828
"github.com/iotexproject/iotex-core/config"
29-
"github.com/iotexproject/iotex-core/pkg/cache"
3029
"github.com/iotexproject/iotex-core/pkg/log"
3130
goproto "github.com/iotexproject/iotex-proto/golang"
3231
"github.com/iotexproject/iotex-proto/golang/iotexrpc"
@@ -66,8 +65,6 @@ const (
6665
unicastTopic = "unicast"
6766
numDialRetries = 8
6867
dialRetryInterval = 2 * time.Second
69-
blackListLen = 1000
70-
blackListTTL = 15 * time.Minute
7168
)
7269

7370
type (
@@ -85,7 +82,7 @@ type Agent struct {
8582
broadcastInboundHandler HandleBroadcastInbound
8683
unicastInboundAsyncHandler HandleUnicastInboundAsync
8784
host *p2p.Host
88-
unicastBlacklist *cache.ThreadSafeLruCache
85+
unicastBlocklist *BlockList
8986
}
9087

9188
// NewAgent instantiates a local P2P agent instance
@@ -97,7 +94,7 @@ func NewAgent(cfg config.Config, broadcastHandler HandleBroadcastInbound, unicas
9794
topicSuffix: hex.EncodeToString(gh[22:]), // last 10 bytes of genesis hash
9895
broadcastInboundHandler: broadcastHandler,
9996
unicastInboundAsyncHandler: unicastHandler,
100-
unicastBlacklist: cache.NewThreadSafeLruCache(blackListLen),
97+
unicastBlocklist: NewBlockList(blockListLen),
10198
}
10299
}
103100

@@ -338,15 +335,24 @@ func (p *Agent) BroadcastOutbound(ctx context.Context, msg proto.Message) (err e
338335

339336
// UnicastOutbound sends a unicast message to the given address
340337
func (p *Agent) UnicastOutbound(ctx context.Context, peer peerstore.PeerInfo, msg proto.Message) (err error) {
341-
var msgType iotexrpc.MessageType
342-
var msgBody []byte
338+
var (
339+
peerName = peer.ID.Pretty()
340+
msgType iotexrpc.MessageType
341+
msgBody []byte
342+
)
343343
defer func() {
344344
status := successStr
345345
if err != nil {
346346
status = failureStr
347347
}
348348
p2pMsgCounter.WithLabelValues("unicast", strconv.Itoa(int(msgType)), "out", peer.ID.Pretty(), status).Inc()
349349
}()
350+
351+
if p.unicastBlocklist.Blocked(peerName, time.Now()) {
352+
err = errors.New("peer is in blocklist at this moment")
353+
return
354+
}
355+
350356
msgType, msgBody, err = convertAppMsg(msg)
351357
if err != nil {
352358
return
@@ -366,14 +372,18 @@ func (p *Agent) UnicastOutbound(ctx context.Context, peer peerstore.PeerInfo, ms
366372
data, err := proto.Marshal(&unicast)
367373
if err != nil {
368374
err = errors.Wrap(err, "error when marshaling unicast message")
369-
return err
375+
return
370376
}
377+
371378
if err = p.host.Unicast(ctx, peer, unicastTopic+p.topicSuffix, data); err != nil {
372379
err = errors.Wrap(err, "error when sending unicast message")
373-
p.unicastBlacklist.Add(peer.ID.Pretty(), time.Now().Add(blackListTTL))
374-
return err
380+
p.unicastBlocklist.Add(peerName, time.Now())
381+
return
375382
}
376-
return err
383+
384+
// remove peer from blocklist upon success
385+
p.unicastBlocklist.Remove(peerName)
386+
return
377387
}
378388

379389
// Info returns agents' peer info.
@@ -391,12 +401,7 @@ func (p *Agent) Neighbors(ctx context.Context) ([]peerstore.PeerInfo, error) {
391401
}
392402

393403
for i, nb := range nbs {
394-
if v, ok := p.unicastBlacklist.Get(nb.ID.Pretty()); ok {
395-
if t, isT := v.(time.Time); isT {
396-
if time.Now().After(t) {
397-
p.unicastBlacklist.Remove(nb.ID.Pretty())
398-
}
399-
}
404+
if p.unicastBlocklist.Blocked(nb.ID.Pretty(), time.Now()) {
400405
continue
401406
}
402407
res = append(res, nbs[i])

0 commit comments

Comments
 (0)