You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by va...@apache.org on 2021/10/24 06:40:38 UTC

[couchdb] 01/01: Add libicu version fetching and emit it in the _node/_local/_versions

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

vatamane pushed a commit to branch get-libicu-detailed-versions
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit e204d5a83c0aeb657d8788d3614766d93778e4d2
Author: Nick Vatamaniuc <va...@apache.org>
AuthorDate: Sun Oct 24 02:33:43 2021 -0400

    Add libicu version fetching and emit it in the _node/_local/_versions
    
    Fetch the libicu base version as well as the collator version. The
    base version may be used to determine which libicu library CouchDB is
    using. The collator version may be used to debug view behavior in case
    when collation order had changed from one version ot the next.
---
 src/chttpd/src/chttpd_node.erl                     | 28 ++++++++++++----
 .../priv/couch_ejson_compare/couch_ejson_compare.c | 38 +++++++++++++++++++++-
 src/couch/src/couch_ejson_compare.erl              | 22 +++++++++++--
 src/couch/test/eunit/couch_ejson_compare_tests.erl | 20 ++++++++++++
 4 files changed, 98 insertions(+), 10 deletions(-)

diff --git a/src/chttpd/src/chttpd_node.erl b/src/chttpd/src/chttpd_node.erl
index 7486aad..e92a1e5 100644
--- a/src/chttpd/src/chttpd_node.erl
+++ b/src/chttpd/src/chttpd_node.erl
@@ -33,13 +33,20 @@ handle_node_req(#httpd{path_parts=[A, <<"_local">>|Rest]}=Req) ->
     handle_node_req(Req#httpd{path_parts=[A, node()] ++ Rest});
 % GET /_node/$node/_versions
 handle_node_req(#httpd{method='GET', path_parts=[_, _Node, <<"_versions">>]}=Req) ->
-    send_json(Req, 200, {[
-        {erlang_version, ?l2b(?COUCHDB_ERLANG_VERSION)},
-        {javascript_engine, {[
-            {name, <<"spidermonkey">>},
-            {version, couch_server:get_spidermonkey_version()}
-        ]}}
-    ]});
+    IcuVer = couch_ejson_compare:get_icu_version(),
+    UcaVer = couch_ejson_compare:get_uca_version(),
+    send_json(Req, 200, #{
+        erlang_version => ?l2b(?COUCHDB_ERLANG_VERSION),
+        collation_driver => #{
+            name => <<"libicu">>,
+            library_version => version_tuple_to_str(IcuVer),
+            collation_algorithm_version => version_tuple_to_str(UcaVer)
+        },
+        javascript_engine => #{
+            name => <<"spidermonkey">>,
+            version => couch_server:get_spidermonkey_version()
+        }
+    });
 handle_node_req(#httpd{path_parts=[_, _Node, <<"_versions">>]}=Req) ->
     send_method_not_allowed(Req, "GET");
 
@@ -322,3 +329,10 @@ run_queues() ->
             [DCQ | SQs] = lists:reverse(statistics(run_queue_lengths)),
             {lists:sum(SQs), DCQ}
     end.
+
+version_tuple_to_str(Version) when is_tuple(Version) ->
+    List1 = tuple_to_list(Version),
+    IsZero = fun(N) -> N == 0 end,
+    List2 = lists:reverse(lists:dropwhile(IsZero, lists:reverse(List1))),
+    List3 = [erlang:integer_to_list(N) || N <- List2],
+    ?l2b(lists:join(".", List3)).
diff --git a/src/couch/priv/couch_ejson_compare/couch_ejson_compare.c b/src/couch/priv/couch_ejson_compare/couch_ejson_compare.c
index f453a29..6e20032 100644
--- a/src/couch/priv/couch_ejson_compare/couch_ejson_compare.c
+++ b/src/couch/priv/couch_ejson_compare/couch_ejson_compare.c
@@ -166,6 +166,40 @@ compare_strings_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
 }
 
 
