81 lines
2.4 KiB
C++
81 lines
2.4 KiB
C++
|
|
#include <time.h>
|
||
|
|
#include <string.h>
|
||
|
|
|
||
|
|
#include "log.h"
|
||
|
|
#include "utils.h"
|
||
|
|
#include "stellar.h"
|
||
|
|
#include "snowflake.h"
|
||
|
|
|
||
|
|
#define snowflake_LOG_ERROR(format, ...) LOG_ERROR("snowflake", format, ##__VA_ARGS__)
|
||
|
|
#define snowflake_LOG_DEBUG(format, ...) LOG_DEBUG("snowflake", format, ##__VA_ARGS__)
|
||
|
|
|
||
|
|
struct snowflake
|
||
|
|
{
|
||
|
|
uint8_t snowflake_base; // 5bit [0, 31]
|
||
|
|
uint8_t snowflake_offset; // 7bit [0, 127]
|
||
|
|
uint64_t device_id; // 12bit [0, 4095] ( base << 7 | offset )
|
||
|
|
uint64_t thread[MAX_THREAD_NUM];
|
||
|
|
};
|
||
|
|
|
||
|
|
struct snowflake g_snowflake = {};
|
||
|
|
|
||
|
|
// return 0: success
|
||
|
|
// return -1: failed
|
||
|
|
int snowflake_id_init(const struct snowflake_options *opts)
|
||
|
|
{
|
||
|
|
memset(&g_snowflake, 0, sizeof(struct snowflake));
|
||
|
|
|
||
|
|
if (opts == NULL)
|
||
|
|
{
|
||
|
|
snowflake_LOG_ERROR("opts is NULL");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (opts->snowflake_base > 31)
|
||
|
|
{
|
||
|
|
snowflake_LOG_ERROR("snowflake_base %u is invalid, range [0, 31]", opts->snowflake_base);
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (opts->snowflake_offset > 127)
|
||
|
|
{
|
||
|
|
snowflake_LOG_ERROR("snowflake_offset %u is invalid, range [0, 127]", opts->snowflake_offset);
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
g_snowflake.snowflake_base = opts->snowflake_base;
|
||
|
|
g_snowflake.snowflake_offset = opts->snowflake_offset;
|
||
|
|
g_snowflake.device_id = ((g_snowflake.snowflake_base << 7) | g_snowflake.snowflake_offset) & 0xFFF;
|
||
|
|
|
||
|
|
snowflake_LOG_DEBUG("snowflake_base: %u, snowflake_offset: %u, device_id: %u",
|
||
|
|
g_snowflake.snowflake_base,
|
||
|
|
g_snowflake.snowflake_offset,
|
||
|
|
g_snowflake.device_id);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
* high -> low
|
||
|
|
*
|
||
|
|
* +------+------------------+----------------+------------------------+---------------------------+
|
||
|
|
* | 1bit | 12bit device_id | 8bit thread_id | 28bit timestamp in sec | 15bit sequence per thread |
|
||
|
|
* +------+------------------+----------------+------------------------+---------------------------+
|
||
|
|
*/
|
||
|
|
uint64_t snowflake_id_generate(uint64_t now_sec)
|
||
|
|
{
|
||
|
|
#define MAX_ID_PER_THREAD (32768)
|
||
|
|
#define MAX_ID_BASE_TIME (268435456L)
|
||
|
|
|
||
|
|
uint64_t thr_idx = (uint16_t)stellar_get_current_thread_index();
|
||
|
|
|
||
|
|
uint64_t global_id = 0;
|
||
|
|
uint64_t id_per_thread = (g_snowflake.thread[thr_idx]++) % MAX_ID_PER_THREAD;
|
||
|
|
uint64_t id_base_time = now_sec % MAX_ID_BASE_TIME;
|
||
|
|
global_id = (g_snowflake.device_id << 51) |
|
||
|
|
(thr_idx << 43) |
|
||
|
|
(id_base_time << 15) |
|
||
|
|
(id_per_thread);
|
||
|
|
|
||
|
|
return global_id;
|
||
|
|
}
|