wantlist.go 2.53 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
package wantlist

import (
	"sort"
7
	"sync"
8

George Antoniadis's avatar
George Antoniadis committed
9
	key "gx/ipfs/Qmce4Y4zg3sYr7xKM5UueS67vhNni6EeWgCRnb7MbLJMew/go-key"
Jeromy's avatar
Jeromy committed
10 11
)

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

// not threadsafe
Jeromy's avatar
Jeromy committed
18
type Wantlist struct {
19
	set map[key.Key]*Entry
Jeromy's avatar
Jeromy committed
20 21
}

22
type Entry struct {
23
	Key      key.Key
24
	Priority int
25 26

	RefCnt int
27 28
}

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{
43
		set: make(map[key.Key]*Entry),
Jeromy's avatar
Jeromy committed
44 45 46
	}
}

47
func (w *ThreadSafe) Add(k key.Key, priority int) bool {
48 49
	w.lk.Lock()
	defer w.lk.Unlock()
50
	return w.Wantlist.Add(k, priority)
51 52
}

53
func (w *ThreadSafe) AddEntry(e *Entry) bool {
54 55
	w.lk.Lock()
	defer w.lk.Unlock()
56
	return w.Wantlist.AddEntry(e)
Jeromy's avatar
Jeromy committed
57 58
}

59
func (w *ThreadSafe) Remove(k key.Key) bool {
60 61
	w.lk.Lock()
	defer w.lk.Unlock()
62
	return w.Wantlist.Remove(k)
63 64
}

65
func (w *ThreadSafe) Contains(k key.Key) (*Entry, bool) {
66 67 68 69 70
	w.lk.RLock()
	defer w.lk.RUnlock()
	return w.Wantlist.Contains(k)
}

71
func (w *ThreadSafe) Entries() []*Entry {
72 73
	w.lk.RLock()
	defer w.lk.RUnlock()
74
	return w.Wantlist.Entries()
75 76
}

77
func (w *ThreadSafe) SortedEntries() []*Entry {
78 79
	w.lk.RLock()
	defer w.lk.RUnlock()
80
	return w.Wantlist.SortedEntries()
81 82
}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
83 84 85 86 87 88 89 90 91 92
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)
}

93
func (w *Wantlist) Add(k key.Key, priority int) bool {
94 95
	if e, ok := w.set[k]; ok {
		e.RefCnt++
96
		return false
Jeromy's avatar
Jeromy committed
97
	}
98

99
	w.set[k] = &Entry{
100
		Key:      k,
Jeromy's avatar
Jeromy committed
101
		Priority: priority,
102
		RefCnt:   1,
103
	}
104 105

	return true
106 107
}

108 109 110 111
func (w *Wantlist) AddEntry(e *Entry) bool {
	if ex, ok := w.set[e.Key]; ok {
		ex.RefCnt++
		return false
Jeromy's avatar
Jeromy committed
112
	}
113
	w.set[e.Key] = e
114
	return true
Jeromy's avatar
Jeromy committed
115 116
}

117
func (w *Wantlist) Remove(k key.Key) bool {
118 119
	e, ok := w.set[k]
	if !ok {
120
		return false
121 122 123 124 125
	}

	e.RefCnt--
	if e.RefCnt <= 0 {
		delete(w.set, k)
126
		return true
127
	}
128
	return false
Jeromy's avatar
Jeromy committed
129 130
}

131
func (w *Wantlist) Contains(k key.Key) (*Entry, bool) {
132 133
	e, ok := w.set[k]
	return e, ok
Jeromy's avatar
Jeromy committed
134 135
}

136
func (w *Wantlist) Entries() []*Entry {
Jeromy's avatar
Jeromy committed
137 138 139 140 141 142 143
	var es entrySlice
	for _, e := range w.set {
		es = append(es, e)
	}
	return es
}

144
func (w *Wantlist) SortedEntries() []*Entry {
Jeromy's avatar
Jeromy committed
145 146 147 148 149 150 151
	var es entrySlice
	for _, e := range w.set {
		es = append(es, e)
	}
	sort.Sort(es)
	return es
}