Browse Source

Merge pull request #1446 from tendermint/1442-data-race-fix-attempt

fix data race
pull/1440/head
Ethan Buchman 7 years ago
committed by GitHub
parent
commit
d93e177a69
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 42 additions and 23 deletions
  1. +15
    -5
      consensus/reactor.go
  2. +9
    -4
      consensus/state.go
  3. +0
    -3
      consensus/types/state.go
  4. +13
    -5
      rpc/core/consensus.go
  5. +2
    -3
      rpc/core/pipe.go
  6. +3
    -3
      rpc/core/types/responses.go

+ 15
- 5
consensus/reactor.go View File

@ -9,7 +9,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/tendermint/go-amino"
amino "github.com/tendermint/go-amino"
cmn "github.com/tendermint/tmlibs/common" cmn "github.com/tendermint/tmlibs/common"
"github.com/tendermint/tmlibs/log" "github.com/tendermint/tmlibs/log"
@ -838,8 +838,8 @@ var (
ErrPeerStateInvalidStartTime = errors.New("Error peer state invalid startTime") ErrPeerStateInvalidStartTime = errors.New("Error peer state invalid startTime")
) )
// PeerState contains the known state of a peer, including its connection
// and threadsafe access to its PeerRoundState.
// PeerState contains the known state of a peer, including its connection and
// threadsafe access to its PeerRoundState.
type PeerState struct { type PeerState struct {
Peer p2p.Peer Peer p2p.Peer
logger log.Logger logger log.Logger
@ -878,12 +878,14 @@ func NewPeerState(peer p2p.Peer) *PeerState {
} }
} }
// SetLogger allows to set a logger on the peer state. Returns the peer state
// itself.
func (ps *PeerState) SetLogger(logger log.Logger) *PeerState { func (ps *PeerState) SetLogger(logger log.Logger) *PeerState {
ps.logger = logger ps.logger = logger
return ps return ps
} }
// GetRoundState returns an atomic snapshot of the PeerRoundState.
// GetRoundState returns an shallow copy of the PeerRoundState.
// There's no point in mutating it since it won't change PeerState. // There's no point in mutating it since it won't change PeerState.
func (ps *PeerState) GetRoundState() *cstypes.PeerRoundState { func (ps *PeerState) GetRoundState() *cstypes.PeerRoundState {
ps.mtx.Lock() ps.mtx.Lock()
@ -893,6 +895,14 @@ func (ps *PeerState) GetRoundState() *cstypes.PeerRoundState {
return &prs return &prs
} }
// GetRoundStateJSON returns a json of PeerRoundState, marshalled using go-amino.
func (ps *PeerState) GetRoundStateJSON() ([]byte, error) {
ps.mtx.Lock()
defer ps.mtx.Unlock()
return cdc.MarshalJSON(ps.PeerRoundState)
}
// GetHeight returns an atomic snapshot of the PeerRoundState's height // GetHeight returns an atomic snapshot of the PeerRoundState's height
// used by the mempool to ensure peers are caught up before broadcasting new txs // used by the mempool to ensure peers are caught up before broadcasting new txs
func (ps *PeerState) GetHeight() int64 { func (ps *PeerState) GetHeight() int64 {
@ -1055,7 +1065,7 @@ func (ps *PeerState) ensureCatchupCommitRound(height int64, round int, numValida
} }
} }
// EnsureVoteVitArrays ensures the bit-arrays have been allocated for tracking
// EnsureVoteBitArrays ensures the bit-arrays have been allocated for tracking
// what votes this peer has received. // what votes this peer has received.
// NOTE: It's important to make sure that numValidators actually matches // NOTE: It's important to make sure that numValidators actually matches
// what the node sees as the number of validators for height. // what the node sees as the number of validators for height.


+ 9
- 4
consensus/state.go View File

