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