Skip to content
  • P
    Projects
  • G
    Groups
  • S
    Snippets
  • Help

丁松杰 / Pole

  • This project
    • Loading...
  • Sign in
Go to a project
  • Project
  • Repository
  • Issues 0
  • Merge Requests 0
  • Pipelines
  • Wiki
  • Snippets
  • Members
  • Activity
  • Graph
  • Charts
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
  • Files
  • Commits
  • Branches
  • Tags
  • Contributors
  • Graph
  • Compare
  • Charts
Switch branch/tag
  • Pole
  • src
  • Pole.Core
  • Utils
  • SnowflakeIdGenerator.cs
Find file
BlameHistoryPermalink
  • dingsongjie's avatar
    精简代码 · 2c98d157
    dingsongjie committed 5 years ago
    2c98d157
SnowflakeIdGenerator.cs 3.99 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
using System;
using System.Collections.Generic;
using System.Text;

namespace Pole.Core.Utils.Abstraction
{
    public  class SnowflakeIdGenerator : ISnowflakeIdGenerator
    {

        private static readonly DateTime Jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
        private int generatorIdBits;
        private long twepoch;
        private int maxGeneratorId;
        private const int SequenceAndGeneratorIdBits = 64 - 1 - 41;
        /// <summary>
        /// 这里的位数决定 每毫秒能生成的最大个数 
        /// </summary>
        private int sequenceBits;
        private int generatorIdShift;
        private const int TimestampLeftShift = SequenceAndGeneratorIdBits;
        private long sequenceMask;
        public long GeneratorId { get; private set; }

        // 毫秒内序列(0~4095) 
        public long Sequence { get; private set; }

        // 上次生成ID的时间截 
        public long LastTimestamp { get; private set; }

        /// <summary>
        /// 时间戳为41位,可以使用69年,年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69
        /// </summary>
        /// <param name="beginTime"></param>
        /// <param name="generatorIdBits"></param>
        public SnowflakeIdGenerator(DateTime beginTime, int generatorIdBits, long generatorId)
        {
            twepoch = Convert.ToInt64((beginTime.ToUniversalTime() - Jan1st1970).TotalMilliseconds);
            this.generatorIdBits = generatorIdBits;
            maxGeneratorId = -1 ^ (-1 << this.generatorIdBits);
            sequenceBits = SequenceAndGeneratorIdBits - generatorIdBits;
            generatorIdShift = sequenceBits;
            sequenceMask = -1L ^ (-1L << sequenceBits);
            GeneratorId = generatorId;
            Sequence = 0L;
            LastTimestamp = -1L;
        }
        public string NextId()
        {
            lock (this)
            {
                long timestamp = GetCurrentTimestamp();
                if (timestamp > LastTimestamp) //时间戳改变,毫秒内序列重置
                {
                    Sequence = 0L;
                }
                else if (timestamp == LastTimestamp) //如果是同一时间生成的,则进行毫秒内序列
                {
                    Sequence = (Sequence + 1) & sequenceMask;
                    if (Sequence == 0) //毫秒内序列溢出
                    {
                        timestamp = GetNextTimestamp(LastTimestamp); //阻塞到下一个毫秒,获得新的时间戳
                    }
                }
                else   //当前时间小于上一次ID生成的时间戳,证明系统时钟被回拨,此时需要做回拨处理
                {
                    Sequence = (Sequence + 1) & sequenceMask;
                    if (Sequence > 0)
                    {
                        timestamp = LastTimestamp;     //停留在最后一次时间戳上,等待系统时间追上后即完全度过了时钟回拨问题。
                    }
                    else   //毫秒内序列溢出
                    {
                        timestamp = LastTimestamp + 1;   //直接进位到下一个毫秒                          
                    }
                }

                LastTimestamp = timestamp;       //上次生成ID的时间截

                //移位并通过或运算拼到一起组成64位的ID
                var id = ((timestamp - twepoch) << TimestampLeftShift)
                        | (GeneratorId << generatorIdShift)
                        | Sequence;
                return id.ToString();
            }
        }
        private static long GetCurrentTimestamp()
        {
            return (long)(DateTime.UtcNow - Jan1st1970).TotalMilliseconds;
        }
        private static long GetNextTimestamp(long lastTimestamp)
        {
            long timestamp = GetCurrentTimestamp();
            while (timestamp <= lastTimestamp)
            {
                timestamp = GetCurrentTimestamp();
            }
            return timestamp;
        }
    }
}