Example #1
0
// reserveHashes reserves a set of hashes for the given peer, skipping previously
// failed ones.
//
// Note, this method expects the queue lock to be already held for writing. The
// reason the lock is not obtained in here is because the parameters already need
// to access the queue, so they already need a lock anyway.
func (q *queue) reserveHashes(p *peer, count int, taskQueue *prque.Prque, taskGen func(int), pendPool map[string]*fetchRequest, maxPending int) *fetchRequest {
	// Short circuit if the peer's already downloading something (sanity check to
	// not corrupt state)
	if _, ok := pendPool[p.id]; ok {
		return nil
	}
	// Calculate an upper limit on the hashes we might fetch (i.e. throttling)
	allowance := maxPending
	if allowance > 0 {
		for _, request := range pendPool {
			allowance -= len(request.Hashes)
		}
	}
	// If there's a task generator, ask it to fill our task queue
	if taskGen != nil && taskQueue.Size() < allowance {
		taskGen(allowance - taskQueue.Size())
	}
	if taskQueue.Empty() {
		return nil
	}
	// Retrieve a batch of hashes, skipping previously failed ones
	send := make(map[common.Hash]int)
	skip := make(map[common.Hash]int)

	for proc := 0; (allowance == 0 || proc < allowance) && len(send) < count && !taskQueue.Empty(); proc++ {
		hash, priority := taskQueue.Pop()
		if p.Lacks(hash.(common.Hash)) {
			skip[hash.(common.Hash)] = int(priority)
		} else {
			send[hash.(common.Hash)] = int(priority)
		}
	}
	// Merge all the skipped hashes back
	for hash, index := range skip {
		taskQueue.Push(hash, float32(index))
	}
	// Assemble and return the block download request
	if len(send) == 0 {
		return nil
	}
	request := &fetchRequest{
		Peer:   p,
		Hashes: send,
		Time:   time.Now(),
	}
	pendPool[p.id] = request

	return request
}