summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Kocoloski <kocolosk@apache.org>2019-09-06 12:10:01 -0400
committerAdam Kocoloski <kocolosk@apache.org>2019-09-24 14:43:04 -0400
commitdddaa3cd44b65d90bc9bd73888c19c0f703b7c97 (patch)
treebe34c959890250bd524d2e7e7eb7c1486eece5e9
parent8553ee662c6bfd08daabf521cf5c46e0e1696b9b (diff)
downloadcouchdb-dddaa3cd44b65d90bc9bd73888c19c0f703b7c97.tar.gz
Support scheduling compactions during time windows
This patch allows administrators to configure smoosh to only execute compactions during a specified time window on a per-channel basis. The (partial) configuration looks like [smoosh] db_channels=overnight_channel [smoosh.overnight_channel] from = 22:00 to = 06:00 strict_window = true If `strict_window` is set to true, smoosh will suspend all currently running compactions in this channel when leaving the time window, and resume them in the next window. If left at the default, currently running compactions will be allowed to complete but no new compactions will be started until the window is open again.
-rw-r--r--src/smoosh_channel.erl27
-rw-r--r--src/smoosh_utils.erl34
2 files changed, 61 insertions, 0 deletions
diff --git a/src/smoosh_channel.erl b/src/smoosh_channel.erl
index 58d3ce73a..d8a8d14a9 100644
--- a/src/smoosh_channel.erl
+++ b/src/smoosh_channel.erl
@@ -63,6 +63,7 @@ flush(ServerRef) ->
init(Name) ->
schedule_unpause(),
+ erlang:send_after(60 * 1000, self(), check_window),
{ok, #state{name=Name}}.
handle_call({last_updated, Object}, _From, State0) ->
@@ -151,6 +152,32 @@ handle_info({Ref, {ok, Pid}}, State0) when is_reference(Ref) ->
{noreply, State}
end;
+handle_info(check_window, State0) ->
+ {ok, State} = code_change(nil, State0, nil),
+ #state{paused = Paused, name = Name} = State,
+ StrictWindow = smoosh_utils:get(Name, "strict_window", "false"),
+ FinalState = case {not Paused, smoosh_utils:in_allowed_window(Name)} of
+ {false, false} ->
+ % already in desired state
+ State;
+ {true, true} ->
+ % already in desired state
+ State;
+ {false, true} ->
+ % resume is always safe even if we did not previously suspend
+ {reply, ok, NewState} = handle_call(resume, nil, State),
+ NewState;
+ {true, false} ->
+ if StrictWindow =:= "true" ->
+ {reply, ok, NewState} = handle_call(suspend, nil, State),
+ NewState;
+ true ->
+ State#state{paused=true}
+ end
+ end,
+ erlang:send_after(60 * 1000, self(), check_window),
+ {noreply, FinalState};
+
handle_info(pause, State0) ->
{ok, State} = code_change(nil, State0, nil),
{noreply, State#state{paused=true}};
diff --git a/src/smoosh_utils.erl b/src/smoosh_utils.erl
index 78ef83aed..b433de033 100644
--- a/src/smoosh_utils.erl
+++ b/src/smoosh_utils.erl
@@ -14,6 +14,9 @@
-include_lib("couch/include/couch_db.hrl").
-export([get/2, get/3, group_pid/1, split/1, stringify/1, ignore_db/1]).
+-export([
+ in_allowed_window/1
+]).
group_pid({Shard, GroupId}) ->
case couch_view_group:open_db_group(Shard, GroupId) of
@@ -56,3 +59,34 @@ ignore_db(DbName) when is_list(DbName) ->
end;
ignore_db(Db) ->
ignore_db(couch_db:name(Db)).
+
+in_allowed_window(Channel) ->
+ From = parse_time(get(Channel, "from"), {00, 00}),
+ To = parse_time(get(Channel, "to"), {24, 00}),
+ in_allowed_window(From, To).
+
+in_allowed_window(From, To) ->
+ {HH, MM, _} = erlang:time(),
+ case From < To of
+ true ->
+ ({HH, MM} >= From) andalso ({HH, MM} < To);
+ false ->
+ ({HH, MM} >= From) orelse ({HH, MM} < To)
+ end.
+
+
+parse_time(undefined, Default) ->
+ Default;
+parse_time(String, Default) ->
+ case string:tokens(String, ":") of
+ [HH, MM] ->
+ try
+ {list_to_integer(HH), list_to_integer(MM)}
+ catch error:badarg ->
+ couch_log:error("Malformed compaction schedule configuration: ~s", [String]),
+ Default
+ end;
+ _Else ->
+ couch_log:error("Malformed compaction schedule configuration: ~s", [String]),
+ Default
+ end.