Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Updated to 2.8.2.

  • Loading branch information...
commit be37790892c35debda9e338f6569765ec71a89d5 1 parent be44f23
Jon Brisbin authored
31 include/rabbit_auth_backend_spec.hrl
... ... @@ -1,31 +0,0 @@
1   -%% The contents of this file are subject to the Mozilla Public License
2   -%% Version 1.1 (the "License"); you may not use this file except in
3   -%% compliance with the License. You may obtain a copy of the License
4   -%% at http://www.mozilla.org/MPL/
5   -%%
6   -%% Software distributed under the License is distributed on an "AS IS"
7   -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
8   -%% the License for the specific language governing rights and
9   -%% limitations under the License.
10   -%%
11   -%% The Original Code is RabbitMQ.
12   -%%
13   -%% The Initial Developer of the Original Code is VMware, Inc.
14   -%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved.
15   -%%
16   -
17   --ifdef(use_specs).
18   -
19   --spec(description/0 :: () -> [{atom(), any()}]).
20   -
21   --spec(check_user_login/2 :: (rabbit_types:username(), [term()]) ->
22   - {'ok', rabbit_types:user()} |
23   - {'refused', string(), [any()]} |
24   - {'error', any()}).
25   --spec(check_vhost_access/2 :: (rabbit_types:user(), rabbit_types:vhost()) ->
26   - boolean() | {'error', any()}).
27   --spec(check_resource_access/3 :: (rabbit_types:user(),
28   - rabbit_types:r(atom()),
29   - rabbit_access_control:permission_atom()) ->
30   - boolean() | {'error', any()}).
31   --endif.
28 include/rabbit_auth_mechanism_spec.hrl
... ... @@ -1,28 +0,0 @@
1   -%% The contents of this file are subject to the Mozilla Public License
2   -%% Version 1.1 (the "License"); you may not use this file except in
3   -%% compliance with the License. You may obtain a copy of the License
4   -%% at http://www.mozilla.org/MPL/
5   -%%
6   -%% Software distributed under the License is distributed on an "AS IS"
7   -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
8   -%% the License for the specific language governing rights and
9   -%% limitations under the License.
10   -%%
11   -%% The Original Code is RabbitMQ.
12   -%%
13   -%% The Initial Developer of the Original Code is VMware, Inc.
14   -%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved.
15   -%%
16   -
17   --ifdef(use_specs).
18   -
19   --spec(description/0 :: () -> [{atom(), any()}]).
20   --spec(should_offer/1 :: (rabbit_net:socket()) -> boolean()).
21   --spec(init/1 :: (rabbit_net:socket()) -> any()).
22   --spec(handle_response/2 :: (binary(), any()) ->
23   - {'ok', rabbit_types:user()} |
24   - {'challenge', binary(), any()} |
25   - {'protocol_error', string(), [any()]} |
26   - {'refused', string(), [any()]}).
27   -
28   --endif.
70 include/rabbit_backing_queue_spec.hrl
... ... @@ -1,70 +0,0 @@
1   -%% The contents of this file are subject to the Mozilla Public License
2   -%% Version 1.1 (the "License"); you may not use this file except in
3   -%% compliance with the License. You may obtain a copy of the License
4   -%% at http://www.mozilla.org/MPL/
5   -%%
6   -%% Software distributed under the License is distributed on an "AS IS"
7   -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
8   -%% the License for the specific language governing rights and
9   -%% limitations under the License.
10   -%%
11   -%% The Original Code is RabbitMQ.
12   -%%
13   -%% The Initial Developer of the Original Code is VMware, Inc.
14   -%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved.
15   -%%
16   -
17   --type(fetch_result(Ack) ::
18   - ('empty' |
19   - %% Message, IsDelivered, AckTag, Remaining_Len
20   - {rabbit_types:basic_message(), boolean(), Ack, non_neg_integer()})).
21   --type(is_durable() :: boolean()).
22   --type(attempt_recovery() :: boolean()).
23   --type(purged_msg_count() :: non_neg_integer()).
24   --type(confirm_required() :: boolean()).
25   --type(async_callback() :: fun ((atom(), fun ((atom(), state()) -> state())) -> 'ok')).
26   --type(duration() :: ('undefined' | 'infinity' | number())).
27   -
28   --type(msg_fun() :: fun((rabbit_types:basic_message(), ack()) -> 'ok')).
29   -
30   --spec(start/1 :: ([rabbit_amqqueue:name()]) -> 'ok').
31   --spec(stop/0 :: () -> 'ok').
32   --spec(init/3 :: (rabbit_types:amqqueue(), attempt_recovery(),
33   - async_callback()) -> state()).
34   --spec(terminate/2 :: (any(), state()) -> state()).
35   --spec(delete_and_terminate/2 :: (any(), state()) -> state()).
36   --spec(purge/1 :: (state()) -> {purged_msg_count(), state()}).
37   --spec(publish/4 :: (rabbit_types:basic_message(),
38   - rabbit_types:message_properties(), pid(), state()) ->
39   - state()).
40   --spec(publish_delivered/5 :: (true, rabbit_types:basic_message(),
41   - rabbit_types:message_properties(), pid(), state())
42   - -> {ack(), state()};
43   - (false, rabbit_types:basic_message(),
44   - rabbit_types:message_properties(), pid(), state())
45   - -> {undefined, state()}).
46   --spec(drain_confirmed/1 :: (state()) -> {[rabbit_guid:guid()], state()}).
47   --spec(dropwhile/3 ::
48   - (fun ((rabbit_types:message_properties()) -> boolean()),
49   - msg_fun() | 'undefined', state())
50   - -> state()).
51   --spec(fetch/2 :: (true, state()) -> {fetch_result(ack()), state()};
52   - (false, state()) -> {fetch_result(undefined), state()}).
53   --spec(ack/2 :: ([ack()], state()) -> {[rabbit_guid:guid()], state()}).
54   --spec(fold/3 :: (msg_fun(), state(), [ack()]) -> state()).
55   --spec(requeue/2 :: ([ack()], state())
56   - -> {[rabbit_guid:guid()], state()}).
57   --spec(len/1 :: (state()) -> non_neg_integer()).
58   --spec(is_empty/1 :: (state()) -> boolean()).
59   --spec(set_ram_duration_target/2 ::
60   - (duration(), state()) -> state()).
61   --spec(ram_duration/1 :: (state()) -> {duration(), state()}).
62   --spec(needs_timeout/1 :: (state()) -> 'false' | 'timed' | 'idle').
63   --spec(timeout/1 :: (state()) -> state()).
64   --spec(handle_pre_hibernate/1 :: (state()) -> state()).
65   --spec(status/1 :: (state()) -> [{atom(), any()}]).
66   --spec(invoke/3 :: (atom(), fun ((atom(), A) -> A), state()) -> state()).
67   --spec(is_duplicate/2 ::
68   - (rabbit_types:basic_message(), state()) ->
69   - {'false'|'published'|'discarded', state()}).
70   --spec(discard/3 :: (rabbit_types:basic_message(), pid(), state()) -> state()).
38 include/rabbit_exchange_type_spec.hrl
... ... @@ -1,38 +0,0 @@
1   -%% The contents of this file are subject to the Mozilla Public License
2   -%% Version 1.1 (the "License"); you may not use this file except in
3   -%% compliance with the License. You may obtain a copy of the License
4   -%% at http://www.mozilla.org/MPL/
5   -%%
6   -%% Software distributed under the License is distributed on an "AS IS"
7   -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
8   -%% the License for the specific language governing rights and
9   -%% limitations under the License.
10   -%%
11   -%% The Original Code is RabbitMQ.
12   -%%
13   -%% The Initial Developer of the Original Code is VMware, Inc.
14   -%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved.
15   -%%
16   -
17   --ifdef(use_specs).
18   -
19   --type(tx() :: 'transaction' | 'none').
20   --type(serial() :: pos_integer() | tx()).
21   -
22   --spec(description/0 :: () -> [{atom(), any()}]).
23   --spec(serialise_events/0 :: () -> boolean()).
24   --spec(route/2 :: (rabbit_types:exchange(), rabbit_types:delivery())
25   - -> rabbit_router:match_result()).
26   --spec(validate/1 :: (rabbit_types:exchange()) -> 'ok').
27   --spec(create/2 :: (tx(), rabbit_types:exchange()) -> 'ok').
28   --spec(delete/3 :: (tx(), rabbit_types:exchange(),
29   - [rabbit_types:binding()]) -> 'ok').
30   --spec(add_binding/3 :: (serial(), rabbit_types:exchange(),
31   - rabbit_types:binding()) -> 'ok').
32   --spec(remove_bindings/3 :: (serial(), rabbit_types:exchange(),
33   - [rabbit_types:binding()]) -> 'ok').
34   --spec(assert_args_equivalence/2 ::
35   - (rabbit_types:exchange(), rabbit_framing:amqp_table())
36   - -> 'ok' | rabbit_types:connection_exit()).
37   -
38   --endif.
45 include/rabbit_msg_store_index.hrl
... ... @@ -1,45 +0,0 @@
1   -%% The contents of this file are subject to the Mozilla Public License
2   -%% Version 1.1 (the "License"); you may not use this file except in
3   -%% compliance with the License. You may obtain a copy of the License
4   -%% at http://www.mozilla.org/MPL/
5   -%%
6   -%% Software distributed under the License is distributed on an "AS IS"
7   -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
8   -%% the License for the specific language governing rights and
9   -%% limitations under the License.
10   -%%
11   -%% The Original Code is RabbitMQ.
12   -%%
13   -%% The Initial Developer of the Original Code is VMware, Inc.
14   -%% Copyright (c) 2007-2012 VMware, Inc. All rights reserved.
15   -%%
16   -
17   --include("rabbit_msg_store.hrl").
18   -
19   -%%----------------------------------------------------------------------------
20   -
21   --ifdef(use_specs).
22   -
23   --type(dir() :: any()).
24   --type(index_state() :: any()).
25   --type(keyvalue() :: any()).
26   --type(fieldpos() :: non_neg_integer()).
27   --type(fieldvalue() :: any()).
28   -
29   --spec(new/1 :: (dir()) -> index_state()).
30   --spec(recover/1 :: (dir()) -> rabbit_types:ok_or_error2(index_state(), any())).
31   --spec(lookup/2 ::
32   - (rabbit_types:msg_id(), index_state()) -> ('not_found' | keyvalue())).
33   --spec(insert/2 :: (keyvalue(), index_state()) -> 'ok').
34   --spec(update/2 :: (keyvalue(), index_state()) -> 'ok').
35   --spec(update_fields/3 :: (rabbit_types:msg_id(), ({fieldpos(), fieldvalue()} |
36   - [{fieldpos(), fieldvalue()}]),
37   - index_state()) -> 'ok').
38   --spec(delete/2 :: (rabbit_types:msg_id(), index_state()) -> 'ok').
39   --spec(delete_object/2 :: (keyvalue(), index_state()) -> 'ok').
40   --spec(delete_by_file/2 :: (fieldvalue(), index_state()) -> 'ok').
41   --spec(terminate/1 :: (index_state()) -> any()).
42   -
43   --endif.
44   -
45   -%%----------------------------------------------------------------------------
65 src/gen_server2.erl
@@ -31,13 +31,13 @@
31 31 %% handle_pre_hibernate/1 then the default action is to hibernate.
32 32 %%
33 33 %% 6) init can return a 4th arg, {backoff, InitialTimeout,
34   -%% MinimumTimeout, DesiredHibernatePeriod} (all in
35   -%% milliseconds). Then, on all callbacks which can return a timeout
36   -%% (including init), timeout can be 'hibernate'. When this is the
37   -%% case, the current timeout value will be used (initially, the
38   -%% InitialTimeout supplied from init). After this timeout has
39   -%% occurred, hibernation will occur as normal. Upon awaking, a new
40   -%% current timeout value will be calculated.
  34 +%% MinimumTimeout, DesiredHibernatePeriod} (all in milliseconds,
  35 +%% 'infinity' does not make sense here). Then, on all callbacks which
  36 +%% can return a timeout (including init), timeout can be
  37 +%% 'hibernate'. When this is the case, the current timeout value will
  38 +%% be used (initially, the InitialTimeout supplied from init). After
  39 +%% this timeout has occurred, hibernation will occur as normal. Upon
  40 +%% awaking, a new current timeout value will be calculated.
