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

import (
	u "github.com/jbenet/go-ipfs/util"
	"sort"
8
	"sync"
Jeromy's avatar
Jeromy committed
9 10
)

11
type ThreadSafe struct {
Brian Tiger Chow's avatar
Brian Tiger Chow committed
12 13
	lk       sync.RWMutex
	Wantlist Wantlist
14 15 16
}

// not threadsafe
Jeromy's avatar
Jeromy committed
17
type Wantlist struct {
Brian Tiger Chow's avatar
Brian Tiger Chow committed
18
	set map[u.Key]Entry
Brian Tiger Chow's avatar
Brian Tiger Chow committed
19
	// TODO provide O(1) len accessor if cost becomes an issue
Jeromy's avatar
Jeromy committed
20 21
}

22
type Entry struct {
Brian Tiger Chow's avatar
Brian Tiger Chow committed
23 24
	// TODO consider making entries immutable so they can be shared safely and
	// slices can be copied efficiently.
25 26 27 28
	Key      u.Key
	Priority int
}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
29
type entrySlice []Entry
30 31 32 33 34 35 36 37 38 39 40

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 }

func NewThreadSafe() *ThreadSafe {
	return &ThreadSafe{
		Wantlist: *New(),
	}
}

41
func New() *Wantlist {
Jeromy's avatar
Jeromy committed
42
	return &Wantlist{
Brian Tiger Chow's avatar
Brian Tiger Chow committed
43
		set: make(map[u.Key]Entry),
Jeromy's avatar
Jeromy committed
44 45 46
	}
}

47 48 49 50 51
func (w *ThreadSafe) Add(k u.Key, priority int) {
	// TODO rm defer for perf
	w.lk.Lock()
	defer w.lk.Unlock()
	w.Wantlist.Add(k, priority)
Jeromy's avatar
Jeromy committed
52 53
}

54 55
func (w *ThreadSafe) Remove(k u.Key) {
	// TODO rm defer for perf
56 57
	w.lk.Lock()
	defer w.lk.Unlock()
58 59 60
	w.Wantlist.Remove(k)
}

61
func (w *ThreadSafe) Contains(k u.Key) (Entry, bool) {
62 63 64 65 66 67
	// TODO rm defer for perf
	w.lk.RLock()
	defer w.lk.RUnlock()
	return w.Wantlist.Contains(k)
}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
68
func (w *ThreadSafe) Entries() []Entry {
69 70
	w.lk.RLock()
	defer w.lk.RUnlock()
71
	return w.Wantlist.Entries()
72 73
}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
74
func (w *ThreadSafe) SortedEntries() []Entry {
75 76
	w.lk.RLock()
	defer w.lk.RUnlock()
77
	return w.Wantlist.SortedEntries()
78 79
}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
80 81 82 83 84 85 86 87 88 89
func (w *ThreadSafe) Len() int {
	w.lk.RLock()
	defer w.lk.RUnlock()
	return w.Wantlist.Len()
}

func (w *Wantlist) Len() int {
	return len(w.set)
}

90
func (w *Wantlist) Add(k u.Key, priority int) {
Jeromy's avatar
Jeromy committed
91 92 93
	if _, ok := w.set[k]; ok {
		return
	}
Brian Tiger Chow's avatar
Brian Tiger Chow committed
94
	w.set[k] = Entry{
95
		Key:      k,
Jeromy's avatar
Jeromy committed
96 97 98 99 100 101 102 103
		Priority: priority,
	}
}

func (w *Wantlist) Remove(k u.Key) {
	delete(w.set, k)
}

104 105 106
func (w *Wantlist) Contains(k u.Key) (Entry, bool) {
	e, ok := w.set[k]
	return e, ok
Jeromy's avatar
Jeromy committed
107 108
}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
109
func (w *Wantlist) Entries() []Entry {
Jeromy's avatar
Jeromy committed
110 111 112 113 114 115 116
	var es entrySlice
	for _, e := range w.set {
		es = append(es, e)
	}
	return es
}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
117
func (w *Wantlist) SortedEntries() []Entry {
Jeromy's avatar
Jeromy committed
118 119 120 121 122 123 124
	var es entrySlice
	for _, e := range w.set {
		es = append(es, e)
	}
	sort.Sort(es)
	return es
}