@ -168,18 +168,23 @@ func (cs *ConsensusState) GetState() sm.State {
return cs.state.Copy() return cs.state.Copy()
} }
// GetRoundState returns a copy of the internal consensus state.
// GetRoundState returns a shallow copy of the internal consensus state.
func (cs *ConsensusState) GetRoundState() *cstypes.RoundState { func (cs *ConsensusState) GetRoundState() *cstypes.RoundState {
cs.mtx.Lock() cs.mtx.Lock()
defer cs.mtx.Unlock() defer cs.mtx.Unlock()
return cs.getRoundState()
}
func (cs *ConsensusState) getRoundState() *cstypes.RoundState {
rs := cs.RoundState // copy rs := cs.RoundState // copy
return &rs return &rs
} }
// GetRoundStateJSON returns a json of RoundState, marshalled using go-amino.
func (cs *ConsensusState) GetRoundStateJSON() ([]byte, error) {
cs.mtx.Lock()
defer cs.mtx.Unlock()
return cdc.MarshalJSON(cs.RoundState)
}
// GetValidators returns a copy of the current validators. // GetValidators returns a copy of the current validators.
func (cs *ConsensusState) GetValidators() (int64, []*types.Validator) { func (cs *ConsensusState) GetValidators() (int64, []*types.Validator) {
cs.mtx.Lock() cs.mtx.Lock()


+ 0
- 3
consensus/types/state.go View File

@ -52,9 +52,6 @@ func (rs RoundStepType) String() string {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// RoundState defines the internal consensus state. // RoundState defines the internal consensus state.
// It is Immutable when returned from ConsensusState.GetRoundState()
// TODO: Actually, only the top pointer is copied,
// so access to field pointers is still racey
// NOTE: Not thread safe. Should only be manipulated by functions downstream // NOTE: Not thread safe. Should only be manipulated by functions downstream
// of the cs.receiveRoutine // of the cs.receiveRoutine
type RoundState struct { type RoundState struct {


+ 13
- 5
rpc/core/consensus.go View File

@ -1,8 +1,9 @@
package core package core
import ( import (
"encoding/json"
cm "github.com/tendermint/tendermint/consensus" cm "github.com/tendermint/tendermint/consensus"
cstypes "github.com/tendermint/tendermint/consensus/types"
p2p "github.com/tendermint/tendermint/p2p" p2p "github.com/tendermint/tendermint/p2p"
ctypes "github.com/tendermint/tendermint/rpc/core/types" ctypes "github.com/tendermint/tendermint/rpc/core/types"
sm "github.com/tendermint/tendermint/state" sm "github.com/tendermint/tendermint/state"
@ -58,7 +59,7 @@ func Validators(heightPtr *int64) (*ctypes.ResultValidators, error) {
return &ctypes.ResultValidators{height, validators.Validators}, nil return &ctypes.ResultValidators{height, validators.Validators}, nil
} }
// Dump consensus state.
// DumpConsensusState dumps consensus state.
// //
// ```shell // ```shell
// curl 'localhost:46657/dump_consensus_state' // curl 'localhost:46657/dump_consensus_state'
@ -83,11 +84,18 @@ func Validators(heightPtr *int64) (*ctypes.ResultValidators, error) {
// } // }
// ``` // ```
func DumpConsensusState() (*ctypes.ResultDumpConsensusState, error) { func DumpConsensusState() (*ctypes.ResultDumpConsensusState, error) {
peerRoundStates := make(map[p2p.ID]*cstypes.PeerRoundState)
peerRoundStates := make(map[p2p.ID]json.RawMessage)
for _, peer := range p2pSwitch.Peers().List() { for _, peer := range p2pSwitch.Peers().List() {
peerState := peer.Get(types.PeerStateKey).(*cm.PeerState) peerState := peer.Get(types.PeerStateKey).(*cm.PeerState)
peerRoundState := peerState.GetRoundState()
peerRoundState, err := peerState.GetRoundStateJSON()
if err != nil {
return nil, err
}
peerRoundStates[peer.ID()] = peerRoundState peerRoundStates[peer.ID()] = peerRoundState
} }
return &ctypes.ResultDumpConsensusState{consensusState.GetRoundState(), peerRoundStates}, nil
roundState, err := consensusState.GetRoundStateJSON()
if err != nil {
return nil, err
}
return &ctypes.ResultDumpConsensusState{roundState, peerRoundStates}, nil
} }

+ 2
- 3
rpc/core/pipe.go View File

@ -3,9 +3,8 @@ package core
import ( import (
"time" "time"
"github.com/tendermint/go-crypto"
crypto "github.com/tendermint/go-crypto"
"github.com/tendermint/tendermint/consensus" "github.com/tendermint/tendermint/consensus"
cstypes "github.com/tendermint/tendermint/consensus/types"
"github.com/tendermint/tendermint/p2p" "github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/proxy" "github.com/tendermint/tendermint/proxy"
sm "github.com/tendermint/tendermint/state" sm "github.com/tendermint/tendermint/state"
@ -23,7 +22,7 @@ var subscribeTimeout = 5 * time.Second
type Consensus interface { type Consensus interface {
GetState() sm.State GetState() sm.State
GetValidators() (int64, []*types.Validator) GetValidators() (int64, []*types.Validator)
GetRoundState() *cstypes.RoundState
GetRoundStateJSON() ([]byte, error)
} }
type P2P interface { type P2P interface {


+ 3
- 3
rpc/core/types/responses.go View File

@ -1,6 +1,7 @@
package core_types package core_types
import ( import (
"encoding/json"
"strings" "strings"
"time" "time"
@ -8,7 +9,6 @@ import (
crypto "github.com/tendermint/go-crypto" crypto "github.com/tendermint/go-crypto"
cmn "github.com/tendermint/tmlibs/common" cmn "github.com/tendermint/tmlibs/common"
cstypes "github.com/tendermint/tendermint/consensus/types"
"github.com/tendermint/tendermint/p2p" "github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/state" "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types" "github.com/tendermint/tendermint/types"
@ -109,8 +109,8 @@ type ResultValidators struct {
} }
type ResultDumpConsensusState struct { type ResultDumpConsensusState struct {
RoundState *cstypes.RoundState `json:"round_state"`
PeerRoundStates map[p2p.ID]*cstypes.PeerRoundState `json:"peer_round_states"`
RoundState json.RawMessage `json:"round_state"`
PeerRoundStates map[p2p.ID]json.RawMessage `json:"peer_round_states"`
} }
type ResultBroadcastTx struct { type ResultBroadcastTx struct {


Loading…
Cancel
Save