snowflake.h

/**
 * snowflake.h
 *
 * nextId()
 * 
 * nextIdFrom(unsigned char datacenterId, unsigned char workerId)
 *
 **/

#include <stdint.h>

// 定义起始的日期时间戳
#define EPOCH 1584340752713ULL

// 获取默认id
uint64_t nextId(void);

// 从指定的数据中心的指定的工作站获取id
uint64_t nextIdFrom(unsigned char, unsigned char);

 

snowflake.c

/**
 * filename: snowflake.c
 *
 * date: 2020-2-20 20:20:02
 *
 * description: 分布式全局唯一标识,
 *         Twitter的Snowflake算法的c语言实现(单线程)。
 *
 **/

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/timeb.h>
#include "snowflake.h"

// 默认的数据中心标识
const unsigned char DEFAULT_DATACENTER_ID = 0;

// 默认的工作站标识
const unsigned char DEFAULT_WORKER_ID = 0;

uint64_t BASE_TIMESTAMP_MILLISEC = EPOCH;    //EPOCH在snowflake.h中定义
uint64_t last_timestamp_millisec = 0;
uint64_t current_timestamp_millisec = 0;

unsigned short squenceNumber = 0;

// 
_Bool invalidWorkerId(const unsigned char, const unsigned char);

// 当前毫秒时间戳
void setCurrentTimeStampMillis(uint64_t *);


uint64_t nextId(void)
{
    return nextIdFrom(DEFAULT_DATACENTER_ID, DEFAULT_WORKER_ID);
}

uint64_t nextIdFrom(unsigned char datacenterId, unsigned char workerId)
{

    invalidWorkerId(datacenterId, workerId);
    //datacenterId &= 0x1F;
    //workerId &= 0x1F;

    setCurrentTimeStampMillis(&current_timestamp_millisec);
    if (squenceNumber >= 0xfff)
    {
        squenceNumber = 0;
        do
        {
            setCurrentTimeStampMillis(&current_timestamp_millisec);
        } while (current_timestamp_millisec <= last_timestamp_millisec);
        
        last_timestamp_millisec = current_timestamp_millisec;
    }

    uint64_t timeStamp = current_timestamp_millisec - BASE_TIMESTAMP_MILLISEC;
    
    uint64_t id = (timeStamp << 22) 
        | (datacenterId << 17)
        | (workerId << 12)
        | squenceNumber++ & 0xfff;
    
    return id;
}

_Bool invalidWorkerId(const unsigned char datacenterId, const unsigned char workerId)
{
    if (datacenterId >= 32 || workerId >= 32){
        fprintf(stderr, "[nextIdFrom() @ snowflake.c] "
                "ERROR! datacenterId and workerId both "
                "must be unsigned integer between 0 to 31, "
                "application exit!\n");
        exit(-1);    // other way: return 0 here;
    }
    return 1;
}


void setCurrentTimeStampMillis(uint64_t * millisec)
{
    struct timeb stCurrentTimeStamp;
    ftime(&stCurrentTimeStamp);
    (*millisec) = (uint64_t)stCurrentTimeStamp.time * 1000 + (uint64_t)stCurrentTimeStamp.millitm;
}

 

main.c

#include <stdio.h>
#include "snowflake.h"

int main(void)
{
    for (int i = 0; i < 600; i++)
    {
        printf("id[%4d]=%20I64u\n", i + 1, nextId() );
    }
    return 0;
}

 

posted on 2020-04-01 00:19  god with us  阅读(563)  评论(0编辑  收藏  举报