This is an automated email from the ASF dual-hosted git repository.

vatamane pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/couchdb.git


The following commit(s) were added to refs/heads/main by this push:
     new 26920c21f Add UUID v4 and v7. Make v7 the default. Optimize UUID 
generation.
26920c21f is described below

commit 26920c21f82be1ab7297feab69e052e437fbe406
Author: Nick Vatamaniuc <[email protected]>
AuthorDate: Mon Oct 13 16:24:05 2025 -0400

    Add UUID v4 and v7. Make v7 the default. Optimize UUID generation.
    
    Add v4 and v7 UUIDs as per RFC9562 [1]
    
    Use v7 as the new default instead of the previous `sequential`.
    
    For v4 and v7 UUIDs add the `[uuids] format` setting to let users control 
the
    encoding. These formats are supported:
    
      * `base_16` : (aka hex) encoding. This is the default and is the same as 
the
        previous (`sequential`) format.
    
      * `base_36` : Base 36 encoding using 0-9,a-z characters. This is the most
                    compact encoding, only 25 characters long.
    
      * `rfc9562` : The standard RFC9562 UUID encoding, as a hex string with 
dashes.
    
    The UUID v4, v7 along with the old `random` UUID types can skip calling the
    `gen_server` since they do not need to keep any state. This should make the
    system more robust and prevent clients from overwhelming the node with
    concurrent requests to the `/_uuid` endpoint.
    
    While at it, expand the test suite and add more coverage and also ensure to
    test the sizes of the returned values.
    
    [1] https://datatracker.ietf.org/doc/rfc9562
---
 rel/overlay/etc/default.ini                |  13 ++-
 src/couch/src/couch_uuids.erl              | 145 +++++++++++++++++++++--------
 src/couch/test/eunit/couch_uuids_tests.erl |  92 +++++++++++++++---
 src/docs/src/config/misc.rst               |  84 ++++++++++++-----
 4 files changed, 259 insertions(+), 75 deletions(-)

diff --git a/rel/overlay/etc/default.ini b/rel/overlay/etc/default.ini
index 6dcda19cb..87b8cfd9a 100644
--- a/rel/overlay/etc/default.ini
+++ b/rel/overlay/etc/default.ini
@@ -615,12 +615,23 @@ partitioned||* = true
 ;     First 14 characters are the time in hex. Last 18 are random.
 ;   utc_id - Time since Jan 1, 1970 UTC with microseconds, plus utc_id_suffix 
string
 ;     First 14 characters are the time in hex. uuids/utc_id_suffix string 
value is appended to these.
-;algorithm = sequential
+;   uuid_v7 - UUID v7. The returned format depends on the [uuids] format 
setting
+;   uuid_v4 - UUID v4. The returned format depends on the [uuids] format 
setting
+;algorithm = uuid_v7
 
 ; The utc_id_suffix value will be appended to uuids generated by the utc_id 
algorithm.
 ; Replicating instances should have unique utc_id_suffix values to ensure 
uniqueness of utc_id ids.
 ;utc_id_suffix =
 
+; Encoding format for UUID v4 and v7. The default is base_16 (aka hex). Other
+; accepted formats are "base_36" and ""rfc9562". Only v4 and v7 algorithm have
+; configurable formats, other algorithms only return base_16 encoded values.
+; Examples of the same UUID value encoded in all the supported formats:
+;   "base_16" : "0199df3759297032b402c3e61fbbf88f"
+;   "base_36" : "03eudcyamunnfraqdgmopx09b"
+;   "rfc9562" : "0199df37-5929-7032-b402-c3e61fbbf88f"
+;format = base_16
+
 ; Maximum number of UUIDs retrievable from /_uuids in a single request
 ;max_count = 1000
 
