mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 23:26:44 +00:00
225 lines
4.5 KiB
Go
225 lines
4.5 KiB
Go
package blockstm
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
)
|
|
|
|
func makeStatusManager(numTasks int) (t taskStatusManager) {
|
|
t.pending = make([]int, numTasks)
|
|
for i := 0; i < numTasks; i++ {
|
|
t.pending[i] = i
|
|
}
|
|
|
|
t.dependency = make(map[int]map[int]bool, numTasks)
|
|
t.blocker = make(map[int]map[int]bool, numTasks)
|
|
|
|
for i := 0; i < numTasks; i++ {
|
|
t.blocker[i] = make(map[int]bool)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
type taskStatusManager struct {
|
|
pending []int
|
|
inProgress []int
|
|
complete []int
|
|
dependency map[int]map[int]bool
|
|
blocker map[int]map[int]bool
|
|
}
|
|
|
|
func insertInList(l []int, v int) []int {
|
|
if len(l) == 0 || v > l[len(l)-1] {
|
|
return append(l, v)
|
|
} else {
|
|
x := sort.SearchInts(l, v)
|
|
if x < len(l) && l[x] == v {
|
|
// already in list
|
|
return l
|
|
}
|
|
a := append(l[:x+1], l[x:]...)
|
|
a[x] = v
|
|
return a
|
|
}
|
|
}
|
|
|
|
func (m *taskStatusManager) takeNextPending() int {
|
|
if len(m.pending) == 0 {
|
|
return -1
|
|
}
|
|
|
|
x := m.pending[0]
|
|
m.pending = m.pending[1:]
|
|
m.inProgress = insertInList(m.inProgress, x)
|
|
|
|
return x
|
|
}
|
|
|
|
func hasNoGap(l []int) bool {
|
|
return l[0]+len(l) == l[len(l)-1]+1
|
|
}
|
|
|
|
func (m taskStatusManager) maxAllComplete() int {
|
|
if len(m.complete) == 0 || m.complete[0] != 0 {
|
|
return -1
|
|
} else if m.complete[len(m.complete)-1] == len(m.complete)-1 {
|
|
return m.complete[len(m.complete)-1]
|
|
} else {
|
|
for i := len(m.complete) - 2; i >= 0; i-- {
|
|
if hasNoGap(m.complete[:i+1]) {
|
|
return m.complete[i]
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1
|
|
}
|
|
|
|
func (m *taskStatusManager) pushPending(tx int) {
|
|
m.pending = insertInList(m.pending, tx)
|
|
}
|
|
|
|
func removeFromList(l []int, v int, expect bool) []int {
|
|
x := sort.SearchInts(l, v)
|
|
if x == -1 || l[x] != v {
|
|
if expect {
|
|
panic(fmt.Errorf("should not happen - element expected in list"))
|
|
}
|
|
|
|
return l
|
|
}
|
|
|
|
switch x {
|
|
case 0:
|
|
return l[1:]
|
|
case len(l) - 1:
|
|
return l[:len(l)-1]
|
|
default:
|
|
return append(l[:x], l[x+1:]...)
|
|
}
|
|
}
|
|
|
|
func (m *taskStatusManager) markComplete(tx int) {
|
|
m.inProgress = removeFromList(m.inProgress, tx, true)
|
|
m.complete = insertInList(m.complete, tx)
|
|
}
|
|
|
|
func (m *taskStatusManager) minPending() int {
|
|
if len(m.pending) == 0 {
|
|
return -1
|
|
} else {
|
|
return m.pending[0]
|
|
}
|
|
}
|
|
|
|
func (m *taskStatusManager) countComplete() int {
|
|
return len(m.complete)
|
|
}
|
|
|
|
func (m *taskStatusManager) addDependencies(blocker int, dependent int) bool {
|
|
if blocker < 0 || blocker >= dependent {
|
|
return false
|
|
}
|
|
|
|
curblockers := m.blocker[dependent]
|
|
|
|
if m.checkComplete(blocker) {
|
|
// Blocker has already completed
|
|
delete(curblockers, blocker)
|
|
|
|
return len(curblockers) > 0
|
|
}
|
|
|
|
if _, ok := m.dependency[blocker]; !ok {
|
|
m.dependency[blocker] = make(map[int]bool)
|
|
}
|
|
|
|
m.dependency[blocker][dependent] = true
|
|
curblockers[blocker] = true
|
|
|
|
return true
|
|
}
|
|
|
|
func (m *taskStatusManager) isBlocked(tx int) bool {
|
|
return len(m.blocker[tx]) > 0
|
|
}
|
|
|
|
func (m *taskStatusManager) removeDependency(tx int) {
|
|
if deps, ok := m.dependency[tx]; ok && len(deps) > 0 {
|
|
for k := range deps {
|
|
delete(m.blocker[k], tx)
|
|
|
|
if len(m.blocker[k]) == 0 {
|
|
if !m.checkComplete(k) && !m.checkPending(k) && !m.checkInProgress(k) {
|
|
m.pushPending(k)
|
|
}
|
|
}
|
|
}
|
|
|
|
delete(m.dependency, tx)
|
|
}
|
|
}
|
|
|
|
func (m *taskStatusManager) clearInProgress(tx int) {
|
|
m.inProgress = removeFromList(m.inProgress, tx, true)
|
|
}
|
|
|
|
func (m *taskStatusManager) checkInProgress(tx int) bool {
|
|
x := sort.SearchInts(m.inProgress, tx)
|
|
if x < len(m.inProgress) && m.inProgress[x] == tx {
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func (m *taskStatusManager) checkPending(tx int) bool {
|
|
x := sort.SearchInts(m.pending, tx)
|
|
if x < len(m.pending) && m.pending[x] == tx {
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func (m *taskStatusManager) checkComplete(tx int) bool {
|
|
x := sort.SearchInts(m.complete, tx)
|
|
if x < len(m.complete) && m.complete[x] == tx {
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// getRevalidationRange: this range will be all tasks from tx (inclusive) that are not currently in progress up to the
|
|
//
|
|
// 'all complete' limit
|
|
func (m *taskStatusManager) getRevalidationRange(txFrom int) (ret []int) {
|
|
max := m.maxAllComplete() // haven't learned to trust compilers :)
|
|
for x := txFrom; x <= max; x++ {
|
|
if !m.checkInProgress(x) {
|
|
ret = append(ret, x)
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (m *taskStatusManager) pushPendingSet(set []int) {
|
|
for _, v := range set {
|
|
if m.checkComplete(v) {
|
|
m.clearComplete(v)
|
|
}
|
|
|
|
m.pushPending(v)
|
|
}
|
|
}
|
|
|
|
func (m *taskStatusManager) clearComplete(tx int) {
|
|
m.complete = removeFromList(m.complete, tx, false)
|
|
}
|
|
|
|
func (m *taskStatusManager) clearPending(tx int) {
|
|
m.pending = removeFromList(m.pending, tx, false)
|
|
}
|