#include #include #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; }