bucket.go 2.06 KB
Newer Older
1 2
//go:generate go run ./generate

3
package kbucket
4 5 6

import (
	"container/list"
7
	"sync"
8

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

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

18
func newBucket() *Bucket {
19 20 21 22
	b := new(Bucket)
	b.list = list.New()
	return b
}
23

24 25 26 27 28 29 30 31 32 33 34
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
}

35
func (b *Bucket) Has(id peer.ID) bool {
36 37 38
	b.lk.RLock()
	defer b.lk.RUnlock()
	for e := b.list.Front(); e != nil; e = e.Next() {
39
		if e.Value.(peer.ID) == id {
40
			return true
41 42
		}
	}
43
	return false
44 45
}

46
func (b *Bucket) Remove(id peer.ID) bool {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
47 48
	b.lk.Lock()
	defer b.lk.Unlock()
49 50 51
	for e := b.list.Front(); e != nil; e = e.Next() {
		if e.Value.(peer.ID) == id {
			b.list.Remove(e)
52
			return true
53 54
		}
	}
55
	return false
56 57
}

58
func (b *Bucket) MoveToFront(id peer.ID) {
59
	b.lk.Lock()
60 61 62 63 64 65
	defer b.lk.Unlock()
	for e := b.list.Front(); e != nil; e = e.Next() {
		if e.Value.(peer.ID) == id {
			b.list.MoveToFront(e)
		}
	}
66 67
}

68
func (b *Bucket) PushFront(p peer.ID) {
69 70 71
	b.lk.Lock()
	b.list.PushFront(p)
	b.lk.Unlock()
72 73
}

74
func (b *Bucket) PopBack() peer.ID {
75 76 77 78
	b.lk.Lock()
	defer b.lk.Unlock()
	last := b.list.Back()
	b.list.Remove(last)
79
	return last.Value.(peer.ID)
80 81
}

82
func (b *Bucket) Len() int {
83 84 85
	b.lk.RLock()
	defer b.lk.RUnlock()
	return b.list.Len()
86 87
}

88
// Split splits a buckets peers into two buckets, the methods receiver will have
89 90 91
// 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 {
92 93 94
	b.lk.Lock()
	defer b.lk.Unlock()

95
	out := list.New()
96
	newbuck := newBucket()
97 98
	newbuck.list = out
	e := b.list.Front()
99
	for e != nil {
100
		peerID := ConvertPeerID(e.Value.(peer.ID))
Matt Joiner's avatar
Matt Joiner committed
101
		peerCPL := CommonPrefixLen(peerID, target)
102
		if peerCPL > cpl {
103 104 105
			cur := e
			out.PushBack(e.Value)
			e = e.Next()
106
			b.list.Remove(cur)
107 108 109 110
			continue
		}
		e = e.Next()
	}
111
	return newbuck
112
}