summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Vatamaniuc <vatamane@gmail.com>2021-10-15 11:00:03 -0400
committerNick Vatamaniuc <nickva@users.noreply.github.com>2021-10-15 11:53:29 -0400
commitc3f08f770d66b486fb2cbe8b4a7fe50551303f8f (patch)
tree8565288f82c269d23262f4aac742fdff703a0dbe
parent029612b27c78405790fd550958028cec5c84e9c8 (diff)
downloadcouchdb-c3f08f770d66b486fb2cbe8b4a7fe50551303f8f.tar.gz
Fix badarith error in get_db_timeout when request timeout = infinity
`infinity` it turns out is a valid configuration value for fabric request_timeout. We can pass that to Erlang `receive` statement, any arithmetic with it would fail. To guard against the crash use the max small int value (60 bits). With enough shards, due to the exponential nature of the algorithm, we still get a nice progression from the minimum 100 msec all the way up to the large int value. This case is illustrated in the test. Issue: https://github.com/apache/couchdb/issues/3789
-rw-r--r--src/fabric/src/fabric_util.erl10
1 files changed, 9 insertions, 1 deletions
diff --git a/src/fabric/src/fabric_util.erl b/src/fabric/src/fabric_util.erl
index e07ab7b55..4c4031627 100644
--- a/src/fabric/src/fabric_util.erl
+++ b/src/fabric/src/fabric_util.erl
@@ -138,6 +138,10 @@ get_shard([#shard{node = Node, name = Name} | Rest], Opts, Timeout, Factor) ->
rexi_monitor:stop(Mon)
end.
+get_db_timeout(N, Factor, MinTimeout, infinity) ->
+ % MaxTimeout may be infinity so we just use the largest Erlang small int to
+ % avoid blowing up the arithmetic
+ get_db_timeout(N, Factor, MinTimeout, 1 bsl 59);
get_db_timeout(N, Factor, MinTimeout, MaxTimeout) ->
%
% The progression of timeouts forms a geometric series:
@@ -460,4 +464,8 @@ get_db_timeout_test() ->
?assertEqual(28346, get_db_timeout(2 * 3, 2, 100, 3600000)),
% No shards at all
- ?assertEqual(60000, get_db_timeout(0, 2, 100, 60000)).
+ ?assertEqual(60000, get_db_timeout(0, 2, 100, 60000)),
+
+ % request_timeout was set to infinity, with enough shards it still gets to
+ % 100 min timeout at the start from the exponential logic
+ ?assertEqual(100, get_db_timeout(64, 2, 100, infinity)).