Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FAB-18283 Ch.Part.API: StatusReport on evicted etcdraft.Chain #2049

Merged
merged 1 commit into from
Oct 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 27 additions & 4 deletions orderer/consensus/etcdraft/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,12 @@ type Chain struct {
periodicChecker *PeriodicCheck

haltCallback func()
// BCCSP instane

statusReportMutex sync.Mutex
clusterRelation types.ClusterRelation
status types.Status

// BCCSP instance
CryptoProvider bccsp.BCCSP
}

Expand Down Expand Up @@ -269,6 +274,8 @@ func NewChain(
createPuller: f,
clock: opts.Clock,
haltCallback: haltCallback,
clusterRelation: types.ClusterRelationMember,
status: types.StatusActive,
Metrics: &Metrics{
ClusterSize: opts.Metrics.ClusterSize.With("channel", support.ChannelID()),
IsLeader: opts.Metrics.IsLeader.With("channel", support.ChannelID()),
Expand Down Expand Up @@ -434,19 +441,32 @@ func (c *Chain) stop() bool {
}
<-c.doneC

c.statusReportMutex.Lock()
defer c.statusReportMutex.Unlock()
c.status = types.StatusInactive

return true
}

// halt stops the chain and calls the haltCallback function, which allows the
// chain to transfer responsibility to a follower or inactive chain when a chain
// chain to transfer responsibility to a follower or the inactive chain registry when a chain
// discovers it is no longer a member of a channel.
func (c *Chain) halt() {
if stopped := c.stop(); !stopped {
c.logger.Info("This node was stopped, the haltCallback will not be called")
return
}
if c.haltCallback != nil {
c.haltCallback()
c.haltCallback() // Must be invoked WITHOUT any internal lock

c.statusReportMutex.Lock()
defer c.statusReportMutex.Unlock()

// If the haltCallback registers the chain in to the inactive chain registry (i.e., system channel exists) then
// this is the correct clusterRelation. If the haltCallback transfers responsibility to a follower.Chain, then
// this chain is about to be GC anyway. The new follower.Chain replacing this one will report the correct
// StatusReport.
c.clusterRelation = types.ClusterRelationConfigTracker
}
}

Expand Down Expand Up @@ -1377,7 +1397,10 @@ func (c *Chain) ValidateConsensusMetadata(oldOrdererConfig, newOrdererConfig cha

// StatusReport returns the ClusterRelation & Status
func (c *Chain) StatusReport() (types.ClusterRelation, types.Status) {
return types.ClusterRelationMember, types.StatusActive
c.statusReportMutex.Lock()
defer c.statusReportMutex.Unlock()

return c.clusterRelation, c.status
}

func (c *Chain) suspectEviction() bool {
Expand Down
18 changes: 18 additions & 0 deletions orderer/consensus/etcdraft/chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1448,6 +1448,15 @@ var _ = Describe("Chain", func() {

By("Asserting the haltCallback is called when the node is removed from the replica set")
Eventually(fakeHaltCallbacker.HaltCallbackCallCount).Should(Equal(1))
By("Asserting the StatusReport responds correctly after eviction")
Eventually(
func() orderer_types.ClusterRelation {
cRel, _ := c1.StatusReport()
return cRel
},
).Should(Equal(orderer_types.ClusterRelationConfigTracker))
_, status := c1.StatusReport()
Expect(status).To(Equal(orderer_types.StatusInactive))

By("Asserting leader can still serve requests as single-node cluster")
c2.cutter.CutNext = true
Expand Down Expand Up @@ -1484,6 +1493,15 @@ var _ = Describe("Chain", func() {
By("Asserting the haltCallback is not called when Halt is called before eviction")
c1.clock.Increment(interval)
Eventually(fakeHaltCallbacker.HaltCallbackCallCount).Should(Equal(0))
By("Asserting the StatusReport responds correctly if the haltCallback is not called")
Eventually(
func() orderer_types.Status {
_, status := c1.StatusReport()
return status
},
).Should(Equal(orderer_types.StatusInactive))
cRel, _ := c1.StatusReport()
Expect(cRel).To(Equal(orderer_types.ClusterRelationMember))
})

It("can remove leader by reconfiguring cluster even if leadership transfer fails", func() {
Expand Down