mirror of
https://github.com/fluencelabs/tendermint
synced 2025-06-12 21:01:21 +00:00
stack trace in p2p/connection panics, bitArray fix
This commit is contained in:
@ -1,8 +1,8 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"math/rand"
|
||||
"strings"
|
||||
|
||||
@ -10,40 +10,43 @@ import (
|
||||
)
|
||||
|
||||
// Not goroutine safe
|
||||
type BitArray []uint64
|
||||
type BitArray struct {
|
||||
bits uint
|
||||
elems []uint64
|
||||
}
|
||||
|
||||
func NewBitArray(length uint) BitArray {
|
||||
return BitArray(make([]uint64, (length+63)/64))
|
||||
func NewBitArray(bits uint) BitArray {
|
||||
return BitArray{bits, make([]uint64, (bits+63)/64)}
|
||||
}
|
||||
|
||||
func ReadBitArray(r io.Reader, n *int64, err *error) BitArray {
|
||||
lengthTotal := ReadUInt32(r, n, err)
|
||||
lengthWritten := ReadUInt32(r, n, err)
|
||||
bits := ReadUVarInt(r, n, err)
|
||||
elemsWritten := ReadUVarInt(r, n, err)
|
||||
if *err != nil {
|
||||
return nil
|
||||
return BitArray{}
|
||||
}
|
||||
buf := make([]uint64, int(lengthTotal))
|
||||
for i := uint32(0); i < lengthWritten; i++ {
|
||||
buf[i] = ReadUInt64(r, n, err)
|
||||
if err != nil {
|
||||
return nil
|
||||
bA := NewBitArray(bits)
|
||||
for i := uint(0); i < elemsWritten; i++ {
|
||||
bA.elems[i] = ReadUInt64(r, n, err)
|
||||
if *err != nil {
|
||||
return BitArray{}
|
||||
}
|
||||
}
|
||||
return BitArray(buf)
|
||||
return bA
|
||||
}
|
||||
|
||||
func (bA BitArray) WriteTo(w io.Writer) (n int64, err error) {
|
||||
// Count the last element > 0.
|
||||
lastNonzeroIndex := -1
|
||||
for i, elem := range bA {
|
||||
elemsToWrite := 0
|
||||
for i, elem := range bA.elems {
|
||||
if elem > 0 {
|
||||
lastNonzeroIndex = i
|
||||
elemsToWrite = i + 1
|
||||
}
|
||||
}
|
||||
WriteUInt32(w, uint32(len(bA)), &n, &err)
|
||||
WriteUInt32(w, uint32(lastNonzeroIndex+1), &n, &err)
|
||||
for i, elem := range bA {
|
||||
if i > lastNonzeroIndex {
|
||||
WriteUVarInt(w, bA.bits, &n, &err)
|
||||
WriteUVarInt(w, uint(elemsToWrite), &n, &err)
|
||||
for i, elem := range bA.elems {
|
||||
if i >= elemsToWrite {
|
||||
break
|
||||
}
|
||||
WriteUInt64(w, elem, &n, &err)
|
||||
@ -51,44 +54,54 @@ func (bA BitArray) WriteTo(w io.Writer) (n int64, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// NOTE: behavior is undefined if i >= bA.bits
|
||||
func (bA BitArray) GetIndex(i uint) bool {
|
||||
return bA[i/64]&uint64(1<<(i%64)) > 0
|
||||
return bA.elems[i/64]&uint64(1<<(i%64)) > 0
|
||||
}
|
||||
|
||||
// NOTE: behavior is undefined if i >= bA.bits
|
||||
func (bA BitArray) SetIndex(i uint, v bool) {
|
||||
if v {
|
||||
bA[i/64] |= uint64(1 << (i % 64))
|
||||
bA.elems[i/64] |= uint64(1 << (i % 64))
|
||||
} else {
|
||||
bA[i/64] &= ^uint64(1 << (i % 64))
|
||||
bA.elems[i/64] &= ^uint64(1 << (i % 64))
|
||||
}
|
||||
}
|
||||
|
||||
func (bA BitArray) Copy() BitArray {
|
||||
c := make([]uint64, len(bA))
|
||||
copy(c, bA)
|
||||
return BitArray(c)
|
||||
c := make([]uint64, len(bA.elems))
|
||||
copy(c, bA.elems)
|
||||
return BitArray{bA.bits, c}
|
||||
}
|
||||
|
||||
func (bA BitArray) copyBits(bits uint) BitArray {
|
||||
c := make([]uint64, (bits+63)/64)
|
||||
copy(c, bA.elems)
|
||||
return BitArray{bits, c}
|
||||
}
|
||||
|
||||
// Returns a BitArray of larger bits size.
|
||||
func (bA BitArray) Or(o BitArray) BitArray {
|
||||
c := bA.Copy()
|
||||
for i, _ := range c {
|
||||
c[i] = o[i] | c[i]
|
||||
c := bA.copyBits(MaxUint(bA.bits, o.bits))
|
||||
for i := 0; i < len(c.elems); i++ {
|
||||
c.elems[i] |= o.elems[i]
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// Returns a BitArray of smaller bit size.
|
||||
func (bA BitArray) And(o BitArray) BitArray {
|
||||
c := bA.Copy()
|
||||
for i, _ := range c {
|
||||
c[i] = o[i] & c[i]
|
||||
c := bA.copyBits(MinUint(bA.bits, o.bits))
|
||||
for i := 0; i < len(c.elems); i++ {
|
||||
c.elems[i] &= o.elems[i]
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func (bA BitArray) Not() BitArray {
|
||||
c := bA.Copy()
|
||||
for i, _ := range c {
|
||||
c[i] = ^c[i]
|
||||
for i := 0; i < len(c.elems); i++ {
|
||||
c.elems[i] = ^c.elems[i]
|
||||
}
|
||||
return c
|
||||
}
|
||||
@ -97,64 +110,40 @@ func (bA BitArray) Sub(o BitArray) BitArray {
|
||||
return bA.And(o.Not())
|
||||
}
|
||||
|
||||
// NOTE: returns counts or a longer int slice as necessary.
|
||||
func (bA BitArray) AddToCounts(counts []int) []int {
|
||||
for bytei := 0; bytei < len(bA); bytei++ {
|
||||
for biti := 0; biti < 64; biti++ {
|
||||
if (bA[bytei] & (1 << uint(biti))) == 0 {
|
||||
continue
|
||||
}
|
||||
index := 64*bytei + biti
|
||||
if len(counts) <= index {
|
||||
counts = append(counts, make([]int, (index-len(counts)+1))...)
|
||||
}
|
||||
counts[index]++
|
||||
}
|
||||
}
|
||||
return counts
|
||||
}
|
||||
|
||||
func (bA BitArray) PickRandom() (int, bool) {
|
||||
randStart := rand.Intn(len(bA))
|
||||
for i := 0; i < len(bA); i++ {
|
||||
bytei := ((i + randStart) % len(bA))
|
||||
if bA[bytei] > 0 {
|
||||
randBitStart := rand.Intn(64)
|
||||
for j := 0; j < 64; j++ {
|
||||
biti := ((j + randBitStart) % 64)
|
||||
//fmt.Printf("%X %v %v %v\n", iHas, j, biti, randBitStart)
|
||||
if (bA[bytei] & (1 << uint(biti))) > 0 {
|
||||
return 64*int(bytei) + int(biti), true
|
||||
length := len(bA.elems)
|
||||
randElemStart := rand.Intn(length)
|
||||
for i := 0; i < length; i++ {
|
||||
elemIdx := ((i + randElemStart) % length)
|
||||
if elemIdx < length-1 {
|
||||
if bA.elems[elemIdx] > 0 {
|
||||
randBitStart := rand.Intn(64)
|
||||
for j := 0; j < 64; j++ {
|
||||
bitIdx := ((j + randBitStart) % 64)
|
||||
if (bA.elems[elemIdx] & (1 << uint(bitIdx))) > 0 {
|
||||
return 64*int(elemIdx) + int(bitIdx), true
|
||||
}
|
||||
}
|
||||
panic("should not happen")
|
||||
}
|
||||
} else {
|
||||
// Special case for last elem, to ignore straggler bits
|
||||
elemBits := int(bA.bits) % 64
|
||||
if elemBits == 0 {
|
||||
elemBits = 64
|
||||
}
|
||||
randBitStart := rand.Intn(elemBits)
|
||||
for j := 0; j < elemBits; j++ {
|
||||
bitIdx := ((j + randBitStart) % elemBits)
|
||||
if (bA.elems[elemIdx] & (1 << uint(bitIdx))) > 0 {
|
||||
return 64*int(elemIdx) + int(bitIdx), true
|
||||
}
|
||||
}
|
||||
panic("should not happen")
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// Pick an index from this BitArray that is 1 && whose count is lowest.
|
||||
func (bA BitArray) PickRarest(counts []int) (rarest int, ok bool) {
|
||||
smallestCount := math.MaxInt32
|
||||
for bytei := 0; bytei < len(bA); bytei++ {
|
||||
if bA[bytei] > 0 {
|
||||
for biti := 0; biti < 64; biti++ {
|
||||
if (bA[bytei] & (1 << uint(biti))) == 0 {
|
||||
continue
|
||||
}
|
||||
index := 64*bytei + biti
|
||||
if counts[index] < smallestCount {
|
||||
smallestCount = counts[index]
|
||||
rarest = index
|
||||
ok = true
|
||||
}
|
||||
}
|
||||
panic("should not happen")
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (bA BitArray) String() string {
|
||||
return bA.StringWithIndent("")
|
||||
}
|
||||
@ -162,8 +151,8 @@ func (bA BitArray) String() string {
|
||||
func (bA BitArray) StringWithIndent(indent string) string {
|
||||
lines := []string{}
|
||||
bits := ""
|
||||
for i := 0; i < len(bA)*64; i++ {
|
||||
if bA.GetIndex(uint(i)) {
|
||||
for i := uint(0); i < bA.bits; i++ {
|
||||
if bA.GetIndex(i) {
|
||||
bits += "X"
|
||||
} else {
|
||||
bits += "_"
|
||||
@ -182,5 +171,5 @@ func (bA BitArray) StringWithIndent(indent string) string {
|
||||
if len(bits) > 0 {
|
||||
lines = append(lines, bits)
|
||||
}
|
||||
return strings.Join(lines, indent)
|
||||
return fmt.Sprintf("BA{%v:%v}", bA.bits, strings.Join(lines, indent))
|
||||
}
|
||||
|
Reference in New Issue
Block a user