41 41 %%
42 42 %% The purpose is that the gen_server2 takes care of adjusting the
43 43 %% current timeout value such that the process will increase the
@@ -135,9 +135,10 @@
135 135 %%% Reason = normal | shutdown | Term, terminate(State) is called
136 136 %%%
137 137 %%% terminate(Reason, State) Let the user module clean up
  138 +%%% Reason = normal | shutdown | {shutdown, Term} | Term
138 139 %%% always called when server terminates
139 140 %%%
140   -%%% ==> ok
  141 +%%% ==> ok | Term
141 142 %%%
142 143 %%% handle_pre_hibernate(State)
143 144 %%%
@@ -182,8 +183,6 @@
182 183 multi_call/2, multi_call/3, multi_call/4,
183 184 enter_loop/3, enter_loop/4, enter_loop/5, enter_loop/6, wake_hib/1]).
184 185
185   --export([behaviour_info/1]).
186   -
187 186 %% System exports
188 187 -export([system_continue/3,
189 188 system_terminate/4,
@@ -200,12 +199,12 @@
200 199 timeout_state, queue, debug, prioritise_call,
201 200 prioritise_cast, prioritise_info}).
202 201
  202 +-ifdef(use_specs).
  203 +
203 204 %%%=========================================================================
204 205 %%% Specs. These exist only to shut up dialyzer's warnings
205 206 %%%=========================================================================
206 207
207   --ifdef(use_specs).
208   -
209 208 -type(gs2_state() :: #gs2_state{}).
210 209
211 210 -spec(handle_common_termination/3 ::
@@ -214,18 +213,58 @@
214 213 -spec(pre_hibernate/1 :: (gs2_state()) -> no_return()).
215 214 -spec(system_terminate/4 :: (_, _, _, gs2_state()) -> no_return()).
216 215
217   --endif.
  216 +-type(millis() :: non_neg_integer()).
218 217
219 218 %%%=========================================================================
220 219 %%% API
221 220 %%%=========================================================================
222 221
  222 +-callback init(Args :: term()) ->
  223 + {ok, State :: term()} |
  224 + {ok, State :: term(), timeout() | hibernate} |
  225 + {ok, State :: term(), timeout() | hibernate,
  226 + {backoff, millis(), millis(), millis()}} |
  227 + ignore |
  228 + {stop, Reason :: term()}.
  229 +-callback handle_call(Request :: term(), From :: {pid(), Tag :: term()},
  230 + State :: term()) ->
  231 + {reply, Reply :: term(), NewState :: term()} |
  232 + {reply, Reply :: term(), NewState :: term(), timeout() | hibernate} |
  233 + {noreply, NewState :: term()} |
  234 + {noreply, NewState :: term(), timeout() | hibernate} |
  235 + {stop, Reason :: term(),
  236 + Reply :: term(), NewState :: term()}.
  237 +-callback handle_cast(Request :: term(), State :: term()) ->
  238 + {noreply, NewState :: term()} |
  239 + {noreply, NewState :: term(), timeout() | hibernate} |
  240 + {stop, Reason :: term(), NewState :: term()}.
  241 +-callback handle_info(Info :: term(), State :: term()) ->
  242 + {noreply, NewState :: term()} |
  243 + {noreply, NewState :: term(), timeout() | hibernate} |
  244 + {stop, Reason :: term(), NewState :: term()}.
  245 +-callback terminate(Reason :: (normal | shutdown | {shutdown, term()} | term()),
  246 + State :: term()) ->
  247 + ok | term().
  248 +-callback code_change(OldVsn :: (term() | {down, term()}), State :: term(),
  249 + Extra :: term()) ->
  250 + {ok, NewState :: term()} | {error, Reason :: term()}.
  251 +
  252 +%% It's not possible to define "optional" -callbacks, so putting specs
  253 +%% for handle_pre_hibernate/1 and handle_post_hibernate/1 will result
  254 +%% in warnings (the same applied for the behaviour_info before).
  255 +
  256 +-else.
  257 +
  258 +-export([behaviour_info/1]).
  259 +
223 260 behaviour_info(callbacks) ->
224 261 [{init,1},{handle_call,3},{handle_cast,2},{handle_info,2},
225 262 {terminate,2},{code_change,3}];
226 263 behaviour_info(_Other) ->
227 264 undefined.
228 265
  266 +-endif.
  267 +
229 268 %%% -----------------------------------------------------------------
230 269 %%% Starts a generic server.
231 270 %%% start(Mod, Args, Options)
76 src/mirrored_supervisor.erl
@@ -120,8 +120,6 @@
120 120 delete_child/2, terminate_child/2,
121 121 which_children/1, count_children/1, check_childspecs/1]).
122 122
123   --export([behaviour_info/1]).
124   -
125 123 -behaviour(?GEN_SERVER).
126 124 -behaviour(?SUPERVISOR).
127 125
@@ -142,15 +140,20 @@
142 140
143 141 -ifdef(use_specs).
144 142
145   --type child() :: pid() | 'undefined'.
146   --type child_id() :: term().
147   --type modules() :: [module()] | 'dynamic'.
148   --type worker() :: 'worker' | 'supervisor'.
149   --type sup_name() :: {'local', Name :: atom()} | {'global', Name :: atom()}.
150   --type sup_ref() :: (Name :: atom())
151   - | {Name :: atom(), Node :: node()}
152   - | {'global', Name :: atom()}
153   - | pid().
  143 +%%--------------------------------------------------------------------------
  144 +%% Callback behaviour
  145 +%%--------------------------------------------------------------------------
  146 +
  147 +-callback init(Args :: term()) ->
  148 + {ok, {{RestartStrategy :: supervisor2:strategy(),
  149 + MaxR :: non_neg_integer(),
  150 + MaxT :: non_neg_integer()},
  151 + [ChildSpec :: supervisor2:child_spec()]}}
  152 + | ignore.
  153 +
  154 +%%--------------------------------------------------------------------------
  155 +%% Specs
  156 +%%--------------------------------------------------------------------------
