C-snowflake uuid 生成器

UUID(Universally Unique IDentifier),通用唯一标识符,也叫GUID(Globally Unique IDentifier)。UUID是使用128bits来表示,即16个字节。通常情况下,16个字节来表示UUID所占用的字节也不算多。但是,在某些场景或应用下,由于某些限制,需要UUID所占空间进一步压缩,压缩到8字节,另外,生成的UUID还需要保持有序性。

snowflake原理

轰隆隆~,2010年Twitter提出了snowflake。snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。但是使用scala实现。

其核心思想是:8字节,最高位符号位总是0,接着使用41bit作为毫秒数,10bit作为机器的ID,12bit作为毫秒内的序列号。那么,在c语言中,使用8字节的基本数据类型用来存储id即可。

  • 1位标识,最高位符号位总是0,所以生成的ID总是正数。
  • 41位时间截(毫秒级),41位的时间截,可以使用69年,(1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69年
  • 10位的机器ID,显然可以表示1024台不同机器。当然还可以进一步细分,可根据自身需求定义。
  • 12位序列号,12位的序列号支持每个节点每毫秒(同一机器,同一时间截)产生4096个ID序号。

理论上,每毫秒可以产生4M个ID。

了解了原理,接下来就实战,干!

snowflake实现

snowflake.h

typedef struct _snowflake_s
{
    uint64_t timestamp;
    uint16_t machine_id;
    uint16_t seq_id;
}snowflake_t;

typedef struct _id_gen_s
{
    uint64_t epoch;
    snowflake_t gid;
}id_gen_t;

id_gen_t* gid_gen_init(uint16_t machine_id);
void gid_gen_uninit(id_gen_t* handle);
uint64_t gid_gen_get(id_gen_t* handle);

snowflake.c

id_gen_t* gid_gen_init(uint16_t machine_id)
{
    id_gen_t* handle = (id_gen_t*)malloc(sizeof(id_gen_t));

    handle->epoch = get_time_now_ms();
    handle->gid.machine_id = machine_id;
    handle->gid.timestamp = get_time_now_ms();
    handle->gid.seq_id = 0;

    return handle;
}

void gid_gen_uninit(id_gen_t* handle)
{
    free(handle);
}

uint64_t gid_gen_get(id_gen_t* handle)
{
    uint64_t now = get_time_now_ms();
    uint64_t gid = 0;

    if (handle->gid.timestamp > now)
    {
        perror("clock moved backwards, refusing to generate id");
        exit(-1);
    }
    else if (handle->gid.timestamp == now)
    {
        __sync_fetch_and_add(&handle->gid.seq_id,1);
        if (0 == (handle->gid.seq_id & SEQ_ID_MASK))//overflow
            now = wait_next_ms(handle->gid.timestamp);//wait next ms
    }
    else
    {
        handle->gid.seq_id = 0;
    }
    handle->gid.timestamp = now;

    gid |= (now&TIMESTAMP_MASK) << (MACHINE_ID_BITS+SEQ_ID_BITS);
    gid |= (handle->gid.machine_id&MACHINE_ID_MASK) << SEQ_ID_BITS;
    gid |= handle->gid.seq_id&SEQ_ID_MASK;
    return gid;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sif_666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值