github.com/metacurrency/holochain@v0.1.0-alpha-26.0.20200915073418-5c83169c9b5b/kad_bucket.go (about) 1 // Copyright (C) 2013-2017, The MetaCurrency Project (Eric Harris-Braun, Arthur Brock, et. al.) 2 // Use of this source code is governed by GPLv3 found in the LICENSE file 3 // 4 // This code is adapted from the libp2p project, specifically: 5 // https://github.com/libp2p/go-libp2p-kbucket/bucket.go 6 // we don't need to unify keyspaces between random strings and peer.IDs which ipfs requires. 7 //---------------------------------------------------------------------------------------- 8 9 package holochain 10 11 import ( 12 "container/list" 13 "sync" 14 15 peer "github.com/libp2p/go-libp2p-peer" 16 ) 17 18 // Bucket holds a list of peers. 19 type Bucket struct { 20 lk sync.RWMutex 21 list *list.List 22 } 23 24 func newBucket() *Bucket { 25 b := new(Bucket) 26 b.list = list.New() 27 return b 28 } 29 30 func (b *Bucket) Peers() []peer.ID { 31 b.lk.RLock() 32 defer b.lk.RUnlock() 33 ps := make([]peer.ID, 0, b.list.Len()) 34 for e := b.list.Front(); e != nil; e = e.Next() { 35 id := e.Value.(peer.ID) 36 ps = append(ps, id) 37 } 38 return ps 39 } 40 41 func (b *Bucket) Has(id peer.ID) bool { 42 b.lk.RLock() 43 defer b.lk.RUnlock() 44 for e := b.list.Front(); e != nil; e = e.Next() { 45 if e.Value.(peer.ID) == id { 46 return true 47 } 48 } 49 return false 50 } 51 52 func (b *Bucket) Remove(id peer.ID) { 53 b.lk.Lock() 54 defer b.lk.Unlock() 55 for e := b.list.Front(); e != nil; e = e.Next() { 56 if e.Value.(peer.ID) == id { 57 b.list.Remove(e) 58 } 59 } 60 } 61 62 func (b *Bucket) MoveToFront(id peer.ID) { 63 b.lk.Lock() 64 defer b.lk.Unlock() 65 for e := b.list.Front(); e != nil; e = e.Next() { 66 if e.Value.(peer.ID) == id { 67 b.list.MoveToFront(e) 68 } 69 } 70 } 71 72 func (b *Bucket) PushFront(p peer.ID) { 73 b.lk.Lock() 74 b.list.PushFront(p) 75 b.lk.Unlock() 76 } 77 78 func (b *Bucket) PopBack() peer.ID { 79 b.lk.Lock() 80 defer b.lk.Unlock() 81 last := b.list.Back() 82 b.list.Remove(last) 83 return last.Value.(peer.ID) 84 } 85 86 func (b *Bucket) Len() int { 87 b.lk.RLock() 88 defer b.lk.RUnlock() 89 return b.list.Len() 90 } 91 92 // Split splits a buckets peers into two buckets, the methods receiver will have 93 // peers with CPL equal to cpl, the returned bucket will have peers with CPL 94 // greater than cpl (returned bucket has closer peers) 95 func (b *Bucket) Split(cpl int, target peer.ID) *Bucket { 96 b.lk.Lock() 97 defer b.lk.Unlock() 98 99 out := list.New() 100 newbuck := newBucket() 101 newbuck.list = out 102 e := b.list.Front() 103 for e != nil { 104 peerID := e.Value.(peer.ID) 105 peerCPL := commonPrefixLen(peerID, target) 106 if peerCPL > cpl { 107 cur := e 108 out.PushBack(e.Value) 109 e = e.Next() 110 b.list.Remove(cur) 111 continue 112 } 113 e = e.Next() 114 } 115 return newbuck 116 }