uuid6 / uuid6-ietf-draft

Next Generation UUID Formats
https://datatracker.ietf.org/doc/draft-peabody-dispatch-new-uuid-format/
187 stars 11 forks source link

Provide a complete UUIDv8 example #111

Closed LiosK closed 2 years ago

LiosK commented 2 years ago

Change Proposal Template

Source (Select one.)

Change Reason (Select all that apply.)

Draft Number, Full Section, Name

A.3. Creating a UUIDv8 Value

Current Text:

UUIDv8 will vary greatly from implementation to implementation. A good candidate use case for UUIDv8 is to embed exotic timestamps like the one found in this example which employs approximately 0.25 milliseconds and approximately 5 microseconds per timestamp tick as a 48 bit value.

#include <stdint.h>
#include <stdio.h>
#include <time.h>

int main() {
  struct timespec tp;
  clock_gettime(CLOCK_REALTIME, &tp);
  uint64_t timestamp = (uint64_t)tp.tv_sec << 12;

  // compute 12 bit (~0.25 msec precision) fraction from nsecs
  timestamp |= ((uint64_t)tp.tv_nsec << 12) / 1000000000;

  printf("%08llx-%04llx\n", timestamp >> 16, timestamp & 0xFFFF);
  return 0;
}

Figure 8: UUIDv8 Function in C

Proposed Text:

UUIDv8 will vary greatly from implementation to implementation. The following example utilizes:

#include <stdint.h>
#include <time.h>

int get_random_bytes(uint8_t *buffer, int count) {
  // ...
}

int generate_uuidv8(uint8_t *uuid, uint8_t node_id) {
  struct timespec tp;
  if (clock_gettime(CLOCK_REALTIME, &tp) != 0)
    return -1; // real-time clock error

  // 32-bit biased timestamp (seconds elapsed since 2020-01-01 00:00:00 UTC)
  uint32_t timestamp_sec = tp.tv_sec - 1577836800;
  uuid[0] = timestamp_sec >> 24;
  uuid[1] = timestamp_sec >> 16;
  uuid[2] = timestamp_sec >> 8;
  uuid[3] = timestamp_sec;

  // 16-bit subsecond fraction (~15 microsecond resolution)
  uint16_t timestamp_subsec = ((uint64_t)tp.tv_nsec << 16) / 1000000000;
  uuid[4] = timestamp_subsec >> 8;
  uuid[5] = timestamp_subsec;

  // 58-bit random number and required ver and var fields
  if (get_random_bytes(&uuid[6], 8) != 0)
    return -1; // random number generator error
  uuid[6] = 0x80 | (uuid[6] & 0x0f);
  uuid[8] = 0x80 | (uuid[8] & 0x3f);

  // 8-bit application-specific node ID to guarantee application-wide uniqueness
  uuid[14] = node_id;

  // 8-bit rolling sequence number to help ensure process-wide uniqueness
  static uint8_t sequence = 0;
  uuid[15] = sequence++; // NOTE: unprotected from race conditions

  return 0;
}

Figure 8: UUIDv8 Function in C


Other Supporting information below:

A complete example of UUIDv8 generation would be more helpful than the partial snippet in the current draft. In the example I packed some useful concepts that had been squeezed out of the UUIDv7 spec.