154 157
155 158 -type startlink_err() :: {'already_started', pid()} | 'shutdown' | term().
156 159 -type startlink_ret() :: {'ok', pid()} | 'ignore' | {'error', startlink_err()}.
@@ -163,54 +166,26 @@
163 166 Args :: term().
164 167
165 168 -spec start_link(SupName, GroupName, Module, Args) -> startlink_ret() when
166   - SupName :: sup_name(),
  169 + SupName :: supervisor2:sup_name(),
167 170 GroupName :: group_name(),
168 171 Module :: module(),
169 172 Args :: term().
170 173
171   --spec start_child(SupRef, ChildSpec) -> supervisor:startchild_ret() when
172   - SupRef :: sup_ref(),
173   - ChildSpec :: supervisor:child_spec() | (List :: [term()]).
174   -
175   --spec restart_child(SupRef, Id) -> Result when
176   - SupRef :: sup_ref(),
177   - Id :: child_id(),
178   - Result :: {'ok', Child :: child()}
179   - | {'ok', Child :: child(), Info :: term()}
180   - | {'error', Error},
181   - Error :: 'running' | 'not_found' | 'simple_one_for_one' | term().
182   -
183   --spec delete_child(SupRef, Id) -> Result when
184   - SupRef :: sup_ref(),
185   - Id :: child_id(),
186   - Result :: 'ok' | {'error', Error},
187   - Error :: 'running' | 'not_found' | 'simple_one_for_one'.
188   -
189   --spec terminate_child(SupRef, Id) -> Result when
190   - SupRef :: sup_ref(),
191   - Id :: pid() | child_id(),
192   - Result :: 'ok' | {'error', Error},
193   - Error :: 'not_found' | 'simple_one_for_one'.
194   -
195   --spec which_children(SupRef) -> [{Id,Child,Type,Modules}] when
196   - SupRef :: sup_ref(),
197   - Id :: child_id() | 'undefined',
198   - Child :: child(),
199   - Type :: worker(),
200   - Modules :: modules().
201   -
202   --spec check_childspecs(ChildSpecs) -> Result when
203   - ChildSpecs :: [supervisor:child_spec()],
204   - Result :: 'ok' | {'error', Error :: term()}.
205   -
206 174 -spec start_internal(Group, ChildSpecs) -> Result when
207 175 Group :: group_name(),
208   - ChildSpecs :: [supervisor:child_spec()],
209   - Result :: startlink_ret().
  176 + ChildSpecs :: [supervisor2:child_spec()],
  177 + Result :: supervisor2:startlink_ret().
