wantlist.go 2.6 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

9
	cid "gx/ipfs/QmcEcrBAMrwMyhSjXt4yfyPpzgSuV8HLHavnfmiKCSRqZU/go-cid"
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[string]*Entry
Jeromy's avatar
Jeromy committed
20 21
}

22
type Entry struct {
23
	Cid      *cid.Cid
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[string]*Entry),
Jeromy's avatar
Jeromy committed
44 45 46
	}
}

47
func (w *ThreadSafe) Add(k *cid.Cid, 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 *cid.Cid) bool {
60 61
	w.lk.Lock()
	defer w.lk.Unlock()
62
	return w.Wantlist.Remove(k)
63 64
}

65
func (w *ThreadSafe) Contains(k *cid.Cid) (*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 94
func (w *Wantlist) Add(c *cid.Cid, priority int) bool {
	k := c.KeyString()
95 96
	if e, ok := w.set[k]; ok {
		e.RefCnt++
97
		return false
Jeromy's avatar
Jeromy committed
98
	}
99

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

	return true
107 108
}

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

119 120
func (w *Wantlist) Remove(c *cid.Cid) bool {
	k := c.KeyString()
121 122
	e, ok := w.set[k]
	if !ok {
123
		return false
124 125 126 127 128
	}

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

134 135
func (w *Wantlist) Contains(k *cid.Cid) (*Entry, bool) {
	e, ok := w.set[k.KeyString()]
136
	return e, ok
Jeromy's avatar
Jeromy committed
137 138
}

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

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