lua-snowflake.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. #define LUA_LIB
  2. #include <stdint.h>
  3. #include <pthread.h>
  4. #include <time.h>
  5. #include <sys/time.h>
  6. #include "spinlock.h"
  7. #include <lua.h>
  8. #include <lauxlib.h>
  9. #define MAX_INDEX_VAL 0x0fff
  10. #define MAX_WORKID_VAL 0x03ff
  11. #define MAX_TIMESTAMP_VAL 0x01ffffffffff
  12. typedef struct _t_ctx {
  13. int64_t last_timestamp;
  14. int32_t work_id;
  15. int16_t index;
  16. } ctx_t;
  17. static volatile int g_inited = 0;
  18. static ctx_t g_ctx = { 0, 0, 0 };
  19. static struct spinlock sync_policy;
  20. static int64_t
  21. get_timestamp() {
  22. struct timeval tv;
  23. gettimeofday(&tv, 0);
  24. return tv.tv_sec * 1000 + tv.tv_usec / 1000;
  25. }
  26. static void
  27. wait_next_msec() {
  28. int64_t current_timestamp = 0;
  29. do {
  30. current_timestamp = get_timestamp();
  31. } while (g_ctx.last_timestamp >= current_timestamp);
  32. g_ctx.last_timestamp = current_timestamp;
  33. g_ctx.index = 0;
  34. }
  35. static uint64_t
  36. next_id() {
  37. spinlock_lock(&sync_policy);
  38. if (!g_inited) {
  39. spinlock_unlock(&sync_policy);
  40. return -1;
  41. }
  42. int64_t current_timestamp = get_timestamp();
  43. if (current_timestamp == g_ctx.last_timestamp) {
  44. if (g_ctx.index < MAX_INDEX_VAL) {
  45. ++g_ctx.index;
  46. } else {
  47. wait_next_msec();
  48. }
  49. } else {
  50. g_ctx.last_timestamp = current_timestamp;
  51. g_ctx.index = 0;
  52. }
  53. int64_t nextid = (int64_t)(
  54. ((g_ctx.last_timestamp & MAX_TIMESTAMP_VAL) << 22) |
  55. ((g_ctx.work_id & MAX_WORKID_VAL) << 12) |
  56. (g_ctx.index & MAX_INDEX_VAL)
  57. );
  58. spinlock_unlock(&sync_policy);
  59. return nextid;
  60. }
  61. static int
  62. init(uint16_t work_id) {
  63. spinlock_lock(&sync_policy);
  64. if (g_inited) {
  65. spinlock_unlock(&sync_policy);
  66. return 0;
  67. }
  68. g_ctx.work_id = work_id;
  69. g_ctx.index = 0;
  70. g_inited = 1;
  71. spinlock_unlock(&sync_policy);
  72. return 0;
  73. }
  74. static int
  75. linit(lua_State* l) {
  76. int16_t work_id = 0;
  77. if (lua_gettop(l) > 0) {
  78. lua_Integer id = luaL_checkinteger(l, 1);
  79. if (id < 0 || id > MAX_WORKID_VAL) {
  80. return luaL_error(l, "Work id is in range of 0 - 1023.");
  81. }
  82. work_id = (int16_t)id;
  83. }
  84. if (init(work_id)) {
  85. return luaL_error(l, "Snowflake has been initialized.");
  86. }
  87. lua_pushboolean(l, 1);
  88. return 1;
  89. }
  90. static int
  91. lnextid(lua_State* l) {
  92. int64_t id = next_id();
  93. lua_pushinteger(l, (lua_Integer)id);
  94. return 1;
  95. }
  96. LUAMOD_API int
  97. luaopen_snowflake_core(lua_State* l) {
  98. spinlock_init(&sync_policy);
  99. luaL_checkversion(l);
  100. luaL_Reg lib[] = {
  101. { "init", linit },
  102. { "gen", lnextid },
  103. { NULL, NULL }
  104. };
  105. luaL_newlib(l, lib);
  106. return 1;
  107. }