tasklist.go 1.69 KB
Newer Older
Jeromy's avatar
Jeromy committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
package strategy

import (
	peer "github.com/jbenet/go-ipfs/peer"
	u "github.com/jbenet/go-ipfs/util"
)

// TODO: at some point, the strategy needs to plug in here
// to help decide how to sort tasks (on add) and how to select
// tasks (on getnext). For now, we are assuming a dumb/nice strategy.
type TaskList struct {
	tasks   []*Task
	taskmap map[u.Key]*Task
}

func NewTaskList() *TaskList {
	return &TaskList{
		taskmap: make(map[u.Key]*Task),
	}
}

type Task struct {
	Key           u.Key
	Target        peer.Peer
	theirPriority int
}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
28
// Push currently adds a new task to the end of the list
Jeromy's avatar
Jeromy committed
29
// TODO: make this into a priority queue
Brian Tiger Chow's avatar
Brian Tiger Chow committed
30
func (tl *TaskList) Push(block u.Key, priority int, to peer.Peer) {
Jeromy's avatar
Jeromy committed
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
	if task, ok := tl.taskmap[to.Key()+block]; ok {
		// TODO: when priority queue is implemented,
		//       rearrange this Task
		task.theirPriority = priority
		return
	}
	task := &Task{
		Key:           block,
		Target:        to,
		theirPriority: priority,
	}
	tl.tasks = append(tl.tasks, task)
	tl.taskmap[to.Key()+block] = task
}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
46
// Pop 'pops' the next task to be performed. Returns nil no task exists.
Brian Tiger Chow's avatar
Brian Tiger Chow committed
47
func (tl *TaskList) Pop() *Task {
Jeromy's avatar
Jeromy committed
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
	var out *Task
	for len(tl.tasks) > 0 {
		// TODO: instead of zero, use exponential distribution
		//       it will help reduce the chance of receiving
		//		 the same block from multiple peers
		out = tl.tasks[0]
		tl.tasks = tl.tasks[1:]
		delete(tl.taskmap, out.Target.Key()+out.Key)
		// Filter out blocks that have been cancelled
		if out.theirPriority >= 0 {
			break
		}
	}

	return out
}

// Cancel lazily cancels the sending of a block to a given peer
func (tl *TaskList) Cancel(k u.Key, p peer.Peer) {
	t, ok := tl.taskmap[p.Key()+k]
	if ok {
		t.theirPriority = -1
	}
}