Skip to content
This repository was archived by the owner on Aug 2, 2021. It is now read-only.

swarm: replace streamer updateSyncing with peer-based syncing#1325

Closed
holisticode wants to merge 6 commits intomasterfrom
subs-by-peer
Closed

swarm: replace streamer updateSyncing with peer-based syncing#1325
holisticode wants to merge 6 commits intomasterfrom
subs-by-peer

Conversation

@holisticode
Copy link
Copy Markdown
Contributor

@holisticode holisticode commented Apr 3, 2019

This PR is an experiment and work in progress.

It is a replacement for udpateSyncing in the Registry to run subscriptions from peers and not globally via the registry.

It is meant as a discussion base to refine the architecture to replace updateSyncing.

Currently there are no removal of subscriptions yet. Some parts may be qualified as bad or even ugly, consequence of quick hacks in order to have first results.

Currently the smoke tests produce a timeout at about 50% rate with this approach. Also, the retrieval tests are very slow (explaining the timeouts)

fixes #1329

Copy link
Copy Markdown
Member

@zelig zelig left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good stuff, lets do it properly ;)

Comment thread swarm/network/kademlia.go Outdated
return suggestedPeer, 0, false
}

func (k *Kademlia) PoOfPeer(peer *BzzPeer) int {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need this function? do we need exporting?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can use chunk.Proximity() directly where it's used if you prefer

Comment thread swarm/network/kademlia.go
return a
})
k.lock.Unlock()
k.notifyKadChange()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all you need is keep the global depth change channel.

Each time that changes, you see it changed from depth=1 to depth 3.

Now you iterate over peers of PO between 2 and 1 and trigger their change channel
the new depth is put on the peers depthC channel

Copy link
Copy Markdown
Contributor Author

@holisticode holisticode Apr 9, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, like this we introduce the same problem again: if there is a new peer added but there is no depth change, then we don't request registrations to that guy

Comment thread swarm/network/protocol.go Outdated
*BzzAddr // remote address -> implements Addr interface = protocols.Peer
*protocols.Peer // represents the connection for online peers
*BzzAddr // remote address -> implements Addr interface = protocols.Peer
ChangeC chan struct{}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as I say this could be chan int

Comment thread swarm/network/protocol.go
}

// TODO: call this function from somewhere
func (p *BzzPeer) Close() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this channel does not need closing

p := &Peer{
Peer: peer,
Peer: peer.Peer,
bzzPeer: peer,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure i understand why you need a change here. One peer can just extend the other if we need both

Comment thread swarm/network/stream/peer.go Outdated
// which means that new subscription requests were being issued before
// a first round finished and the servers were being created
//TODO: needs investigation about why that is
timer = time.NewTimer(p.streamer.syncUpdateDelay)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we need a timer here?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would keep the logic for initial wait for now. Lets assume it is signalled on startSyncing channel.
then the peer connection would start an update loop like this:

var change chan int
po := proximity(p.Over(), p.baseAddr)
newdepth := kad.NeighbourhoodDepth
nn = po >= newdepth
for {
  depth = newdepth
  select  {
      case <- startC:
           change = peer.ChangeC
      case newdepth := <- change:
           if changed := nn ^ po >= depth; changed {
                  nn = !nn
                  if nn {
                      //request peer to subscribe to PO bins depth, depth+1, po - 1, po+1, ... MaxProxDisplay
                      continue
                  }
                  //quit all but po
                  continue
           } 
           // if only depth changed then 
           if nn {
              if newdepth < depth {
                 // request  peer to subscribe to PO bins newdepth, newdepth+1,... depth -1
             } else {
                // quit PO depth, depth+1, ... newdepth-1
     case <- p.quit:
           // quit all subs
    }
}

Comment thread swarm/network/kademlia.go
depth := k.NeighbourhoodDepth()
k.EachConn(nil, 255, func(p *Peer, po int) bool {
go p.NotifyChanged()
go p.NotifyChanged(depth)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if put in a go routine, changes are not guaranteed to be in proper order. You need syncronous write here.
The peer chance channel should be bufferred.

nn = !nn
if nn {
//request peer to subscribe to PO bins depth, depth+1, po - 1, po+1, ... MaxProxDisplay
poList := []int{depth, depth + 1, po - 1}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not correct, since po can == depth etc.
You need

					for i := depth; i <= kad.MaxProxDisplay; i++ {
						if po != i {
                                                     p.doSubscribe(i) // with some error handling
                                                }
					}

case <-timer.C:
change = p.bzzPeer.ChangeC
case newdepth := <-change:
if changed := nn != (po >= depth); changed {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here it is best to drain all changes from the channel to arrive at the last one

for {
   select {
      case newdepth = <-change:
      case default:
  }
}

continue
}
//quit all but po
poList := make([]int, 1)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for i := depth; i <= kad.MaxProxDisplay;  i++ {
     if po  != i {
         p.doQuit(i)
     }
}

log.Error(err.Error())
// if only depth changed then
if nn {
if newdepth < depth {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for i := newdepth; i <= depth-1; i++ {
    p.doSubscribe(i)
}

return err
}
} else {
// quit PO depth, depth+1, ... newdepth-1
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for i := depth + 1; i < newdepth; i++ {
    p.doQuit(i) // with some error handling
}

//do the actual subscription
err := subscriptionFunc(p.streamer, p.bzzPeer, uint8(bin))
//request peer to subscribe to PO bins depth, depth+1, po - 1, po+1, ... MaxProxDisplay
func (p *Peer) doRegister(poList []int) error {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we call this in an iterator loop, no need to call with a slice and iterate.
just call it with a single po arg

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's not call it doRegister, but doSubscribe or better
subscribeToSyncStream

}

// quit - TODO: should this return error?
func (p *Peer) doQuit(poList []int) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again no iteration needed and best to call the function quitSyncStream

live := NewStream("SYNC", FormatSyncBinKey(uint8(po)), true)
history := getHistoryStream(live)
err := p.streamer.Quit(p.ID(), live)
if err != nil && err != p2p.ErrShuttingDown {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure you need to bother catching these

// then starting a simulation, distribute chunks to nodes
// and start retrieval.
// The snapshot should have 'streamer' in its service list.
func runPureRetrievalTest(nodeCount int, chunkCount int) error {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, such a test is super important. I always though we had written this already...

@zelig
Copy link
Copy Markdown
Member

zelig commented Apr 13, 2019

obsolete by #1336

@zelig zelig closed this Apr 13, 2019
@holisticode holisticode deleted the subs-by-peer branch September 2, 2019 15:20
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

syncing subscriptions should be requested when a peer connection is established

2 participants