diff --git a/README.md b/README.md index e03b21b..c2e1a13 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # libsnowflakeid -[![Latest release](https://img.shields.io/badge/latest_release-1.0.1-orange.svg)](https://github.com/thibaultmeyer/libsnowflakeid/releases) +[![Latest release](https://img.shields.io/badge/latest_release-1.0.2-orange.svg)](https://github.com/thibaultmeyer/libsnowflakeid/releases) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/thibaultmeyer/libsnowflakeid/blob/master/LICENSE) [![CodeFactor](https://www.codefactor.io/repository/github/thibaultmeyer/libsnowflakeid/badge)](https://www.codefactor.io/repository/github/thibaultmeyer/libsnowflakeid) @@ -22,7 +22,11 @@ clang or MSVC are being correctly installed. ```c int main(const int argc, const char *const *argv) { enum e_snowflakeid_init_status status_out; - struct s_snowflakeid_generator_ctx *ctx = snowflakeid_initialize(datacenter_id, worker_id, &status_out); + struct s_snowflakeid_generator_ctx *ctx = snowflakeid_initialize( + datacenter_id, + worker_id, + offset_time_ms, + &status_out); if (status_out == SNOWFLAKEID_INIT_SUCCESS) { uint64_t id = snowflakeid_next_value(ctx); diff --git a/src/libsnowflakeid.h b/src/libsnowflakeid.h index cb05bbd..f56fbef 100644 --- a/src/libsnowflakeid.h +++ b/src/libsnowflakeid.h @@ -60,6 +60,7 @@ typedef enum e_snowflakeid_init_status { */ typedef struct s_snowflakeid_generator_ctx { uint64_t last_time_ms; + uint64_t offset_time_ms; uint8_t datacenter_id; uint8_t worker_id; uint16_t sequence_number; @@ -76,27 +77,29 @@ void snowflakeid_destroy(struct s_snowflakeid_generator_ctx *ctx); /** * Returns the SnowflakeID library version as a number. * - * @return the SnowflakeID library version as a number (ie: 100) + * @return The SnowflakeID library version as a number (ie: 100) */ int snowflakeid_get_version_as_int(void); /** * Returns the SnowflakeID library version as a string. * - * @return the SnowflakeID library version as a string (ie: 1.0.0) + * @return The SnowflakeID library version as a string (ie: 1.0.0) */ const char *snowflakeid_get_version_as_str(void); /** * Initialize Snowflake ID generator context. * - * @param datacenter_id [IN] The Datacenter ID (Max. value = 32) - * @param worker_id [IN] The Worker ID (Max. value = 32) - * @param status_out [OUT] The operation status (ie: SNOWFLAKEID_INIT_SUCCESS) + * @param datacenter_id [IN] The Datacenter ID (Max. value = 32) + * @param worker_id [IN] The Worker ID (Max. value = 32) + * @param offset_time_ms [IN] Offset in milliseconds to be subtracted from the real "current time" + * @param status_out [OUT] The operation status (ie: SNOWFLAKEID_INIT_SUCCESS) * @return Initialized Snowflake ID generator context, or NULL in case of error */ struct s_snowflakeid_generator_ctx *snowflakeid_initialize(uint8_t datacenter_id, uint8_t worker_id, + uint64_t offset_time_ms, enum e_snowflakeid_init_status *status_out); /** diff --git a/src/snowflakeid_initialize.c b/src/snowflakeid_initialize.c index fcccd5d..6581f4a 100644 --- a/src/snowflakeid_initialize.c +++ b/src/snowflakeid_initialize.c @@ -3,6 +3,7 @@ struct s_snowflakeid_generator_ctx *snowflakeid_initialize(const uint8_t datacenter_id, const uint8_t worker_id, + const uint64_t offset_time_ms, enum e_snowflakeid_init_status *status_out) { // Verify datacenter_id and worker_id if (datacenter_id > 31 || worker_id > 31) { @@ -41,6 +42,7 @@ struct s_snowflakeid_generator_ctx *snowflakeid_initialize(const uint8_t datacen // Configure ctx ctx->last_time_ms = 0; + ctx->offset_time_ms = offset_time_ms; ctx->datacenter_id = datacenter_id; ctx->worker_id = worker_id; ctx->sequence_number = 0; diff --git a/src/snowflakeid_next_value.c b/src/snowflakeid_next_value.c index 8581fea..0025a2e 100644 --- a/src/snowflakeid_next_value.c +++ b/src/snowflakeid_next_value.c @@ -2,7 +2,7 @@ #ifdef _WIN32 -static inline uint64_t get_current_time_ms(void) { +static inline uint64_t get_current_time_ms(const uint64_t *const offset_time_ms) { static const ULONGLONG epoch_offset_us = 116444736000000000ULL; FILETIME filetime; ULARGE_INTEGER x; @@ -15,38 +15,39 @@ static inline uint64_t get_current_time_ms(void) { x.LowPart = filetime.dwLowDateTime; x.HighPart = filetime.dwHighDateTime; - return ((x.QuadPart - epoch_offset_us) / 10000); + return (((x.QuadPart - epoch_offset_us) / 10000) - *offset_time_ms); } #else -static inline uint64_t get_current_time_ms(void) { +static inline uint64_t get_current_time_ms(const uint64_t *const offset_time_ms) { struct timeval tv = {0}; gettimeofday(&tv, NULL); - return ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); + return ((tv.tv_sec * 1000) + (tv.tv_usec / 1000) - *offset_time_ms); } #endif -static inline uint64_t get_next_time_ms(const uint64_t *const not_until_time_ms) { +static inline uint64_t get_next_time_ms(const uint64_t *const not_until_time_ms, + const uint64_t *const offset_time_ms) { uint64_t current_time_ms; do { - current_time_ms = get_current_time_ms(); + current_time_ms = get_current_time_ms(offset_time_ms); } while (*not_until_time_ms == current_time_ms); return current_time_ms; } uint64_t snowflakeid_next_value(s_snowflakeid_generator_ctx *const ctx) { - uint64_t current_time_ms = get_current_time_ms(); + uint64_t current_time_ms = get_current_time_ms(&ctx->offset_time_ms); SNOWFLAKEID_LOCK_WAIT_FOR(ctx->internal_lock); if (ctx->last_time_ms == current_time_ms) { ctx->sequence_number = (ctx->sequence_number + 1) % SNOWFLAKEID_SEQUENCE_MAX; if (ctx->sequence_number == 0) { - current_time_ms = get_next_time_ms(&ctx->last_time_ms); + current_time_ms = get_next_time_ms(&ctx->last_time_ms, &ctx->offset_time_ms); } } else { ctx->sequence_number = 0; diff --git a/test/test_main.c b/test/test_main.c index fe38678..903935e 100644 --- a/test/test_main.c +++ b/test/test_main.c @@ -4,6 +4,10 @@ #include #include "../src/libsnowflakeid.h" +#define DATACENTER_ID_VALUE 5 +#define WORKER_ID_VALUE 1 +#define OFFSET_TIME_MS_VALUE 0 + #ifdef _WIN32 static inline uint64_t get_current_time_ms(void) { static const ULONGLONG epoch_offset_us = 116444736000000000ULL; @@ -33,7 +37,12 @@ static inline uint64_t get_current_time_ms(void) { int main(const int argc, const char *const *argv) { enum e_snowflakeid_init_status status_out; - struct s_snowflakeid_generator_ctx *ctx = snowflakeid_initialize(5, 1, &status_out); + struct s_snowflakeid_generator_ctx *ctx = snowflakeid_initialize( + DATACENTER_ID_VALUE, + WORKER_ID_VALUE, + OFFSET_TIME_MS_VALUE, + &status_out); + if (ctx == NULL) { printf("Can't create CTX: %d\n", status_out); return (-1);