mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
les: serving queue docs and fixed total capacity logic
This commit is contained in:
parent
a67f0ae4ad
commit
bd460f3deb
3 changed files with 114 additions and 56 deletions
118
les/handler.go
118
les/handler.go
|
|
@ -366,7 +366,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
|
|
||||||
var deliverMsg *Msg
|
var deliverMsg *Msg
|
||||||
|
|
||||||
sendReq := func(reqID, amount uint64, reply *reply, servingTime uint64) {
|
sendResponse := func(reqID, amount uint64, reply *reply, servingTime uint64) {
|
||||||
p.responseLock.Lock()
|
p.responseLock.Lock()
|
||||||
defer p.responseLock.Unlock()
|
defer p.responseLock.Unlock()
|
||||||
|
|
||||||
|
|
@ -457,11 +457,13 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
unknown bool
|
unknown bool
|
||||||
)
|
)
|
||||||
for !unknown && len(headers) < int(query.Amount) && bytes < softResponseLimit {
|
for !unknown && len(headers) < int(query.Amount) && bytes < softResponseLimit {
|
||||||
|
if !first && !task.waitOrStop() {
|
||||||
|
return
|
||||||
|
}
|
||||||
// Retrieve the next header satisfying the query
|
// Retrieve the next header satisfying the query
|
||||||
var origin *types.Header
|
var origin *types.Header
|
||||||
if hashMode {
|
if hashMode {
|
||||||
if first {
|
if first {
|
||||||
first = false
|
|
||||||
origin = pm.blockchain.GetHeaderByHash(query.Origin.Hash)
|
origin = pm.blockchain.GetHeaderByHash(query.Origin.Hash)
|
||||||
if origin != nil {
|
if origin != nil {
|
||||||
query.Origin.Number = origin.Number.Uint64()
|
query.Origin.Number = origin.Number.Uint64()
|
||||||
|
|
@ -524,8 +526,9 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
// Number based traversal towards the leaf block
|
// Number based traversal towards the leaf block
|
||||||
query.Origin.Number += query.Skip + 1
|
query.Origin.Number += query.Skip + 1
|
||||||
}
|
}
|
||||||
|
first = false
|
||||||
}
|
}
|
||||||
sendReq(req.ReqID, query.Amount, p.ReplyBlockHeaders(req.ReqID, headers), task.done())
|
sendResponse(req.ReqID, query.Amount, p.ReplyBlockHeaders(req.ReqID, headers), task.done())
|
||||||
}()
|
}()
|
||||||
|
|
||||||
case BlockHeadersMsg:
|
case BlockHeadersMsg:
|
||||||
|
|
@ -572,7 +575,10 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
return errResp(ErrRequestRejected, "")
|
return errResp(ErrRequestRejected, "")
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
for _, hash := range req.Hashes {
|
for i, hash := range req.Hashes {
|
||||||
|
if i != 0 && !task.waitOrStop() {
|
||||||
|
return
|
||||||
|
}
|
||||||
if bytes >= softResponseLimit {
|
if bytes >= softResponseLimit {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -584,7 +590,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sendReq(req.ReqID, uint64(reqCnt), p.ReplyBlockBodiesRLP(req.ReqID, bodies), task.done())
|
sendResponse(req.ReqID, uint64(reqCnt), p.ReplyBlockBodiesRLP(req.ReqID, bodies), task.done())
|
||||||
}()
|
}()
|
||||||
|
|
||||||
case BlockBodiesMsg:
|
case BlockBodiesMsg:
|
||||||
|
|
@ -628,7 +634,10 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
return errResp(ErrRequestRejected, "")
|
return errResp(ErrRequestRejected, "")
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
for _, req := range req.Reqs {
|
for i, req := range req.Reqs {
|
||||||
|
if i != 0 && !task.waitOrStop() {
|
||||||
|
return
|
||||||
|
}
|
||||||
// Retrieve the requested state entry, stopping if enough was found
|
// Retrieve the requested state entry, stopping if enough was found
|
||||||
if number := rawdb.ReadHeaderNumber(pm.chainDb, req.BHash); number != nil {
|
if number := rawdb.ReadHeaderNumber(pm.chainDb, req.BHash); number != nil {
|
||||||
if header := rawdb.ReadHeader(pm.chainDb, req.BHash, *number); header != nil {
|
if header := rawdb.ReadHeader(pm.chainDb, req.BHash, *number); header != nil {
|
||||||
|
|
@ -649,7 +658,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sendReq(req.ReqID, uint64(reqCnt), p.ReplyCode(req.ReqID, data), task.done())
|
sendResponse(req.ReqID, uint64(reqCnt), p.ReplyCode(req.ReqID, data), task.done())
|
||||||
}()
|
}()
|
||||||
|
|
||||||
case CodeMsg:
|
case CodeMsg:
|
||||||
|
|
@ -693,7 +702,10 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
return errResp(ErrRequestRejected, "")
|
return errResp(ErrRequestRejected, "")
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
for _, hash := range req.Hashes {
|
for i, hash := range req.Hashes {
|
||||||
|
if i != 0 && !task.waitOrStop() {
|
||||||
|
return
|
||||||
|
}
|
||||||
if bytes >= softResponseLimit {
|
if bytes >= softResponseLimit {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -715,7 +727,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
bytes += len(encoded)
|
bytes += len(encoded)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sendReq(req.ReqID, uint64(reqCnt), p.ReplyReceiptsRLP(req.ReqID, receipts), task.done())
|
sendResponse(req.ReqID, uint64(reqCnt), p.ReplyReceiptsRLP(req.ReqID, receipts), task.done())
|
||||||
}()
|
}()
|
||||||
|
|
||||||
case ReceiptsMsg:
|
case ReceiptsMsg:
|
||||||
|
|
@ -759,7 +771,10 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
return errResp(ErrRequestRejected, "")
|
return errResp(ErrRequestRejected, "")
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
for _, req := range req.Reqs {
|
for i, req := range req.Reqs {
|
||||||
|
if i != 0 && !task.waitOrStop() {
|
||||||
|
return
|
||||||
|
}
|
||||||
// Retrieve the requested state entry, stopping if enough was found
|
// Retrieve the requested state entry, stopping if enough was found
|
||||||
if number := rawdb.ReadHeaderNumber(pm.chainDb, req.BHash); number != nil {
|
if number := rawdb.ReadHeaderNumber(pm.chainDb, req.BHash); number != nil {
|
||||||
if header := rawdb.ReadHeader(pm.chainDb, req.BHash, *number); header != nil {
|
if header := rawdb.ReadHeader(pm.chainDb, req.BHash, *number); header != nil {
|
||||||
|
|
@ -789,7 +804,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sendReq(req.ReqID, uint64(reqCnt), p.ReplyProofs(req.ReqID, proofs), task.done())
|
sendResponse(req.ReqID, uint64(reqCnt), p.ReplyProofs(req.ReqID, proofs), task.done())
|
||||||
}()
|
}()
|
||||||
|
|
||||||
case GetProofsV2Msg:
|
case GetProofsV2Msg:
|
||||||
|
|
@ -816,7 +831,10 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
|
|
||||||
nodes := light.NewNodeSet()
|
nodes := light.NewNodeSet()
|
||||||
|
|
||||||
for _, req := range req.Reqs {
|
for i, req := range req.Reqs {
|
||||||
|
if i != 0 && !task.waitOrStop() {
|
||||||
|
return
|
||||||
|
}
|
||||||
// Look up the state belonging to the request
|
// Look up the state belonging to the request
|
||||||
if statedb == nil || req.BHash != lastBHash {
|
if statedb == nil || req.BHash != lastBHash {
|
||||||
statedb, root, lastBHash = nil, common.Hash{}, req.BHash
|
statedb, root, lastBHash = nil, common.Hash{}, req.BHash
|
||||||
|
|
@ -851,7 +869,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sendReq(req.ReqID, uint64(reqCnt), p.ReplyProofsV2(req.ReqID, nodes.NodeList()), task.done())
|
sendResponse(req.ReqID, uint64(reqCnt), p.ReplyProofsV2(req.ReqID, nodes.NodeList()), task.done())
|
||||||
}()
|
}()
|
||||||
|
|
||||||
case ProofsV1Msg:
|
case ProofsV1Msg:
|
||||||
|
|
@ -917,7 +935,10 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
trieDb := trie.NewDatabase(ethdb.NewTable(pm.chainDb, light.ChtTablePrefix))
|
trieDb := trie.NewDatabase(ethdb.NewTable(pm.chainDb, light.ChtTablePrefix))
|
||||||
for _, req := range req.Reqs {
|
for i, req := range req.Reqs {
|
||||||
|
if i != 0 && !task.waitOrStop() {
|
||||||
|
return
|
||||||
|
}
|
||||||
if header := pm.blockchain.GetHeaderByNumber(req.BlockNum); header != nil {
|
if header := pm.blockchain.GetHeaderByNumber(req.BlockNum); header != nil {
|
||||||
sectionHead := rawdb.ReadCanonicalHash(pm.chainDb, req.ChtNum*pm.iConfig.ChtSize-1)
|
sectionHead := rawdb.ReadCanonicalHash(pm.chainDb, req.ChtNum*pm.iConfig.ChtSize-1)
|
||||||
if root := light.GetChtRoot(pm.chainDb, req.ChtNum-1, sectionHead); root != (common.Hash{}) {
|
if root := light.GetChtRoot(pm.chainDb, req.ChtNum-1, sectionHead); root != (common.Hash{}) {
|
||||||
|
|
@ -938,7 +959,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sendReq(req.ReqID, uint64(reqCnt), p.ReplyHeaderProofs(req.ReqID, proofs), task.done())
|
sendResponse(req.ReqID, uint64(reqCnt), p.ReplyHeaderProofs(req.ReqID, proofs), task.done())
|
||||||
}()
|
}()
|
||||||
|
|
||||||
case GetHelperTrieProofsMsg:
|
case GetHelperTrieProofsMsg:
|
||||||
|
|
@ -969,7 +990,10 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
auxTrie *trie.Trie
|
auxTrie *trie.Trie
|
||||||
)
|
)
|
||||||
nodes := light.NewNodeSet()
|
nodes := light.NewNodeSet()
|
||||||
for _, req := range req.Reqs {
|
for i, req := range req.Reqs {
|
||||||
|
if i != 0 && !task.waitOrStop() {
|
||||||
|
return
|
||||||
|
}
|
||||||
if auxTrie == nil || req.Type != lastType || req.TrieIdx != lastIdx {
|
if auxTrie == nil || req.Type != lastType || req.TrieIdx != lastIdx {
|
||||||
auxTrie, lastType, lastIdx = nil, req.Type, req.TrieIdx
|
auxTrie, lastType, lastIdx = nil, req.Type, req.TrieIdx
|
||||||
|
|
||||||
|
|
@ -999,7 +1023,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sendReq(req.ReqID, uint64(reqCnt), p.ReplyHelperTrieProofs(req.ReqID, HelperTrieResps{Proofs: nodes.NodeList(), AuxData: auxData}), task.done())
|
sendResponse(req.ReqID, uint64(reqCnt), p.ReplyHelperTrieProofs(req.ReqID, HelperTrieResps{Proofs: nodes.NodeList(), AuxData: auxData}), task.done())
|
||||||
}()
|
}()
|
||||||
|
|
||||||
case HeaderProofsMsg:
|
case HeaderProofsMsg:
|
||||||
|
|
@ -1057,8 +1081,13 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
return errResp(ErrRequestRejected, "")
|
return errResp(ErrRequestRejected, "")
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
pm.txpool.AddRemotes(txs)
|
for i, tx := range txs {
|
||||||
sendReq(0, uint64(reqCnt), nil, task.done())
|
if i != 0 && !task.waitOrStop() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pm.txpool.AddRemotes([]*types.Transaction{tx})
|
||||||
|
}
|
||||||
|
sendResponse(0, uint64(reqCnt), nil, task.done())
|
||||||
}()
|
}()
|
||||||
|
|
||||||
case SendTxV2Msg:
|
case SendTxV2Msg:
|
||||||
|
|
@ -1078,21 +1107,22 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
return errResp(ErrRequestRejected, "")
|
return errResp(ErrRequestRejected, "")
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
hashes := make([]common.Hash, len(req.Txs))
|
stats := make([]txStatus, len(req.Txs))
|
||||||
for i, tx := range req.Txs {
|
for i, tx := range req.Txs {
|
||||||
hashes[i] = tx.Hash()
|
if i != 0 && !task.waitOrStop() {
|
||||||
}
|
return
|
||||||
stats := pm.txStatus(hashes)
|
}
|
||||||
for i, stat := range stats {
|
hash := tx.Hash()
|
||||||
if stat.Status == core.TxStatusUnknown {
|
stats[i] = pm.txStatus(hash)
|
||||||
if errs := pm.txpool.AddRemotes([]*types.Transaction{req.Txs[i]}); errs[0] != nil {
|
if stats[i].Status == core.TxStatusUnknown {
|
||||||
|
if errs := pm.txpool.AddRemotes([]*types.Transaction{tx}); errs[0] != nil {
|
||||||
stats[i].Error = errs[0].Error()
|
stats[i].Error = errs[0].Error()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
stats[i] = pm.txStatus([]common.Hash{hashes[i]})[0]
|
stats[i] = pm.txStatus(hash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sendReq(req.ReqID, uint64(reqCnt), p.ReplyTxStatus(req.ReqID, stats), task.done())
|
sendResponse(req.ReqID, uint64(reqCnt), p.ReplyTxStatus(req.ReqID, stats), task.done())
|
||||||
}()
|
}()
|
||||||
|
|
||||||
case GetTxStatusMsg:
|
case GetTxStatusMsg:
|
||||||
|
|
@ -1112,8 +1142,14 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
return errResp(ErrRequestRejected, "")
|
return errResp(ErrRequestRejected, "")
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
stats := pm.txStatus(req.Hashes)
|
stats := make([]txStatus, len(req.Hashes))
|
||||||
sendReq(req.ReqID, uint64(reqCnt), p.ReplyTxStatus(req.ReqID, stats), task.done())
|
for i, hash := range req.Hashes {
|
||||||
|
if i != 0 && !task.waitOrStop() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
stats[i] = pm.txStatus(hash)
|
||||||
|
}
|
||||||
|
sendResponse(req.ReqID, uint64(reqCnt), p.ReplyTxStatus(req.ReqID, stats), task.done())
|
||||||
}()
|
}()
|
||||||
|
|
||||||
case TxStatusMsg:
|
case TxStatusMsg:
|
||||||
|
|
@ -1190,21 +1226,17 @@ func (pm *ProtocolManager) getHelperTrieAuxData(req HelperTrieReq) []byte {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pm *ProtocolManager) txStatus(hashes []common.Hash) []txStatus {
|
func (pm *ProtocolManager) txStatus(hash common.Hash) txStatus {
|
||||||
stats := make([]txStatus, len(hashes))
|
var stat txStatus
|
||||||
for i, stat := range pm.txpool.Status(hashes) {
|
stat.Status = pm.txpool.Status([]common.Hash{hash})[0]
|
||||||
// Save the status we've got from the transaction pool
|
// If the transaction is unknown to the pool, try looking it up locally
|
||||||
stats[i].Status = stat
|
if stat.Status == core.TxStatusUnknown {
|
||||||
|
if tx, blockHash, blockNumber, txIndex := rawdb.ReadTransaction(pm.chainDb, hash); tx != nil {
|
||||||
// If the transaction is unknown to the pool, try looking it up locally
|
stat.Status = core.TxStatusIncluded
|
||||||
if stat == core.TxStatusUnknown {
|
stat.Lookup = &rawdb.LegacyTxLookupEntry{BlockHash: blockHash, BlockIndex: blockNumber, Index: txIndex}
|
||||||
if tx, blockHash, blockNumber, txIndex := rawdb.ReadTransaction(pm.chainDb, hashes[i]); tx != nil {
|
|
||||||
stats[i].Status = core.TxStatusIncluded
|
|
||||||
stats[i].Lookup = &rawdb.LegacyTxLookupEntry{BlockHash: blockHash, BlockIndex: blockNumber, Index: txIndex}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return stats
|
return stat
|
||||||
}
|
}
|
||||||
|
|
||||||
// isULCEnabled returns true if we can use ULC
|
// isULCEnabled returns true if we can use ULC
|
||||||
|
|
|
||||||
|
|
@ -154,18 +154,20 @@ func (s *LesServer) startEventLoop() {
|
||||||
totalRechargeCh := make(chan uint64, 100)
|
totalRechargeCh := make(chan uint64, 100)
|
||||||
totalRecharge := s.costTracker.subscribeTotalRecharge(totalRechargeCh)
|
totalRecharge := s.costTracker.subscribeTotalRecharge(totalRechargeCh)
|
||||||
totalCapacityCh := make(chan uint64, 100)
|
totalCapacityCh := make(chan uint64, 100)
|
||||||
|
updateRecharge := func() {
|
||||||
|
if processing {
|
||||||
|
s.protocolManager.servingQueue.setThreads(s.thcBlockProcessing)
|
||||||
|
s.fcManager.SetRechargeCurve(flowcontrol.PieceWiseLinear{{0, 0}, {totalRecharge, totalRecharge}})
|
||||||
|
} else {
|
||||||
|
s.protocolManager.servingQueue.setThreads(s.thcNormal)
|
||||||
|
s.fcManager.SetRechargeCurve(flowcontrol.PieceWiseLinear{{0, 0}, {totalRecharge / 10, totalRecharge}, {totalRecharge, totalRecharge}})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateRecharge()
|
||||||
totalCapacity := s.fcManager.SubscribeTotalCapacity(totalCapacityCh)
|
totalCapacity := s.fcManager.SubscribeTotalCapacity(totalCapacityCh)
|
||||||
|
s.priorityClientPool.setLimits(s.maxPeers, totalCapacity)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
updateRecharge := func() {
|
|
||||||
if processing {
|
|
||||||
s.protocolManager.servingQueue.setThreads(s.thcBlockProcessing)
|
|
||||||
s.fcManager.SetRechargeCurve(flowcontrol.PieceWiseLinear{{0, 0}, {totalRecharge, totalRecharge}})
|
|
||||||
} else {
|
|
||||||
s.protocolManager.servingQueue.setThreads(s.thcNormal)
|
|
||||||
s.fcManager.SetRechargeCurve(flowcontrol.PieceWiseLinear{{0, 0}, {totalRecharge / 10, totalRecharge}, {totalRecharge, totalRecharge}})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case processing = <-blockProcFeed:
|
case processing = <-blockProcFeed:
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common/prque"
|
"github.com/ethereum/go-ethereum/common/prque"
|
||||||
)
|
)
|
||||||
|
|
||||||
// servingQueue runs serving tasks in a limited number of threads and puts the
|
// servingQueue allows running tasks in a limited number of threads and puts the
|
||||||
// waiting tasks in a priority queue
|
// waiting tasks in a priority queue
|
||||||
type servingQueue struct {
|
type servingQueue struct {
|
||||||
tokenCh chan runToken
|
tokenCh chan runToken
|
||||||
|
|
@ -34,7 +34,7 @@ type servingQueue struct {
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
threadCount int // number of currently running threads
|
threadCount int // number of currently running threads
|
||||||
queue *prque.Prque // priority queue for waiting or suspended tasks
|
queue *prque.Prque // priority queue for waiting or suspended tasks
|
||||||
best *servingTask // either best == nil (queue empty) or waitingForTask is empty
|
best *servingTask // the highest priority task (not included in the queue)
|
||||||
suspendBias int64 // priority bias against suspending an already running task
|
suspendBias int64 // priority bias against suspending an already running task
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -55,8 +55,13 @@ type servingTask struct {
|
||||||
tokenCh chan runToken
|
tokenCh chan runToken
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// runToken received by servingTask.start allows the task to run. Closing the
|
||||||
|
// channel by servingTask.stop signals the thread controller to allow a new task
|
||||||
|
// to start running.
|
||||||
type runToken chan struct{}
|
type runToken chan struct{}
|
||||||
|
|
||||||
|
// start blocks until the task can start and returns true if it is allowed to run.
|
||||||
|
// Returning false means that the task should be cancelled.
|
||||||
func (t *servingTask) start() bool {
|
func (t *servingTask) start() bool {
|
||||||
select {
|
select {
|
||||||
case t.token = <-t.sq.tokenCh:
|
case t.token = <-t.sq.tokenCh:
|
||||||
|
|
@ -80,12 +85,18 @@ func (t *servingTask) start() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// done signals the thread controller about the task being finished and returns
|
||||||
|
// the total serving time of the task in nanoseconds.
|
||||||
func (t *servingTask) done() uint64 {
|
func (t *servingTask) done() uint64 {
|
||||||
t.servingTime += uint64(mclock.Now())
|
t.servingTime += uint64(mclock.Now())
|
||||||
close(t.token)
|
close(t.token)
|
||||||
return t.servingTime
|
return t.servingTime
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// waitOrStop can be called during the execution of the task. It blocks if there
|
||||||
|
// is a higher priority task waiting (a bias is applied in favor of the currently
|
||||||
|
// running task). Returning true means that the execution can be resumed. False
|
||||||
|
// means the task should be cancelled.
|
||||||
func (t *servingTask) waitOrStop() bool {
|
func (t *servingTask) waitOrStop() bool {
|
||||||
t.done()
|
t.done()
|
||||||
if !t.biasAdded {
|
if !t.biasAdded {
|
||||||
|
|
@ -113,6 +124,7 @@ func newServingQueue(suspendBias int64) *servingQueue {
|
||||||
return sq
|
return sq
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// newTask creates a new task with the given priority
|
||||||
func (sq *servingQueue) newTask(priority int64) *servingTask {
|
func (sq *servingQueue) newTask(priority int64) *servingTask {
|
||||||
return &servingTask{
|
return &servingTask{
|
||||||
sq: sq,
|
sq: sq,
|
||||||
|
|
@ -120,6 +132,12 @@ func (sq *servingQueue) newTask(priority int64) *servingTask {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// threadController is started in multiple goroutines and controls the execution
|
||||||
|
// of tasks. The number of active thread controllers equals the allowed number of
|
||||||
|
// concurrently running threads. It tries to fetch the highest priority queued
|
||||||
|
// task first. If there are no queued tasks waiting then it can directly catch
|
||||||
|
// run tokens from the token channel and allow the corresponding tasks to run
|
||||||
|
// without entering the priority queue.
|
||||||
func (sq *servingQueue) threadController() {
|
func (sq *servingQueue) threadController() {
|
||||||
for {
|
for {
|
||||||
token := make(runToken)
|
token := make(runToken)
|
||||||
|
|
@ -152,6 +170,7 @@ func (sq *servingQueue) threadController() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// addTask inserts a task into the priority queue
|
||||||
func (sq *servingQueue) addTask(task *servingTask) {
|
func (sq *servingQueue) addTask(task *servingTask) {
|
||||||
if sq.best == nil {
|
if sq.best == nil {
|
||||||
sq.best = task
|
sq.best = task
|
||||||
|
|
@ -164,6 +183,9 @@ func (sq *servingQueue) addTask(task *servingTask) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// queueLoop is an event loop running in a goroutine. It receives tasks from queueAddCh
|
||||||
|
// and always tries to send the highest priority task to queueBestCh. Successfully sent
|
||||||
|
// tasks are removed from the queue.
|
||||||
func (sq *servingQueue) queueLoop() {
|
func (sq *servingQueue) queueLoop() {
|
||||||
for {
|
for {
|
||||||
if sq.best != nil {
|
if sq.best != nil {
|
||||||
|
|
@ -192,6 +214,8 @@ func (sq *servingQueue) queueLoop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// threadCountLoop is an event loop running in a goroutine. It adjusts the number
|
||||||
|
// of active thread controller goroutines.
|
||||||
func (sq *servingQueue) threadCountLoop() {
|
func (sq *servingQueue) threadCountLoop() {
|
||||||
var threadCountTarget int
|
var threadCountTarget int
|
||||||
for {
|
for {
|
||||||
|
|
@ -220,7 +244,7 @@ func (sq *servingQueue) threadCountLoop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// setThreads sets the processing thread count, suspending tasks as soon as
|
// setThreads sets the allowed processing thread count, suspending tasks as soon as
|
||||||
// possible if necessary.
|
// possible if necessary.
|
||||||
func (sq *servingQueue) setThreads(threadCount int) {
|
func (sq *servingQueue) setThreads(threadCount int) {
|
||||||
select {
|
select {
|
||||||
|
|
@ -230,7 +254,7 @@ func (sq *servingQueue) setThreads(threadCount int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop stops task processing as soon as possible
|
// stop stops task processing as soon as possible and shuts down the serving queue.
|
||||||
func (sq *servingQueue) stop() {
|
func (sq *servingQueue) stop() {
|
||||||
close(sq.quit)
|
close(sq.quit)
|
||||||
sq.wg.Wait()
|
sq.wg.Wait()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue