github.com/hdt3213/godis@v1.2.9/lib/idgenerator/snowflake.go (about)

     1  package idgenerator
     2  
     3  import (
     4  	"hash/fnv"
     5  	"log"
     6  	"sync"
     7  	"time"
     8  )
     9  
    10  const (
    11  	// epoch0 is set to the twitter snowflake epoch of Nov 04 2010 01:42:54 UTC in milliseconds
    12  	// You may customize this to set a different epoch for your application.
    13  	epoch0      int64 = 1288834974657
    14  	maxSequence int64 = -1 ^ (-1 << uint64(nodeLeft))
    15  	timeLeft    uint8 = 22
    16  	nodeLeft    uint8 = 10
    17  	nodeMask    int64 = -1 ^ (-1 << uint64(timeLeft-nodeLeft))
    18  )
    19  
    20  // IDGenerator generates unique uint64 ID using snowflake algorithm
    21  type IDGenerator struct {
    22  	mu        *sync.Mutex
    23  	lastStamp int64
    24  	nodeID    int64
    25  	sequence  int64
    26  	epoch     time.Time
    27  }
    28  
    29  // MakeGenerator creates a new IDGenerator
    30  func MakeGenerator(node string) *IDGenerator {
    31  	fnv64 := fnv.New64()
    32  	_, _ = fnv64.Write([]byte(node))
    33  	nodeID := int64(fnv64.Sum64()) & nodeMask
    34  
    35  	var curTime = time.Now()
    36  	epoch := curTime.Add(time.Unix(epoch0/1000, (epoch0%1000)*1000000).Sub(curTime))
    37  
    38  	return &IDGenerator{
    39  		mu:        &sync.Mutex{},
    40  		lastStamp: -1,
    41  		nodeID:    nodeID,
    42  		sequence:  1,
    43  		epoch:     epoch,
    44  	}
    45  }
    46  
    47  // NextID returns next unique ID
    48  func (w *IDGenerator) NextID() int64 {
    49  	w.mu.Lock()
    50  	defer w.mu.Unlock()
    51  
    52  	timestamp := time.Since(w.epoch).Nanoseconds() / 1000000
    53  	if timestamp < w.lastStamp {
    54  		log.Fatal("can not generate id")
    55  	}
    56  	if w.lastStamp == timestamp {
    57  		w.sequence = (w.sequence + 1) & maxSequence
    58  		if w.sequence == 0 {
    59  			for timestamp <= w.lastStamp {
    60  				timestamp = time.Since(w.epoch).Nanoseconds() / 1000000
    61  			}
    62  		}
    63  	} else {
    64  		w.sequence = 0
    65  	}
    66  	w.lastStamp = timestamp
    67  	id := (timestamp << timeLeft) | (w.nodeID << nodeLeft) | w.sequence
    68  	//fmt.Printf("%d %d %d\n", timestamp, w.sequence, id)
    69  	return id
    70  }