Skip to content

Commit

Permalink
Compaction: Add snooze_period_ms for finer tuning
Browse files Browse the repository at this point in the history
We are experiencing an issue similar to #1579, partly because we have
dozens of thousands of databases.

On our servers:
- `snooze_period = 0` leads to a significant CPU load,
- `snooze_period = 1` is too long for compaction to finish within 20
  hours (after 20 hours, compaction is stopped to allow other
  CPU-intensive processes to run, and when compaction restarts, it does
  not pick up where it left 4 hours earlier -- by the way proposal at
  #1775 would be really great to fix that!)

This commit introduces a new option `snooze_period_ms` (measured in
milliseconds), and deprecates `snooze_period` while still supporting it
for obvious legacy reasons.
  • Loading branch information
adrienverge committed Jan 29, 2019
1 parent 25838d0 commit c3eb760
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 7 deletions.
5 changes: 3 additions & 2 deletions rel/overlay/etc/default.ini
Expand Up @@ -435,8 +435,9 @@ min_file_size = 131072
; databases, the compaction_daemon can create significant CPU load when
; checking whether databases and view indexes need compacting. The
; snooze_period setting ensures a smoother CPU load. Defaults to
; 3 seconds wait.
; snooze_period = 3
; 3000 milliseconds wait. Note that this option was formerly called
; snooze_period, measured in seconds (it is currently still supported).
; snooze_period_ms = 3000

[compactions]
; List of compaction rules for the compaction daemon.
Expand Down
71 changes: 67 additions & 4 deletions src/couch/src/couch_compaction_daemon.erl
Expand Up @@ -125,8 +125,16 @@ handle_config_terminate(_, stop, _) ->
handle_config_terminate(_Server, _Reason, _State) ->
erlang:send_after(?RELISTEN_DELAY, whereis(?MODULE), restart_config_listener).

get_snooze_period() ->
% The snooze_period_ms option should be used, but snooze_period is supported
% for legacy reasons.
Default = config:get_integer("compaction_daemon", "snooze_period", 3),
case config:get_integer("compaction_daemon", "snooze_period_ms", -1) of
-1 -> Default * 1000;
SnoozePeriod -> SnoozePeriod
end.

compact_loop(Parent) ->
SnoozePeriod = config:get_integer("compaction_daemon", "snooze_period", 3),
{ok, _} = couch_server:all_databases(
fun(DbName, Acc) ->
case ets:info(?CONFIG_ETS, size) =:= 0 of
Expand All @@ -140,7 +148,7 @@ compact_loop(Parent) ->
case check_period(Config) of
true ->
maybe_compact_db(Parent, DbName, Config),
ok = timer:sleep(SnoozePeriod * 1000);
ok = timer:sleep(get_snooze_period());
false ->
ok
end
Expand Down Expand Up @@ -231,8 +239,7 @@ maybe_compact_views(DbName, [DDocName | Rest], Config) ->
timeout ->
ok
end,
SnoozePeriod = config:get_integer("compaction_daemon", "snooze_period", 3),
ok = timer:sleep(SnoozePeriod * 1000);
ok = timer:sleep(get_snooze_period());
false ->
ok
end.
Expand Down Expand Up @@ -597,4 +604,60 @@ abs_path2_test() ->
?assertEqual({ok, "/a/b/"}, abs_path2("/a/b")),
ok.

get_snooze_period_test_() ->
{
foreach,
fun() ->
meck:new(config, [passthrough])
end,
fun(_) ->
meck:unload()
end,
[
{"should return default value without config attributes",
fun should_default_without_config/0},
{"should respect old config attribute",
fun should_respect_old_config/0},
{"should respect old config set to zero",
fun should_respect_old_config_zero/0},
{"should respect new config attribute",
fun should_respect_new_config/0},
{"should respect new config set to zero",
fun should_respect_new_config_zero/0}
]
}.

should_default_without_config() ->
?assertEqual(3000, get_snooze_period()).

should_respect_old_config() ->
meck:expect(config, get_integer, fun
("compaction_daemon", "snooze_period", _) -> 1;
(_, _, Default) -> Default
end),
?assertEqual(1000, get_snooze_period()).

should_respect_old_config_zero() ->
meck:expect(config, get_integer, fun
("compaction_daemon", "snooze_period", _) -> 0;
(_, _, Default) -> Default
end),
?assertEqual(0, get_snooze_period()).

should_respect_new_config() ->
meck:expect(config, get_integer, fun
("compaction_daemon", "snooze_period", _) -> 1;
("compaction_daemon", "snooze_period_ms", _) -> 300;
(_, _, Default) -> Default
end),
?assertEqual(300, get_snooze_period()).

should_respect_new_config_zero() ->
meck:expect(config, get_integer, fun
("compaction_daemon", "snooze_period", _) -> 1;
("compaction_daemon", "snooze_period_ms", _) -> 0;
(_, _, Default) -> Default
end),
?assertEqual(0, get_snooze_period()).

-endif.
2 changes: 1 addition & 1 deletion src/couch/test/couchdb_compaction_daemon_tests.erl
Expand Up @@ -24,7 +24,7 @@
start() ->
Ctx = test_util:start_couch(),
ok = config:set("compaction_daemon", "check_interval", "3", false),
ok = config:set("compaction_daemon", "snooze_period", "0", false),
ok = config:set("compaction_daemon", "snooze_period_ms", "0", false),
ok = config:set("compaction_daemon", "min_file_size", "100000", false),
ok = config:delete("compactions", "_default", false),
ok = meck:new(?MODS_TO_MOCK, [passthrough]),
Expand Down

0 comments on commit c3eb760

Please sign in to comment.