#include #include #include "idgen.h" #include "mylock.h" #include "utils.h" #include "xce/errnox.h" int idgen_ctx_init(idgen_ctx_t* ctx) { if (ctx == NULL) { return -EINVAL; } mylock_init(&(ctx->lock)); ctx->timestamp = time(NULL); ctx->sequence = 0; return 0; } /* Caller holds ctx->lock. Starts a fresh sequence when the second changes * and returns the timestamp to stamp the new ID with. */ static time_t idgen_tick_locked(idgen_ctx_t* ctx) { time_t now = time(NULL); if (now != ctx->timestamp) { ctx->timestamp = now; ctx->sequence = 0; } return ctx->timestamp; } int idgen(idgen_ctx_t* ctx, size_t clusterId, size_t apiserverId, size_t arraySize, uint64_t* pidx) { uint64_t idx; uint64_t ts, tag, seq; if ((ctx == NULL) || (clusterId > MAX_CLUSTER_ID) || (apiserverId > MAX_APISERVER_ID) || (arraySize < 1) || (arraySize > MAX_ARRAY_IDX + 1) || (pidx == NULL)) { return -EINVAL; } mylock_lock(&(ctx->lock)); ts = idgen_tick_locked(ctx); if (arraySize == 1) { /* non array job */ tag = 0x0; seq = ctx->sequence; ctx->sequence++; } else { tag = TAG_JOB_ARRAY; seq = ROUNDUP(ctx->sequence, N_ARRAY_IDX_BITS); ctx->sequence = ROUNDUP(seq + 1, N_ARRAY_IDX_BITS); } mylock_unlock(&(ctx->lock)); idx = MAKE_JOBID(clusterId, apiserverId, ts, tag, seq); *pidx = idx; return arraySize; } int idgen_array(idgen_ctx_t* ctx, size_t clusterId, size_t apiserverId, size_t n, uint64_t* first) { uint64_t ts, block_start; if ((ctx == NULL) || (clusterId > MAX_CLUSTER_ID) || (apiserverId > MAX_APISERVER_ID) || (n < 1) || (n > MAX_ARRAY_IDX) || (first == NULL)) { return -EINVAL; } mylock_lock(&(ctx->lock)); ts = idgen_tick_locked(ctx); block_start = ROUNDUP((uint64_t)ctx->sequence, N_ARRAY_IDX_BITS); if (block_start > UMAX_BITS(N_SEQUENCE_BITS)) { /* the next whole block lies outside the sequence field; a tick * above cannot get here (it resets the sequence to 0), so the * context is unchanged */ mylock_unlock(&(ctx->lock)); return -EOVERFLOW; } ctx->sequence = (uint32_t)(block_start + ((uint64_t)1 << N_ARRAY_IDX_BITS)); mylock_unlock(&(ctx->lock)); *first = MAKE_JOBID(clusterId, apiserverId, ts, TAG_JOB_ARRAY, block_start | 1); return (int)n; } void idgen_ctx_fini(idgen_ctx_t* ctx) { if (ctx == NULL) { return; } mylock_fini(&(ctx->lock)); }