mirror of
				https://github.com/HDT3213/godis.git
				synced 2025-10-31 03:56:22 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			71 lines
		
	
	
		
			1.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			71 lines
		
	
	
		
			1.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package idgenerator
 | |
| 
 | |
| import (
 | |
| 	"hash/fnv"
 | |
| 	"log"
 | |
| 	"sync"
 | |
| 	"time"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	// epoch0 is set to the twitter snowflake epoch of Nov 04 2010 01:42:54 UTC in milliseconds
 | |
| 	// You may customize this to set a different epoch for your application.
 | |
| 	epoch0      int64 = 1288834974657
 | |
| 	maxSequence int64 = -1 ^ (-1 << uint64(nodeLeft))
 | |
| 	timeLeft    uint8 = 22
 | |
| 	nodeLeft    uint8 = 10
 | |
| 	nodeMask    int64 = -1 ^ (-1 << uint64(timeLeft-nodeLeft))
 | |
| )
 | |
| 
 | |
| // IDGenerator generates unique uint64 ID using snowflake algorithm
 | |
| type IDGenerator struct {
 | |
| 	mu        *sync.Mutex
 | |
| 	lastStamp int64
 | |
| 	nodeID    int64
 | |
| 	sequence  int64
 | |
| 	epoch     time.Time
 | |
| }
 | |
| 
 | |
| // MakeGenerator creates a new IDGenerator
 | |
| func MakeGenerator(node string) *IDGenerator {
 | |
| 	fnv64 := fnv.New64()
 | |
| 	_, _ = fnv64.Write([]byte(node))
 | |
| 	nodeID := int64(fnv64.Sum64()) & nodeMask
 | |
| 
 | |
| 	var curTime = time.Now()
 | |
| 	epoch := curTime.Add(time.Unix(epoch0/1000, (epoch0%1000)*1000000).Sub(curTime))
 | |
| 
 | |
| 	return &IDGenerator{
 | |
| 		mu:        &sync.Mutex{},
 | |
| 		lastStamp: -1,
 | |
| 		nodeID:    nodeID,
 | |
| 		sequence:  1,
 | |
| 		epoch:     epoch,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // NextID returns next unique ID
 | |
| func (w *IDGenerator) NextID() int64 {
 | |
| 	w.mu.Lock()
 | |
| 	defer w.mu.Unlock()
 | |
| 
 | |
| 	timestamp := time.Since(w.epoch).Nanoseconds() / 1000000
 | |
| 	if timestamp < w.lastStamp {
 | |
| 		log.Fatal("can not generate id")
 | |
| 	}
 | |
| 	if w.lastStamp == timestamp {
 | |
| 		w.sequence = (w.sequence + 1) & maxSequence
 | |
| 		if w.sequence == 0 {
 | |
| 			for timestamp <= w.lastStamp {
 | |
| 				timestamp = time.Since(w.epoch).Nanoseconds() / 1000000
 | |
| 			}
 | |
| 		}
 | |
| 	} else {
 | |
| 		w.sequence = 0
 | |
| 	}
 | |
| 	w.lastStamp = timestamp
 | |
| 	id := (timestamp << timeLeft) | (w.nodeID << nodeLeft) | w.sequence
 | |
| 	//fmt.Printf("%d %d %d\n", timestamp, w.sequence, id)
 | |
| 	return id
 | |
| }
 | 
