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

Jeromy's avatar
Jeromy committed
8
	cid "github.com/ipfs/go-cid"
Jeromy's avatar
Jeromy committed
9 10
)

11 12
type SessionTrackedWantlist struct {
	set map[cid.Cid]*sessionTrackedEntry
13 14
}

Jeromy's avatar
Jeromy committed
15
type Wantlist struct {
Steven Allen's avatar
Steven Allen committed
16
	set map[cid.Cid]*Entry
Jeromy's avatar
Jeromy committed
17 18
}

19
type Entry struct {
20
	Cid      cid.Cid
21
	Priority int
22

23 24
	// Trash in a book-keeping field
	Trash bool
Jeromy's avatar
Jeromy committed
25 26
}

27 28 29 30 31
type sessionTrackedEntry struct {
	*Entry
	sesTrk map[uint64]struct{}
}

32
// NewRefEntry creates a new reference tracked wantlist entry.
33
func NewRefEntry(c cid.Cid, p int) *Entry {
Jeromy's avatar
Jeromy committed
34 35 36 37
	return &Entry{
		Cid:      c,
		Priority: p,
	}
38 39
}

40
type entrySlice []*Entry
41 42 43 44 45

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 }

46 47 48
func NewSessionTrackedWantlist() *SessionTrackedWantlist {
	return &SessionTrackedWantlist{
		set: make(map[cid.Cid]*sessionTrackedEntry),
49 50 51
	}
}

52
func New() *Wantlist {
Jeromy's avatar
Jeromy committed
53
	return &Wantlist{
Steven Allen's avatar
Steven Allen committed
54
		set: make(map[cid.Cid]*Entry),
Jeromy's avatar
Jeromy committed
55 56 57
	}
}

Jeromy's avatar
Jeromy committed
58 59 60 61
// Add adds the given cid to the wantlist with the specified priority, governed
// by the session ID 'ses'.  if a cid is added under multiple session IDs, then
// it must be removed by each of those sessions before it is no longer 'in the
// wantlist'. Calls to Add are idempotent given the same arguments. Subsequent
62
// calls with different values for priority will not update the priority.
Jeromy's avatar
Jeromy committed
63 64
// TODO: think through priority changes here
// Add returns true if the cid did not exist in the wantlist before this call
65
// (even if it was under a different session).
66 67
func (w *SessionTrackedWantlist) Add(c cid.Cid, priority int, ses uint64) bool {

Steven Allen's avatar
Steven Allen committed
68
	if e, ok := w.set[c]; ok {
69
		e.sesTrk[ses] = struct{}{}
Jeromy's avatar
Jeromy committed
70 71 72
		return false
	}

73 74 75
	w.set[c] = &sessionTrackedEntry{
		Entry:  &Entry{Cid: c, Priority: priority},
		sesTrk: map[uint64]struct{}{ses: struct{}{}},
Jeromy's avatar
Jeromy committed
76 77 78
	}

	return true
79 80
}

81
// AddEntry adds given Entry to the wantlist. For more information see Add method.
82
func (w *SessionTrackedWantlist) AddEntry(e *Entry, ses uint64) bool {
Steven Allen's avatar
Steven Allen committed
83
	if ex, ok := w.set[e.Cid]; ok {
84
		ex.sesTrk[ses] = struct{}{}
Jeromy's avatar
Jeromy committed
85 86
		return false
	}
87 88 89 90
	w.set[e.Cid] = &sessionTrackedEntry{
		Entry:  e,
		sesTrk: map[uint64]struct{}{ses: struct{}{}},
	}
Jeromy's avatar
Jeromy committed
91
	return true
Jeromy's avatar
Jeromy committed
92 93
}

