taskmerger.go 2.44 KB
Newer Older
dirkmc's avatar
dirkmc committed
1 2 3
package decision

import (
4
	"gitlab.dms3.io/dms3/go-peertaskqueue/peertask"
dirkmc's avatar
dirkmc committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
)

// taskData is extra data associated with each task in the request queue
type taskData struct {
	// Tasks can be want-have or want-block
	IsWantBlock bool
	// Whether to immediately send a response if the block is not found
	SendDontHave bool
	// The size of the block corresponding to the task
	BlockSize int
	// Whether the block was found
	HaveBlock bool
}

type taskMerger struct{}

func newTaskMerger() *taskMerger {
	return &taskMerger{}
}

// The request queue uses this Method to decide if a newly pushed task has any
// new information beyond the tasks with the same Topic (CID) in the queue.
func (*taskMerger) HasNewInfo(task peertask.Task, existing []peertask.Task) bool {
	haveSize := false
	isWantBlock := false
	for _, et := range existing {
		etd := et.Data.(*taskData)
		if etd.HaveBlock {
			haveSize = true
		}

		if etd.IsWantBlock {
			isWantBlock = true
		}
	}

	// If there is no active want-block and the new task is a want-block,
	// the new task is better
	newTaskData := task.Data.(*taskData)
	if !isWantBlock && newTaskData.IsWantBlock {
		return true
	}

	// If there is no size information for the CID and the new task has
	// size information, the new task is better
	if !haveSize && newTaskData.HaveBlock {
		return true
	}

	return false
}

// The request queue uses Merge to merge a newly pushed task with an existing
// task with the same Topic (CID)
func (*taskMerger) Merge(task peertask.Task, existing *peertask.Task) {
	newTask := task.Data.(*taskData)
	existingTask := existing.Data.(*taskData)

	// If we now have block size information, update the task with
	// the new block size
	if !existingTask.HaveBlock && newTask.HaveBlock {
		existingTask.HaveBlock = newTask.HaveBlock
		existingTask.BlockSize = newTask.BlockSize
	}

	// If replacing a want-have with a want-block
	if !existingTask.IsWantBlock && newTask.IsWantBlock {
		// Change the type from want-have to want-block
		existingTask.IsWantBlock = true
		// If the want-have was a DONT_HAVE, or the want-block has a size
		if !existingTask.HaveBlock || newTask.HaveBlock {
			// Update the entry size
			existingTask.HaveBlock = newTask.HaveBlock
			existing.Work = task.Work
		}
	}

	// If the task is a want-block, make sure the entry size is equal
	// to the block size (because we will send the whole block)
	if existingTask.IsWantBlock && existingTask.HaveBlock {
		existing.Work = existingTask.BlockSize
	}
}