wantlist.go 2.88 KB
Newer Older
1
// Package wantlist implements an object for bitswap that contains the keys
Jeromy's avatar
Jeromy committed
2
// that a given peer wants.
Jeromy's avatar
Jeromy committed
3 4 5 6
package wantlist

import (
	"sort"
7

8
	pb "gitlab.dms3.io/dms3/go-bitswap/message/pb"
dirkmc's avatar
dirkmc committed
9

10
	cid "gitlab.dms3.io/dms3/go-cid"
Jeromy's avatar
Jeromy committed
11 12
)

13
// Wantlist is a raw list of wanted blocks and their priorities
Jeromy's avatar
Jeromy committed
14
type Wantlist struct {
15
	set map[cid.Cid]Entry
Jeromy's avatar
Jeromy committed
16 17
}

18
// Entry is an entry in a want list, consisting of a cid and its priority
19
type Entry struct {
20
	Cid      cid.Cid
21
	Priority int32
dirkmc's avatar
dirkmc committed
22
	WantType pb.Message_Wantlist_WantType
23 24
}

25
// NewRefEntry creates a new reference tracked wantlist entry.
26
func NewRefEntry(c cid.Cid, p int32) Entry {
27
	return Entry{
Jeromy's avatar
Jeromy committed
28 29
		Cid:      c,
		Priority: p,
dirkmc's avatar
dirkmc committed
30
		WantType: pb.Message_Wantlist_Block,
Jeromy's avatar
Jeromy committed
31
	}
32 33
}

34
type entrySlice []Entry
35 36 37 38 39

func (es entrySlice) Len() int           { return len(es) }
func (es entrySlice) Swap(i, j int)      { es[i], es[j] = es[j], es[i] }
func (es entrySlice) Less(i, j int) bool { return es[i].Priority > es[j].Priority }

40
// New generates a new raw Wantlist
41
func New() *Wantlist {
Jeromy's avatar
Jeromy committed
42
	return &Wantlist{
43
		set: make(map[cid.Cid]Entry),
Jeromy's avatar
Jeromy committed
44 45 46
	}
}

47
// Len returns the number of entries in a wantlist.
Brian Tiger Chow's avatar
Brian Tiger Chow committed
48 49 50 51
func (w *Wantlist) Len() int {
	return len(w.set)
}

52
// Add adds an entry in a wantlist from CID & Priority, if not already present.
53
func (w *Wantlist) Add(c cid.Cid, priority int32, wantType pb.Message_Wantlist_WantType) bool {
dirkmc's avatar
dirkmc committed
54 55 56 57
	e, ok := w.set[c]

	// Adding want-have should not override want-block
	if ok && (e.WantType == pb.Message_Wantlist_Block || wantType == pb.Message_Wantlist_Have) {
58
		return false
Jeromy's avatar
Jeromy committed
59
	}
60

61
	w.set[c] = Entry{
62
		Cid:      c,
Jeromy's avatar
Jeromy committed
63
		Priority: priority,
dirkmc's avatar
dirkmc committed
64
		WantType: wantType,
65
	}
66 67

	return true
68 69
}

dirkmc's avatar
dirkmc committed
70 71 72 73
// Remove removes the given cid from the wantlist.
func (w *Wantlist) Remove(c cid.Cid) bool {
	_, ok := w.set[c]
	if !ok {
74
		return false
Jeromy's avatar
Jeromy committed
75
	}
dirkmc's avatar
dirkmc committed
76 77

	delete(w.set, c)
78
	return true
Jeromy's avatar
Jeromy committed
79 80
}

dirkmc's avatar
dirkmc committed
81 82 83 84
// Remove removes the given cid from the wantlist, respecting the type:
// Remove with want-have will not remove an existing want-block.
func (w *Wantlist) RemoveType(c cid.Cid, wantType pb.Message_Wantlist_WantType) bool {
	e, ok := w.set[c]
85
	if !ok {
86
		return false
87 88
	}

dirkmc's avatar
dirkmc committed
89 90 91 92 93
	// Removing want-have should not remove want-block
	if e.WantType == pb.Message_Wantlist_Block && wantType == pb.Message_Wantlist_Have {
		return false
	}

Steven Allen's avatar
Steven Allen committed
94
	delete(w.set, c)
95
	return true
Jeromy's avatar
Jeromy committed
96 97
}

98 99
// Contains returns the entry, if present, for the given CID, plus whether it
// was present.
100
func (w *Wantlist) Contains(c cid.Cid) (Entry, bool) {
Steven Allen's avatar
Steven Allen committed
101
	e, ok := w.set[c]
102
	return e, ok
Jeromy's avatar
Jeromy committed
103 104
}

105
// Entries returns all wantlist entries for a want list.
106 107
func (w *Wantlist) Entries() []Entry {
	es := make([]Entry, 0, len(w.set))
Jeromy's avatar
Jeromy committed
108 109 110 111 112 113
	for _, e := range w.set {
		es = append(es, e)
	}
	return es
}

dirkmc's avatar
dirkmc committed
114 115 116 117 118 119
// Absorb all the entries in other into this want list
func (w *Wantlist) Absorb(other *Wantlist) {
	for _, e := range other.Entries() {
		w.Add(e.Cid, e.Priority, e.WantType)
	}
}
120 121 122 123 124

// SortEntries sorts the list of entries by priority.
func SortEntries(es []Entry) {
	sort.Sort(entrySlice(es))
}