track recently synced tipsets to avoid unnecessary worker spawning
This commit is contained in:
parent
2b82e5a118
commit
ab7a66b90d
@ -16,6 +16,8 @@ import (
|
|||||||
|
|
||||||
var BootstrapPeerThreshold = 1
|
var BootstrapPeerThreshold = 1
|
||||||
|
|
||||||
|
var RecentSyncBufferSize = 10
|
||||||
|
|
||||||
var coalesceTipsets = false
|
var coalesceTipsets = false
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -55,6 +57,7 @@ type syncManager struct {
|
|||||||
nextWorker uint64
|
nextWorker uint64
|
||||||
pend syncBucketSet
|
pend syncBucketSet
|
||||||
heads map[peer.ID]*types.TipSet
|
heads map[peer.ID]*types.TipSet
|
||||||
|
recent *syncBuffer
|
||||||
|
|
||||||
mx sync.Mutex
|
mx sync.Mutex
|
||||||
state map[uint64]*workerState
|
state map[uint64]*workerState
|
||||||
@ -90,8 +93,9 @@ func NewSyncManager(sync SyncFunc) SyncManager {
|
|||||||
workq: make(chan peerHead),
|
workq: make(chan peerHead),
|
||||||
statusq: make(chan workerStatus),
|
statusq: make(chan workerStatus),
|
||||||
|
|
||||||
heads: make(map[peer.ID]*types.TipSet),
|
heads: make(map[peer.ID]*types.TipSet),
|
||||||
state: make(map[uint64]*workerState),
|
state: make(map[uint64]*workerState),
|
||||||
|
recent: newSyncBuffer(RecentSyncBufferSize),
|
||||||
|
|
||||||
doSync: sync,
|
doSync: sync,
|
||||||
}
|
}
|
||||||
@ -203,6 +207,9 @@ func (sm *syncManager) handleWorkerStatus(status workerStatus) {
|
|||||||
// we failed to sync this target -- log it and try to work on an extended chain
|
// we failed to sync this target -- log it and try to work on an extended chain
|
||||||
// if there is nothing related to be worked on, we stop working on this chain.
|
// if there is nothing related to be worked on, we stop working on this chain.
|
||||||
log.Errorf("error during sync in %s: %s", ws.ts, status.err)
|
log.Errorf("error during sync in %s: %s", ws.ts, status.err)
|
||||||
|
} else {
|
||||||
|
// add to the recently synced buffer
|
||||||
|
sm.recent.Push(ws.ts)
|
||||||
}
|
}
|
||||||
|
|
||||||
// we are done with this target, select the next sync target and spawn a worker if there is work
|
// we are done with this target, select the next sync target and spawn a worker if there is work
|
||||||
@ -286,6 +293,12 @@ func (sm *syncManager) addSyncTarget(ts *types.TipSet) (*types.TipSet, bool, err
|
|||||||
// Note: we don't need the state lock here to access the active worker states, as the only
|
// Note: we don't need the state lock here to access the active worker states, as the only
|
||||||
// competing threads that may access it do so through State() which is read only.
|
// competing threads that may access it do so through State() which is read only.
|
||||||
|
|
||||||
|
// if we have recently synced this or any heavier tipset we just ignore it; this can happen
|
||||||
|
// with an empty worker set after we just finished syncing to a target
|
||||||
|
if sm.recent.Synced(ts) {
|
||||||
|
return nil, false, nil
|
||||||
|
}
|
||||||
|
|
||||||
// if the worker set is empty, we have finished syncing and were waiting for the next tipset
|
// if the worker set is empty, we have finished syncing and were waiting for the next tipset
|
||||||
// in this case, we just return the tipset as work to be done
|
// in this case, we just return the tipset as work to be done
|
||||||
if len(sm.state) == 0 {
|
if len(sm.state) == 0 {
|
||||||
@ -341,6 +354,10 @@ func (sm *syncManager) selectSyncTarget(done *types.TipSet) (*types.TipSet, bool
|
|||||||
}
|
}
|
||||||
|
|
||||||
heaviest := related.heaviestTipSet()
|
heaviest := related.heaviestTipSet()
|
||||||
|
if isHeavier(done, heaviest) {
|
||||||
|
return nil, false, nil
|
||||||
|
}
|
||||||
|
|
||||||
for _, ws := range sm.state {
|
for _, ws := range sm.state {
|
||||||
if isHeavier(ws.ts, heaviest) {
|
if isHeavier(ws.ts, heaviest) {
|
||||||
return nil, false, nil
|
return nil, false, nil
|
||||||
@ -354,6 +371,47 @@ func isHeavier(a, b *types.TipSet) bool {
|
|||||||
return a.ParentWeight().GreaterThan(b.ParentWeight())
|
return a.ParentWeight().GreaterThan(b.ParentWeight())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sync buffer -- this is a circular buffer of recently synced tipsets
|
||||||
|
type syncBuffer struct {
|
||||||
|
buf []*types.TipSet
|
||||||
|
next int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSyncBuffer(size int) *syncBuffer {
|
||||||
|
return &syncBuffer{buf: make([]*types.TipSet, size)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sb *syncBuffer) Push(ts *types.TipSet) {
|
||||||
|
i := int(sb.next % int64(len(sb.buf)))
|
||||||
|
sb.buf[i] = ts
|
||||||
|
sb.next++
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sb *syncBuffer) Synced(ts *types.TipSet) bool {
|
||||||
|
synced := func(a, b *types.TipSet) bool {
|
||||||
|
return a.Equals(b) || isHeavier(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
if sb.next < int64(len(sb.buf)) {
|
||||||
|
for i := int(sb.next - 1); i >= 0; i-- {
|
||||||
|
if synced(sb.buf[i], ts) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for j := 1; j < len(sb.buf); j++ {
|
||||||
|
i := int((sb.next - int64(j)) % int64(len(sb.buf)))
|
||||||
|
if synced(sb.buf[i], ts) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// sync buckets and related utilities
|
// sync buckets and related utilities
|
||||||
type syncBucketSet struct {
|
type syncBucketSet struct {
|
||||||
buckets []*syncTargetBucket
|
buckets []*syncTargetBucket
|
||||||
|
Loading…
Reference in New Issue
Block a user