From 600f859a05355fd08db3acae5b93ea1ada49613c Mon Sep 17 00:00:00 2001 From: Nick North Date: Sun, 24 Jun 2012 18:38:32 +0100 Subject: [PATCH 1/3] utc_id_suffix changes --- etc/couchdb/default.ini.tpl.in | 5 +++++ share/www/script/test/uuids.js | 27 +++++++++++++++++++++++- src/couchdb/couch_uuids.erl | 10 ++++++++- test/etap/041-uuid-gen-id-suffix.ini | 20 ++++++++++++++++++ test/etap/041-uuid-gen.t | 31 ++++++++++++++++++++++++++-- 5 files changed, 89 insertions(+), 4 deletions(-) create mode 100644 test/etap/041-uuid-gen-id-suffix.ini diff --git a/etc/couchdb/default.ini.tpl.in b/etc/couchdb/default.ini.tpl.in index ce849057fc2..80802eac3b1 100644 --- a/etc/couchdb/default.ini.tpl.in +++ b/etc/couchdb/default.ini.tpl.in @@ -178,7 +178,12 @@ _view = {couch_mrview_http, handle_view_req} ; random prefix is regenerated and the process starts over. ; utc_random - Time since Jan 1, 1970 UTC with microseconds ; First 14 characters are the time in hex. Last 18 are random. +; utc_id_suffix - Time since Jan 1, 1970 UTC with microseconds, plus id_suffix string +; First 14 characters are the time in hex. uuids/id_suffix string value is appended to these. algorithm = sequential +; The id_suffix value will be appended to uuids generated by the utc_id_suffix algorithm. +; Replicating instances should have unique id_suffixes to ensure uniqueness of utc_id_suffix ids. +id_suffix = [stats] ; rate is in milliseconds diff --git a/share/www/script/test/uuids.js b/share/www/script/test/uuids.js index fc33a1059e6..1ebda870d56 100644 --- a/share/www/script/test/uuids.js +++ b/share/www/script/test/uuids.js @@ -117,4 +117,29 @@ couchTests.uuids = function(debug) { utc_testfun ); -}; + // Test utc_id_suffix uuids + var id_suffix = "frog"; + var suffix_testfun = function() { + xhr = CouchDB.request("GET", "/_uuids?count=10"); + T(xhr.status == 200); + result = JSON.parse(xhr.responseText); + for(var i = 1; i < result.uuids.length; i++) { + T(result.uuids[i].length == 14 + id_suffix.length); + T(result.uuids[i].substring(14) == id_suffix); + T(result.uuids[i-1] < result.uuids[i], "utc_id_suffix uuids are ordered."); + } + }; + + run_on_modified_server([{ + "section": "uuids", + "key": "algorithm", + "value": "utc_id_suffix" + }, { + "section": "uuids", + "key": "id_suffix", + "value": id_suffix + }], + suffix_testfun + ); + + }; \ No newline at end of file diff --git a/src/couchdb/couch_uuids.erl b/src/couchdb/couch_uuids.erl index e1851e1d438..b97b03d1dce 100644 --- a/src/couchdb/couch_uuids.erl +++ b/src/couchdb/couch_uuids.erl @@ -33,12 +33,15 @@ random() -> list_to_binary(couch_util:to_hex(crypto:rand_bytes(16))). utc_random() -> + utc_suffix(couch_util:to_hex(crypto:rand_bytes(9))). + +utc_suffix(Suffix) -> Now = {_, _, 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}}), Prefix = io_lib:format("~14.16.0b", [(Nowsecs - Then) * 1000000 + Micro]), - list_to_binary(Prefix ++ couch_util:to_hex(crypto:rand_bytes(9))). + list_to_binary(Prefix ++ Suffix). init([]) -> ok = couch_config:register( @@ -53,6 +56,8 @@ handle_call(create, _From, random) -> {reply, random(), random}; handle_call(create, _From, utc_random) -> {reply, utc_random(), utc_random}; +handle_call(create, _From, {utc_id_suffix, IdSuffix}) -> + {reply, utc_suffix(IdSuffix), {utc_id_suffix, IdSuffix}}; handle_call(create, _From, {sequential, Pref, Seq}) -> Result = ?l2b(Pref ++ io_lib:format("~6.16.0b", [Seq])), case Seq >= 16#fff000 of @@ -83,11 +88,14 @@ inc() -> state() -> AlgoStr = couch_config:get("uuids", "algorithm", "random"), + IdSuffix = couch_config:get("uuids", "id_suffix", ""), case couch_util:to_existing_atom(AlgoStr) of random -> random; utc_random -> utc_random; + utc_id_suffix -> + {utc_id_suffix, IdSuffix}; sequential -> {sequential, new_prefix(), inc()}; Unknown -> diff --git a/test/etap/041-uuid-gen-id-suffix.ini b/test/etap/041-uuid-gen-id-suffix.ini new file mode 100644 index 00000000000..da01fb8bf43 --- /dev/null +++ b/test/etap/041-uuid-gen-id-suffix.ini @@ -0,0 +1,20 @@ +; Licensed to the Apache Software Foundation (ASF) under one +; or more contributor license agreements. See the NOTICE file +; distributed with this work for additional information +; regarding copyright ownership. The ASF licenses this file +; to you 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. + +[uuids] +id_suffix = bozo +algorithm = utc_id_suffix diff --git a/test/etap/041-uuid-gen.t b/test/etap/041-uuid-gen.t index 1e6aa9eee5b..2bec64906c4 100755 --- a/test/etap/041-uuid-gen.t +++ b/test/etap/041-uuid-gen.t @@ -22,6 +22,9 @@ seq_alg_config() -> utc_alg_config() -> test_util:source_file("test/etap/041-uuid-gen-utc.ini"). +id_suffix_config() -> + test_util:source_file("test/etap/041-uuid-gen-id-suffix.ini"). + % Run tests and wait for the gen_servers to shutdown run_test(IniFiles, Test) -> {ok, Pid} = couch_config:start_link(IniFiles), @@ -40,7 +43,7 @@ run_test(IniFiles, Test) -> main(_) -> test_util:init_code_path(), application:start(crypto), - etap:plan(6), + etap:plan(9), case (catch test()) of ok -> @@ -63,6 +66,7 @@ test() -> run_test([default_config()], TestUnique), run_test([default_config(), seq_alg_config()], TestUnique), run_test([default_config(), utc_alg_config()], TestUnique), + run_test([default_config(), id_suffix_config()], TestUnique), TestMonotonic = fun () -> etap:is( @@ -73,6 +77,7 @@ test() -> end, run_test([default_config(), seq_alg_config()], TestMonotonic), run_test([default_config(), utc_alg_config()], TestMonotonic), + run_test([default_config(), id_suffix_config()], TestMonotonic), % Pretty sure that the average of a uniform distribution is the % midpoint of the range. Thus, to exceed a threshold, we need @@ -94,7 +99,18 @@ test() -> "should roll over every so often." ) end, - run_test([default_config(), seq_alg_config()], TestRollOver). + run_test([default_config(), seq_alg_config()], TestRollOver), + + TestSuffix = fun() -> + UUID = binary_to_list(couch_uuids:new()), + Suffix = get_suffix(UUID), + etap:is( + test_same_suffix(100, Suffix), + true, + "utc_id_suffix ids should have the same suffix." + ) + end, + run_test([default_config(), id_suffix_config()], TestSuffix). test_unique(0, _) -> true; @@ -116,3 +132,14 @@ gen_until_pref_change(Prefix, N) -> Prefix -> gen_until_pref_change(Prefix, N+1); _ -> N end. + +get_suffix(UUID) -> + element(2, lists:split(14, binary_to_list(UUID))). + +test_same_suffix(0, _) -> + true; +test_same_suffix(N, Suffix) -> + case get_suffix(couch_uuids:new()) of + Suffix -> test_same_suffix(N-1, Suffix); + _ -> false + end. From bf78e6b18c7bbb8ffde8383aab0868ad8c10d5da Mon Sep 17 00:00:00 2001 From: NickNorth Date: Mon, 6 Aug 2012 09:23:04 +0100 Subject: [PATCH 2/3] Use utc_id_suffix more consistently --- etc/couchdb/default.ini.tpl.in | 10 +++++----- share/www/script/test/uuids.js | 10 +++++----- src/couchdb/couch_uuids.erl | 8 ++++---- test/etap/041-uuid-gen-id-suffix.ini | 2 +- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/etc/couchdb/default.ini.tpl.in b/etc/couchdb/default.ini.tpl.in index 80802eac3b1..fb462d79281 100644 --- a/etc/couchdb/default.ini.tpl.in +++ b/etc/couchdb/default.ini.tpl.in @@ -178,12 +178,12 @@ _view = {couch_mrview_http, handle_view_req} ; random prefix is regenerated and the process starts over. ; utc_random - Time since Jan 1, 1970 UTC with microseconds ; First 14 characters are the time in hex. Last 18 are random. -; utc_id_suffix - Time since Jan 1, 1970 UTC with microseconds, plus id_suffix string -; First 14 characters are the time in hex. uuids/id_suffix string value is appended to these. +; utc_id_suffix - 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 -; The id_suffix value will be appended to uuids generated by the utc_id_suffix algorithm. -; Replicating instances should have unique id_suffixes to ensure uniqueness of utc_id_suffix ids. -id_suffix = +; The utc_id_suffix value will be appended to uuids generated by the utc_id_suffix algorithm. +; Replicating instances should have unique utc_id_suffixes to ensure uniqueness of utc_id_suffix ids. +utc_id_suffix = [stats] ; rate is in milliseconds diff --git a/share/www/script/test/uuids.js b/share/www/script/test/uuids.js index 1ebda870d56..3db96833ca0 100644 --- a/share/www/script/test/uuids.js +++ b/share/www/script/test/uuids.js @@ -118,14 +118,14 @@ couchTests.uuids = function(debug) { ); // Test utc_id_suffix uuids - var id_suffix = "frog"; + var utc_id_suffix = "frog"; var suffix_testfun = function() { xhr = CouchDB.request("GET", "/_uuids?count=10"); T(xhr.status == 200); result = JSON.parse(xhr.responseText); for(var i = 1; i < result.uuids.length; i++) { - T(result.uuids[i].length == 14 + id_suffix.length); - T(result.uuids[i].substring(14) == id_suffix); + T(result.uuids[i].length == 14 + utc_id_suffix.length); + T(result.uuids[i].substring(14) == utc_id_suffix); T(result.uuids[i-1] < result.uuids[i], "utc_id_suffix uuids are ordered."); } }; @@ -136,8 +136,8 @@ couchTests.uuids = function(debug) { "value": "utc_id_suffix" }, { "section": "uuids", - "key": "id_suffix", - "value": id_suffix + "key": "utc_id_suffix", + "value": utc_id_suffix }], suffix_testfun ); diff --git a/src/couchdb/couch_uuids.erl b/src/couchdb/couch_uuids.erl index b97b03d1dce..fe1bcc14078 100644 --- a/src/couchdb/couch_uuids.erl +++ b/src/couchdb/couch_uuids.erl @@ -56,8 +56,8 @@ handle_call(create, _From, random) -> {reply, random(), random}; handle_call(create, _From, utc_random) -> {reply, utc_random(), utc_random}; -handle_call(create, _From, {utc_id_suffix, IdSuffix}) -> - {reply, utc_suffix(IdSuffix), {utc_id_suffix, IdSuffix}}; +handle_call(create, _From, {utc_id_suffix, UtcIdSuffix}) -> + {reply, utc_suffix(UtcIdSuffix), {utc_id_suffix, UtcIdSuffix}}; handle_call(create, _From, {sequential, Pref, Seq}) -> Result = ?l2b(Pref ++ io_lib:format("~6.16.0b", [Seq])), case Seq >= 16#fff000 of @@ -88,14 +88,14 @@ inc() -> state() -> AlgoStr = couch_config:get("uuids", "algorithm", "random"), - IdSuffix = couch_config:get("uuids", "id_suffix", ""), + UtcIdSuffix = couch_config:get("uuids", "utc_id_suffix", ""), case couch_util:to_existing_atom(AlgoStr) of random -> random; utc_random -> utc_random; utc_id_suffix -> - {utc_id_suffix, IdSuffix}; + {utc_id_suffix, UtcIdSuffix}; sequential -> {sequential, new_prefix(), inc()}; Unknown -> diff --git a/test/etap/041-uuid-gen-id-suffix.ini b/test/etap/041-uuid-gen-id-suffix.ini index da01fb8bf43..4998924743f 100644 --- a/test/etap/041-uuid-gen-id-suffix.ini +++ b/test/etap/041-uuid-gen-id-suffix.ini @@ -16,5 +16,5 @@ ; under the License. [uuids] -id_suffix = bozo +utc_id_suffix = bozo algorithm = utc_id_suffix From 318362b9086c698d644e697ff917a589ed7afbff Mon Sep 17 00:00:00 2001 From: NickNorth Date: Mon, 6 Aug 2012 09:33:23 +0100 Subject: [PATCH 3/3] Updated CHANGES, NEWS and THANKS for utc_id_suffix UUID algorithm. --- CHANGES | 4 ++++ NEWS | 1 + THANKS | 1 + 3 files changed, 6 insertions(+) diff --git a/CHANGES b/CHANGES index e3777beedb8..8de4b6d2f97 100644 --- a/CHANGES +++ b/CHANGES @@ -46,6 +46,10 @@ Test Suite: * Improved tracebacks printed by the JS CLI tests * Improved the reliability of a number of tests +UUID Algorithms: + + * Added the utc_id_suffix algorithm. + Version 1.2.1 ------------- diff --git a/NEWS b/NEWS index 30b0d27d167..b4ad9473960 100644 --- a/NEWS +++ b/NEWS @@ -22,6 +22,7 @@ This version has not been released yet. * Added Server-Sent Events protocol to db changes API. * Moved the JS test suite to the CLI * Make password hashing synchronous when using the /_config/admins API. + * Added utc_id_suffix UUID algorithm. Version 1.2.1 ------------- diff --git a/THANKS b/THANKS index 06ea1b3cc90..674d5921b16 100644 --- a/THANKS +++ b/THANKS @@ -92,6 +92,7 @@ suggesting improvements or submitting changes. Some of these people are: * RogutÄ—s Sparnuotos * Gavin McDonald * Fedor Indutny + * Nick North # Dear committer who merges a commit from a non-committer: # You don't have to manually maintain the THANKS file anymore (yay!). # Non-committer authors get automatically appended to THANKS and