From 281b7d7949e905bbe0f89072eaa981101da051fe Mon Sep 17 00:00:00 2001 From: YACOVM Date: Wed, 19 Apr 2017 15:59:55 +0300 Subject: [PATCH] [FAB-3241] Gossip: Do not send redundant StateInfo In gossip, whenever the channel related metadata is updated, a "dirty flag" is turned on, and periodically a goroutine disseminates to peers if the dirty flag is turned on. There is a bug that this dirty flag is never turned off. This causes a redundant dissemination of StateInfo. The stateInfo is periodically pulled from peers via a pull mechanism anyway so there is no point in having periodical dissemination and thus the dirty flag should be turned off after dissemination. Change-Id: Ie508df33c28e007e952195faed7837db5641e41a Signed-off-by: Yacov Manevich --- gossip/gossip/channel/channel.go | 3 ++ gossip/gossip/channel/channel_test.go | 61 +++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/gossip/gossip/channel/channel.go b/gossip/gossip/channel/channel.go index 5b0e67e7559..b2e2aa51c44 100644 --- a/gossip/gossip/channel/channel.go +++ b/gossip/gossip/channel/channel.go @@ -251,6 +251,9 @@ func (gc *gossipChannel) publishStateInfo() { stateInfoMsg := gc.stateInfoMsg gc.RUnlock() gc.Gossip(stateInfoMsg) + if len(gc.GetMembership()) > 0 { + atomic.StoreInt32(&gc.shouldGossipStateInfo, int32(0)) + } } func (gc *gossipChannel) createBlockPuller() pull.Mediator { diff --git a/gossip/gossip/channel/channel_test.go b/gossip/gossip/channel/channel_test.go index b876b042636..7da6bb72adc 100644 --- a/gossip/gossip/channel/channel_test.go +++ b/gossip/gossip/channel/channel_test.go @@ -1088,6 +1088,67 @@ func TestChannelGetPeers(t *testing.T) { assert.Len(t, gc.GetPeers(), 0) } +func TestOnDemandGossip(t *testing.T) { + t.Parallel() + + // Scenario: update the metadata and ensure only 1 dissemination + // takes place when membership is not empty + + cs := &cryptoService{} + adapter := new(gossipAdapterMock) + configureAdapter(adapter) + + gossipedEvents := make(chan struct{}) + + conf := conf + conf.PublishStateInfoInterval = time.Millisecond * 200 + adapter.On("GetConf").Return(conf) + adapter.On("GetMembership").Return([]discovery.NetworkMember{}) + adapter.On("Gossip", mock.Anything).Run(func(mock.Arguments) { + gossipedEvents <- struct{}{} + }) + gc := NewGossipChannel(pkiIDInOrg1, cs, channelA, adapter, api.JoinChannelMessage(&joinChanMsg{})) + defer gc.Stop() + select { + case <-gossipedEvents: + assert.Fail(t, "Should not have gossiped because metadata has not been updated yet") + case <-time.After(time.Millisecond * 500): + } + gc.UpdateStateInfo(createStateInfoMsg(0, pkiIDInOrg1, channelA)) + select { + case <-gossipedEvents: + case <-time.After(time.Second): + assert.Fail(t, "Didn't gossip within a timely manner") + } + select { + case <-gossipedEvents: + case <-time.After(time.Second): + assert.Fail(t, "Should have gossiped a second time, because membership is empty") + } + adapter = new(gossipAdapterMock) + configureAdapter(adapter, []discovery.NetworkMember{{}}...) + adapter.On("Gossip", mock.Anything).Run(func(mock.Arguments) { + gossipedEvents <- struct{}{} + }) + gc.(*gossipChannel).Adapter = adapter + select { + case <-gossipedEvents: + case <-time.After(time.Second): + assert.Fail(t, "Should have gossiped a third time") + } + select { + case <-gossipedEvents: + assert.Fail(t, "Should not have gossiped a fourth time, because dirty flag should have been turned off") + case <-time.After(time.Millisecond * 500): + } + gc.UpdateStateInfo(createStateInfoMsg(1, pkiIDInOrg1, channelA)) + select { + case <-gossipedEvents: + case <-time.After(time.Second): + assert.Fail(t, "Should have gossiped a block now, because got a new StateInfo message") + } +} + func createDataUpdateMsg(nonce uint64) *proto.SignedGossipMessage { return (&proto.GossipMessage{ Nonce: 0,