id.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. /*
  2. Copyright 2014 CoreOS, Inc.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package idutil
  14. import (
  15. "math"
  16. "sync"
  17. "time"
  18. )
  19. const (
  20. tsLen = 5 * 8
  21. cntLen = 2 * 8
  22. suffixLen = tsLen + cntLen
  23. )
  24. // The initial id is in this format:
  25. // High order byte is memberID, next 5 bytes are from timestamp,
  26. // and low order 2 bytes are 0s.
  27. // | prefix | suffix |
  28. // | 1 byte | 5 bytes | 2 bytes |
  29. // | memberID | timestamp | cnt |
  30. //
  31. // The timestamp 5 bytes is different when the machine is restart
  32. // after 1 ms and before 35 years.
  33. //
  34. // It increases suffix to generate the next id.
  35. // The count field may overflow to timestamp field, which is intentional.
  36. // It helps to extend the event window to 2^56. This doesn't break that
  37. // id generated after restart is unique because etcd throughput is <<
  38. // 65536req/ms.
  39. type Generator struct {
  40. mu sync.Mutex
  41. // high order byte
  42. prefix uint64
  43. // low order 7 bytes
  44. suffix uint64
  45. }
  46. func NewGenerator(memberID uint8, now time.Time) *Generator {
  47. prefix := uint64(memberID) << suffixLen
  48. unixMilli := uint64(now.UnixNano()) / uint64(time.Millisecond/time.Nanosecond)
  49. suffix := lowbit(unixMilli, tsLen) << cntLen
  50. return &Generator{
  51. prefix: prefix,
  52. suffix: suffix,
  53. }
  54. }
  55. // Next generates a id that is unique.
  56. func (g *Generator) Next() uint64 {
  57. g.mu.Lock()
  58. defer g.mu.Unlock()
  59. g.suffix++
  60. id := g.prefix | lowbit(g.suffix, suffixLen)
  61. return id
  62. }
  63. func lowbit(x uint64, n uint) uint64 {
  64. return x & (math.MaxUint64 >> (64 - n))
  65. }