fix bitArray nil bugs

This commit is contained in:
Jae Kwon 2015-05-07 17:35:58 -07:00
parent ba17961269
commit 6020223e85
2 changed files with 70 additions and 33 deletions

View File

@ -21,14 +21,19 @@ func NewBitArray(bits uint) *BitArray {
}
func (bA *BitArray) Size() uint {
if bA == nil {
return 0
}
return bA.Bits
}
// NOTE: behavior is undefined if i >= bA.Bits
func (bA *BitArray) GetIndex(i uint) bool {
if bA == nil {
return false
}
bA.mtx.Lock()
defer bA.mtx.Unlock()
return bA.getIndex(i)
}
@ -41,9 +46,11 @@ func (bA *BitArray) getIndex(i uint) bool {
// NOTE: behavior is undefined if i >= bA.Bits
func (bA *BitArray) SetIndex(i uint, v bool) bool {
if bA == nil {
return false
}
bA.mtx.Lock()
defer bA.mtx.Unlock()
return bA.setIndex(i, v)
}
@ -60,6 +67,9 @@ func (bA *BitArray) setIndex(i uint, v bool) bool {
}
func (bA *BitArray) Copy() *BitArray {
if bA == nil {
return nil
}
bA.mtx.Lock()
defer bA.mtx.Unlock()
return bA.copy()
@ -85,9 +95,11 @@ func (bA *BitArray) copyBits(bits uint) *BitArray {
// Returns a BitArray of larger bits size.
func (bA *BitArray) Or(o *BitArray) *BitArray {
if bA == nil {
o.Copy()
}
bA.mtx.Lock()
defer bA.mtx.Unlock()
c := bA.copyBits(MaxUint(bA.Bits, o.Bits))
for i := 0; i < len(c.Elems); i++ {
c.Elems[i] |= o.Elems[i]
@ -97,9 +109,11 @@ func (bA *BitArray) Or(o *BitArray) *BitArray {
// Returns a BitArray of smaller bit size.
func (bA *BitArray) And(o *BitArray) *BitArray {
if bA == nil {
return nil
}
bA.mtx.Lock()
defer bA.mtx.Unlock()
return bA.and(o)
}
@ -112,9 +126,11 @@ func (bA *BitArray) and(o *BitArray) *BitArray {
}
func (bA *BitArray) Not() *BitArray {
if bA == nil {
return nil // Degenerate
}
bA.mtx.Lock()
defer bA.mtx.Unlock()
c := bA.copy()
for i := 0; i < len(c.Elems); i++ {
c.Elems[i] = ^c.Elems[i]
@ -123,9 +139,11 @@ func (bA *BitArray) Not() *BitArray {
}
func (bA *BitArray) Sub(o *BitArray) *BitArray {
if bA == nil {
return nil
}
bA.mtx.Lock()
defer bA.mtx.Unlock()
if bA.Bits > o.Bits {
c := bA.copy()
for i := 0; i < len(o.Elems)-1; i++ {
@ -139,11 +157,14 @@ func (bA *BitArray) Sub(o *BitArray) *BitArray {
}
return c
} else {
return bA.and(o.Not())
return bA.and(o.Not()) // Note degenerate case where o == nil
}
}
func (bA *BitArray) IsFull() bool {
if bA == nil {
return true
}
bA.mtx.Lock()
defer bA.mtx.Unlock()
@ -165,6 +186,9 @@ func (bA *BitArray) IsFull() bool {
}
func (bA *BitArray) PickRandom() (uint, bool) {
if bA == nil {
return 0, false
}
bA.mtx.Lock()
defer bA.mtx.Unlock()
@ -210,14 +234,16 @@ func (bA *BitArray) String() string {
}
bA.mtx.Lock()
defer bA.mtx.Unlock()
return bA.stringIndented("")
}
func (bA *BitArray) StringIndented(indent string) string {
if bA == nil {
return "nil-BitArray"
}
bA.mtx.Lock()
defer bA.mtx.Unlock()
return bA.StringIndented(indent)
return bA.stringIndented(indent)
}
func (bA *BitArray) stringIndented(indent string) string {

View File

@ -433,7 +433,6 @@ OUTER_LOOP:
return
}
rs := conR.conS.GetRoundState()
ps.EnsureVoteBitArrays(rs.Height, rs.Validators.Size())
prs := ps.GetRoundState()
switch sleeping {
@ -443,7 +442,14 @@ OUTER_LOOP:
sleeping = 0
}
trySendVote := func(voteSet *VoteSet, peerVoteSet *BitArray) (sent bool) {
// Returns true when useful work was done.
trySendVote := func(height uint, voteSet *VoteSet, peerVoteSet *BitArray) (sent bool) {
if voteSet == nil {
return false
} else if peerVoteSet == nil {
ps.EnsureVoteBitArrays(height, voteSet.Size())
return true
}
// TODO: give priority to our vote.
if index, ok := voteSet.BitArray().Sub(peerVoteSet.Copy()).PickRandom(); ok {
vote := voteSet.GetByIndex(index)
@ -456,7 +462,14 @@ OUTER_LOOP:
return false
}
// Returns true when useful work was done.
trySendCommitFromValidation := func(blockMeta *types.BlockMeta, validation *types.Validation, peerVoteSet *BitArray) (sent bool) {
if validation == nil {
return false
} else if peerVoteSet == nil {
ps.EnsureVoteBitArrays(blockMeta.Header.Height, uint(len(validation.Commits)))
return true
}
if index, ok := validation.BitArray().Sub(prs.Commits.Copy()).PickRandom(); ok {
commit := validation.Commits[index]
log.Debug("Picked commit to send", "index", index, "commit", commit)
@ -482,31 +495,27 @@ OUTER_LOOP:
// If there are lastcommits to send...
if prs.Round == 0 && prs.Step == RoundStepNewHeight {
if prs.LastCommits != nil && rs.LastCommits != nil {
if prs.LastCommits.Size() == rs.LastCommits.Size() {
if trySendVote(rs.LastCommits, prs.LastCommits) {
continue OUTER_LOOP
}
}
if trySendVote(rs.Height-1, rs.LastCommits, prs.LastCommits) {
continue OUTER_LOOP
}
}
// If there are prevotes to send...
if rs.Round == prs.Round && prs.Step <= RoundStepPrevote {
if trySendVote(rs.Prevotes, prs.Prevotes) {
if trySendVote(rs.Height, rs.Prevotes, prs.Prevotes) {
continue OUTER_LOOP
}
}
// If there are precommits to send...
if rs.Round == prs.Round && prs.Step <= RoundStepPrecommit {
if trySendVote(rs.Precommits, prs.Precommits) {
if trySendVote(rs.Height, rs.Precommits, prs.Precommits) {
continue OUTER_LOOP
}
}
// If there are any commits to send...
if trySendVote(rs.Commits, prs.Commits) {
if trySendVote(rs.Height, rs.Commits, prs.Commits) {
continue OUTER_LOOP
}
}
@ -517,7 +526,7 @@ OUTER_LOOP:
// If peer is lagging by height 1, match our LastCommits or SeenValidation to peer's Commits.
if rs.Height == prs.Height+1 && rs.LastCommits.Size() > 0 {
// If there are lastcommits to send...
if trySendVote(rs.LastCommits, prs.Commits) {
if trySendVote(prs.Height, rs.LastCommits, prs.Commits) {
continue OUTER_LOOP
} else {
ps.SetHasAllCatchupCommits(prs.Height)
@ -665,18 +674,20 @@ func (ps *PeerState) EnsureVoteBitArrays(height uint, numValidators uint) {
ps.mtx.Lock()
defer ps.mtx.Unlock()
if ps.Height != height {
return
}
if ps.Prevotes == nil {
ps.Prevotes = NewBitArray(numValidators)
}
if ps.Precommits == nil {
ps.Precommits = NewBitArray(numValidators)
}
if ps.Commits == nil {
ps.Commits = NewBitArray(numValidators)
if ps.Height == height {
if ps.Prevotes == nil {
ps.Prevotes = NewBitArray(numValidators)
}
if ps.Precommits == nil {
ps.Precommits = NewBitArray(numValidators)
}
if ps.Commits == nil {
ps.Commits = NewBitArray(numValidators)
}
} else if ps.Height == height+1 {
if ps.LastCommits == nil {
ps.LastCommits = NewBitArray(numValidators)
}
}
}