summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Vatamaniuc <vatamane@apache.org>2021-10-24 02:33:43 -0400
committerNick Vatamaniuc <nickva@users.noreply.github.com>2021-10-24 14:51:17 -0400
commitc1bb4e4856edd93255d75ebe158b4da38bbf3333 (patch)
treee0363657db5015b572c9e3f999101f2902dcb9e5
parentbdde402a146788b7a43837311cb8208c92baeb43 (diff)
downloadcouchdb-c1bb4e4856edd93255d75ebe158b4da38bbf3333.tar.gz
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.
-rw-r--r--src/chttpd/src/chttpd_node.erl28
-rw-r--r--src/couch/priv/couch_ejson_compare/couch_ejson_compare.c38
-rw-r--r--src/couch/src/couch_ejson_compare.erl22
-rw-r--r--src/couch/test/eunit/couch_ejson_compare_tests.erl20
4 files changed, 98 insertions, 10 deletions
diff --git a/src/chttpd/src/chttpd_node.erl b/src/chttpd/src/chttpd_node.erl
index 7486aadfe..e92a1e506 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 f453a295f..6e200320d 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 8681296f1..b02b9ba7c 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 790f6e54c..1dfbad4ed 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),