From 6f16c43c40bda7cf663c56b3efdb7f58ecd367ea Mon Sep 17 00:00:00 2001 From: Andrey Borodin Date: Sat, 23 Nov 2024 11:15:49 +0300 Subject: [PATCH v37 2/2] Mix in 2 bits of entropy into timestampt of UUID on MacOS --- src/backend/utils/adt/uuid.c | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/src/backend/utils/adt/uuid.c b/src/backend/utils/adt/uuid.c index b137805696..ce8cf64908 100644 --- a/src/backend/utils/adt/uuid.c +++ b/src/backend/utils/adt/uuid.c @@ -31,12 +31,19 @@ #define NS_PER_US INT64CONST(1000) /* - * In UUID version 7, we use 12 bits in "rand_a" to store 1/4096 fractions of - * sub-millisecond. This is the minimum amount of nanoseconds that guarantees - * step advancement of sub-millisecond part. + * In UUID version 7, we use 12 bits in "rand_a" to store 1/4096 + * fractions of sub-millisecond. On systems that have only 10 bits of sub-ms + * precision we still use 1/4096 parts of a millisecond, but fill lower 2 bits + * with random numbers. SUBMS_MINIMAL_STEP is the minimum amount of + * nanoseconds that guarantees step of UUID increased clock precision. */ +#if defined(__darwin__) || defined(_MSC_VER) +#define SUBMS_MINIMAL_STEP_BITS 10 +#else +#define SUBMS_MINIMAL_STEP_BITS 12 +#endif #define SUBMS_BITS 12 -#define SUBMS_MINIMAL_STEP_NS ((NS_PER_MS / (1 << SUBMS_BITS)) + 1) +#define SUBMS_MINIMAL_STEP_NS ((NS_PER_MS / (1 << SUBMS_MINIMAL_STEP_BITS)) + 1) /* sortsupport for uuid */ typedef struct @@ -523,7 +530,10 @@ generate_uuidv7(int64 ns) uuid->data[4] = (unsigned char) (unix_ts_ms >> 8); uuid->data[5] = (unsigned char) unix_ts_ms; - /* sub-millisecond timestamp fraction (12 bits) */ + /* + * sub-millisecond timestamp fraction (SUBMS_BITS bits, not + * SUBMS_MINIMAL_STEP_BITS) + */ increased_clock_precision = ((ns % NS_PER_MS) * (1 << SUBMS_BITS)) / NS_PER_MS; /* Fill the increased clock precision to "rand_a" bits */ @@ -536,6 +546,19 @@ generate_uuidv7(int64 ns) (errcode(ERRCODE_INTERNAL_ERROR), errmsg("could not generate random values"))); +#if defined(__darwin__) || defined(WIN32) + /* + * On MacOS real time is truncted to microseconds. Thus, 2 least + * significant are dependent on other time-specific bits, thus they do not + * contribute to uniqueness. To make these bit random we mix in two bits + * from CSPRNG. + * + * SUBMS_MINIMAL_STEP is chosen so that we still guarantee monotonicity + * despite altering these bits. + */ + uuid->data[7] = uuid->data[7] ^ (uuid->data[8] >> 6); +#endif + /* * Set magic numbers for a "version 7" (pseudorandom) UUID and variant, * see https://www.rfc-editor.org/rfc/rfc9562#name-version-field -- 2.39.5 (Apple Git-154)