producer/adjusthash.go (91 lines of code) (raw):
package producer
import (
"crypto/md5"
"encoding/hex"
"errors"
"fmt"
"strconv"
"strings"
)
const zero32Str = "00000000000000000000000000000000"
func toHex(x byte) byte {
if x < 10 {
return '0' + x
}
return 'a' - 10 + x
}
func getBitValue(val byte, bits int) byte {
if bits >= 16 {
return val
}
if bits >= 8 {
return val & (0xf - 1)
}
if bits >= 4 {
return val & (0xf - 3)
}
if bits >= 2 {
return val & (0xf - 7)
}
return val & (0xf - 15)
}
func AdjustHash(shardhash string, buckets int) (string, error) {
h := md5.New()
h.Write([]byte(shardhash))
cipherStr := h.Sum(nil)
var destBuf strings.Builder
destBuf.Grow(32)
i := 0
for buckets > 0 && i < len(cipherStr) {
if (i & 0x01) == 0 {
destBuf.WriteByte(toHex(getBitValue(cipherStr[i>>1]>>4, buckets)))
} else {
destBuf.WriteByte(toHex(getBitValue(cipherStr[i>>1]&0xF, buckets)))
}
buckets = buckets >> 4
i++
}
destBuf.WriteString(zero32Str[0 : 32-i])
return destBuf.String(), nil
}
func AdjustHashOld(shardhash string, buckets int) (string, error) {
res := Md5ToBin(ToMd5(shardhash))
x, err := BitCount(buckets)
if err != nil {
return "", err
}
tt := res[0:x]
tt = FillZero(tt, 8)
base, _ := strconv.ParseInt(tt, 2, 10)
yy := strconv.FormatInt(base, 16)
return FillZero(yy, 32), nil
}
// smilar as java Integer.bitCount
func BitCount(buckets int) (int, error) {
bin := strconv.FormatInt(int64(buckets), 2)
if strings.Contains(bin[1:], "1") || buckets <= 0 {
return -1, errors.New(fmt.Sprintf("buckets must be a power of 2, got %v,and The parameter "+
"buckets must be greater than or equal to 1 and less than or equal to 256.", buckets))
}
return strings.Count(bin, "0"), nil
}
func ToMd5(name string) string {
h := md5.New()
h.Write([]byte(name))
cipherStr := h.Sum(nil)
return hex.EncodeToString(cipherStr)
}
func Md5ToBin(md5 string) string {
bArr, _ := hex.DecodeString(md5)
res := ""
for _, b := range bArr {
res = fmt.Sprintf("%s%.8b", res, b)
}
return res
}
func FillZero(x string, n int) string {
length := n - (strings.Count(x, "") - 1)
for i := 0; i < length; i++ {
x = x + "0"
}
return x
}