import (
"sync"
+ "time"
log "github.com/sirupsen/logrus"
"github.com/bytom/protocol/bc/types"
)
+var (
+ orphanBlockTTL = 60 * time.Minute
+ orphanExpireWorkInterval = 3 * time.Minute
+)
+
+type orphanBlock struct {
+ *types.Block
+ expiration time.Time
+}
+
// OrphanManage is use to handle all the orphan block
type OrphanManage struct {
- //TODO: add orphan cached block limit
- orphan map[bc.Hash]*types.Block
+ orphan map[bc.Hash]*orphanBlock
prevOrphans map[bc.Hash][]*bc.Hash
mtx sync.RWMutex
}
// NewOrphanManage return a new orphan block
func NewOrphanManage() *OrphanManage {
- return &OrphanManage{
- orphan: make(map[bc.Hash]*types.Block),
+ o := &OrphanManage{
+ orphan: make(map[bc.Hash]*orphanBlock),
prevOrphans: make(map[bc.Hash][]*bc.Hash),
}
+
+ go o.orphanExpireWorker()
+ return o
}
// BlockExist check is the block in OrphanManage
return
}
- o.orphan[blockHash] = block
+ o.orphan[blockHash] = &orphanBlock{block, time.Now().Add(orphanBlockTTL)}
o.prevOrphans[block.PreviousBlockHash] = append(o.prevOrphans[block.PreviousBlockHash], &blockHash)
log.WithFields(log.Fields{"hash": blockHash.String(), "height": block.Height}).Info("add block to orphan")
func (o *OrphanManage) Delete(hash *bc.Hash) {
o.mtx.Lock()
defer o.mtx.Unlock()
+ o.delete(hash)
+}
+
+// Get return the orphan block by hash
+func (o *OrphanManage) Get(hash *bc.Hash) (*types.Block, bool) {
+ o.mtx.RLock()
+ block, ok := o.orphan[*hash]
+ o.mtx.RUnlock()
+ return block.Block, ok
+}
+
+// GetPrevOrphans return the list of child orphans
+func (o *OrphanManage) GetPrevOrphans(hash *bc.Hash) ([]*bc.Hash, bool) {
+ o.mtx.RLock()
+ prevOrphans, ok := o.prevOrphans[*hash]
+ o.mtx.RUnlock()
+ return prevOrphans, ok
+}
+
+func (o *OrphanManage) delete(hash *bc.Hash) {
block, ok := o.orphan[*hash]
if !ok {
return
}
delete(o.orphan, *hash)
- prevOrphans, ok := o.prevOrphans[block.PreviousBlockHash]
+ prevOrphans, ok := o.prevOrphans[block.Block.PreviousBlockHash]
if !ok || len(prevOrphans) == 1 {
- delete(o.prevOrphans, block.PreviousBlockHash)
+ delete(o.prevOrphans, block.Block.PreviousBlockHash)
return
}
for i, preOrphan := range prevOrphans {
if preOrphan == hash {
- o.prevOrphans[block.PreviousBlockHash] = append(prevOrphans[:i], prevOrphans[i+1:]...)
+ o.prevOrphans[block.Block.PreviousBlockHash] = append(prevOrphans[:i], prevOrphans[i+1:]...)
return
}
}
}
-// Get return the orphan block by hash
-func (o *OrphanManage) Get(hash *bc.Hash) (*types.Block, bool) {
- o.mtx.RLock()
- block, ok := o.orphan[*hash]
- o.mtx.RUnlock()
- return block, ok
+func (o *OrphanManage) orphanExpireWorker() {
+ ticker := time.NewTicker(orphanExpireWorkInterval)
+ for now := range ticker.C {
+ o.orphanExpire(now)
+ }
+ ticker.Stop()
}
-// GetPrevOrphans return the list of child orphans
-func (o *OrphanManage) GetPrevOrphans(hash *bc.Hash) ([]*bc.Hash, bool) {
- o.mtx.RLock()
- prevOrphans, ok := o.prevOrphans[*hash]
- o.mtx.RUnlock()
- return prevOrphans, ok
+func (o *OrphanManage) orphanExpire(now time.Time) {
+ o.mtx.Lock()
+ defer o.mtx.Unlock()
+ for hash, orphan := range o.orphan {
+ if orphan.expiration.Before(now) {
+ o.delete(&hash)
+ }
+ }
}