wantlist.go 2.51 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 10 11

	key "github.com/ipfs/go-ipfs/blocks/key"

	"gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
Jeromy's avatar
Jeromy committed
12 13
)

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

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

24
type Entry struct {
Brian Tiger Chow's avatar
Brian Tiger Chow committed
25 26
	// TODO consider making entries immutable so they can be shared safely and
	// slices can be copied efficiently.
27
	Key      key.Key
28
	Priority int
29
	Ctx      context.Context
30 31
}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
32
type entrySlice []Entry
33 34 35 36 37 38 39 40 41 42 43

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(),
	}
}

44
func New() *Wantlist {
Jeromy's avatar
Jeromy committed
45
	return &Wantlist{
46
		set: make(map[key.Key]Entry),
Jeromy's avatar
Jeromy committed
47 48 49
	}
}

50 51 52 53 54 55 56
func (w *ThreadSafe) Add(ctx context.Context, k key.Key, priority int) {
	w.lk.Lock()
	defer w.lk.Unlock()
	w.Wantlist.Add(ctx, k, priority)
}

func (w *ThreadSafe) AddEntry(e Entry) {
57 58
	w.lk.Lock()
	defer w.lk.Unlock()
59
	w.Wantlist.AddEntry(e)
Jeromy's avatar
Jeromy committed
60 61
}

62
func (w *ThreadSafe) Remove(k key.Key) {
63 64
	w.lk.Lock()
	defer w.lk.Unlock()
65 66 67
	w.Wantlist.Remove(k)
}

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

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

Brian Tiger Chow's avatar
Brian Tiger Chow committed
80
func (w *ThreadSafe) SortedEntries() []Entry {
81 82
	w.lk.RLock()
	defer w.lk.RUnlock()
83
	return w.Wantlist.SortedEntries()
84 85
}

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

96
func (w *Wantlist) Add(ctx context.Context, k key.Key, priority int) {
Jeromy's avatar
Jeromy committed
97 98 99
	if _, ok := w.set[k]; ok {
		return
	}
Brian Tiger Chow's avatar
Brian Tiger Chow committed
100
	w.set[k] = Entry{
101
		Key:      k,
Jeromy's avatar
Jeromy committed
102
		Priority: priority,
103 104 105 106 107 108 109
		Ctx:      ctx,
	}
}

func (w *Wantlist) AddEntry(e Entry) {
	if _, ok := w.set[e.Key]; ok {
		return
Jeromy's avatar
Jeromy committed
110
	}
111
	w.set[e.Key] = e
Jeromy's avatar
Jeromy committed
112 113
}

114
func (w *Wantlist) Remove(k key.Key) {
Jeromy's avatar
Jeromy committed
115 116 117
	delete(w.set, k)
}

118
func (w *Wantlist) Contains(k key.Key) (Entry, bool) {
119 120
	e, ok := w.set[k]
	return e, ok
Jeromy's avatar
Jeromy committed
121 122
}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
123
func (w *Wantlist) Entries() []Entry {
Jeromy's avatar
Jeromy committed
124 125 126 127 128 129 130
	var es entrySlice
	for _, e := range w.set {
		es = append(es, e)
	}
	return es
}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
131
func (w *Wantlist) SortedEntries() []Entry {
Jeromy's avatar
Jeromy committed
132 133 134 135 136 137 138
	var es entrySlice
	for _, e := range w.set {
		es = append(es, e)
	}
	sort.Sort(es)
	return es
}