2024-08-23 15:21:07 +08:00
|
|
|
#include <stdint.h>
|
|
|
|
|
#include <stdlib.h>
|
2024-08-16 11:02:19 +08:00
|
|
|
|
|
|
|
|
#include "snowflake.h"
|
2024-08-23 18:44:17 +08:00
|
|
|
#include "log_private.h"
|
2024-08-16 11:02:19 +08:00
|
|
|
|
2024-08-23 18:44:17 +08:00
|
|
|
#define SNOWFLAKE_LOG_ERROR(format, ...) STELLAR_LOG_ERROR(__thread_local_logger, "snowflake", format, ##__VA_ARGS__)
|
2024-08-16 11:02:19 +08:00
|
|
|
|
|
|
|
|
struct snowflake
|
|
|
|
|
{
|
2024-08-23 15:21:07 +08:00
|
|
|
uint8_t worker_base_id; // 5 bit [0, 31]
|
|
|
|
|
uint8_t worker_offset_id; // 7 bit [0, 127]
|
|
|
|
|
uint64_t thread_id; // limit 256
|
|
|
|
|
uint64_t device_id; // 12 bit [0, 4095] ( base << 7 | offset )
|
|
|
|
|
uint64_t sequence;
|
2024-08-16 11:02:19 +08:00
|
|
|
};
|
|
|
|
|
|
2024-08-23 15:21:07 +08:00
|
|
|
struct snowflake *snowflake_new(uint16_t thread_id, uint8_t worker_base_id, uint8_t worker_offset_id)
|
2024-08-16 11:02:19 +08:00
|
|
|
{
|
2024-08-23 15:21:07 +08:00
|
|
|
if (thread_id > 255)
|
2024-08-16 11:02:19 +08:00
|
|
|
{
|
2024-08-23 15:21:07 +08:00
|
|
|
SNOWFLAKE_LOG_ERROR("thread_id %u is invalid, range [0, 255]", thread_id);
|
|
|
|
|
return NULL;
|
2024-08-16 11:02:19 +08:00
|
|
|
}
|
2024-08-23 15:21:07 +08:00
|
|
|
if (worker_base_id > 31)
|
|
|
|
|
{
|
|
|
|
|
SNOWFLAKE_LOG_ERROR("worker_base_id %u is invalid, range [0, 31]", worker_base_id);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
if (worker_offset_id > 127)
|
2024-08-16 11:02:19 +08:00
|
|
|
{
|
2024-08-23 15:21:07 +08:00
|
|
|
SNOWFLAKE_LOG_ERROR("worker_offset_id %u is invalid, range [0, 127]", worker_offset_id);
|
|
|
|
|
return NULL;
|
2024-08-16 11:02:19 +08:00
|
|
|
}
|
|
|
|
|
|
2024-08-23 15:21:07 +08:00
|
|
|
struct snowflake *sf = (struct snowflake *)calloc(1, sizeof(struct snowflake));
|
|
|
|
|
if (sf == NULL)
|
2024-08-16 11:02:19 +08:00
|
|
|
{
|
2024-08-23 15:21:07 +08:00
|
|
|
SNOWFLAKE_LOG_ERROR("calloc snowflake failed");
|
|
|
|
|
return NULL;
|
2024-08-16 11:02:19 +08:00
|
|
|
}
|
|
|
|
|
|
2024-08-23 15:21:07 +08:00
|
|
|
sf->worker_base_id = worker_base_id;
|
|
|
|
|
sf->worker_offset_id = worker_offset_id;
|
|
|
|
|
sf->thread_id = thread_id;
|
|
|
|
|
sf->device_id = ((worker_base_id << 7) | worker_offset_id) & 0xFFF;
|
|
|
|
|
sf->sequence = 0;
|
2024-08-16 11:02:19 +08:00
|
|
|
|
2024-08-23 15:21:07 +08:00
|
|
|
return sf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void snowflake_free(struct snowflake *sf)
|
|
|
|
|
{
|
|
|
|
|
if (sf != NULL)
|
|
|
|
|
{
|
|
|
|
|
free(sf);
|
|
|
|
|
sf = NULL;
|
|
|
|
|
}
|
2024-08-16 11:02:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* high -> low
|
|
|
|
|
*
|
|
|
|
|
* +------+------------------+----------------+------------------------+---------------------------+
|
|
|
|
|
* | 1bit | 12bit device_id | 8bit thread_id | 28bit timestamp in sec | 15bit sequence per thread |
|
|
|
|
|
* +------+------------------+----------------+------------------------+---------------------------+
|
|
|
|
|
*/
|
2024-08-23 15:21:07 +08:00
|
|
|
|
2024-08-16 11:02:19 +08:00
|
|
|
#define MAX_ID_PER_THREAD (32768)
|
|
|
|
|
#define MAX_ID_BASE_TIME (268435456L)
|
|
|
|
|
|
2024-08-23 15:21:07 +08:00
|
|
|
uint64_t snowflake_generate(struct snowflake *sf, uint64_t now_sec)
|
|
|
|
|
{
|
|
|
|
|
if (sf == NULL)
|
|
|
|
|
{
|
|
|
|
|
SNOWFLAKE_LOG_ERROR("snowflake is NULL");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2024-08-16 11:02:19 +08:00
|
|
|
|
2024-08-23 15:21:07 +08:00
|
|
|
uint64_t id = 0;
|
|
|
|
|
uint64_t id_per_thread = (sf->sequence++) % MAX_ID_PER_THREAD;
|
2024-08-16 11:02:19 +08:00
|
|
|
uint64_t id_base_time = now_sec % MAX_ID_BASE_TIME;
|
2024-08-23 15:21:07 +08:00
|
|
|
id = (sf->device_id << 51) |
|
|
|
|
|
(sf->thread_id << 43) |
|
|
|
|
|
(id_base_time << 15) |
|
|
|
|
|
(id_per_thread);
|
2024-08-16 11:02:19 +08:00
|
|
|
|
2024-08-23 15:21:07 +08:00
|
|
|
return id;
|
2024-08-16 11:02:19 +08:00
|
|
|
}
|
2024-08-23 15:21:07 +08:00
|
|
|
|
|
|
|
|
void snowflake_deserialize(uint64_t id, struct snowflake_meta *meta)
|
|
|
|
|
{
|
|
|
|
|
if (meta == NULL)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
meta->sequence = id & 0x7FFF;
|
|
|
|
|
meta->time_cycle = MAX_ID_BASE_TIME;
|
|
|
|
|
meta->time_relative = (id >> 15) & 0xFFFFFFF;
|
|
|
|
|
meta->thread_id = (id >> 43) & 0xFF;
|
|
|
|
|
meta->device_id = (id >> 51) & 0xFFF;
|
|
|
|
|
meta->worker_base_id = (meta->device_id >> 7) & 0x1F;
|
|
|
|
|
meta->worker_offset_id = meta->device_id & 0x7F;
|
|
|
|
|
}
|