summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Radestock <matthias@rabbitmq.com>2013-01-08 18:04:47 +0000
committerMatthias Radestock <matthias@rabbitmq.com>2013-01-08 18:04:47 +0000
commit0e929121c541ca467d9a30cc48b981b5f61ca997 (patch)
tree9e5f5ddb6c6877b5333e0a1ad3628683739f1ca9
parent06ed05a9ab5b603aa20b022c4463f89f8b76c582 (diff)
downloadrabbitmq-server-0e929121c541ca467d9a30cc48b981b5f61ca997.tar.gz
rationalise timer maintenance
- introduce a couple of helper functions and use them wherever we can - pay attention to the result of timer cancellation, to prevent duplicate timer creation - stop all timers when a queue terminates. More out of politeness than necessity.
-rw-r--r--src/rabbit_amqqueue_process.erl86
-rw-r--r--src/rabbit_mirror_queue_slave.erl28
-rw-r--r--src/rabbit_misc.erl19
-rw-r--r--src/rabbit_msg_store.erl13
4 files changed, 70 insertions, 76 deletions
diff --git a/src/rabbit_amqqueue_process.erl b/src/rabbit_amqqueue_process.erl
index 536ed48a..2293d001 100644
--- a/src/rabbit_amqqueue_process.erl
+++ b/src/rabbit_amqqueue_process.erl
@@ -254,7 +254,11 @@ init_dlx_routing_key(RoutingKey, State) ->
terminate_shutdown(Fun, State) ->
State1 = #q{backing_queue_state = BQS} =
- stop_sync_timer(stop_rate_timer(State)),
+ lists:foldl(fun (F, S) -> F(S) end, State,
+ [fun stop_sync_timer/1,
+ fun stop_rate_timer/1,
+ fun stop_expiry_timer/1,
+ fun stop_ttl_timer/1]),
case BQS of
undefined -> State1;
_ -> ok = rabbit_memory_monitor:deregister(self()),
@@ -289,36 +293,18 @@ backing_queue_module(Q) ->
true -> rabbit_mirror_queue_master
end.
-ensure_sync_timer(State = #q{sync_timer_ref = undefined}) ->
- TRef = erlang:send_after(?SYNC_INTERVAL, self(), sync_timeout),
- State#q{sync_timer_ref = TRef};
ensure_sync_timer(State) ->
- State.
+ rabbit_misc:ensure_timer(State, #q.sync_timer_ref,
+ ?SYNC_INTERVAL, sync_timeout).
-stop_sync_timer(State = #q{sync_timer_ref = undefined}) ->
- State;
-stop_sync_timer(State = #q{sync_timer_ref = TRef}) ->
- erlang:cancel_timer(TRef),
- State#q{sync_timer_ref = undefined}.
-
-ensure_rate_timer(State = #q{rate_timer_ref = undefined}) ->
- TRef = erlang:send_after(
- ?RAM_DURATION_UPDATE_INTERVAL, self(), update_ram_duration),
- State#q{rate_timer_ref = TRef};
-ensure_rate_timer(State) ->
- State.
+stop_sync_timer(State) -> rabbit_misc:stop_timer(State, #q.sync_timer_ref).
-stop_rate_timer(State = #q{rate_timer_ref = undefined}) ->
- State;
-stop_rate_timer(State = #q{rate_timer_ref = TRef}) ->
- erlang:cancel_timer(TRef),
- State#q{rate_timer_ref = undefined}.
+ensure_rate_timer(State) ->
+ rabbit_misc:ensure_timer(State, #q.rate_timer_ref,
+ ?RAM_DURATION_UPDATE_INTERVAL,
+ update_ram_duration).
-stop_expiry_timer(State = #q{expiry_timer_ref = undefined}) ->
- State;
-stop_expiry_timer(State = #q{expiry_timer_ref = TRef}) ->
- erlang:cancel_timer(TRef),
- State#q{expiry_timer_ref = undefined}.
+stop_rate_timer(State) -> rabbit_misc:stop_timer(State, #q.rate_timer_ref).
%% We wish to expire only when there are no consumers *and* the expiry
%% hasn't been refreshed (by queue.declare or basic.get) for the
@@ -328,11 +314,34 @@ ensure_expiry_timer(State = #q{expires = undefined}) ->
ensure_expiry_timer(State = #q{expires = Expires}) ->
case is_unused(State) of
true -> NewState = stop_expiry_timer(State),
- TRef = erlang:send_after(Expires, self(), maybe_expire),
- NewState#q{expiry_timer_ref = TRef};
+ rabbit_misc:ensure_timer(NewState, #q.expiry_timer_ref,
+ Expires, maybe_expire);
false -> State
end.
+stop_expiry_timer(State) -> rabbit_misc:stop_timer(State, #q.expiry_timer_ref).
+
+ensure_ttl_timer(undefined, State) ->
+ State;
+ensure_ttl_timer(Expiry, State = #q{ttl_timer_ref = undefined}) ->
+ After = (case Expiry - now_micros() of
+ V when V > 0 -> V + 999; %% always fire later
+ _ -> 0
+ end) div 1000,
+ TRef = erlang:send_after(After, self(), drop_expired),
+ State#q{ttl_timer_ref = TRef, ttl_timer_expiry = Expiry};
+ensure_ttl_timer(Expiry, State = #q{ttl_timer_ref = TRef,
+ ttl_timer_expiry = TExpiry})
+ when Expiry + 1000 < TExpiry ->
+ case erlang:cancel_timer(TRef) of
+ false -> State;
+ _ -> ensure_ttl_timer(Expiry, State#q{ttl_timer_ref = undefined})
+ end;
+ensure_ttl_timer(_Expiry, State) ->
+ State.
+
+stop_ttl_timer(State) -> rabbit_misc:stop_timer(State, #q.ttl_timer_ref).
+
ensure_stats_timer(State) ->
rabbit_event:ensure_stats_timer(State, #q.stats_timer, emit_stats).
@@ -764,25 +773,6 @@ dead_letter_msgs(Fun, Reason, X, State = #q{dlx_routing_key = RK,
queue_monitors = QMons1,
backing_queue_state = BQS2}}.
-ensure_ttl_timer(undefined, State) ->
- State;
-ensure_ttl_timer(Expiry, State = #q{ttl_timer_ref = undefined}) ->
- After = (case Expiry - now_micros() of
- V when V > 0 -> V + 999; %% always fire later
- _ -> 0
- end) div 1000,
- TRef = erlang:send_after(After, self(), drop_expired),
- State#q{ttl_timer_ref = TRef, ttl_timer_expiry = Expiry};
-ensure_ttl_timer(Expiry, State = #q{ttl_timer_ref = TRef,
- ttl_timer_expiry = TExpiry})
- when Expiry + 1000 < TExpiry ->
- case erlang:cancel_timer(TRef) of
- false -> State;
- _ -> ensure_ttl_timer(Expiry, State#q{ttl_timer_ref = undefined})
- end;
-ensure_ttl_timer(_Expiry, State) ->
- State.
-
dead_letter_publish(Msg, Reason, X, RK, MsgSeqNo, QName) ->
DLMsg = make_dead_letter_msg(Msg, Reason, X#exchange.name, RK, QName),
Delivery = rabbit_basic:delivery(false, DLMsg, MsgSeqNo),
diff --git a/src/rabbit_mirror_queue_slave.erl b/src/rabbit_mirror_queue_slave.erl
index feddf45a..9f12b34e 100644
--- a/src/rabbit_mirror_queue_slave.erl
+++ b/src/rabbit_mirror_queue_slave.erl
@@ -589,30 +589,18 @@ next_state(State = #state{backing_queue = BQ, backing_queue_state = BQS}) ->
backing_queue_timeout(State = #state { backing_queue = BQ }) ->
run_backing_queue(BQ, fun (M, BQS) -> M:timeout(BQS) end, State).
-ensure_sync_timer(State = #state { sync_timer_ref = undefined }) ->
- TRef = erlang:send_after(?SYNC_INTERVAL, self(), sync_timeout),
- State #state { sync_timer_ref = TRef };
ensure_sync_timer(State) ->
- State.
+ rabbit_misc:ensure_timer(State, #state.sync_timer_ref,
+ ?SYNC_INTERVAL, sync_timeout).
+
+stop_sync_timer(State) -> rabbit_misc:stop_timer(State, #state.sync_timer_ref).
-stop_sync_timer(State = #state { sync_timer_ref = undefined }) ->
- State;
-stop_sync_timer(State = #state { sync_timer_ref = TRef }) ->
- erlang:cancel_timer(TRef),
- State #state { sync_timer_ref = undefined }.
-
-ensure_rate_timer(State = #state { rate_timer_ref = undefined }) ->
- TRef = erlang:send_after(?RAM_DURATION_UPDATE_INTERVAL,
- self(), update_ram_duration),
- State #state { rate_timer_ref = TRef };
ensure_rate_timer(State) ->
- State.
+ rabbit_misc:ensure_timer(State, #state.rate_timer_ref,
+ ?RAM_DURATION_UPDATE_INTERVAL,
+ update_ram_duration).
-stop_rate_timer(State = #state { rate_timer_ref = undefined }) ->
- State;
-stop_rate_timer(State = #state { rate_timer_ref = TRef }) ->
- erlang:cancel_timer(TRef),
- State #state { rate_timer_ref = undefined }.
+stop_rate_timer(State) -> rabbit_misc:stop_timer(State, #state.rate_timer_ref).
ensure_monitoring(ChPid, State = #state { known_senders = KS }) ->
State #state { known_senders = pmon:monitor(ChPid, KS) }.
diff --git a/src/rabbit_misc.erl b/src/rabbit_misc.erl
index ce3e3802..73a4c922 100644
--- a/src/rabbit_misc.erl
+++ b/src/rabbit_misc.erl
@@ -67,6 +67,7 @@
-export([check_expiry/1]).
-export([base64url/1]).
-export([interval_operation/4]).
+-export([ensure_timer/4, stop_timer/2]).
-export([get_parent/0]).
%% Horrible macro to use in guards
@@ -242,6 +243,8 @@
-spec(interval_operation/4 ::
({atom(), atom(), any()}, float(), non_neg_integer(), non_neg_integer())
-> {any(), non_neg_integer()}).
+-spec(ensure_timer/4 :: (A, non_neg_integer(), non_neg_integer(), any()) -> A).
+-spec(stop_timer/2 :: (A, non_neg_integer()) -> A).
-spec(get_parent/0 :: () -> pid()).
-endif.
@@ -1047,6 +1050,22 @@ interval_operation({M, F, A}, MaxRatio, IdealInterval, LastInterval) ->
round(LastInterval / 1.5)])
end}.
+ensure_timer(State, Idx, After, Msg) ->
+ case element(Idx, State) of
+ undefined -> TRef = erlang:send_after(After, self(), Msg),
+ setelement(Idx, State, TRef);
+ _ -> State
+ end.
+
+stop_timer(State, Idx) ->
+ case element(Idx, State) of
+ undefined -> State;
+ TRef -> case erlang:cancel_timer(TRef) of
+ false -> State;
+ _ -> setelement(Idx, State, undefined)
+ end
+ end.
+
%% -------------------------------------------------------------------------
%% Begin copypasta from gen_server2.erl
diff --git a/src/rabbit_msg_store.erl b/src/rabbit_msg_store.erl
index c2e55022..485a3256 100644
--- a/src/rabbit_msg_store.erl
+++ b/src/rabbit_msg_store.erl
@@ -943,15 +943,12 @@ next_state(State = #msstate { cref_to_msg_ids = CTM }) ->
_ -> {State, 0}
end.
-start_sync_timer(State = #msstate { sync_timer_ref = undefined }) ->
- TRef = erlang:send_after(?SYNC_INTERVAL, self(), sync),
- State #msstate { sync_timer_ref = TRef }.
+start_sync_timer(State) ->
+ rabbit_misc:ensure_timer(State, #msstate.sync_timer_ref,
+ ?SYNC_INTERVAL, sync).
-stop_sync_timer(State = #msstate { sync_timer_ref = undefined }) ->
- State;
-stop_sync_timer(State = #msstate { sync_timer_ref = TRef }) ->
- erlang:cancel_timer(TRef),
- State #msstate { sync_timer_ref = undefined }.
+stop_sync_timer(State) ->
+ rabbit_misc:stop_timer(State, #msstate.sync_timer_ref).
internal_sync(State = #msstate { current_file_handle = CurHdl,
cref_to_msg_ids = CTM }) ->