diff --git a/src/couch/src/couch_uuids.erl b/src/couch/src/couch_uuids.erl
index f9c11398d..3a75c3305 100644
--- a/src/couch/src/couch_uuids.erl
+++ b/src/couch/src/couch_uuids.erl
@@ -17,13 +17,14 @@
 
 -export([start/0, stop/0]).
 -export([new/0, random/0]).
--export([v7_hex/0, v7_bin/0]).
+-export([v7_bin/0]).
 -export([init/1]).
 -export([handle_call/3, handle_cast/2, handle_info/2]).
 
 % config_listener api
 -export([handle_config_change/5, handle_config_terminate/3]).
 
+-define(DEFAULT_ALGORITHM, "uuid_v7").
 -define(RELISTEN_DELAY, 5000).
 
 start() ->
@@ -33,7 +34,13 @@ stop() ->
     gen_server:cast(?MODULE, stop).
 
 new() ->
-    gen_server:call(?MODULE, create).
+    % Some algorithms can bypass the gen_server
+    case config_algorithm() of
+        "random" -> random();
+        "uuid_v4" -> v4();
+        "uuid_v7" -> v7();
+        _ -> gen_server:call(?MODULE, create)
+    end.
 
 random() ->
     couch_util:to_hex_bin(crypto:strong_rand_bytes(16)).
@@ -42,16 +49,12 @@ init([]) ->
     ok = config:listen_for_changes(?MODULE, nil),
     {ok, state()}.
 
-handle_call(create, _From, random) ->
-    {reply, random(), random};
-handle_call(create, _From, uuid_v7) ->
-    {reply, v7_hex(), uuid_v7};
 handle_call(create, _From, {utc_random, ClockSeq}) ->
     {UtcRandom, NewClockSeq} = utc_random(ClockSeq),
     {reply, UtcRandom, {utc_random, NewClockSeq}};
 handle_call(create, _From, {utc_id, UtcIdSuffix, ClockSeq}) ->
-    Now = os:timestamp(),
-    {UtcId, NewClockSeq} = utc_suffix(UtcIdSuffix, ClockSeq, Now),
+    OsMicros = micros_since_epoch(),
+    {UtcId, NewClockSeq} = utc_suffix(UtcIdSuffix, ClockSeq, OsMicros),
     {reply, UtcId, {utc_id, UtcIdSuffix, NewClockSeq}};
 handle_call(create, _From, {sequential, Pref, Seq}) ->
     Result = ?l2b(Pref ++ io_lib:format("~6.16.0b", [Seq])),
@@ -109,10 +112,58 @@ v7_bin() ->
     <<RandA:12, RandB:62, _:6>> = crypto:strong_rand_bytes(10),
     <<MSec:48, 7:4, RandA:12, 2:2, RandB:62>>.
 
-v7_hex() ->
-    <<A:8/binary, B:4/binary, C:4/binary, D:4/binary, E:12/binary>> = 
couch_util:to_hex_bin(
-        v7_bin()
-    ),
+%% UUID Version 4
+%% https://www.rfc-editor.org/rfc/rfc9562#name-uuid-version-4
+%%
+%%  0                   1                   2                   3
+%%  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+%% +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+%% |                           random_a                            |
+%% +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+%% |          random_a             |  ver  |       random_b        |
+%% +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+%% |var|                       random_c                            |
+%% +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+%% |                           random_c                            |
+%% +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+%%
+%% ver = 0100 = 4
+%% var = 10 = 2
+%%
+v4_bin() ->
+    <<A:48, B:12, C:62, _:6>> = crypto:strong_rand_bytes(16),
+    <<A:48, 4:4, B:12, 2:2, C:62>>.
+
+v7() ->
+    Bin = v7_bin(),
+    Format = config:get("uuids", "format", "base_16"),
+    uuid_format(Bin, Format).
+
+v4() ->
+    Bin = v4_bin(),
+    Format = config:get("uuids", "format", "base_16"),
+    uuid_format(Bin, Format).
+
+uuid_format(<<_:128>> = Bin, "rfc9562") ->
+    rfc9562_format(Bin);
+uuid_format(<<_:128>> = Bin, "base_36") ->
+    encode_base36(Bin);
+uuid_format(<<_:128>> = Bin, "base_16") ->
+    couch_util:to_hex_bin(Bin);
+uuid_format(<<_:128>>, Other) when is_list(Other) ->
+    error({unsupported_uuid_format, Other}).
+
+% Opt for a fixed width represention
+% 25 == length(integer_to_list(1 bsl 128 - 1, 36)).
+%
+encode_base36(<<Int:128>>) ->
+    String = integer_to_list(Int, 36),
+    Lower = string:to_lower(String),
+    iolist_to_binary(io_lib:format("~25..0s", [Lower])).
+
+rfc9562_format(<<_:128>> = Bin) ->
+    Hex = couch_util:to_hex_bin(Bin),
+    <<A:8/binary, B:4/binary, C:4/binary, D:4/binary, E:12/binary>> = Hex,
     <<A/binary, "-", B/binary, "-", C/binary, "-", D/binary, "-", E/binary>>.
 
 new_prefix() ->
