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

3
package kbucket
4 5 6

import (
	"container/list"
7
	"github.com/libp2p/go-libp2p-core/peer"
8
)
Jeromy's avatar
Jeromy committed
9

10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
// PeerState is the state of the peer as seen by the Routing Table.
type PeerState int

const (
	// PeerStateActive indicates that we know the peer is active/alive.
	PeerStateActive PeerState = iota
	// PeerStateMissing indicates that we do not know the state of the peer.
	PeerStateMissing
)

// PeerInfo holds all related information for a peer in the K-Bucket.
type PeerInfo struct {
	Id    peer.ID
	State PeerState
}

// bucket holds a list of peers.
Aarsh Shah's avatar
Aarsh Shah committed
27 28 29 30
// we synchronize on the Routing Table lock for all access to the bucket
// and so do not need any locks in the bucket.
// if we want/need to avoid locking the table for accessing a bucket in the future,
// it WILL be the caller's responsibility to synchronize all access to a bucket.
31
type bucket struct {
32 33 34
	list *list.List
}

35 36
func newBucket() *bucket {
	b := new(bucket)
37 38 39
	b.list = list.New()
	return b
}
40

41
// returns all peers in the bucket
Aarsh Shah's avatar
Aarsh Shah committed
42
// it is safe for the caller to modify the returned objects as it is a defensive copy
43 44 45
func (b *bucket) peers() []PeerInfo {
	var ps []PeerInfo
	for e := b.list.Front(); e != nil; e = e.Next() {
Aarsh Shah's avatar
Aarsh Shah committed
46 47
		p := e.Value.(*PeerInfo)
		ps = append(ps, *p)
48 49 50 51 52 53
	}
	return ps
}

// return the Ids of all the peers in the bucket.
func (b *bucket) peerIds() []peer.ID {
54 55
	ps := make([]peer.ID, 0, b.list.Len())
	for e := b.list.Front(); e != nil; e = e.Next() {
Aarsh Shah's avatar
Aarsh Shah committed
56
		p := e.Value.(*PeerInfo)
57
		ps = append(ps, p.Id)
58 59 60 61
	}
	return ps
}

Aarsh Shah's avatar
Aarsh Shah committed
62 63 64
// returns the peer with the given Id if it exists
// returns nil if the peerId does not exist
func (b *bucket) getPeer(p peer.ID) *PeerInfo {
65
	for e := b.list.Front(); e != nil; e = e.Next() {
Aarsh Shah's avatar
Aarsh Shah committed
66 67
		if e.Value.(*PeerInfo).Id == p {
			return e.Value.(*PeerInfo)
68 69
		}
	}
Aarsh Shah's avatar
Aarsh Shah committed
70
	return nil
71 72
}

73 74 75
// removes the peer with the given Id from the bucket.
// returns true if successful, false otherwise.
func (b *bucket) remove(id peer.ID) bool {
76
	for e := b.list.Front(); e != nil; e = e.Next() {
Aarsh Shah's avatar
Aarsh Shah committed
77
		if e.Value.(*PeerInfo).Id == id {
78
			b.list.Remove(e)
79
			return true
80 81
		}
	}
82
	return false
83 84
}

85 86
func (b *bucket) moveToFront(id peer.ID) {

87
	for e := b.list.Front(); e != nil; e = e.Next() {
Aarsh Shah's avatar
Aarsh Shah committed
88
		if e.Value.(*PeerInfo).Id == id {
89 90 91
			b.list.MoveToFront(e)
		}
	}
92 93
}

Aarsh Shah's avatar
Aarsh Shah committed
94
func (b *bucket) pushFront(p *PeerInfo) {
95
	b.list.PushFront(p)
96 97
}

98
func (b *bucket) len() int {
99
	return b.list.Len()
100 101
}

102
// splits a buckets peers into two buckets, the methods receiver will have
103 104
// peers with CPL equal to cpl, the returned bucket will have peers with CPL
// greater than cpl (returned bucket has closer peers)
105
func (b *bucket) split(cpl int, target ID) *bucket {
106
	out := list.New()
107
	newbuck := newBucket()
108 109
	newbuck.list = out
	e := b.list.Front()
110
	for e != nil {
Aarsh Shah's avatar
Aarsh Shah committed
111
		peerID := ConvertPeerID(e.Value.(*PeerInfo).Id)
Matt Joiner's avatar
Matt Joiner committed
112
		peerCPL := CommonPrefixLen(peerID, target)
113
		if peerCPL > cpl {
114 115 116
			cur := e
			out.PushBack(e.Value)
			e = e.Next()
117
			b.list.Remove(cur)
118 119 120 121
			continue
		}
		e = e.Next()
	}
122
	return newbuck
123
}