pkg/idutil: reduce conflict rate from 1% to 0.005%

Perviously, we only use 8bits from member identification
in id generation. The conflict rate is A(256,3)/256^3, which
is around 1%. Now we use 16bites to reduce the rate to 0.005%.

We can attach the full member id into id generation if needed...
This commit is contained in:
Xiang Li 2016-02-04 13:06:27 -08:00
parent 0cdf1c45cf
commit e44e753e66
3 changed files with 9 additions and 9 deletions

View File

@ -358,7 +358,7 @@ func NewServer(cfg *ServerConfig) (*EtcdServer, error) {
lstats: lstats,
SyncTicker: time.Tick(500 * time.Millisecond),
peerRt: prt,
reqIDGen: idutil.NewGenerator(uint8(id), time.Now()),
reqIDGen: idutil.NewGenerator(uint16(id), time.Now()),
forceVersionC: make(chan struct{}),
msgSnapC: make(chan raftpb.Message, maxInFlightMsgSnap),
}

View File

@ -24,7 +24,7 @@ import (
const (
tsLen = 5 * 8
cntLen = 2 * 8
cntLen = 8
suffixLen = tsLen + cntLen
)
@ -32,7 +32,7 @@ const (
// High order byte is memberID, next 5 bytes are from timestamp,
// and low order 2 bytes are 0s.
// | prefix | suffix |
// | 1 byte | 5 bytes | 2 bytes |
// | 2 bytes | 5 bytes | 1 byte |
// | memberID | timestamp | cnt |
//
// The timestamp 5 bytes is different when the machine is restart
@ -42,16 +42,16 @@ const (
// The count field may overflow to timestamp field, which is intentional.
// It helps to extend the event window to 2^56. This doesn't break that
// id generated after restart is unique because etcd throughput is <<
// 65536req/ms.
// 256req/ms(250k reqs/second).
type Generator struct {
mu sync.Mutex
// high order byte
// high order 2 bytes
prefix uint64
// low order 7 bytes
// low order 6 bytes
suffix uint64
}
func NewGenerator(memberID uint8, now time.Time) *Generator {
func NewGenerator(memberID uint16, now time.Time) *Generator {
prefix := uint64(memberID) << suffixLen
unixMilli := uint64(now.UnixNano()) / uint64(time.Millisecond/time.Nanosecond)
suffix := lowbit(unixMilli, tsLen) << cntLen

View File

@ -22,7 +22,7 @@ import (
func TestNewGenerator(t *testing.T) {
g := NewGenerator(0x12, time.Unix(0, 0).Add(0x3456*time.Millisecond))
id := g.Next()
wid := uint64(0x1200000034560001)
wid := uint64(0x12000000345601)
if id != wid {
t.Errorf("id = %x, want %x", id, wid)
}
@ -45,7 +45,7 @@ func TestNewGeneratorUnique(t *testing.T) {
func TestNext(t *testing.T) {
g := NewGenerator(0x12, time.Unix(0, 0).Add(0x3456*time.Millisecond))
wid := uint64(0x1200000034560001)
wid := uint64(0x12000000345601)
for i := 0; i < 1000; i++ {
id := g.Next()
if id != wid+uint64(i) {