diff --git a/HISTORY b/HISTORY index cb429e0..6a69b48 100644 --- a/HISTORY +++ b/HISTORY @@ -1,4 +1,7 @@ +Version 1.28 2016-05-14 + * id generator support extra bits + Version 1.27 2016-04-15 * add function fd_set_cloexec * php-fastcommon.spec.in support PHP 7 diff --git a/libfastcommon.spec b/libfastcommon.spec index 3cb92e9..18a06a7 100644 --- a/libfastcommon.spec +++ b/libfastcommon.spec @@ -2,7 +2,7 @@ %define LibFastcommonDevel libfastcommon-devel Name: libfastcommon -Version: 1.0.27 +Version: 1.0.28 Release: 1%{?dist} Summary: c common functions library extracted from my open source projects FastDFS License: GPL diff --git a/php-fastcommon/fastcommon.c b/php-fastcommon/fastcommon.c index ad367fd..0568bbf 100644 --- a/php-fastcommon/fastcommon.c +++ b/php-fastcommon/fastcommon.c @@ -44,6 +44,7 @@ const zend_fcall_info empty_fcall_info = { 0, NULL, NULL, NULL, NULL, 0, NULL, N ZEND_FE(fastcommon_is_private_ip, NULL) ZEND_FE(fastcommon_id_generator_init, NULL) ZEND_FE(fastcommon_id_generator_next, NULL) + ZEND_FE(fastcommon_id_generator_get_extra, NULL) ZEND_FE(fastcommon_id_generator_destroy, NULL) {NULL, NULL, NULL} /* Must be the last line */ }; @@ -368,7 +369,7 @@ ZEND_FUNCTION(fastcommon_is_private_ip) /* bool fastcommon_id_generator_init([string filename = "/tmp/fastcommon_id_generator.sn", - int machine_id = 0, int mid_bits = 16, int sn_bits = 16]) + int machine_id = 0, int mid_bits = 16, int extra_bits = 0, int sn_bits = 16]) return true for success, false for fail */ ZEND_FUNCTION(fastcommon_id_generator_init) @@ -377,11 +378,12 @@ ZEND_FUNCTION(fastcommon_id_generator_init) zend_size_t filename_len; long machine_id; long mid_bits; + long extra_bits; long sn_bits; char *filename; argc = ZEND_NUM_ARGS(); - if (argc > 4) { + if (argc > 5) { logError("file: "__FILE__", line: %d, " "fastcommon_id_generator_init parameters count: %d is invalid", __LINE__, argc); @@ -392,9 +394,11 @@ ZEND_FUNCTION(fastcommon_id_generator_init) filename_len = 0; machine_id = 0; mid_bits = 16; + extra_bits = 0; sn_bits = 16; - if (zend_parse_parameters(argc TSRMLS_CC, "|slll", &filename, - &filename_len, &machine_id, &mid_bits, &sn_bits) == FAILURE) + if (zend_parse_parameters(argc TSRMLS_CC, "|sllll", &filename, + &filename_len, &machine_id, &mid_bits, &extra_bits, + &sn_bits) == FAILURE) { logError("file: "__FILE__", line: %d, " "zend_parse_parameters fail!", __LINE__); @@ -407,8 +411,8 @@ ZEND_FUNCTION(fastcommon_id_generator_init) RETURN_BOOL(false); } - if (id_generator_init_ex(&idg_context, filename, - machine_id, mid_bits, sn_bits) != 0) + if (id_generator_init_extra(&idg_context, filename, + machine_id, mid_bits, extra_bits, sn_bits) != 0) { RETURN_BOOL(false); } @@ -417,22 +421,30 @@ ZEND_FUNCTION(fastcommon_id_generator_init) } /* -long/string fastcommon_id_generator_next() +long/string fastcommon_id_generator_next([int extra]) return id for success, false for fail return long in 64 bits OS, return string in 32 bits Os */ ZEND_FUNCTION(fastcommon_id_generator_next) { int argc; + long extra; int64_t id; argc = ZEND_NUM_ARGS(); - if (argc != 0) { + if (argc > 1) { logError("file: "__FILE__", line: %d, " "fastcommon_id_generator_next parameters count: %d is invalid", __LINE__, argc); RETURN_BOOL(false); } + extra = 0; + if (zend_parse_parameters(argc TSRMLS_CC, "|l", &extra) == FAILURE) + { + logError("file: "__FILE__", line: %d, " + "zend_parse_parameters fail!", __LINE__); + RETURN_BOOL(false); + } if (idg_context.fd < 0) { if (id_generator_init(&idg_context, DEFAULT_SN_FILENAME) != 0) { @@ -440,7 +452,7 @@ ZEND_FUNCTION(fastcommon_id_generator_next) } } - if (id_generator_next(&idg_context, &id) != 0) { + if (id_generator_next_extra(&idg_context, extra, &id) != 0) { RETURN_BOOL(false); } @@ -456,6 +468,38 @@ ZEND_FUNCTION(fastcommon_id_generator_next) #endif } +/* +int fastcommon_id_generator_get_extra(long id) +return the extra data +*/ +ZEND_FUNCTION(fastcommon_id_generator_get_extra) +{ + int argc; + long id; + + argc = ZEND_NUM_ARGS(); + if (argc != 1) { + logError("file: "__FILE__", line: %d, " + "fastcommon_id_generator_get_extra parameters count: %d is invalid", + __LINE__, argc); + RETURN_BOOL(false); + } + + if (zend_parse_parameters(argc TSRMLS_CC, "l", &id) == FAILURE) + { + logError("file: "__FILE__", line: %d, " + "zend_parse_parameters fail!", __LINE__); + RETURN_BOOL(false); + } + if (idg_context.fd < 0) { + logError("file: "__FILE__", line: %d, " + "must call fastcommon_id_generator_init first", __LINE__); + RETURN_BOOL(false); + } + + RETURN_LONG(id_generator_get_extra(&idg_context, id)); +} + /* bool fastcommon_id_generator_destroy() return true for success, false for fail diff --git a/php-fastcommon/fastcommon.h b/php-fastcommon/fastcommon.h index 46cd248..f297065 100644 --- a/php-fastcommon/fastcommon.h +++ b/php-fastcommon/fastcommon.h @@ -28,6 +28,7 @@ ZEND_FUNCTION(fastcommon_is_private_ip); ZEND_FUNCTION(fastcommon_id_generator_init); ZEND_FUNCTION(fastcommon_id_generator_next); +ZEND_FUNCTION(fastcommon_id_generator_get_extra); ZEND_FUNCTION(fastcommon_id_generator_destroy); #ifdef __cplusplus diff --git a/php-fastcommon/test.php b/php-fastcommon/test.php index 7f50f3e..d2f8687 100644 --- a/php-fastcommon/test.php +++ b/php-fastcommon/test.php @@ -16,13 +16,15 @@ while (($next_ip=fastcommon_get_next_local_ip($next_ip))) echo "local ip: $next_ip, private: $is_private_ip\n"; } -fastcommon_id_generator_init(); -//fastcommon_id_generator_init("/tmp/sn.txt", 0, 8, 16); +//fastcommon_id_generator_init(); +fastcommon_id_generator_init("/tmp/sn.txt", 0, 8, 10, 14); -var_dump(fastcommon_id_generator_next()); -for ($i=0; $i<10; $i++) { - $id = fastcommon_id_generator_next(); - printf("%d %X\n", $id, $id); +$id = fastcommon_id_generator_next(1024); +printf("%d %X, extra: %d\n", $id, $id, fastcommon_id_generator_get_extra($id)); + +for ($i=0; $i<1024; $i++) { + $id = fastcommon_id_generator_next($i); + printf("%d %X, extra: %d\n", $id, $id, fastcommon_id_generator_get_extra($id)); } fastcommon_id_generator_destroy(); diff --git a/src/id_generator.c b/src/id_generator.c index b458ee0..5cabb1e 100644 --- a/src/id_generator.c +++ b/src/id_generator.c @@ -21,8 +21,9 @@ #include "local_ip_func.h" #include "id_generator.h" -int id_generator_init_ex(struct idg_context *context, const char *filename, - const int machine_id, const int mid_bits, const int sn_bits) +int id_generator_init_extra(struct idg_context *context, const char *filename, + const int machine_id, const int mid_bits, const int extra_bits, + const int sn_bits) { int result; int mid; @@ -34,6 +35,14 @@ int id_generator_init_ex(struct idg_context *context, const char *filename, context->fd = -1; return EINVAL; } + if (extra_bits < 0 || extra_bits > 16) + { + logError("file: "__FILE__", line: %d, " + "invalid bits of extra data: %d", + __LINE__, extra_bits); + context->fd = -1; + return EINVAL; + } if (sn_bits < 8) { logError("file: "__FILE__", line: %d, " @@ -42,11 +51,11 @@ int id_generator_init_ex(struct idg_context *context, const char *filename, context->fd = -1; return EINVAL; } - if (mid_bits + sn_bits > 32) + if (mid_bits + extra_bits + sn_bits > 32) { logError("file: "__FILE__", line: %d, " - "invalid mid_bits + sn_bits: %d > 32", - __LINE__, mid_bits + sn_bits); + "invalid mid_bits + extra_bits + sn_bits: %d > 32", + __LINE__, mid_bits + extra_bits + sn_bits); context->fd = -1; return EINVAL; } @@ -119,13 +128,17 @@ int id_generator_init_ex(struct idg_context *context, const char *filename, context->machine_id = mid; context->mid_bits = mid_bits; + context->extra_bits = extra_bits; context->sn_bits = sn_bits; - context->mid_sn_bits = mid_bits + sn_bits; - context->masked_mid = ((int64_t)mid) << context->sn_bits; - context->sn_mask = ((int64_t)1 << context->sn_bits) - 1; + context->mes_bits_sum = mid_bits + extra_bits + sn_bits; + context->masked_mid = ((int64_t)mid) << (extra_bits + sn_bits); + context->extra_mask = ((int64_t)1 << (extra_bits + sn_bits)) - + ((int64_t)1 << sn_bits); + context->sn_mask = ((int64_t)1 << sn_bits) - 1; - logDebug("mid: 0x%08X, masked_mid: 0x%08llX, sn_mask: 0x%08llX\n", - mid, context->masked_mid, context->sn_mask); + logDebug("mid: 0x%08X, masked_mid: 0x%08llX, extra_mask: 0x%08llX, " + "sn_mask: 0x%08llX\n", mid, context->masked_mid, + context->extra_mask, context->sn_mask); return 0; } @@ -139,7 +152,8 @@ void id_generator_destroy(struct idg_context *context) } } -int id_generator_next(struct idg_context *context, int64_t *id) +int id_generator_next_extra(struct idg_context *context, const int extra, + int64_t *id) { int result; int len; @@ -206,8 +220,9 @@ int id_generator_next(struct idg_context *context, int64_t *id) file_unlock(context->fd); - *id = (((int64_t)time(NULL)) << context->mid_sn_bits) | - context->masked_mid | (sn & context->sn_mask); + *id = (((int64_t)time(NULL)) << context->mes_bits_sum) | + context->masked_mid | ((extra << context->sn_bits) & context->extra_mask) | + (sn & context->sn_mask); return result; } diff --git a/src/id_generator.h b/src/id_generator.h index 73e528b..3832ea0 100644 --- a/src/id_generator.h +++ b/src/id_generator.h @@ -8,8 +8,8 @@ /** 64 bits id generator for multi processes, the generated id format: - 32 bits timestamp + X bits machine id + Y bits serial number - such as 12 bits machine id and 20 bits serial number + 32 bits timestamp + X bits machine id + Y bits of extra data + Z bits serial number + such as 12 bits machine id, 0 bits extra data and 20 bits serial number */ #ifndef ID_GENERATOR_H @@ -31,12 +31,29 @@ struct idg_context { int fd; int machine_id; int mid_bits; //bits of machine id + int extra_bits; //extra bits int sn_bits; //bits of serial number - int mid_sn_bits; //mid_bits + sn_bits + int mes_bits_sum; //mid_bits + extra_bits + sn_bits int64_t masked_mid; + int64_t extra_mask; int64_t sn_mask; }; +/** +* init function +* parameter: +* context: the id generator context +* filename: the filename to store id +* machine_id: the machine id, 0 for auto generate by local ip address +* mid_bits: the bits of machine id, such as 16 +* extra_bits: the extra bits, such as 0 +* sn_bits: the bits of serial no, such as 16, mid_bits + sn_bits must <= 32 +* return error no, 0 for success, none zero for fail +*/ +int id_generator_init_extra(struct idg_context *context, const char *filename, + const int machine_id, const int mid_bits, const int extra_bits, + const int sn_bits); + /** * init function * parameter: @@ -47,13 +64,20 @@ struct idg_context { * sn_bits: the bits of serial no, such as 16, mid_bits + sn_bits must <= 32 * return error no, 0 for success, none zero for fail */ -int id_generator_init_ex(struct idg_context *context, const char *filename, - const int machine_id, const int mid_bits, const int sn_bits); +static inline int id_generator_init_ex(struct idg_context *context, + const char *filename, const int machine_id, const int mid_bits, + const int sn_bits) +{ + const int extra_bits = 0; + return id_generator_init_extra(context, filename, machine_id, mid_bits, + extra_bits, sn_bits); +} /** * init function set machine_id to 2 bytes of local ip address set mid_bits to 16 + set extra_bits to 0 set sn_bits to 16 * parameter: * context: the id generator context @@ -64,8 +88,10 @@ static inline int id_generator_init(struct idg_context *context, const char *fil { const int machine_id = 0; const int mid_bits = 16; + const int extra_bits = 0; const int sn_bits = 16; - return id_generator_init_ex(context, filename, machine_id, mid_bits, sn_bits); + return id_generator_init_extra(context, filename, machine_id, mid_bits, + extra_bits, sn_bits); } /** @@ -76,6 +102,17 @@ static inline int id_generator_init(struct idg_context *context, const char *fil */ void id_generator_destroy(struct idg_context *context); +/** +* generate next id ex +* parameter: +* context: the id generator context +* extra: the extra data +* id: store the id +* return error no, 0 for success, none zero for fail +*/ +int id_generator_next_extra(struct idg_context *context, const int extra, + int64_t *id); + /** * generate next id * parameter: @@ -83,7 +120,22 @@ void id_generator_destroy(struct idg_context *context); * id: store the id * return error no, 0 for success, none zero for fail */ -int id_generator_next(struct idg_context *context, int64_t *id); +static inline int id_generator_next(struct idg_context *context, int64_t *id) +{ + return id_generator_next_extra(context, 0, id); +} + +/** +* get extra data from id +* parameter: +* context: the id generator context +* id: the id +* return the extra data +*/ +static inline int id_generator_get_extra(struct idg_context *context, const int64_t id) +{ + return (int)((id & context->extra_mask) >> context->sn_bits); +} #ifdef __cplusplus } diff --git a/src/tests/test_id_generator.c b/src/tests/test_id_generator.c index 2991c17..b7521f4 100644 --- a/src/tests/test_id_generator.c +++ b/src/tests/test_id_generator.c @@ -21,15 +21,16 @@ int main(int argc, char *argv[]) int i; int64_t id; const int machine_id = 0; - const int mid_bits = 12; - const int sn_bits = 16; + const int mid_bits = 8; + const int extra_bits = 10; + const int sn_bits = 14; log_init(); g_log_context.log_level = LOG_DEBUG; //result = id_generator_init(&context, "/tmp/sn.txt"); - result = id_generator_init_ex(&context, "/tmp/sn.txt", - machine_id, mid_bits, sn_bits); + result = id_generator_init_extra(&context, "/tmp/sn.txt", + machine_id, mid_bits, extra_bits, sn_bits); if (result != 0) { return result; @@ -37,12 +38,12 @@ int main(int argc, char *argv[]) for (i=0; i<100; i++) { - result = id_generator_next(&context, &id); + result = id_generator_next_extra(&context, i, &id); if (result != 0) { break; } - printf("%"PRId64"\n", id); + printf("id: %"PRId64", extra: %d\n", id, id_generator_get_extra(&context, id)); } id_generator_destroy(&context);