Jeromy's avatar
Jeromy committed
94 95 96 97
// Remove removes the given cid from being tracked by the given session.
// 'true' is returned if this call to Remove removed the final session ID
// tracking the cid. (meaning true will be returned iff this call caused the
// value of 'Contains(c)' to change from true to false)
98
func (w *SessionTrackedWantlist) Remove(c cid.Cid, ses uint64) bool {
Steven Allen's avatar
Steven Allen committed
99
	e, ok := w.set[c]
Jeromy's avatar
Jeromy committed
100 101 102 103
	if !ok {
		return false
	}

104 105
	delete(e.sesTrk, ses)
	if len(e.sesTrk) == 0 {
Steven Allen's avatar
Steven Allen committed
106
		delete(w.set, c)
Jeromy's avatar
Jeromy committed
107 108 109
		return true
	}
	return false
110 111
}

Jeromy's avatar
Jeromy committed
112
// Contains returns true if the given cid is in the wantlist tracked by one or
113
// more sessions.
114
func (w *SessionTrackedWantlist) Contains(k cid.Cid) (*Entry, bool) {
Steven Allen's avatar
Steven Allen committed
115
	e, ok := w.set[k]
116 117 118 119
	if !ok {
		return nil, false
	}
	return e.Entry, true
120 121
}

122
func (w *SessionTrackedWantlist) Entries() []*Entry {
123
	es := make([]*Entry, 0, len(w.set))
Jeromy's avatar
Jeromy committed
124
	for _, e := range w.set {
125
		es = append(es, e.Entry)
Jeromy's avatar
Jeromy committed
126 127
	}
	return es
128 129
}

130
func (w *SessionTrackedWantlist) SortedEntries() []*Entry {
131 132
	es := w.Entries()
	sort.Sort(entrySlice(es))
Jeromy's avatar
Jeromy committed
133
	return es
134 135
}

136
func (w *SessionTrackedWantlist) Len() int {
Jeromy's avatar
Jeromy committed
137
	return len(w.set)
Brian Tiger Chow's avatar
Brian Tiger Chow committed
138 139
}

140 141 142 143 144 145 146 147
func (w *SessionTrackedWantlist) CopyWants(to *SessionTrackedWantlist) {
	for _, e := range w.set {
		for k := range e.sesTrk {
			to.AddEntry(e.Entry, k)
		}
	}
}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
148 149 150 151
func (w *Wantlist) Len() int {
	return len(w.set)
}

152
func (w *Wantlist) Add(c cid.Cid, priority int) bool {
Steven Allen's avatar
Steven Allen committed
153
	if _, ok := w.set[c]; ok {
154
		return false
Jeromy's avatar
Jeromy committed
155
	}
156

Steven Allen's avatar
Steven Allen committed
157
	w.set[c] = &Entry{
158
		Cid:      c,
Jeromy's avatar
Jeromy committed
159
		Priority: priority,
160
	}
161 162

	return true
163 164
}

165
func (w *Wantlist) AddEntry(e *Entry) bool {
Steven Allen's avatar
Steven Allen committed
166
	if _, ok := w.set[e.Cid]; ok {
167
		return false
Jeromy's avatar
Jeromy committed
168
	}
Steven Allen's avatar
Steven Allen committed
169
	w.set[e.Cid] = e
170
	return true
Jeromy's avatar
Jeromy committed
171 172
}

173
func (w *Wantlist) Remove(c cid.Cid) bool {
Steven Allen's avatar
Steven Allen committed
174
	_, ok := w.set[c]
175
	if !ok {
176
		return false
177 178
	}

Steven Allen's avatar
Steven Allen committed
179
	delete(w.set, c)
180
	return true
Jeromy's avatar
Jeromy committed
181 182
}

Steven Allen's avatar
Steven Allen committed
183 184
func (w *Wantlist) Contains(c cid.Cid) (*Entry, bool) {
	e, ok := w.set[c]
185
	return e, ok
Jeromy's avatar
Jeromy committed
186 187
}

188
func (w *Wantlist) Entries() []*Entry {
189
	es := make([]*Entry, 0, len(w.set))
Jeromy's avatar
Jeromy committed
190 191 192 193 194 195
	for _, e := range w.set {
		es = append(es, e)
	}
	return es
}

196
func (w *Wantlist) SortedEntries() []*Entry {
197 198
	es := w.Entries()
	sort.Sort(entrySlice(es))
Jeromy's avatar
Jeromy committed
199 200
	return es
}