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

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

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
7
	peer "github.com/jbenet/go-ipfs/p2p/peer"
8
)
Jeromy's avatar
Jeromy committed
9

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

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

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

33
func (b *Bucket) find(id peer.ID) *list.Element {
34 35 36
	b.lk.RLock()
	defer b.lk.RUnlock()
	for e := b.list.Front(); e != nil; e = e.Next() {
37
		if e.Value.(peer.ID) == id {
38 39 40 41 42 43
			return e
		}
	}
	return nil
}

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

54
func (b *Bucket) moveToFront(e *list.Element) {
55 56 57
	b.lk.Lock()
	b.list.MoveToFront(e)
	b.lk.Unlock()
58 59
}

60
func (b *Bucket) pushFront(p peer.ID) {
61 62 63
	b.lk.Lock()
	b.list.PushFront(p)
	b.lk.Unlock()
64 65
}

66
func (b *Bucket) popBack() peer.ID {
67 68 69 70
	b.lk.Lock()
	defer b.lk.Unlock()
	last := b.list.Back()
	b.list.Remove(last)
71
	return last.Value.(peer.ID)
72 73
}

74
func (b *Bucket) len() int {
75 76 77
	b.lk.RLock()
	defer b.lk.RUnlock()
	return b.list.Len()
78 79
}

80
// Split splits a buckets peers into two buckets, the methods receiver will have
81 82 83
// 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 {
84 85 86
	b.lk.Lock()
	defer b.lk.Unlock()

87
	out := list.New()
88
	newbuck := newBucket()
89 90
	newbuck.list = out
	e := b.list.Front()
91
	for e != nil {
92
		peerID := ConvertPeerID(e.Value.(peer.ID))
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
93
		peerCPL := commonPrefixLen(peerID, target)
94
		if peerCPL > cpl {
95 96 97
			cur := e
			out.PushBack(e.Value)
			e = e.Next()
98
			b.list.Remove(cur)
99 100 101 102
			continue
		}
		e = e.Next()
	}
103
	return newbuck
104
}