+ERL_NIF_TERM
+get_icu_version(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+    UVersionInfo ver = {0};
+    ERL_NIF_TERM tup[U_MAX_VERSION_LENGTH] = {0};
+    int i;
+
+    u_getVersion(ver);
+
+    for (i = 0; i < U_MAX_VERSION_LENGTH; i++) {
+        tup[i] = enif_make_int(env, ver[i]);
+    }
+
+    return enif_make_tuple_from_array(env, tup, U_MAX_VERSION_LENGTH);
+}
+
+
+ERL_NIF_TERM
+get_uca_version(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+    UVersionInfo ver = {0};
+    ERL_NIF_TERM tup[U_MAX_VERSION_LENGTH] = {0};
+    int i;
+
+    ucol_getUCAVersion(get_collator(), ver);
+
+    for (i = 0; i < U_MAX_VERSION_LENGTH; i++) {
+        tup[i] = enif_make_int(env, ver[i]);
+    }
+
+    return enif_make_tuple_from_array(env, tup, U_MAX_VERSION_LENGTH);
+}
+
+
 int
 less_json(int depth, ctx_t* ctx, ERL_NIF_TERM a, ERL_NIF_TERM b)
 {
@@ -531,7 +565,9 @@ on_unload(ErlNifEnv* env, void* priv_data)
 
 static ErlNifFunc nif_functions[] = {
     {"less_nif", 2, less_json_nif},
-    {"compare_strings_nif", 2, compare_strings_nif}
+    {"compare_strings_nif", 2, compare_strings_nif},
+    {"get_icu_version", 0, get_icu_version},
+    {"get_uca_version", 0, get_uca_version}
 };
 
 
diff --git a/src/couch/src/couch_ejson_compare.erl b/src/couch/src/couch_ejson_compare.erl
index 8681296..b02b9ba 100644
--- a/src/couch/src/couch_ejson_compare.erl
+++ b/src/couch/src/couch_ejson_compare.erl
@@ -12,10 +12,20 @@
 
 -module(couch_ejson_compare).
 
--export([less/2, less_json_ids/2, less_json/2]).
+-export([
+    less/2,
+    less_json_ids/2,
+    less_json/2,
+    get_icu_version/0,
+    get_uca_version/0
+]).
 
 % For testing
--export([less_nif/2, less_erl/2, compare_strings_nif/2]).
+-export([
+    less_nif/2,
+    less_erl/2,
+    compare_strings_nif/2
+]).
 
 
 -on_load(init/0).
@@ -51,6 +61,14 @@ less_json(A,B) ->
     less(A, B) < 0.
 
 
+get_icu_version() ->
+    erlang:nif_error(get_icu_version).
+
+
+get_uca_version() ->
+    erlang:nif_error(get_uca_version).
+
+
 less_nif(A, B) ->
     erlang:nif_error(less_nif_load_error, [A, B]).
 
diff --git a/src/couch/test/eunit/couch_ejson_compare_tests.erl b/src/couch/test/eunit/couch_ejson_compare_tests.erl
index 790f6e5..1dfbad4 100644
--- a/src/couch/test/eunit/couch_ejson_compare_tests.erl
+++ b/src/couch/test/eunit/couch_ejson_compare_tests.erl
@@ -183,6 +183,26 @@ zero_width_chars() ->
 
 % Regular EUnit tests
 
+get_icu_version_test() ->
+    Ver = couch_ejson_compare:get_icu_version(),
+    ?assertMatch({_, _, _, _}, Ver),
+    {V1, V2, V3, V4} = Ver,
+    ?assert(is_integer(V1) andalso V1 > 0),
+    ?assert(is_integer(V2) andalso V2 >= 0),
+    ?assert(is_integer(V3) andalso V3 >= 0),
+    ?assert(is_integer(V4) andalso V4 >= 0).
+
+
+get_uca_version_test() ->
+    Ver = couch_ejson_compare:get_uca_version(),
+    ?assertMatch({_, _, _, _}, Ver),
+    {V1, V2, V3, V4} = Ver,
+    ?assert(is_integer(V1) andalso V1 > 0),
+    ?assert(is_integer(V2) andalso V2 >= 0),
+    ?assert(is_integer(V3) andalso V3 >= 0),
+    ?assert(is_integer(V4) andalso V4 >= 0).
+
+
 max_depth_error_list_test() ->
     % NIF can handle terms with depth <= 9
     Nested9 = nest_list(<<"val">>, 9),