@@ -122,37 +173,35 @@ inc() ->
     rand:uniform(16#ffd).
 
 state() ->
-    AlgoStr = config:get("uuids", "algorithm", "sequential"),
+    AlgoStr = config_algorithm(),
     case couch_util:to_existing_atom(AlgoStr) of
         random ->
             random;
         utc_random ->
-            ClockSeq = micros_since_epoch(os:timestamp()),
+            ClockSeq = micros_since_epoch(),
             {utc_random, ClockSeq};
         utc_id ->
-            ClockSeq = micros_since_epoch(os:timestamp()),
+            ClockSeq = micros_since_epoch(),
             UtcIdSuffix = config:get("uuids", "utc_id_suffix", ""),
             {utc_id, UtcIdSuffix, ClockSeq};
         sequential ->
             {sequential, new_prefix(), inc()};
         uuid_v7 ->
             uuid_v7;
+        uuid_v4 ->
+            uuid_v4;
         Unknown ->
             throw({unknown_uuid_algorithm, Unknown})
     end.
 
-micros_since_epoch({_, _, Micro} = Now) ->
-    Nowish = calendar:now_to_universal_time(Now),
-    Nowsecs = calendar:datetime_to_gregorian_seconds(Nowish),
-    Then = calendar:datetime_to_gregorian_seconds({{1970, 1, 1}, {0, 0, 0}}),
-    (Nowsecs - Then) * 1000000 + Micro.
+micros_since_epoch() ->
+    os:system_time(microsecond).
 
 utc_random(ClockSeq) ->
     Suffix = couch_util:to_hex(crypto:strong_rand_bytes(9)),
-    utc_suffix(Suffix, ClockSeq, os:timestamp()).
+    utc_suffix(Suffix, ClockSeq, micros_since_epoch()).
 
-utc_suffix(Suffix, ClockSeq, Now) ->
-    OsMicros = micros_since_epoch(Now),
+utc_suffix(Suffix, ClockSeq, OsMicros) when is_integer(OsMicros) ->
     NewClockSeq =
         if
             OsMicros =< ClockSeq ->
@@ -165,6 +214,9 @@ utc_suffix(Suffix, ClockSeq, Now) ->
     Prefix = io_lib:format("~14.16.0b", [NewClockSeq]),
     {list_to_binary(Prefix ++ Suffix), NewClockSeq}.
 
+config_algorithm() ->
+    config:get("uuids", "algorithm", ?DEFAULT_ALGORITHM).
+
 -ifdef(TEST).
 
 -include_lib("eunit/include/eunit.hrl").
@@ -172,43 +224,60 @@ utc_suffix(Suffix, ClockSeq, Now) ->
 utc_id_time_does_not_advance_test() ->
     % Timestamp didn't advance but local clock sequence should and new UUIds
     % should be generated
-    Now = {0, 1, 2},
-    ClockSeq0 = micros_since_epoch({3, 4, 5}),
-    {UtcId0, ClockSeq1} = utc_suffix("", ClockSeq0, Now),
+    ClockSeq0 = 345,
+    {UtcId0, ClockSeq1} = utc_suffix("", ClockSeq0, 12),
     ?assert(is_binary(UtcId0)),
     ?assertEqual(ClockSeq0 + 1, ClockSeq1),
-    {UtcId1, ClockSeq2} = utc_suffix("", ClockSeq1, Now),
+    {UtcId1, ClockSeq2} = utc_suffix("", ClockSeq1, ClockSeq0),
     ?assertNotEqual(UtcId0, UtcId1),
     ?assertEqual(ClockSeq1 + 1, ClockSeq2).
 
 utc_id_time_advanced_test() ->
     % Timestamp advanced, a new UUID generated and also the last clock sequence
     % is updated to that timestamp.
-    Now0 = {0, 1, 2},
-    ClockSeq0 = micros_since_epoch({3, 4, 5}),
-    {UtcId0, ClockSeq1} = utc_suffix("", ClockSeq0, Now0),
+    ClockSeq0 = 345,
+    {UtcId0, ClockSeq1} = utc_suffix("", ClockSeq0, 12),
     ?assert(is_binary(UtcId0)),
     ?assertEqual(ClockSeq0 + 1, ClockSeq1),
-    Now1 = {9, 9, 9},
-    {UtcId1, ClockSeq2} = utc_suffix("", ClockSeq1, Now1),
+    ClockSeq2 = 999,
+    {UtcId1, ClockSeq3} = utc_suffix("", ClockSeq1, ClockSeq2),
     ?assert(is_binary(UtcId1)),
     ?assertNotEqual(UtcId0, UtcId1),
-    ?assertEqual(micros_since_epoch(Now1), ClockSeq2).
+    ?assertEqual(ClockSeq2, ClockSeq3).
 
 utc_random_test_time_does_not_advance_test() ->
-    {MSec, Sec, USec} = os:timestamp(),
-    Future = {MSec + 10, Sec, USec},
-    ClockSeqFuture = micros_since_epoch(Future),
+    OsMicros = os:system_time(microsecond),
+    ClockSeqFuture = OsMicros + 10_000_000,
     {UtcRandom, NextClockSeq} = utc_random(ClockSeqFuture),
     ?assert(is_binary(UtcRandom)),
     ?assertEqual(32, byte_size(UtcRandom)),
     ?assertEqual(ClockSeqFuture + 1, NextClockSeq).
 
 utc_random_test_time_advance_test() ->
-    ClockSeqPast = micros_since_epoch({1, 1, 1}),
+    ClockSeqPast = 111,
     {UtcRandom, NextClockSeq} = utc_random(ClockSeqPast),
     ?assert(is_binary(UtcRandom)),
     ?assertEqual(32, byte_size(UtcRandom)),
-    ?assert(NextClockSeq > micros_since_epoch({1000, 0, 0})).
+    ?assert(NextClockSeq > 1_000_000_000).
+
+uuid_v7_test() ->
+    Bin = v7_bin(),
+    ?assertEqual(36, byte_size(uuid_format(Bin, "rfc9562"))),
+    ?assertEqual(32, byte_size(uuid_format(Bin, "base_16"))),
+    ?assertEqual(25, byte_size(uuid_format(Bin, "base_36"))),
+    ?assertError({unsupported_uuid_format, "X"}, uuid_format(Bin, "X")),
+    Fun1 = fun(_, Acc) -> sets:add_element(v7_bin(), Acc) end,
+    Set1 = lists:foldl(Fun1, couch_util:new_set(), lists:seq(1, 10_000)),
+    ?assertEqual(10_000, sets:size(Set1)).
+
+uuid_v4_test() ->
+    Bin = v4_bin(),
+    ?assertEqual(36, byte_size(uuid_format(Bin, "rfc9562"))),
+    ?assertEqual(32, byte_size(uuid_format(Bin, "base_16"))),
+    ?assertEqual(25, byte_size(uuid_format(Bin, "base_36"))),
+    ?assertError({unsupported_uuid_format, "X"}, uuid_format(Bin, "X")),
+    Fun1 = fun(_, Acc) -> sets:add_element(v7_bin(), Acc) end,
+    Set1 = lists:foldl(Fun1, couch_util:new_set(), lists:seq(1, 10_000)),
+    ?assertEqual(10_000, sets:size(Set1)).
 
 -endif.
diff --git a/src/couch/test/eunit/couch_uuids_tests.erl 
b/src/couch/test/eunit/couch_uuids_tests.erl
index 3dde842cb..a770485f6 100644
--- a/src/couch/test/eunit/couch_uuids_tests.erl
+++ b/src/couch/test/eunit/couch_uuids_tests.erl
@@ -17,52 +17,108 @@
 -define(TIMEOUT, 20).
 
 setup_all() ->
-    test_util:start_applications([config, couch_log]),
+    test_util:start_applications([config, couch_stats, couch_log]),
     couch_uuids:start().
 
 teardown_all(_) ->
     couch_uuids:stop(),
-    test_util:stop_applications([config, couch_log]).
+    test_util:stop_applications([config, couch_stats, couch_log]).
 
 uuids_test_() ->
     {
         setup,
         fun setup_all/0,
         fun teardown_all/1,
-        [
-            {timeout, ?TIMEOUT, fun default_algorithm/0},
-            {timeout, ?TIMEOUT, fun sequential_algorithm/0},
-            {timeout, ?TIMEOUT, fun utc_algorithm/0},
-            {timeout, ?TIMEOUT, fun utc_id_suffix_algorithm/0}
-        ]
+        with([
+            ?TDEF(default_algorithm, ?TIMEOUT),
+            ?TDEF(sequential_algorithm, ?TIMEOUT),
+            ?TDEF(utc_algorithm, ?TIMEOUT),
+            ?TDEF(utc_id_suffix_algorithm, ?TIMEOUT),
+            ?TDEF(random_algorithm, ?TIMEOUT),
+            ?TDEF(uuid_v4_rfc9562, ?TIMEOUT),
+            ?TDEF(uuid_v4_base_16, ?TIMEOUT),
+            ?TDEF(uuid_v4_base_36, ?TIMEOUT),
+            ?TDEF(uuid_v7_rfc9562, ?TIMEOUT),
+            ?TDEF(uuid_v7_base_16, ?TIMEOUT),
+            ?TDEF(uuid_v7_base_36, ?TIMEOUT)
+        ])
     }.
 
-default_algorithm() ->
+default_algorithm(_) ->
     config:delete("uuids", "algorithm", false),
     check_unique().
 
-sequential_algorithm() ->
+random_algorithm(_) ->
+    config:set("uuids", "algorithm", "random", false),
+    check_unique(),
+    check_size(32).
+
+sequential_algorithm(_) ->
     config:set("uuids", "algorithm", "sequential", false),
     check_unique(),
     check_increment_monotonically(),
-    check_rollover().
+    check_rollover(),
+    check_size(32).
 
-utc_algorithm() ->
+utc_algorithm(_) ->
     config:set("uuids", "algorithm", "utc_random", false),
     check_unique(),
-    check_increment_monotonically().
+    check_increment_monotonically(),
+    check_size(32).
 
-utc_id_suffix_algorithm() ->
+utc_id_suffix_algorithm(_) ->
     config:set("uuids", "algorithm", "utc_id", false),
     config:set("uuids", "utc_id_suffix", "bozo", false),
     check_unique(),
     check_increment_monotonically(),
-    check_preserve_suffix().
+    check_preserve_suffix(),
+    % 14 character time prefix + bozo
+    check_size(18).
+
+uuid_v4_rfc9562(_) ->
+    config:set("uuids", "algorithm", "uuid_v4", false),
+    config:set("uuids", "format", "rfc9562", false),
+    check_unique(),
+    check_size(36).
+
+uuid_v4_base_16(_) ->
+    config:set("uuids", "algorithm", "uuid_v4", false),
+    config:set("uuids", "format", "base_16", false),
+    check_unique(),
+    check_size(32).
+
+uuid_v4_base_36(_) ->
+    config:set("uuids", "algorithm", "uuid_v4", false),
+    config:set("uuids", "format", "base_36", false),
+    check_unique(),
+    check_size(25).
+
+uuid_v7_rfc9562(_) ->
+    config:set("uuids", "algorithm", "uuid_v7", false),
+    config:set("uuids", "format", "rfc9562", false),
+    check_unique(),
+    check_size(36).
+
+uuid_v7_base_16(_) ->
+    config:set("uuids", "algorithm", "uuid_v7", false),
+    config:set("uuids", "format", "base_16", false),
+    check_unique(),
+    check_size(32).
+
+uuid_v7_base_36(_) ->
+    config:set("uuids", "algorithm", "uuid_v7", false),
+    config:set("uuids", "format", "base_36", false),
+    check_unique(),
+    check_size(25).
 
 check_unique() ->
     %% this one may really runs for too long on slow hosts
     ?assert(test_unique(10000, [couch_uuids:new()])).
 
+check_size(Size) ->
+    %% this one may really runs for too long on slow hosts
+    ?assert(test_size(Size, 10000)).
+
 check_increment_monotonically() ->
     ?assert(couch_uuids:new() < couch_uuids:new()).
 
@@ -77,6 +133,12 @@ check_preserve_suffix() ->
     Suffix = get_suffix(UUID),
     ?assert(test_same_suffix(10000, Suffix)).
 
+test_size(_Size, 0) ->
+    true;
+test_size(Size, N) ->
+    ?assertEqual(Size, byte_size(couch_uuids:new())),
+    test_size(Size, N - 1).
+
 test_unique(0, _) ->
     true;
 test_unique(N, UUIDs) ->
diff --git a/src/docs/src/config/misc.rst b/src/docs/src/config/misc.rst
index 6c9d6003e..ac5c258b5 100644
--- a/src/docs/src/config/misc.rst
+++ b/src/docs/src/config/misc.rst
@@ -66,7 +66,8 @@ UUIDs Configuration
     .. config:option:: algorithm :: Generation Algorithm
 
         .. versionchanged:: 1.3 Added ``utc_id`` algorithm.
-        .. versionchanged:: 3.6 Added ``uuid_v7`` algorithm.
+        .. versionchanged:: 3.6 Added ``uuid_v4`` and ``uuid_v7`` algorithms.
+        .. versionchanged:: 3.6 ``uuid_v7`` algorithm became the default.
 
         CouchDB provides various algorithms to generate the UUID values that
         are  used for document `_id`'s by default::
@@ -159,22 +160,43 @@ UUIDs Configuration
                   ]
               }
 