210 178
211 179 -spec create_tables() -> Result when
212 180 Result :: 'ok'.
213 181
  182 +-else.
  183 +
  184 +-export([behaviour_info/1]).
  185 +
  186 +behaviour_info(callbacks) -> [{init,1}];
  187 +behaviour_info(_Other) -> undefined.
  188 +
214 189 -endif.
215 190
216 191 %%----------------------------------------------------------------------------
@@ -250,9 +225,6 @@ which_children(Sup) -> fold(which_children, Sup, fun lists:append/2).
250 225 count_children(Sup) -> fold(count_children, Sup, fun add_proplists/2).
251 226 check_childspecs(Specs) -> ?SUPERVISOR:check_childspecs(Specs).
252 227
253   -behaviour_info(callbacks) -> [{init,1}];
254   -behaviour_info(_Other) -> undefined.
255   -
256 228 call(Sup, Msg) ->
257 229 ?GEN_SERVER:call(child(Sup, mirroring), Msg, infinity).
258 230
64 src/pmon.erl
... ... @@ -0,0 +1,64 @@
  1 +%% The contents of this file are subject to the Mozilla Public License
  2 +%% Version 1.1 (the "License"); you may not use this file except in
  3 +%% compliance with the License. You may obtain a copy of the License
  4 +%% at http://www.mozilla.org/MPL/
  5 +%%
  6 +%% Software distributed under the License is distributed on an "AS IS"
  7 +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  8 +%% the License for the specific language governing rights and
  9 +%% limitations under the License.
  10 +%%
  11 +%% The Original Code is RabbitMQ.
  12 +%%
  13 +%% The Initial Developer of the Original Code is VMware, Inc.
  14 +%% Copyright (c) 2011-2012 VMware, Inc. All rights reserved.
  15 +%%
  16 +
  17 +-module(pmon).
  18 +
  19 +-export([new/0, monitor/2, monitor_all/2, demonitor/2, is_monitored/2, erase/2,
  20 + monitored/1, is_empty/1]).
  21 +
  22 +-ifdef(use_specs).
  23 +
  24 +%%----------------------------------------------------------------------------
  25 +
  26 +-export_type([?MODULE/0]).
  27 +
  28 +-opaque(?MODULE() :: dict()).
  29 +
  30 +-spec(new/0 :: () -> ?MODULE()).
  31 +-spec(monitor/2 :: (pid(), ?MODULE()) -> ?MODULE()).
  32 +-spec(monitor_all/2 :: ([pid()], ?MODULE()) -> ?MODULE()).
  33 +-spec(demonitor/2 :: (pid(), ?MODULE()) -> ?MODULE()).
  34 +-spec(is_monitored/2 :: (pid(), ?MODULE()) -> boolean()).
  35 +-spec(erase/2 :: (pid(), ?MODULE()) -> ?MODULE()).
  36 +-spec(monitored/1 :: (?MODULE()) -> [pid()]).
  37 +-spec(is_empty/1 :: (?MODULE()) -> boolean()).
  38 +
  39 +-endif.
  40 +
  41 +new() -> dict:new().
  42 +
  43 +monitor(Pid, M) ->
  44 + case dict:is_key(Pid, M) of
  45 + true -> M;
  46 + false -> dict:store(Pid, erlang:monitor(process, Pid), M)
  47 + end.
  48 +
  49 +monitor_all(Pids, M) -> lists:foldl(fun monitor/2, M, Pids).
  50 +
  51 +demonitor(Pid, M) ->
  52 + case dict:find(Pid, M) of
  53 + {ok, MRef} -> erlang:demonitor(MRef),
  54 + dict:erase(Pid, M);
  55 + error -> M
  56 + end.
  57 +
  58 +is_monitored(Pid, M) -> dict:is_key(Pid, M).
  59 +
  60 +erase(Pid, M) -> dict:erase(Pid, M).
  61 +
  62 +monitored(M) -> dict:fetch_keys(M).
  63 +
  64 +is_empty(M) -> dict:size(M) == 0.
