├── README.md └── idworker.go /README.md: -------------------------------------------------------------------------------- 1 | # go-id-worker 2 | 3 | IdWorker in golang. 4 | 5 | [HTTP Interface Open source project (https://github.com/gitstliu/idservice)](https://github.com/gitstliu/idservice) 6 | 7 | 8 | go-id-worker is an id creator, for generating a global unique id. The type of id is int64. 9 | 10 | ## You can get it like this. 11 | ``` 12 | go get "github.com/gitstliu/go-id-worker" 13 | ``` 14 | 15 | ## And import it like this. 16 | ``` 17 | import ( 18 | "github.com/gitstliu/go-id-worker" 19 | ) 20 | ``` 21 | 22 | ## Create and use an idWorker like this. 23 | ``` 24 | currWoker := &idworker.IdWorker{} 25 | currWoker.InitIdWorker(1000, 1) 26 | newId , newIdErr:= currWoker.NexiId() 27 | ...... 28 | ``` 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /idworker.go: -------------------------------------------------------------------------------- 1 | package idworker 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "sync" 7 | "time" 8 | ) 9 | 10 | type IdWorker struct { 11 | startTime int64 12 | workerIdBits uint 13 | datacenterIdBits uint 14 | maxWorkerId int64 15 | maxDatacenterId int64 16 | sequenceBits uint 17 | workerIdLeftShift uint 18 | datacenterIdLeftShift uint 19 | timestampLeftShift uint 20 | sequenceMask int64 21 | workerId int64 22 | datacenterId int64 23 | sequence int64 24 | lastTimestamp int64 25 | signMask int64 26 | idLock *sync.Mutex 27 | } 28 | 29 | func (this *IdWorker) InitIdWorker(workerId, datacenterId int64) error { 30 | 31 | var baseValue int64 = -1 32 | this.startTime = 1463834116272 33 | this.workerIdBits = 5 34 | this.datacenterIdBits = 5 35 | this.maxWorkerId = baseValue ^ (baseValue << this.workerIdBits) 36 | this.maxDatacenterId = baseValue ^ (baseValue << this.datacenterIdBits) 37 | this.sequenceBits = 12 38 | this.workerIdLeftShift = this.sequenceBits 39 | this.datacenterIdLeftShift = this.workerIdBits + this.workerIdLeftShift 40 | this.timestampLeftShift = this.datacenterIdBits + this.datacenterIdLeftShift 41 | this.sequenceMask = baseValue ^ (baseValue << this.sequenceBits) 42 | this.sequence = 0 43 | this.lastTimestamp = -1 44 | this.signMask = ^baseValue + 1 45 | 46 | this.idLock = &sync.Mutex{} 47 | 48 | if this.workerId < 0 || this.workerId > this.maxWorkerId { 49 | return errors.New(fmt.Sprintf("workerId[%v] is less than 0 or greater than maxWorkerId[%v].", workerId, datacenterId)) 50 | } 51 | if this.datacenterId < 0 || this.datacenterId > this.maxDatacenterId { 52 | return errors.New(fmt.Sprintf("datacenterId[%d] is less than 0 or greater than maxDatacenterId[%d].", workerId, datacenterId)) 53 | } 54 | this.workerId = workerId 55 | this.datacenterId = datacenterId 56 | return nil 57 | } 58 | 59 | func (this *IdWorker) NextId() (int64, error) { 60 | this.idLock.Lock() 61 | timestamp := time.Now().UnixNano() 62 | if timestamp < this.lastTimestamp { 63 | return -1, errors.New(fmt.Sprintf("Clock moved backwards. Refusing to generate id for %d milliseconds", this.lastTimestamp-timestamp)) 64 | } 65 | 66 | if timestamp == this.lastTimestamp { 67 | this.sequence = (this.sequence + 1) & this.sequenceMask 68 | if this.sequence == 0 { 69 | timestamp = this.tilNextMillis() 70 | this.sequence = 0 71 | } 72 | } else { 73 | this.sequence = 0 74 | } 75 | 76 | this.lastTimestamp = timestamp 77 | 78 | this.idLock.Unlock() 79 | 80 | id := ((timestamp - this.startTime) << this.timestampLeftShift) | 81 | (this.datacenterId << this.datacenterIdLeftShift) | 82 | (this.workerId << this.workerIdLeftShift) | 83 | this.sequence 84 | 85 | if id < 0 { 86 | id = -id 87 | } 88 | 89 | return id, nil 90 | } 91 | 92 | func (this *IdWorker) tilNextMillis() int64 { 93 | timestamp := time.Now().UnixNano() 94 | if timestamp <= this.lastTimestamp { 95 | timestamp = time.Now().UnixNano() / int64(time.Millisecond) 96 | } 97 | return timestamp 98 | } 99 | --------------------------------------------------------------------------------