-        - ``uuid_v7``: UUID v7 string in hex.
+        - ``uuid_v7``: UUID v7. The option :option:`uuids/format` control the
+          encoding format. The default is ``base_16``.
 
           .. code-block:: javascript
 
                {
                    "uuids": [
-                       "0199d2456e7f7b0a9b7130f9a9db8bee",
-                       "0199d2456e7f72dda9f758fcc259c5fc",
-                       "0199d2456e7f751c80b461180f7c7717",
-                       "0199d2456e7f7c569b317d53367ca45a",
-                       "0199d2456e7f77bfbffe92682c9c8c69",
-                       "0199d2456e7f703ea97286f3d976343e",
-                       "0199d2456e7f7f729142ed3b2da9101f",
-                       "0199d2456e7f7723905c1f91f40d54f5",
-                       "0199d2456e7f7e40979c7e2e22ffeb6a",
-                       "0199d2456e7f7a42b43acfcc1e18eb84"
+                      "0199df3833cc79c89bdde9530efc4f0c",
+                      "0199df3833cc7694af52300fce26dc2f",
+                      "0199df3833cc78bf93c0a7b7f1c00d5c",
+                      "0199df3833cc740d84ee0932e8ff1df3",
+                      "0199df3833cc751bb45b27cfbcc3c753",
+                      "0199df3833cc7a7cbce5469d3f52ba83",
+                      "0199df3833cc7b3f8c3f517a3a84b649",
+                      "0199df3833cc74b9b3cacaa0ebfbc842",
+                      "0199df3833cc7f49ae722b96ba1dbb3a",
+                      "0199df3833cc7db39f01868033e1dbec"
+                   ]
+               }
+
+        - ``uuid_v4``: UUID v4. The option :option:`uuids/format` control the
+          encoding format. The default is ``base_16``.
+
+          .. code-block:: javascript
+
+               {
+                   "uuids": [
+                       "e7981ba78fb844b4a87d18c54f4caef4",
+                       "f21cd92e8a4749f390cbd77f693514db",
+                       "4f469b5e6a374da3aa51271754ad027d",
+                       "0ae8035fe7fd42118ef693b996c2516d",
+                       "96250347ba69460197235d3809d74985",
+                       "2b3693f4503b47618df70c6bbe068af5",
+                       "cbec8e3375054a83b5f73fd115bb1500",
+                       "71589f1d9a9748beae8dc09bbe904d04",
+                       "59b581909b1d4f67a00aea5f29cfcb39",
+                       "4f33c962a3e64a5f89b05a05e680f3ee"
                    ]
                }
 