132 src/rabbit_amqqueue.erl
@@ -32,7 +32,7 @@
32 32
33 33
34 34 %% internal
35   --export([internal_declare/2, internal_delete/1, run_backing_queue/3,
  35 +-export([internal_declare/2, internal_delete/2, run_backing_queue/3,
36 36 set_ram_duration_target/2, set_maximum_since_use/2]).
37 37
38 38 -include("rabbit.hrl").
@@ -109,7 +109,7 @@
109 109 -spec(stat/1 ::
110 110 (rabbit_types:amqqueue())
111 111 -> {'ok', non_neg_integer(), non_neg_integer()}).
112   --spec(delete_immediately/1 :: (rabbit_types:amqqueue()) -> 'ok').
  112 +-spec(delete_immediately/1 :: (qpids()) -> 'ok').
113 113 -spec(delete/3 ::
114 114 (rabbit_types:amqqueue(), 'false', 'false')
115 115 -> qlen();
@@ -144,11 +144,11 @@
144 144 -spec(notify_sent_queue_down/1 :: (pid()) -> 'ok').
145 145 -spec(unblock/2 :: (pid(), pid()) -> 'ok').
146 146 -spec(flush_all/2 :: (qpids(), pid()) -> 'ok').
147   --spec(internal_delete/1 ::
148   - (name()) -> rabbit_types:ok_or_error('not_found') |
149   - rabbit_types:connection_exit() |
150   - fun (() -> rabbit_types:ok_or_error('not_found') |
151   - rabbit_types:connection_exit())).
  147 +-spec(internal_delete/2 ::
  148 + (name(), pid()) -> rabbit_types:ok_or_error('not_found') |
  149 + rabbit_types:connection_exit() |
  150 + fun (() -> rabbit_types:ok_or_error('not_found') |
  151 + rabbit_types:connection_exit())).
152 152 -spec(run_backing_queue/3 ::
153 153 (pid(), atom(),
154 154 (fun ((atom(), A) -> {[rabbit_types:msg_id()], A}))) -> 'ok').
@@ -231,7 +231,7 @@ internal_declare(Q = #amqqueue{name = QueueName}, false) ->
231 231 [ExistingQ = #amqqueue{pid = QPid}] ->
232 232 case rabbit_misc:is_process_alive(QPid) of
233 233 true -> rabbit_misc:const(ExistingQ);
234   - false -> TailFun = internal_delete(QueueName),
  234 + false -> TailFun = internal_delete(QueueName, QPid),
235 235 fun () -> TailFun(), ExistingQ end
236 236 end
237 237 end
@@ -330,54 +330,60 @@ assert_args_equivalence(#amqqueue{name = QueueName, arguments = Args},
330 330 [<<"x-expires">>, <<"x-message-ttl">>, <<"x-ha-policy">>]).
331 331
332 332 check_declare_arguments(QueueName, Args) ->
333   - [case Fun(rabbit_misc:table_lookup(Args, Key), Args) of
334   - ok -> ok;
335   - {error, Error} -> rabbit_misc:protocol_error(
336   - precondition_failed,
337   - "invalid arg '~s' for ~s: ~255p",
338   - [Key, rabbit_misc:rs(QueueName), Error])
339   - end ||
340   - {Key, Fun} <-
341   - [{<<"x-expires">>, fun check_integer_argument/2},
342   - {<<"x-message-ttl">>, fun check_integer_argument/2},
343   - {<<"x-ha-policy">>, fun check_ha_policy_argument/2},
344   - {<<"x-dead-letter-exchange">>, fun check_string_argument/2},
345   - {<<"x-dead-letter-routing-key">>,
346   - fun check_dlxrk_argument/2}]],
  333 + Checks = [{<<"x-expires">>, fun check_positive_int_arg/2},
  334 + {<<"x-message-ttl">>, fun check_non_neg_int_arg/2},
  335 + {<<"x-ha-policy">>, fun check_ha_policy_arg/2},
  336 + {<<"x-dead-letter-exchange">>, fun check_string_arg/2},
  337 + {<<"x-dead-letter-routing-key">>, fun check_dlxrk_arg/2}],
  338 + [case rabbit_misc:table_lookup(Args, Key) of
  339 + undefined -> ok;
  340 + TypeVal -> case Fun(TypeVal, Args) of
  341 + ok -> ok;
  342 + {error, Error} -> rabbit_misc:protocol_error(
  343 + precondition_failed,
  344 + "invalid arg '~s' for ~s: ~255p",
  345 + [Key, rabbit_misc:rs(QueueName),
  346 + Error])
  347 + end
  348 + end || {Key, Fun} <- Checks],
347 349 ok.
348 350
349   -check_string_argument(undefined, _Args) ->
350   - ok;
351   -check_string_argument({longstr, _}, _Args) ->
  351 +check_string_arg({longstr, _}, _Args) ->
352 352 ok;
353   -check_string_argument({Type, _}, _) ->
  353 +check_string_arg({Type, _}, _) ->
354 354 {error, {unacceptable_type, Type}}.
355 355
356   -check_integer_argument(undefined, _Args) ->
357   - ok;
358   -check_integer_argument({Type, Val}, _Args) when Val > 0 ->
  356 +check_int_arg({Type, _}, _) ->
359 357 case lists:member(Type, ?INTEGER_ARG_TYPES) of
360 358 true -> ok;
361 359 false -> {error, {unacceptable_type, Type}}
362   - end;
363   -check_integer_argument({_Type, Val}, _Args) ->
364   - {error, {value_zero_or_less, Val}}.
  360 + end.
365 361
366   -check_dlxrk_argument(undefined, _Args) ->
367   - ok;
368   -check_dlxrk_argument({longstr, _}, Args) ->
  362 +check_positive_int_arg({Type, Val}, Args) ->
  363 + case check_int_arg({Type, Val}, Args) of
  364 + ok when Val > 0 -> ok;
  365 + ok -> {error, {value_zero_or_less, Val}};
  366 + Error -> Error
  367 + end.
  368 +
  369 +check_non_neg_int_arg({Type, Val}, Args) ->
  370 + case check_int_arg({Type, Val}, Args) of
  371 + ok when Val >= 0 -> ok;
  372 + ok -> {error, {value_less_than_zero, Val}};
  373 + Error -> Error
  374 + end.
  375 +
  376 +check_dlxrk_arg({longstr, _}, Args) ->
369 377 case rabbit_misc:table_lookup(Args, <<"x-dead-letter-exchange">>) of
370 378 undefined -> {error, routing_key_but_no_dlx_defined};
371 379 _ -> ok
372 380 end;
373   -check_dlxrk_argument({Type, _}, _Args) ->
  381 +check_dlxrk_arg({Type, _}, _Args) ->
374 382 {error, {unacceptable_type, Type}}.
375 383
376   -check_ha_policy_argument(undefined, _Args) ->
377   - ok;
378   -check_ha_policy_argument({longstr, <<"all">>}, _Args) ->
  384 +check_ha_policy_arg({longstr, <<"all">>}, _Args) ->
379 385 ok;
380   -check_ha_policy_argument({longstr, <<"nodes">>}, Args) ->
  386 +check_ha_policy_arg({longstr, <<"nodes">>}, Args) ->
381 387 case rabbit_misc:table_lookup(Args, <<"x-ha-policy-params">>) of
382 388 undefined ->
383 389 {error, {require, 'x-ha-policy-params'}};
@@ -393,9 +399,9 @@ check_ha_policy_argument({longstr, <<"nodes">>}, Args) ->
393 399 {Type, _} ->
394 400 {error, {ha_nodes_policy_params_not_array_of_longstr, Type}}
395 401 end;
396   -check_ha_policy_argument({longstr, Policy}, _Args) ->
  402 +check_ha_policy_arg({longstr, Policy}, _Args) ->
397 403 {error, {invalid_ha_policy, Policy}};
398   -check_ha_policy_argument({Type, _}, _Args) ->
  404 +check_ha_policy_arg({Type, _}, _Args) ->
399 405 {error, {unacceptable_type, Type}}.
400 406
401 407 list() ->
@@ -462,8 +468,9 @@ consumers_all(VHostPath) ->
462 468 stat(#amqqueue{pid = QPid}) ->
463 469 delegate_call(QPid, stat).
464 470
465   -delete_immediately(#amqqueue{ pid = QPid }) ->
466   - gen_server2:cast(QPid, delete_immediately).
  471 +delete_immediately(QPids) ->
  472 + [gen_server2:cast(QPid, delete_immediately) || QPid <- QPids],
  473 + ok.
467 474
468 475 delete(#amqqueue{ pid = QPid }, IfUnused, IfEmpty) ->
469 476 delegate_call(QPid, {delete, IfUnused, IfEmpty}).
@@ -534,13 +541,19 @@ internal_delete1(QueueName) ->
534 541 %% after the transaction.
535 542 rabbit_binding:remove_for_destination(QueueName).
536 543
537   -internal_delete(QueueName) ->
  544 +internal_delete(QueueName, QPid) ->
538 545 rabbit_misc:execute_mnesia_tx_with_tail(
539 546 fun () ->
540 547 case mnesia:wread({rabbit_queue, QueueName}) of
541 548 [] -> rabbit_misc:const({error, not_found});
542 549 [_] -> Deletions = internal_delete1(QueueName),
543   - rabbit_binding:process_deletions(Deletions)
  550 + T = rabbit_binding:process_deletions(Deletions),
  551 + fun() ->
  552 + ok = T(),
  553 + ok = rabbit_event:notify(queue_deleted,
  554 + [{pid, QPid},
  555 + {name, QueueName}])
  556 + end
544 557 end
545 558 end).
546 559
@@ -555,14 +568,25 @@ set_maximum_since_use(QPid, Age) ->
555 568
556 569 on_node_down(Node) ->
557 570 rabbit_misc:execute_mnesia_tx_with_tail(
558   - fun () -> Dels = qlc:e(qlc:q([delete_queue(QueueName) ||
559   - #amqqueue{name = QueueName, pid = Pid,
560   - slave_pids = []}
561   - <- mnesia:table(rabbit_queue),
562   - node(Pid) == Node])),
563   - rabbit_binding:process_deletions(
564   - lists:foldl(fun rabbit_binding:combine_deletions/2,
565   - rabbit_binding:new_deletions(), Dels))
  571 + fun () -> QsDels =
  572 + qlc:e(qlc:q([{{QName, Pid}, delete_queue(QName)} ||
  573 + #amqqueue{name = QName, pid = Pid,
  574 + slave_pids = []}
  575 + <- mnesia:table(rabbit_queue),
  576 + node(Pid) == Node])),
  577 + {Qs, Dels} = lists:unzip(QsDels),
  578 + T = rabbit_binding:process_deletions(
  579 + lists:foldl(fun rabbit_binding:combine_deletions/2,
  580 + rabbit_binding:new_deletions(), Dels)),
  581 + fun () ->
  582 + T(),
  583 + lists:foreach(
  584 + fun({QName, QPid}) ->
  585 + ok = rabbit_event:notify(queue_deleted,
  586 + [{pid, QPid},
  587 + {name, QName}])
  588 + end, Qs)
  589 + end
566 590 end).
567 591
568 592 delete_queue(QueueName) ->
83 src/rabbit_auth_backend.erl
@@ -16,42 +16,57 @@
16 16
17 17 -module(rabbit_auth_backend).
18 18
  19 +-ifdef(use_specs).
  20 +
  21 +%% A description proplist as with auth mechanisms,
  22 +%% exchanges. Currently unused.
  23 +-callback description() -> [proplist:property()].
  24 +
  25 +%% Check a user can log in, given a username and a proplist of
  26 +%% authentication information (e.g. [{password, Password}]).
  27 +%%
  28 +%% Possible responses:
  29 +%% {ok, User}
  30 +%% Authentication succeeded, and here's the user record.
  31 +%% {error, Error}
  32 +%% Something went wrong. Log and die.
  33 +%% {refused, Msg, Args}
  34 +%% Client failed authentication. Log and die.
  35 +-callback check_user_login(rabbit_types:username(), [term()]) ->
  36 + {'ok', rabbit_types:user()} |
  37 + {'refused', string(), [any()]} |
  38 + {'error', any()}.
  39 +
  40 +%% Given #user and vhost, can a user log in to a vhost?
  41 +%% Possible responses:
  42 +%% true
  43 +%% false
  44 +%% {error, Error}
  45 +%% Something went wrong. Log and die.
  46 +-callback check_vhost_access(rabbit_types:user(), rabbit_types:vhost()) ->
  47 + boolean() | {'error', any()}.
  48 +
  49 +
  50 +%% Given #user, resource and permission, can a user access a resource?
  51 +%%
  52 +%% Possible responses:
  53 +%% true
  54 +%% false
  55 +%% {error, Error}
  56 +%% Something went wrong. Log and die.
  57 +-callback check_resource_access(rabbit_types:user(),
  58 + rabbit_types:r(atom()),
  59 + rabbit_access_control:permission_atom()) ->
  60 + boolean() | {'error', any()}.
  61 +
  62 +-else.
  63 +
19 64 -export([behaviour_info/1]).
20 65
21 66 behaviour_info(callbacks) ->
22   - [
23   - %% A description proplist as with auth mechanisms,
24   - %% exchanges. Currently unused.
25   - {description, 0},
26   -
27   - %% Check a user can log in, given a username and a proplist of
28   - %% authentication information (e.g. [{password, Password}]).
29   - %%
30   - %% Possible responses:
31   - %% {ok, User}
32   - %% Authentication succeeded, and here's the user record.
33   - %% {error, Error}
34   - %% Something went wrong. Log and die.
35   - %% {refused, Msg, Args}
36   - %% Client failed authentication. Log and die.
37   - {check_user_login, 2},
38   -
39   - %% Given #user and vhost, can a user log in to a vhost?
40   - %% Possible responses:
41   - %% true
42   - %% false
43   - %% {error, Error}
44   - %% Something went wrong. Log and die.
45   - {check_vhost_access, 2},
46   -
47   - %% Given #user, resource and permission, can a user access a resource?
48   - %%
49   - %% Possible responses:
50   - %% true
51   - %% false
52   - %% {error, Error}
53   - %% Something went wrong. Log and die.
54   - {check_resource_access, 3}
55   - ];
  67 + [{description, 0}, {check_user_login, 2}, {check_vhost_access, 2},
  68 + {check_resource_access, 3}];
56 69 behaviour_info(_Other) ->
57 70 undefined.
  71 +
  72 +-endif.
56 src/rabbit_auth_mechanism.erl
@@ -16,31 +16,41 @@
16 16
17 17 -module(rabbit_auth_mechanism).
18 18
  19 +-ifdef(use_specs).
  20 +
  21 +%% A description.
  22 +-callback description() -> [proplist:property()].
  23 +
  24 +%% If this mechanism is enabled, should it be offered for a given socket?
  25 +%% (primarily so EXTERNAL can be SSL-only)
  26 +-callback should_offer(rabbit_net:socket()) -> boolean().
  27 +
  28 +%% Called before authentication starts. Should create a state
  29 +%% object to be passed through all the stages of authentication.
  30 +-callback init(rabbit_net:socket()) -> any().
  31 +
  32 +%% Handle a stage of authentication. Possible responses:
  33 +%% {ok, User}
  34 +%% Authentication succeeded, and here's the user record.
  35 +%% {challenge, Challenge, NextState}
  36 +%% Another round is needed. Here's the state I want next time.
  37 +%% {protocol_error, Msg, Args}
  38 +%% Client got the protocol wrong. Log and die.
  39 +%% {refused, Msg, Args}
  40 +%% Client failed authentication. Log and die.
  41 +-callback handle_response(binary(), any()) ->
  42 + {'ok', rabbit_types:user()} |
  43 + {'challenge', binary(), any()} |
  44 + {'protocol_error', string(), [any()]} |
  45 + {'refused', string(), [any()]}.
  46 +
  47 +-else.
  48 +
19 49 -export([behaviour_info/1]).
20 50
21 51 behaviour_info(callbacks) ->
22   - [
23   - %% A description.
24   - {description, 0},
25   -
26   - %% If this mechanism is enabled, should it be offered for a given socket?
27   - %% (primarily so EXTERNAL can be SSL-only)
28   - {should_offer, 1},
29   -
30   - %% Called before authentication starts. Should create a state
31   - %% object to be passed through all the stages of authentication.
32   - {init, 1},
33   -
34   - %% Handle a stage of authentication. Possible responses:
35   - %% {ok, User}
36   - %% Authentication succeeded, and here's the user record.
37   - %% {challenge, Challenge, NextState}
38   - %% Another round is needed. Here's the state I want next time.
39   - %% {protocol_error, Msg, Args}
40   - %% Client got the protocol wrong. Log and die.
41   - %% {refused, Msg, Args}
42   - %% Client failed authentication. Log and die.
43   - {handle_response, 2}
44   - ];
  52 + [{description, 0}, {should_offer, 1}, {init, 1}, {handle_response, 2}];
45 53 behaviour_info(_Other) ->
46 54 undefined.
  55 +
  56 +-endif.
351 src/rabbit_backing_queue.erl
@@ -16,164 +16,203 @@
16 16
17 17 -module(rabbit_backing_queue).
18 18
  19 +-ifdef(use_specs).
  20 +
  21 +%% We can't specify a per-queue ack/state with callback signatures
  22 +-type(ack() :: any()).
  23 +-type(state() :: any()).
  24 +
  25 +-type(fetch_result(Ack) ::
  26 + ('empty' |
  27 + %% Message, IsDelivered, AckTag, Remaining_Len
  28 + {rabbit_types:basic_message(), boolean(), Ack, non_neg_integer()})).
  29 +-type(is_durable() :: boolean()).
  30 +-type(attempt_recovery() :: boolean()).
  31 +-type(purged_msg_count() :: non_neg_integer()).
  32 +-type(confirm_required() :: boolean()).
  33 +-type(async_callback() :: fun ((atom(), fun ((atom(), state()) -> state())) -> 'ok')).
  34 +-type(duration() :: ('undefined' | 'infinity' | number())).
  35 +
  36 +-type(msg_fun() :: fun((rabbit_types:basic_message(), ack()) -> 'ok') |
  37 + 'undefined').
  38 +-type(msg_pred() :: fun ((rabbit_types:message_properties()) -> boolean())).
  39 +
  40 +%% Called on startup with a list of durable queue names. The queues
  41 +%% aren't being started at this point, but this call allows the
  42 +%% backing queue to perform any checking necessary for the consistency
  43 +%% of those queues, or initialise any other shared resources.
  44 +-callback start([rabbit_amqqueue:name()]) -> 'ok'.
  45 +
  46 +%% Called to tear down any state/resources. NB: Implementations should
  47 +%% not depend on this function being called on shutdown and instead
  48 +%% should hook into the rabbit supervision hierarchy.
  49 +-callback stop() -> 'ok'.
  50 +
  51 +%% Initialise the backing queue and its state.
  52 +%%
  53 +%% Takes
  54 +%% 1. the amqqueue record
  55 +%% 2. a boolean indicating whether the queue is an existing queue that
  56 +%% should be recovered
  57 +%% 3. an asynchronous callback which accepts a function of type
  58 +%% backing-queue-state to backing-queue-state. This callback
  59 +%% function can be safely invoked from any process, which makes it
  60 +%% useful for passing messages back into the backing queue,
  61 +%% especially as the backing queue does not have control of its own
  62 +%% mailbox.
  63 +-callback init(rabbit_types:amqqueue(), attempt_recovery(),
  64 + async_callback()) -> state().
  65 +
  66 +%% Called on queue shutdown when queue isn't being deleted.
  67 +-callback terminate(any(), state()) -> state().
  68 +
  69 +%% Called when the queue is terminating and needs to delete all its
  70 +%% content.
  71 +-callback delete_and_terminate(any(), state()) -> state().
  72 +
  73 +%% Remove all messages in the queue, but not messages which have been
  74 +%% fetched and are pending acks.
  75 +-callback purge(state()) -> {purged_msg_count(), state()}.
  76 +
  77 +%% Publish a message.
  78 +-callback publish(rabbit_types:basic_message(),
  79 + rabbit_types:message_properties(), pid(), state()) ->
  80 + state().
  81 +
  82 +%% Called for messages which have already been passed straight
  83 +%% out to a client. The queue will be empty for these calls
  84 +%% (i.e. saves the round trip through the backing queue).
  85 +-callback publish_delivered(true, rabbit_types:basic_message(),
  86 + rabbit_types:message_properties(), pid(), state())
  87 + -> {ack(), state()};
  88 + (false, rabbit_types:basic_message(),
  89 + rabbit_types:message_properties(), pid(), state())
  90 + -> {undefined, state()}.
  91 +
  92 +%% Return ids of messages which have been confirmed since the last
  93 +%% invocation of this function (or initialisation).
  94 +%%
  95 +%% Message ids should only appear in the result of drain_confirmed
  96 +%% under the following circumstances:
  97 +%%
  98 +%% 1. The message appears in a call to publish_delivered/4 and the
  99 +%% first argument (ack_required) is false; or
  100 +%% 2. The message is fetched from the queue with fetch/2 and the first
  101 +%% argument (ack_required) is false; or
  102 +%% 3. The message is acked (ack/2 is called for the message); or
  103 +%% 4. The message is fully fsync'd to disk in such a way that the
  104 +%% recovery of the message is guaranteed in the event of a crash of
  105 +%% this rabbit node (excluding hardware failure).
  106 +%%
  107 +%% In addition to the above conditions, a message id may only appear
  108 +%% in the result of drain_confirmed if
  109 +%% #message_properties.needs_confirming = true when the msg was
  110 +%% published (through whichever means) to the backing queue.
  111 +%%
  112 +%% It is legal for the same message id to appear in the results of
  113 +%% multiple calls to drain_confirmed, which means that the backing
  114 +%% queue is not required to keep track of which messages it has
  115 +%% already confirmed. The confirm will be issued to the publisher the
  116 +%% first time the message id appears in the result of
  117 +%% drain_confirmed. All subsequent appearances of that message id will
  118 +%% be ignored.
  119 +-callback drain_confirmed(state()) -> {[rabbit_guid:guid()], state()}.
  120 +
  121 +%% Drop messages from the head of the queue while the supplied predicate returns
  122 +%% true. Also accepts a boolean parameter that determines whether the messages
  123 +%% necessitate an ack or not. If they do, the function returns a list of
  124 +%% messages with the respective acktags.
  125 +-callback dropwhile(msg_pred(), true, state())
  126 + -> {[{rabbit_types:basic_message(), ack()}], state()};
  127 + (msg_pred(), false, state())
  128 + -> {undefined, state()}.
  129 +
  130 +%% Produce the next message.
  131 +-callback fetch(true, state()) -> {fetch_result(ack()), state()};
  132 + (false, state()) -> {fetch_result(undefined), state()}.
  133 +
  134 +%% Acktags supplied are for messages which can now be forgotten
  135 +%% about. Must return 1 msg_id per Ack, in the same order as Acks.
  136 +-callback ack([ack()], state()) -> {[rabbit_guid:guid()], state()}.
  137 +
  138 +%% Acktags supplied are for messages which should be processed. The
  139 +%% provided callback function is called with each message.
  140 +-callback fold(msg_fun(), state(), [ack()]) -> state().
  141 +
  142 +%% Reinsert messages into the queue which have already been delivered
  143 +%% and were pending acknowledgement.
  144 +-callback requeue([ack()], state()) -> {[rabbit_guid:guid()], state()}.
  145 +
  146 +%% How long is my queue?
  147 +-callback len(state()) -> non_neg_integer().
  148 +
  149 +%% Is my queue empty?
  150 +-callback is_empty(state()) -> boolean().
  151 +
  152 +%% For the next three functions, the assumption is that you're
  153 +%% monitoring something like the ingress and egress rates of the
  154 +%% queue. The RAM duration is thus the length of time represented by
  155 +%% the messages held in RAM given the current rates. If you want to
  156 +%% ignore all of this stuff, then do so, and return 0 in
  157 +%% ram_duration/1.
  158 +
  159 +%% The target is to have no more messages in RAM than indicated by the
  160 +%% duration and the current queue rates.
  161 +-callback set_ram_duration_target(duration(), state()) -> state().
  162 +
  163 +%% Optionally recalculate the duration internally (likely to be just
  164 +%% update your internal rates), and report how many seconds the
  165 +%% messages in RAM represent given the current rates of the queue.
  166 +-callback ram_duration(state()) -> {duration(), state()}.
  167 +
  168 +%% Should 'timeout' be called as soon as the queue process can manage
  169 +%% (either on an empty mailbox, or when a timer fires)?
  170 +-callback needs_timeout(state()) -> 'false' | 'timed' | 'idle'.
  171 +
  172 +%% Called (eventually) after needs_timeout returns 'idle' or 'timed'.
  173 +%% Note this may be called more than once for each 'idle' or 'timed'
  174 +%% returned from needs_timeout
  175 +-callback timeout(state()) -> state().
  176 +
  177 +%% Called immediately before the queue hibernates.
  178 +-callback handle_pre_hibernate(state()) -> state().
  179 +
  180 +%% Exists for debugging purposes, to be able to expose state via
  181 +%% rabbitmqctl list_queues backing_queue_status
  182 +-callback status(state()) -> [{atom(), any()}].
  183 +
  184 +%% Passed a function to be invoked with the relevant backing queue's
  185 +%% state. Useful for when the backing queue or other components need
  186 +%% to pass functions into the backing queue.
  187 +-callback invoke(atom(), fun ((atom(), A) -> A), state()) -> state().
  188 +
  189 +%% Called prior to a publish or publish_delivered call. Allows the BQ
  190 +%% to signal that it's already seen this message (and in what capacity
  191 +%% - i.e. was it published previously or discarded previously) and
  192 +%% thus the message should be dropped.
  193 +-callback is_duplicate(rabbit_types:basic_message(), state())
  194 + -> {'false'|'published'|'discarded', state()}.
  195 +
  196 +%% Called to inform the BQ about messages which have reached the
  197 +%% queue, but are not going to be further passed to BQ for some
  198 +%% reason. Note that this is may be invoked for messages for which
  199 +%% BQ:is_duplicate/2 has already returned {'published' | 'discarded',
  200 +%% BQS}.
  201 +-callback discard(rabbit_types:basic_message(), pid(), state()) -> state().
  202 +
  203 +-else.
  204 +
19 205 -export([behaviour_info/1]).
20 206
21 207 behaviour_info(callbacks) ->
22   - [
23   - %% Called on startup with a list of durable queue names. The
24   - %% queues aren't being started at this point, but this call
25   - %% allows the backing queue to perform any checking necessary for
26   - %% the consistency of those queues, or initialise any other
27   - %% shared resources.
28   - {start, 1},
29   -
30   - %% Called to tear down any state/resources. NB: Implementations
31   - %% should not depend on this function being called on shutdown
32   - %% and instead should hook into the rabbit supervision hierarchy.
33   - {stop, 0},
34   -
35   - %% Initialise the backing queue and its state.
36   - %%
37   - %% Takes
38   - %% 1. the amqqueue record
39   - %% 2. a boolean indicating whether the queue is an existing queue
40   - %% that should be recovered
41   - %% 3. an asynchronous callback which accepts a function of type
42   - %% backing-queue-state to backing-queue-state. This callback
43   - %% function can be safely invoked from any process, which
44   - %% makes it useful for passing messages back into the backing
45   - %% queue, especially as the backing queue does not have
46   - %% control of its own mailbox.
47   - {init, 3},
48   -
49   - %% Called on queue shutdown when queue isn't being deleted.
50   - {terminate, 2},
51   -
52   - %% Called when the queue is terminating and needs to delete all
53   - %% its content.
54   - {delete_and_terminate, 2},
55   -
56   - %% Remove all messages in the queue, but not messages which have
57   - %% been fetched and are pending acks.
58   - {purge, 1},
59   -
60   - %% Publish a message.
61   - {publish, 4},
62   -
63   - %% Called for messages which have already been passed straight
64   - %% out to a client. The queue will be empty for these calls
65   - %% (i.e. saves the round trip through the backing queue).
66   - {publish_delivered, 5},
67   -
68   - %% Return ids of messages which have been confirmed since
69   - %% the last invocation of this function (or initialisation).
70   - %%
71   - %% Message ids should only appear in the result of
72   - %% drain_confirmed under the following circumstances:
73   - %%
74   - %% 1. The message appears in a call to publish_delivered/4 and
75   - %% the first argument (ack_required) is false; or
76   - %% 2. The message is fetched from the queue with fetch/2 and the
77   - %% first argument (ack_required) is false; or
78   - %% 3. The message is acked (ack/2 is called for the message); or
79   - %% 4. The message is fully fsync'd to disk in such a way that the
80   - %% recovery of the message is guaranteed in the event of a
81   - %% crash of this rabbit node (excluding hardware failure).
82   - %%
83   - %% In addition to the above conditions, a message id may only