summaryrefslogtreecommitdiff
path: root/src/couch/src/couch_uuids.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/couch/src/couch_uuids.erl')
-rw-r--r--src/couch/src/couch_uuids.erl188
1 files changed, 0 insertions, 188 deletions
diff --git a/src/couch/src/couch_uuids.erl b/src/couch/src/couch_uuids.erl
deleted file mode 100644
index be6089dff..000000000
--- a/src/couch/src/couch_uuids.erl
+++ /dev/null
@@ -1,188 +0,0 @@
-% Licensed under the Apache License, Version 2.0 (the "License"); you may not
-% use this file except in compliance with the License. You may obtain a copy of
-% the License at
-%
-% http://www.apache.org/licenses/LICENSE-2.0
-%
-% Unless required by applicable law or agreed to in writing, software
-% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-% License for the specific language governing permissions and limitations under
-% the License.
--module(couch_uuids).
--include_lib("couch/include/couch_db.hrl").
-
--behaviour(gen_server).
--vsn(3).
--behaviour(config_listener).
-
--export([start/0, stop/0]).
--export([new/0, random/0]).
-
--export([init/1, terminate/2, code_change/3]).
--export([handle_call/3, handle_cast/2, handle_info/2]).
-
-% config_listener api
--export([handle_config_change/5, handle_config_terminate/3]).
-
--define(RELISTEN_DELAY, 5000).
-
-start() ->
- gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
-
-stop() ->
- gen_server:cast(?MODULE, stop).
-
-new() ->
- gen_server:call(?MODULE, create).
-
-random() ->
- list_to_binary(couch_util:to_hex(crypto:strong_rand_bytes(16))).
-
-init([]) ->
- ok = config:listen_for_changes(?MODULE, nil),
- {ok, state()}.
-
-terminate(_Reason, _State) ->
- ok.
-
-handle_call(create, _From, random) ->
- {reply, random(), random};
-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),
- {reply, UtcId, {utc_id, UtcIdSuffix, NewClockSeq}};
-handle_call(create, _From, {sequential, Pref, Seq}) ->
- Result = ?l2b(Pref ++ io_lib:format("~6.16.0b", [Seq])),
- case Seq >= 16#fff000 of
- true ->
- {reply, Result, {sequential, new_prefix(), inc()}};
- _ ->
- {reply, Result, {sequential, Pref, Seq + inc()}}
- end.
-
-handle_cast(change, _State) ->
- {noreply, state()};
-handle_cast(stop, State) ->
- {stop, normal, State};
-handle_cast(_Msg, State) ->
- {noreply, State}.
-
-handle_info(restart_config_listener, State) ->
- ok = config:listen_for_changes(?MODULE, nil),
- {noreply, State};
-handle_info(_Info, State) ->
- {noreply, State}.
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-handle_config_change("uuids", _, _, _, _) ->
- {ok, gen_server:cast(?MODULE, change)};
-handle_config_change(_, _, _, _, _) ->
- {ok, nil}.
-
-handle_config_terminate(_, stop, _) ->
- ok;
-handle_config_terminate(_Server, _Reason, _State) ->
- gen_server:cast(?MODULE, change),
- erlang:send_after(?RELISTEN_DELAY, whereis(?MODULE), restart_config_listener).
-
-new_prefix() ->
- couch_util:to_hex((crypto:strong_rand_bytes(13))).
-
-inc() ->
- couch_rand:uniform(16#ffd).
-
-state() ->
- AlgoStr = config:get("uuids", "algorithm", "sequential"),
- case couch_util:to_existing_atom(AlgoStr) of
- random ->
- random;
- utc_random ->
- ClockSeq = micros_since_epoch(os:timestamp()),
- {utc_random, ClockSeq};
- utc_id ->
- ClockSeq = micros_since_epoch(os:timestamp()),
- UtcIdSuffix = config:get("uuids", "utc_id_suffix", ""),
- {utc_id, UtcIdSuffix, ClockSeq};
- sequential ->
- {sequential, new_prefix(), inc()};
- 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.
-
-utc_random(ClockSeq) ->
- Suffix = couch_util:to_hex(crypto:strong_rand_bytes(9)),
- utc_suffix(Suffix, ClockSeq, os:timestamp()).
-
-utc_suffix(Suffix, ClockSeq, Now) ->
- OsMicros = micros_since_epoch(Now),
- NewClockSeq =
- if
- OsMicros =< ClockSeq ->
- % Timestamp is lagging, use ClockSeq as Timestamp
- ClockSeq + 1;
- OsMicros > ClockSeq ->
- % Timestamp advanced, use it, and reset ClockSeq with it
- OsMicros
- end,
- Prefix = io_lib:format("~14.16.0b", [NewClockSeq]),
- {list_to_binary(Prefix ++ Suffix), NewClockSeq}.
-
--ifdef(TEST).
-
--include_lib("eunit/include/eunit.hrl").
-
-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),
- ?assert(is_binary(UtcId0)),
- ?assertEqual(ClockSeq0 + 1, ClockSeq1),
- {UtcId1, ClockSeq2} = utc_suffix("", ClockSeq1, Now),
- ?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),
- ?assert(is_binary(UtcId0)),
- ?assertEqual(ClockSeq0 + 1, ClockSeq1),
- Now1 = {9, 9, 9},
- {UtcId1, ClockSeq2} = utc_suffix("", ClockSeq1, Now1),
- ?assert(is_binary(UtcId1)),
- ?assertNotEqual(UtcId0, UtcId1),
- ?assertEqual(micros_since_epoch(Now1), ClockSeq2).
-
-utc_random_test_time_does_not_advance_test() ->
- {MSec, Sec, USec} = os:timestamp(),
- Future = {MSec + 10, Sec, USec},
- ClockSeqFuture = micros_since_epoch(Future),
- {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}),
- {UtcRandom, NextClockSeq} = utc_random(ClockSeqPast),
- ?assert(is_binary(UtcRandom)),
- ?assertEqual(32, byte_size(UtcRandom)),
- ?assert(NextClockSeq > micros_since_epoch({1000, 0, 0})).
-
--endif.