Commit 89e665e3 authored by Janoš Guljaš's avatar Janoš Guljaš Committed by GitHub

kademlia pslice copy on write (#350)

parent 659fe4c0
...@@ -33,17 +33,17 @@ func New(maxBins int) *PSlice { ...@@ -33,17 +33,17 @@ func New(maxBins int) *PSlice {
// iterates over all peers from deepest bin to shallowest. // iterates over all peers from deepest bin to shallowest.
func (s *PSlice) EachBin(pf topology.EachPeerFunc) error { func (s *PSlice) EachBin(pf topology.EachPeerFunc) error {
s.RLock() s.RLock()
defer s.RUnlock() peers, bins := s.peers, s.bins
s.RUnlock()
if len(s.peers) == 0 { if len(peers) == 0 {
return nil return nil
} }
var binEnd = uint(len(s.peers)) var binEnd = uint(len(peers))
for i := len(s.bins) - 1; i >= 0; i-- { for i := len(bins) - 1; i >= 0; i-- {
peers := s.peers[s.bins[i]:binEnd] for _, v := range peers[bins[i]:binEnd] {
for _, v := range peers {
stop, next, err := pf(v, uint8(i)) stop, next, err := pf(v, uint8(i))
if err != nil { if err != nil {
return err return err
...@@ -55,7 +55,7 @@ func (s *PSlice) EachBin(pf topology.EachPeerFunc) error { ...@@ -55,7 +55,7 @@ func (s *PSlice) EachBin(pf topology.EachPeerFunc) error {
break break
} }
} }
binEnd = s.bins[i] binEnd = bins[i]
} }
return nil return nil
...@@ -64,22 +64,22 @@ func (s *PSlice) EachBin(pf topology.EachPeerFunc) error { ...@@ -64,22 +64,22 @@ func (s *PSlice) EachBin(pf topology.EachPeerFunc) error {
// EachBinRev iterates over all peers from shallowest bin to deepest. // EachBinRev iterates over all peers from shallowest bin to deepest.
func (s *PSlice) EachBinRev(pf topology.EachPeerFunc) error { func (s *PSlice) EachBinRev(pf topology.EachPeerFunc) error {
s.RLock() s.RLock()
defer s.RUnlock() peers, bins := s.peers, s.bins
s.RUnlock()
if len(s.peers) == 0 { if len(peers) == 0 {
return nil return nil
} }
var binEnd int var binEnd int
for i := 0; i <= len(s.bins)-1; i++ { for i := 0; i <= len(bins)-1; i++ {
if i == len(s.bins)-1 { if i == len(bins)-1 {
binEnd = len(s.peers) binEnd = len(peers)
} else { } else {
binEnd = int(s.bins[i+1]) binEnd = int(bins[i+1])
} }
peers := s.peers[s.bins[i]:binEnd] for _, v := range peers[bins[i]:binEnd] {
for _, v := range peers {
stop, next, err := pf(v, uint8(i)) stop, next, err := pf(v, uint8(i))
if err != nil { if err != nil {
return err return err
...@@ -150,11 +150,17 @@ func (s *PSlice) Add(addr swarm.Address, po uint8) { ...@@ -150,11 +150,17 @@ func (s *PSlice) Add(addr swarm.Address, po uint8) {
if e, _ := s.exists(addr); e { if e, _ := s.exists(addr); e {
return return
} }
head := s.peers[:s.bins[po]]
tail := append([]swarm.Address{addr}, s.peers[s.bins[po]:]...)
s.peers = append(head, tail...)
s.incDeeper(po) peers, bins := s.copy()
head := peers[:s.bins[po]]
tail := append([]swarm.Address{addr}, peers[s.bins[po]:]...)
peers = append(head, tail...)
s.peers = peers
incDeeper(bins, po)
s.bins = bins
} }
// Remove a peer at a certain PO. // Remove a peer at a certain PO.
...@@ -167,33 +173,46 @@ func (s *PSlice) Remove(addr swarm.Address, po uint8) { ...@@ -167,33 +173,46 @@ func (s *PSlice) Remove(addr swarm.Address, po uint8) {
return return
} }
s.peers = append(s.peers[:i], s.peers[i+1:]...) peers, bins := s.copy()
s.decDeeper(po)
peers = append(peers[:i], peers[i+1:]...)
s.peers = peers
decDeeper(bins, po)
s.bins = bins
} }
// incDeeper increments the peers slice bin index for proximity order > po for non-empty bins only. // incDeeper increments the peers slice bin index for proximity order > po for non-empty bins only.
// Must be called under lock. // Must be called under lock.
func (s *PSlice) incDeeper(po uint8) { func incDeeper(bins []uint, po uint8) {
if po > uint8(len(s.bins)) { if po > uint8(len(bins)) {
panic("po too high") panic("po too high")
} }
for i := po + 1; i < uint8(len(s.bins)); i++ { for i := po + 1; i < uint8(len(bins)); i++ {
// don't increment if the value in k.bins == len(k.peers) // don't increment if the value in k.bins == len(k.peers)
// otherwise the calling context gets an out of bound error // otherwise the calling context gets an out of bound error
// when accessing the slice // when accessing the slice
s.bins[i]++ bins[i]++
} }
} }
// decDeeper decrements the peers slice bin indexes for proximity order > po. // decDeeper decrements the peers slice bin indexes for proximity order > po.
// Must be called under lock. // Must be called under lock.
func (s *PSlice) decDeeper(po uint8) { func decDeeper(bins []uint, po uint8) {
if po > uint8(len(s.bins)) { if po > uint8(len(bins)) {
panic("po too high") panic("po too high")
} }
for i := po + 1; i < uint8(len(s.bins)); i++ { for i := po + 1; i < uint8(len(bins)); i++ {
s.bins[i]-- bins[i]--
} }
} }
func (s *PSlice) copy() (peers []swarm.Address, bins []uint) {
peers = make([]swarm.Address, len(s.peers))
copy(peers, s.peers)
bins = make([]uint, len(s.bins))
copy(bins, s.bins)
return peers, bins
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment