myxce/src/lib/idgen.c
Rongsong Shen ef728435d4
feat(job-array-one-based-index): array ID allocation numbered from 1 (task 1.3)
idgen_array() allocates the next whole 32768 block and returns its
first element (array tag, index 1), refusing n outside 1..32767 and a
block past the 20-bit sequence (-EOVERFLOW, context unchanged). The
reset-on-new-second step is shared with idgen() via idgen_tick_locked();
idgen() itself is unchanged until task 9.1.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-01 09:24:00 +00:00

107 lines
2.6 KiB
C

#include <stdint.h>
#include <time.h>
#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));
}