bucket.go 3.22 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 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
// 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.
type bucket struct {
30 31 32 33
	lk   sync.RWMutex
	list *list.List
}

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

40 41 42 43 44 45 46 47 48 49 50 51 52 53
// returns all peers in the bucket
func (b *bucket) peers() []PeerInfo {
	b.lk.RLock()
	defer b.lk.RUnlock()
	var ps []PeerInfo
	for e := b.list.Front(); e != nil; e = e.Next() {
		p := e.Value.(PeerInfo)
		ps = append(ps, p)
	}
	return ps
}

// return the Ids of all the peers in the bucket.
func (b *bucket) peerIds() []peer.ID {
54 55 56 57
	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() {
58 59
		p := e.Value.(PeerInfo)
		ps = append(ps, p.Id)
60 61 62 63
	}
	return ps
}

64 65 66
// returns the peer with the given Id and true if peer exists
// returns false if the peerId does not exist
func (b *bucket) getPeer(p peer.ID) (PeerInfo, bool) {
67 68 69
	b.lk.RLock()
	defer b.lk.RUnlock()
	for e := b.list.Front(); e != nil; e = e.Next() {
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
		if e.Value.(PeerInfo).Id == p {
			return e.Value.(PeerInfo), true
		}
	}
	return PeerInfo{}, false
}

// replaces the peer based on the Id.
// returns true if the replace was successful, false otherwise.
func (b *bucket) replace(p PeerInfo) bool {
	b.lk.Lock()
	defer b.lk.Unlock()
	for e := b.list.Front(); e != nil; e = e.Next() {
		if e.Value.(PeerInfo).Id == p.Id {
			b.list.Remove(e)
			b.list.PushBack(p)
86
			return true
87 88
		}
	}
89
	return false
90 91
}

92 93 94
// removes the peer with the given Id from the bucket.
// returns true if successful, false otherwise.
func (b *bucket) remove(id peer.ID) bool {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
95 96
	b.lk.Lock()
	defer b.lk.Unlock()
97
	for e := b.list.Front(); e != nil; e = e.Next() {
98
		if e.Value.(PeerInfo).Id == id {
99
			b.list.Remove(e)
100
			return true
101 102
		}
	}
103
	return false
104 105
}

106
func (b *bucket) moveToFront(id peer.ID) {
107
	b.lk.Lock()
108
	defer b.lk.Unlock()
109

110
	for e := b.list.Front(); e != nil; e = e.Next() {
111
		if e.Value.(PeerInfo).Id == id {
112 113 114
			b.list.MoveToFront(e)
		}
	}
115 116
}

117
func (b *bucket) pushFront(p PeerInfo) {
118 119 120
	b.lk.Lock()
	b.list.PushFront(p)
	b.lk.Unlock()
121 122
}

123
func (b *bucket) len() int {
124 125 126
	b.lk.RLock()
	defer b.lk.RUnlock()
	return b.list.Len()
127 128
}

129
// splits a buckets peers into two buckets, the methods receiver will have
130 131
// peers with CPL equal to cpl, the returned bucket will have peers with CPL
// greater than cpl (returned bucket has closer peers)
132
func (b *bucket) split(cpl int, target ID) *bucket {
133 134 135
	b.lk.Lock()
	defer b.lk.Unlock()

136
	out := list.New()
137
	newbuck := newBucket()
138 139
	newbuck.list = out
	e := b.list.Front()
140
	for e != nil {
141
		peerID := ConvertPeerID(e.Value.(PeerInfo).Id)
Matt Joiner's avatar
Matt Joiner committed
142
		peerCPL := CommonPrefixLen(peerID, target)
143
		if peerCPL > cpl {
144 145 146
			cur := e
			out.PushBack(e.Value)
			e = e.Next()
147
			b.list.Remove(cur)
148 149 150 151
			continue
		}
		e = e.Next()
	}
152
	return newbuck
153
}