@@ -182,17 +204,37 @@ UUIDs Configuration
             **Impact of UUID choices:** the choice of UUID has a significant
             impact on the layout of the B-tree, prior to compaction.
 
-            For example, using a sequential UUID algorithm while uploading a
-            large batch of documents will avoid the need to rewrite many
-            intermediate B-tree nodes. A random UUID algorithm may require
+            For example, using the UUID v7 or sequential algorithms while
+            uploading a large batch of documents will avoid the need to rewrite
+            many intermediate B-tree nodes. A random UUID algorithm may require
             rewriting intermediate nodes on a regular basis, resulting in
-            significantly decreased throughput and wasted disk space space due 
to
-            the append-only B-tree design.
+            significantly decreased throughput and wasted disk space space due
+            to the append-only B-tree design.
+
+            It is generally recommended to set your own UUIDs, or use the UUID
+            v7 or sequential algorithms unless you have a specific need and 
take
+            into account the likely need for compaction to re-balance the
+            B-tree and reclaim wasted space.
+
+    .. config:option:: format :: Encoding format for UUID v4 and UUID v7 
algorithms
+
+        .. versionadded:: 3.6
+
+        Configure encoding format of UUID v4 and v7::
+
+            [uuids]
+            format = base_16
+
+        Available formats:
+
+        - ``base_16``: 32 byte long, hex-encoded value.
+          For example: ``"0199df3759297032b402c3e61fbbf88f"``
+
+        - ``base_36``: 25 byte long, base-36 encoded value using 0-9 and a-z 
characters.
+          For example: ``"03eudcyamunnfraqdgmopx09b"``
 
-            It is generally recommended to set your own UUIDs, or use the
-            sequential algorithm unless you have a specific need and take into
-            account the likely need for compaction to re-balance the B-tree and
-            reclaim wasted space.
+        - ``rfc9562``: 36 byte long standard formatting for UUIDs (see 
https://www.rfc-editor.org/rfc/rfc9562)
+          For example: ``"0199df37-5929-7032-b402-c3e61fbbf88f"``
 
     .. config:option:: utc_id_suffix :: UTC ID Suffix
 

Reply via email to