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  }