parent
975857fc85
commit
0da96b942e
@ -0,0 +1,172 @@ |
||||
package stagedstreamsync |
||||
|
||||
import ( |
||||
"sync" |
||||
|
||||
sttypes "github.com/harmony-one/harmony/p2p/stream/types" |
||||
"github.com/ledgerwatch/erigon-lib/kv" |
||||
"github.com/rs/zerolog" |
||||
) |
||||
|
||||
type ReceiptDownloadDetails struct { |
||||
loopID int |
||||
streamID sttypes.StreamID |
||||
} |
||||
|
||||
// receiptDownloadManager is the helper structure for get receipts request management
|
||||
type receiptDownloadManager struct { |
||||
chain blockChain |
||||
tx kv.RwTx |
||||
|
||||
targetBN uint64 |
||||
requesting map[uint64]struct{} // receipt numbers that have been assigned to workers but not received
|
||||
processing map[uint64]struct{} // receipt numbers received requests but not inserted
|
||||
retries *prioritizedNumbers // requests where error happens
|
||||
rq *resultQueue // result queue wait to be inserted into blockchain
|
||||
rdd map[uint64]ReceiptDownloadDetails // details about how this receipt was downloaded
|
||||
|
||||
logger zerolog.Logger |
||||
lock sync.Mutex |
||||
} |
||||
|
||||
func newReceiptDownloadManager(tx kv.RwTx, chain blockChain, targetBN uint64, logger zerolog.Logger) *receiptDownloadManager { |
||||
return &receiptDownloadManager{ |
||||
chain: chain, |
||||
tx: tx, |
||||
targetBN: targetBN, |
||||
requesting: make(map[uint64]struct{}), |
||||
processing: make(map[uint64]struct{}), |
||||
retries: newPrioritizedNumbers(), |
||||
rq: newResultQueue(), |
||||
rdd: make(map[uint64]ReceiptDownloadDetails), |
||||
logger: logger, |
||||
} |
||||
} |
||||
|
||||
// GetNextBatch get the next receipt numbers batch
|
||||
func (rdm *receiptDownloadManager) GetNextBatch() []uint64 { |
||||
rdm.lock.Lock() |
||||
defer rdm.lock.Unlock() |
||||
|
||||
cap := ReceiptsPerRequest |
||||
|
||||
bns := rdm.getBatchFromRetries(cap) |
||||
if len(bns) > 0 { |
||||
cap -= len(bns) |
||||
rdm.addBatchToRequesting(bns) |
||||
} |
||||
|
||||
if rdm.availableForMoreTasks() { |
||||
addBNs := rdm.getBatchFromUnprocessed(cap) |
||||
rdm.addBatchToRequesting(addBNs) |
||||
bns = append(bns, addBNs...) |
||||
} |
||||
|
||||
return bns |
||||
} |
||||
|
||||
// HandleRequestError handles the error result
|
||||
func (rdm *receiptDownloadManager) HandleRequestError(bns []uint64, err error, streamID sttypes.StreamID) { |
||||
rdm.lock.Lock() |
||||
defer rdm.lock.Unlock() |
||||
|
||||
// add requested receipt numbers to retries
|
||||
for _, bn := range bns { |
||||
delete(rdm.requesting, bn) |
||||
rdm.retries.push(bn) |
||||
} |
||||
} |
||||
|
||||
// HandleRequestResult handles get blocks result
|
||||
func (rdm *receiptDownloadManager) HandleRequestResult(bns []uint64, blockBytes [][]byte, sigBytes [][]byte, loopID int, streamID sttypes.StreamID) error { |
||||
rdm.lock.Lock() |
||||
defer rdm.lock.Unlock() |
||||
|
||||
for i, bn := range bns { |
||||
delete(rdm.requesting, bn) |
||||
if indexExists(blockBytes, i) && len(blockBytes[i]) <= 1 { |
||||
rdm.retries.push(bn) |
||||
} else { |
||||
rdm.processing[bn] = struct{}{} |
||||
rdm.rdd[bn] = ReceiptDownloadDetails{ |
||||
loopID: loopID, |
||||
streamID: streamID, |
||||
} |
||||
} |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// SetDownloadDetails sets the download details for a batch of blocks
|
||||
func (rdm *receiptDownloadManager) SetDownloadDetails(bns []uint64, loopID int, streamID sttypes.StreamID) error { |
||||
rdm.lock.Lock() |
||||
defer rdm.lock.Unlock() |
||||
|
||||
for _, bn := range bns { |
||||
rdm.rdd[bn] = ReceiptDownloadDetails{ |
||||
loopID: loopID, |
||||
streamID: streamID, |
||||
} |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// GetDownloadDetails returns the download details for a receipt
|
||||
func (rdm *receiptDownloadManager) GetDownloadDetails(blockNumber uint64) (loopID int, streamID sttypes.StreamID) { |
||||
rdm.lock.Lock() |
||||
defer rdm.lock.Unlock() |
||||
|
||||
return rdm.rdd[blockNumber].loopID, rdm.rdd[blockNumber].streamID |
||||
} |
||||
|
||||
// getBatchFromRetries get the receipt number batch to be requested from retries.
|
||||
func (rdm *receiptDownloadManager) getBatchFromRetries(cap int) []uint64 { |
||||
var ( |
||||
requestBNs []uint64 |
||||
curHeight = rdm.chain.CurrentBlock().NumberU64() |
||||
) |
||||
for cnt := 0; cnt < cap; cnt++ { |
||||
bn := rdm.retries.pop() |
||||
if bn == 0 { |
||||
break // no more retries
|
||||
} |
||||
if bn <= curHeight { |
||||
continue |
||||
} |
||||
requestBNs = append(requestBNs, bn) |
||||
} |
||||
return requestBNs |
||||
} |
||||
|
||||
// getBatchFromUnprocessed returns a batch of receipt numbers to be requested from unprocessed.
|
||||
func (rdm *receiptDownloadManager) getBatchFromUnprocessed(cap int) []uint64 { |
||||
var ( |
||||
requestBNs []uint64 |
||||
curHeight = rdm.chain.CurrentBlock().NumberU64() |
||||
) |
||||
bn := curHeight + 1 |
||||
// TODO: this algorithm can be potentially optimized.
|
||||
for cnt := 0; cnt < cap && bn <= rdm.targetBN; cnt++ { |
||||
for bn <= rdm.targetBN { |
||||
_, ok1 := rdm.requesting[bn] |
||||
_, ok2 := rdm.processing[bn] |
||||
if !ok1 && !ok2 { |
||||
requestBNs = append(requestBNs, bn) |
||||
bn++ |
||||
break |
||||
} |
||||
bn++ |
||||
} |
||||
} |
||||
return requestBNs |
||||
} |
||||
|
||||
func (rdm *receiptDownloadManager) availableForMoreTasks() bool { |
||||
return rdm.rq.results.Len() < SoftQueueCap |
||||
} |
||||
|
||||
func (rdm *receiptDownloadManager) addBatchToRequesting(bns []uint64) { |
||||
for _, bn := range bns { |
||||
rdm.requesting[bn] = struct{}{} |
||||
} |
||||
} |
Loading…
Reference in new issue