mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
les: move priceFactors notion into balance tracker
This commit is contained in:
parent
45bc1f2a35
commit
6714ac0933
4 changed files with 55 additions and 60 deletions
|
|
@ -188,7 +188,7 @@ func (api *PrivateLightServerAPI) SetClientParams(ids []enode.ID, params map[str
|
||||||
if client != nil {
|
if client != nil {
|
||||||
update, err := api.setParams(params, client, nil, nil)
|
update, err := api.setParams(params, client, nil, nil)
|
||||||
if update {
|
if update {
|
||||||
updatePriceFactors(&client.balanceTracker, client.posFactors, client.negFactors, client.capacity)
|
updatePriceFactors(&client.balanceTracker, client.posFactors, client.negFactors)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,23 @@ type expirationController interface {
|
||||||
negExpiration(mclock.AbsTime) float64
|
negExpiration(mclock.AbsTime) float64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// priceFactors determine the pricing policy (may apply either to positive or
|
||||||
|
// negative balances which may have different factors).
|
||||||
|
// - timeFactor is cost unit per nanosecond of connection time
|
||||||
|
// - capacityFactor is cost unit per nanosecond of connection time per 1000000 capacity
|
||||||
|
// - requestFactor is cost unit per request "realCost" unit
|
||||||
|
type priceFactors struct {
|
||||||
|
timeFactor, capacityFactor, requestFactor float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p priceFactors) timePrice(cap uint64) float64 {
|
||||||
|
return p.timeFactor + float64(cap)*p.capacityFactor/1000000
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p priceFactors) reqPrice() float64 {
|
||||||
|
return p.requestFactor
|
||||||
|
}
|
||||||
|
|
||||||
// balanceTracker keeps track of the positive and negative balances of a connected
|
// balanceTracker keeps track of the positive and negative balances of a connected
|
||||||
// client and calculates actual and projected future priority values required by
|
// client and calculates actual and projected future priority values required by
|
||||||
// prque.LazyQueue.
|
// prque.LazyQueue.
|
||||||
|
|
@ -49,8 +66,7 @@ type balanceTracker struct {
|
||||||
stopped bool
|
stopped bool
|
||||||
capacity uint64
|
capacity uint64
|
||||||
balance balance
|
balance balance
|
||||||
timeFactor, requestFactor float64
|
posFactor, negFactor priceFactors
|
||||||
negTimeFactor, negRequestFactor float64
|
|
||||||
sumReqCost uint64
|
sumReqCost uint64
|
||||||
lastUpdate, nextUpdate, initTime mclock.AbsTime
|
lastUpdate, nextUpdate, initTime mclock.AbsTime
|
||||||
updateEvent mclock.Timer
|
updateEvent mclock.Timer
|
||||||
|
|
@ -93,10 +109,8 @@ func (bt *balanceTracker) stop(now mclock.AbsTime) {
|
||||||
|
|
||||||
bt.stopped = true
|
bt.stopped = true
|
||||||
bt.addBalance(now)
|
bt.addBalance(now)
|
||||||
bt.negTimeFactor = 0
|
bt.posFactor = priceFactors{0, 0, 0}
|
||||||
bt.negRequestFactor = 0
|
bt.negFactor = priceFactors{0, 0, 0}
|
||||||
bt.timeFactor = 0
|
|
||||||
bt.requestFactor = 0
|
|
||||||
if bt.updateEvent != nil {
|
if bt.updateEvent != nil {
|
||||||
bt.updateEvent.Stop()
|
bt.updateEvent.Stop()
|
||||||
bt.updateEvent = nil
|
bt.updateEvent = nil
|
||||||
|
|
@ -119,13 +133,14 @@ func (bt *balanceTracker) balanceToPriority(b balance) int64 {
|
||||||
func (bt *balanceTracker) posBalanceMissing(targetPriority int64, targetCapacity uint64, after time.Duration) uint64 {
|
func (bt *balanceTracker) posBalanceMissing(targetPriority int64, targetCapacity uint64, after time.Duration) uint64 {
|
||||||
now := bt.clock.Now()
|
now := bt.clock.Now()
|
||||||
if targetPriority > 0 {
|
if targetPriority > 0 {
|
||||||
negPrice := uint64(float64(after) * bt.negTimeFactor)
|
timePrice := bt.negFactor.timePrice(targetCapacity)
|
||||||
|
timeCost := uint64(float64(after) * timePrice)
|
||||||
negBalance := bt.balance.neg.value(bt.exp.negExpiration(now))
|
negBalance := bt.balance.neg.value(bt.exp.negExpiration(now))
|
||||||
if negPrice+negBalance < uint64(targetPriority) {
|
if timeCost+negBalance < uint64(targetPriority) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
if uint64(targetPriority) > negBalance && bt.negTimeFactor > 1e-100 {
|
if uint64(targetPriority) > negBalance && timePrice > 1e-100 {
|
||||||
if negTime := time.Duration(float64(uint64(targetPriority)-negBalance) / bt.negTimeFactor); negTime < after {
|
if negTime := time.Duration(float64(uint64(targetPriority)-negBalance) / timePrice); negTime < after {
|
||||||
after -= negTime
|
after -= negTime
|
||||||
} else {
|
} else {
|
||||||
after = 0
|
after = 0
|
||||||
|
|
@ -133,7 +148,8 @@ func (bt *balanceTracker) posBalanceMissing(targetPriority int64, targetCapacity
|
||||||
}
|
}
|
||||||
targetPriority = 0
|
targetPriority = 0
|
||||||
}
|
}
|
||||||
posRequired := uint64(float64(-targetPriority)*float64(targetCapacity)+float64(after)*bt.timeFactor) + 1
|
timePrice := bt.posFactor.timePrice(targetCapacity)
|
||||||
|
posRequired := uint64(float64(-targetPriority)*float64(targetCapacity)+float64(after)*timePrice) + 1
|
||||||
if posRequired >= maxBalance {
|
if posRequired >= maxBalance {
|
||||||
return math.MaxUint64 // target not reachable
|
return math.MaxUint64 // target not reachable
|
||||||
}
|
}
|
||||||
|
|
@ -150,7 +166,7 @@ func (bt *balanceTracker) reducedBalance(at mclock.AbsTime, avgReqCost float64)
|
||||||
dt := float64(at - bt.lastUpdate)
|
dt := float64(at - bt.lastUpdate)
|
||||||
b := bt.balance
|
b := bt.balance
|
||||||
if b.pos.base != 0 {
|
if b.pos.base != 0 {
|
||||||
factor := bt.timeFactor + bt.requestFactor*avgReqCost
|
factor := bt.posFactor.timePrice(bt.capacity) + bt.posFactor.reqPrice()*avgReqCost
|
||||||
diff := -int64(dt * factor)
|
diff := -int64(dt * factor)
|
||||||
dd := b.pos.add(diff, bt.exp.posExpiration(at))
|
dd := b.pos.add(diff, bt.exp.posExpiration(at))
|
||||||
if dd == diff {
|
if dd == diff {
|
||||||
|
|
@ -160,7 +176,7 @@ func (bt *balanceTracker) reducedBalance(at mclock.AbsTime, avgReqCost float64)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if dt > 0 {
|
if dt > 0 {
|
||||||
factor := bt.negTimeFactor + bt.negRequestFactor*avgReqCost
|
factor := bt.negFactor.timePrice(bt.capacity) + bt.negFactor.reqPrice()*avgReqCost
|
||||||
b.neg.add(int64(dt*factor), bt.exp.negExpiration(at))
|
b.neg.add(int64(dt*factor), bt.exp.negExpiration(at))
|
||||||
}
|
}
|
||||||
return b
|
return b
|
||||||
|
|
@ -176,7 +192,8 @@ func (bt *balanceTracker) timeUntil(priority int64) (time.Duration, bool) {
|
||||||
var dt float64
|
var dt float64
|
||||||
if bt.balance.pos.base != 0 {
|
if bt.balance.pos.base != 0 {
|
||||||
posBalance := bt.balance.pos.value(bt.exp.posExpiration(now))
|
posBalance := bt.balance.pos.value(bt.exp.posExpiration(now))
|
||||||
if bt.timeFactor < 1e-100 {
|
timePrice := bt.posFactor.timePrice(bt.capacity)
|
||||||
|
if timePrice < 1e-100 {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
if priority < 0 {
|
if priority < 0 {
|
||||||
|
|
@ -184,10 +201,10 @@ func (bt *balanceTracker) timeUntil(priority int64) (time.Duration, bool) {
|
||||||
if newBalance > posBalance {
|
if newBalance > posBalance {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
dt = float64(posBalance-newBalance) / bt.timeFactor
|
dt = float64(posBalance-newBalance) / timePrice
|
||||||
return time.Duration(dt), true
|
return time.Duration(dt), true
|
||||||
} else {
|
} else {
|
||||||
dt = float64(posBalance) / bt.timeFactor
|
dt = float64(posBalance) / timePrice
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if priority < 0 {
|
if priority < 0 {
|
||||||
|
|
@ -196,11 +213,12 @@ func (bt *balanceTracker) timeUntil(priority int64) (time.Duration, bool) {
|
||||||
}
|
}
|
||||||
// if we have a positive balance then dt equals the time needed to get it to zero
|
// if we have a positive balance then dt equals the time needed to get it to zero
|
||||||
negBalance := bt.balance.neg.value(bt.exp.negExpiration(now))
|
negBalance := bt.balance.neg.value(bt.exp.negExpiration(now))
|
||||||
|
timePrice := bt.negFactor.timePrice(bt.capacity)
|
||||||
if uint64(priority) > negBalance {
|
if uint64(priority) > negBalance {
|
||||||
if bt.negTimeFactor < 1e-100 {
|
if timePrice < 1e-100 {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
dt += float64(uint64(priority)-negBalance) / bt.negTimeFactor
|
dt += float64(uint64(priority)-negBalance) / timePrice
|
||||||
}
|
}
|
||||||
return time.Duration(dt), true
|
return time.Duration(dt), true
|
||||||
}
|
}
|
||||||
|
|
@ -321,8 +339,8 @@ func (bt *balanceTracker) requestCost(cost uint64) uint64 {
|
||||||
|
|
||||||
posExp := bt.exp.posExpiration(now)
|
posExp := bt.exp.posExpiration(now)
|
||||||
if bt.balance.pos.base != 0 {
|
if bt.balance.pos.base != 0 {
|
||||||
if bt.requestFactor != 0 {
|
if bt.posFactor.reqPrice() != 0 {
|
||||||
c := -int64(fcost * bt.requestFactor)
|
c := -int64(fcost * bt.posFactor.reqPrice())
|
||||||
cc := bt.balance.pos.add(c, posExp)
|
cc := bt.balance.pos.add(c, posExp)
|
||||||
if c == cc {
|
if c == cc {
|
||||||
fcost = 0
|
fcost = 0
|
||||||
|
|
@ -335,8 +353,8 @@ func (bt *balanceTracker) requestCost(cost uint64) uint64 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if fcost > 0 {
|
if fcost > 0 {
|
||||||
if bt.negRequestFactor != 0 {
|
if bt.negFactor.reqPrice() != 0 {
|
||||||
bt.balance.neg.add(int64(fcost*bt.negRequestFactor), bt.exp.negExpiration(now))
|
bt.balance.neg.add(int64(fcost*bt.negFactor.reqPrice()), bt.exp.negExpiration(now))
|
||||||
bt.checkCallbacks(now)
|
bt.checkCallbacks(now)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -368,7 +386,7 @@ func (bt *balanceTracker) setBalance(pos, neg expiredValue) error {
|
||||||
|
|
||||||
// setFactors sets the price factors. timeFactor is the price of a nanosecond of
|
// setFactors sets the price factors. timeFactor is the price of a nanosecond of
|
||||||
// connection while requestFactor is the price of a "realCost" unit.
|
// connection while requestFactor is the price of a "realCost" unit.
|
||||||
func (bt *balanceTracker) setFactors(neg bool, timeFactor, requestFactor float64) {
|
func (bt *balanceTracker) setFactors(posFactor, negFactor priceFactors) {
|
||||||
bt.lock.Lock()
|
bt.lock.Lock()
|
||||||
defer bt.lock.Unlock()
|
defer bt.lock.Unlock()
|
||||||
|
|
||||||
|
|
@ -377,13 +395,7 @@ func (bt *balanceTracker) setFactors(neg bool, timeFactor, requestFactor float64
|
||||||
}
|
}
|
||||||
now := bt.clock.Now()
|
now := bt.clock.Now()
|
||||||
bt.addBalance(now)
|
bt.addBalance(now)
|
||||||
if neg {
|
bt.posFactor, bt.negFactor = posFactor, negFactor
|
||||||
bt.negTimeFactor = timeFactor
|
|
||||||
bt.negRequestFactor = requestFactor
|
|
||||||
} else {
|
|
||||||
bt.timeFactor = timeFactor
|
|
||||||
bt.requestFactor = requestFactor
|
|
||||||
}
|
|
||||||
bt.checkCallbacks(now)
|
bt.checkCallbacks(now)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -70,8 +70,7 @@ func TestBalanceTimeCost(t *testing.T) {
|
||||||
)
|
)
|
||||||
tracker.init(clock, 1000)
|
tracker.init(clock, 1000)
|
||||||
defer tracker.stop(clock.Now())
|
defer tracker.stop(clock.Now())
|
||||||
tracker.setFactors(false, 1, 1)
|
tracker.setFactors(priceFactors{1, 0, 1}, priceFactors{1, 0, 1})
|
||||||
tracker.setFactors(true, 1, 1)
|
|
||||||
|
|
||||||
tracker.setBalance(expval(uint64(time.Minute)), expval(0)) // 1 minute time allowance
|
tracker.setBalance(expval(uint64(time.Minute)), expval(0)) // 1 minute time allowance
|
||||||
|
|
||||||
|
|
@ -114,8 +113,7 @@ func TestBalanceReqCost(t *testing.T) {
|
||||||
)
|
)
|
||||||
tracker.init(clock, 1000)
|
tracker.init(clock, 1000)
|
||||||
defer tracker.stop(clock.Now())
|
defer tracker.stop(clock.Now())
|
||||||
tracker.setFactors(false, 1, 1)
|
tracker.setFactors(priceFactors{1, 0, 1}, priceFactors{1, 0, 1})
|
||||||
tracker.setFactors(true, 1, 1)
|
|
||||||
|
|
||||||
tracker.setBalance(expval(uint64(time.Minute)), expval(0)) // 1 minute time serving time allowance
|
tracker.setBalance(expval(uint64(time.Minute)), expval(0)) // 1 minute time serving time allowance
|
||||||
var inputs = []struct {
|
var inputs = []struct {
|
||||||
|
|
@ -146,8 +144,7 @@ func TestBalanceToPriority(t *testing.T) {
|
||||||
)
|
)
|
||||||
tracker.init(clock, 1000) // cap = 1000
|
tracker.init(clock, 1000) // cap = 1000
|
||||||
defer tracker.stop(clock.Now())
|
defer tracker.stop(clock.Now())
|
||||||
tracker.setFactors(false, 1, 1)
|
tracker.setFactors(priceFactors{1, 0, 1}, priceFactors{1, 0, 1})
|
||||||
tracker.setFactors(true, 1, 1)
|
|
||||||
|
|
||||||
var inputs = []struct {
|
var inputs = []struct {
|
||||||
pos uint64
|
pos uint64
|
||||||
|
|
@ -175,8 +172,7 @@ func TestEstimatedPriority(t *testing.T) {
|
||||||
)
|
)
|
||||||
tracker.init(clock, 1000000000) // cap = 1000,000,000
|
tracker.init(clock, 1000000000) // cap = 1000,000,000
|
||||||
defer tracker.stop(clock.Now())
|
defer tracker.stop(clock.Now())
|
||||||
tracker.setFactors(false, 1, 1)
|
tracker.setFactors(priceFactors{1, 0, 1}, priceFactors{1, 0, 1})
|
||||||
tracker.setFactors(true, 1, 1)
|
|
||||||
|
|
||||||
tracker.setBalance(expval(uint64(time.Minute)), expval(0))
|
tracker.setBalance(expval(uint64(time.Minute)), expval(0))
|
||||||
var inputs = []struct {
|
var inputs = []struct {
|
||||||
|
|
@ -219,8 +215,7 @@ func TestCallbackChecking(t *testing.T) {
|
||||||
)
|
)
|
||||||
tracker.init(clock, 1000000) // cap = 1000,000
|
tracker.init(clock, 1000000) // cap = 1000,000
|
||||||
defer tracker.stop(clock.Now())
|
defer tracker.stop(clock.Now())
|
||||||
tracker.setFactors(false, 1, 1)
|
tracker.setFactors(priceFactors{1, 0, 1}, priceFactors{1, 0, 1})
|
||||||
tracker.setFactors(true, 1, 1)
|
|
||||||
|
|
||||||
var inputs = []struct {
|
var inputs = []struct {
|
||||||
priority int64
|
priority int64
|
||||||
|
|
@ -246,8 +241,7 @@ func TestCallback(t *testing.T) {
|
||||||
)
|
)
|
||||||
tracker.init(clock, 1000) // cap = 1000
|
tracker.init(clock, 1000) // cap = 1000
|
||||||
defer tracker.stop(clock.Now())
|
defer tracker.stop(clock.Now())
|
||||||
tracker.setFactors(false, 1, 1)
|
tracker.setFactors(priceFactors{1, 0, 1}, priceFactors{1, 0, 1})
|
||||||
tracker.setFactors(true, 1, 1)
|
|
||||||
|
|
||||||
callCh := make(chan struct{}, 1)
|
callCh := make(chan struct{}, 1)
|
||||||
tracker.setBalance(expval(uint64(time.Minute)), expval(0))
|
tracker.setBalance(expval(uint64(time.Minute)), expval(0))
|
||||||
|
|
|
||||||
|
|
@ -154,15 +154,6 @@ func connMaxPriority(a interface{}, until mclock.AbsTime) int64 {
|
||||||
return pri
|
return pri
|
||||||
}
|
}
|
||||||
|
|
||||||
// priceFactors determine the pricing policy (may apply either to positive or
|
|
||||||
// negative balances which may have different factors).
|
|
||||||
// - timeFactor is cost unit per nanosecond of connection time
|
|
||||||
// - capacityFactor is cost unit per nanosecond of connection time per 1000000 capacity
|
|
||||||
// - requestFactor is cost unit per request "realCost" unit
|
|
||||||
type priceFactors struct {
|
|
||||||
timeFactor, capacityFactor, requestFactor float64
|
|
||||||
}
|
|
||||||
|
|
||||||
// newClientPool creates a new client pool
|
// newClientPool creates a new client pool
|
||||||
func newClientPool(db ethdb.Database, minCap, freeClientCap uint64, clock mclock.Clock, removePeer func(enode.ID)) *clientPool {
|
func newClientPool(db ethdb.Database, minCap, freeClientCap uint64, clock mclock.Clock, removePeer func(enode.ID)) *clientPool {
|
||||||
ndb := newNodeDB(db, clock)
|
ndb := newNodeDB(db, clock)
|
||||||
|
|
@ -470,7 +461,7 @@ func (f *clientPool) initBalanceTracker(bt *balanceTracker, pb tokenBalance, nb
|
||||||
bt.init(f.clock, capacity)
|
bt.init(f.clock, capacity)
|
||||||
bt.setBalance(pb.value, nb.value)
|
bt.setBalance(pb.value, nb.value)
|
||||||
if active {
|
if active {
|
||||||
updatePriceFactors(bt, f.defaultPosFactors, f.defaultNegFactors, capacity)
|
updatePriceFactors(bt, f.defaultPosFactors, f.defaultNegFactors)
|
||||||
} else {
|
} else {
|
||||||
zeroPriceFactors(bt)
|
zeroPriceFactors(bt)
|
||||||
}
|
}
|
||||||
|
|
@ -654,7 +645,7 @@ func (f *clientPool) tryActivateClients() {
|
||||||
e.peer.updateCapacity(capacity)
|
e.peer.updateCapacity(capacity)
|
||||||
balance, _ := e.balanceTracker.getBalance(now)
|
balance, _ := e.balanceTracker.getBalance(now)
|
||||||
e.balanceTracker.setCapacity(capacity)
|
e.balanceTracker.setCapacity(capacity)
|
||||||
updatePriceFactors(&e.balanceTracker, f.defaultPosFactors, f.defaultNegFactors, capacity)
|
updatePriceFactors(&e.balanceTracker, f.defaultPosFactors, f.defaultNegFactors)
|
||||||
// Register activated client to connection queue.
|
// Register activated client to connection queue.
|
||||||
f.inactiveBalances.subExp(balance)
|
f.inactiveBalances.subExp(balance)
|
||||||
f.activeBalances.addExp(balance)
|
f.activeBalances.addExp(balance)
|
||||||
|
|
@ -782,7 +773,7 @@ func (f *clientPool) setCapacity(id enode.ID, freeID string, capacity uint64, mi
|
||||||
c.balanceTracker.setCapacity(capacity)
|
c.balanceTracker.setCapacity(capacity)
|
||||||
f.activeQueue.Update(c.queueIndex)
|
f.activeQueue.Update(c.queueIndex)
|
||||||
totalConnectedGauge.Update(int64(f.activeCap))
|
totalConnectedGauge.Update(int64(f.activeCap))
|
||||||
updatePriceFactors(&c.balanceTracker, c.posFactors, c.negFactors, c.capacity)
|
updatePriceFactors(&c.balanceTracker, c.posFactors, c.negFactors)
|
||||||
c.peer.updateCapacity(c.capacity)
|
c.peer.updateCapacity(c.capacity)
|
||||||
f.tryActivateClients()
|
f.tryActivateClients()
|
||||||
}
|
}
|
||||||
|
|
@ -811,15 +802,13 @@ func (f *clientPool) requestCost(p *clientPeer, cost uint64) uint64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// updatePriceFactors sets the pricing factors for an individual connected client
|
// updatePriceFactors sets the pricing factors for an individual connected client
|
||||||
func updatePriceFactors(bt *balanceTracker, posFactors, negFactors priceFactors, capacity uint64) {
|
func updatePriceFactors(bt *balanceTracker, posFactors, negFactors priceFactors) {
|
||||||
bt.setFactors(true, negFactors.timeFactor+float64(capacity)*negFactors.capacityFactor/1000000, negFactors.requestFactor)
|
bt.setFactors(posFactors, negFactors)
|
||||||
bt.setFactors(false, posFactors.timeFactor+float64(capacity)*posFactors.capacityFactor/1000000, posFactors.requestFactor)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// zeroPriceFactors sets the pricing factors to zero
|
// zeroPriceFactors sets the pricing factors to zero
|
||||||
func zeroPriceFactors(bt *balanceTracker) {
|
func zeroPriceFactors(bt *balanceTracker) {
|
||||||
bt.setFactors(true, 0, 0)
|
bt.setFactors(priceFactors{0, 0, 0}, priceFactors{0, 0, 0})
|
||||||
bt.setFactors(false, 0, 0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// getPosBalance retrieves a single positive balance entry from cache or the database
|
// getPosBalance retrieves a single positive balance entry from cache or the database
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue