bucket.go 2.43 KB
Newer Older
1
package kbucket
2 3 4

import (
	"container/list"
5
	"sync"
6
	"time"
7

8
	"github.com/libp2p/go-libp2p-core/peer"
9
)
Jeromy's avatar
Jeromy committed
10

11
// Bucket holds a list of peers.
12 13 14
type Bucket struct {
	lk   sync.RWMutex
	list *list.List
15 16 17

	lastQueriedAtLk sync.RWMutex
	lastQueriedAt   time.Time
18 19
}

20
func newBucket() *Bucket {
21 22
	b := new(Bucket)
	b.list = list.New()
23
	b.lastQueriedAt = time.Now()
24 25
	return b
}
26

Aarsh Shah's avatar
Aarsh Shah committed
27
func (b *Bucket) LastQueriedAt() time.Time {
28 29 30 31 32 33 34 35 36 37 38 39 40
	b.lastQueriedAtLk.RLock()
	defer b.lastQueriedAtLk.RUnlock()

	return b.lastQueriedAt
}

func (b *Bucket) ResetLastQueriedAt(newTime time.Time) {
	b.lastQueriedAtLk.Lock()
	defer b.lastQueriedAtLk.Unlock()

	b.lastQueriedAt = newTime
}

41 42 43 44 45 46 47 48 49 50 51
func (b *Bucket) Peers() []peer.ID {
	b.lk.RLock()
	defer b.lk.RUnlock()
	ps := make([]peer.ID, 0, b.list.Len())
	for e := b.list.Front(); e != nil; e = e.Next() {
		id := e.Value.(peer.ID)
		ps = append(ps, id)
	}
	return ps
}

52
func (b *Bucket) Has(id peer.ID) bool {
53 54 55
	b.lk.RLock()
	defer b.lk.RUnlock()
	for e := b.list.Front(); e != nil; e = e.Next() {
56
		if e.Value.(peer.ID) == id {
57
			return true
58 59
		}
	}
60
	return false
61 62
}

63
func (b *Bucket) Remove(id peer.ID) bool {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
64 65
	b.lk.Lock()
	defer b.lk.Unlock()
66 67 68
	for e := b.list.Front(); e != nil; e = e.Next() {
		if e.Value.(peer.ID) == id {
			b.list.Remove(e)
69
			return true
70 71
		}
	}
72
	return false
73 74
}

75
func (b *Bucket) MoveToFront(id peer.ID) {
76
	b.lk.Lock()
77 78 79 80 81 82
	defer b.lk.Unlock()
	for e := b.list.Front(); e != nil; e = e.Next() {
		if e.Value.(peer.ID) == id {
			b.list.MoveToFront(e)
		}
	}
83 84
}

85
func (b *Bucket) PushFront(p peer.ID) {
86 87 88
	b.lk.Lock()
	b.list.PushFront(p)
	b.lk.Unlock()
89 90
}

91
func (b *Bucket) PopBack() peer.ID {
92 93 94 95
	b.lk.Lock()
	defer b.lk.Unlock()
	last := b.list.Back()
	b.list.Remove(last)
96
	return last.Value.(peer.ID)
97 98
}

99
func (b *Bucket) Len() int {
100 101 102
	b.lk.RLock()
	defer b.lk.RUnlock()
	return b.list.Len()
103 104
}

105
// Split splits a buckets peers into two buckets, the methods receiver will have
106 107 108
// peers with CPL equal to cpl, the returned bucket will have peers with CPL
// greater than cpl (returned bucket has closer peers)
func (b *Bucket) Split(cpl int, target ID) *Bucket {
109 110 111
	b.lk.Lock()
	defer b.lk.Unlock()

112
	out := list.New()
113
	newbuck := newBucket()
114 115
	newbuck.list = out
	e := b.list.Front()
116
	for e != nil {
117
		peerID := ConvertPeerID(e.Value.(peer.ID))
Matt Joiner's avatar
Matt Joiner committed
118
		peerCPL := CommonPrefixLen(peerID, target)
119
		if peerCPL > cpl {
120 121 122
			cur := e
			out.PushBack(e.Value)
			e = e.Next()
123
			b.list.Remove(cur)
124 125 126 127
			continue
		}
		e = e.Next()
	}
128
	return newbuck
129
}
Steven Allen's avatar
Steven Allen committed
130 131

//go:generate go run ./generate