summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSimon MacMullen <simon@rabbitmq.com>2012-04-17 12:32:11 +0100
committerSimon MacMullen <simon@rabbitmq.com>2012-04-17 12:32:11 +0100
commit690b4035e81a546cc20fe240fdb9192cf0f2175c (patch)
treefaaa1b4b793cb604e7077bc717dce9852ba6efdd /src
parent17e3aba9d96b99b8ec394fa10378f937e0a98da0 (diff)
parent44dfd96de05e3e1df655093502e0fe6f8e38dbfd (diff)
downloadrabbitmq-server-690b4035e81a546cc20fe240fdb9192cf0f2175c.tar.gz
Merge bug 24871 (as foretold in prophecy^W bug 20337 comment 199)
Diffstat (limited to 'src')
-rw-r--r--src/gen_server2.erl65
-rw-r--r--src/gm.erl103
-rw-r--r--src/mirrored_supervisor.erl76
-rw-r--r--src/rabbit_auth_backend.erl83
-rw-r--r--src/rabbit_auth_backend_internal.erl2
-rw-r--r--src/rabbit_auth_mechanism.erl56
-rw-r--r--src/rabbit_auth_mechanism_amqplain.erl2
-rw-r--r--src/rabbit_auth_mechanism_cr_demo.erl2
-rw-r--r--src/rabbit_auth_mechanism_plain.erl2
-rw-r--r--src/rabbit_backing_queue.erl348
-rw-r--r--src/rabbit_exchange_type.erl66
-rw-r--r--src/rabbit_exchange_type_direct.erl1
-rw-r--r--src/rabbit_exchange_type_fanout.erl1
-rw-r--r--src/rabbit_exchange_type_headers.erl1
-rw-r--r--src/rabbit_exchange_type_invalid.erl1
-rw-r--r--src/rabbit_exchange_type_topic.erl1
-rw-r--r--src/rabbit_mirror_queue_master.erl4
-rw-r--r--src/rabbit_msg_store_ets_index.erl4
-rw-r--r--src/rabbit_msg_store_index.erl27
-rw-r--r--src/rabbit_variable_queue.erl4
-rw-r--r--src/supervisor2.erl135
21 files changed, 611 insertions, 373 deletions
diff --git a/src/gen_server2.erl b/src/gen_server2.erl
index f8537487..78bbbe06 100644
--- a/src/gen_server2.erl
+++ b/src/gen_server2.erl
@@ -31,13 +31,13 @@
%% handle_pre_hibernate/1 then the default action is to hibernate.
%%
%% 6) init can return a 4th arg, {backoff, InitialTimeout,
-%% MinimumTimeout, DesiredHibernatePeriod} (all in
-%% milliseconds). Then, on all callbacks which can return a timeout
-%% (including init), timeout can be 'hibernate'. When this is the
-%% case, the current timeout value will be used (initially, the
-%% InitialTimeout supplied from init). After this timeout has
-%% occurred, hibernation will occur as normal. Upon awaking, a new
-%% current timeout value will be calculated.
+%% MinimumTimeout, DesiredHibernatePeriod} (all in milliseconds,
+%% 'infinity' does not make sense here). Then, on all callbacks which
+%% can return a timeout (including init), timeout can be
+%% 'hibernate'. When this is the case, the current timeout value will
+%% be used (initially, the InitialTimeout supplied from init). After
+%% this timeout has occurred, hibernation will occur as normal. Upon
+%% awaking, a new current timeout value will be calculated.
%%
%% The purpose is that the gen_server2 takes care of adjusting the
%% current timeout value such that the process will increase the
@@ -135,9 +135,10 @@
%%% Reason = normal | shutdown | Term, terminate(State) is called
%%%
%%% terminate(Reason, State) Let the user module clean up
+%%% Reason = normal | shutdown | {shutdown, Term} | Term
%%% always called when server terminates
%%%
-%%% ==> ok
+%%% ==> ok | Term
%%%
%%% handle_pre_hibernate(State)
%%%
@@ -182,8 +183,6 @@
multi_call/2, multi_call/3, multi_call/4,
enter_loop/3, enter_loop/4, enter_loop/5, enter_loop/6, wake_hib/1]).
--export([behaviour_info/1]).
-
%% System exports
-export([system_continue/3,
system_terminate/4,
@@ -200,12 +199,12 @@
timeout_state, queue, debug, prioritise_call,
prioritise_cast, prioritise_info}).
+-ifdef(use_specs).
+
%%%=========================================================================
%%% Specs. These exist only to shut up dialyzer's warnings
%%%=========================================================================
--ifdef(use_specs).
-
-type(gs2_state() :: #gs2_state{}).
-spec(handle_common_termination/3 ::
@@ -214,18 +213,58 @@
-spec(pre_hibernate/1 :: (gs2_state()) -> no_return()).
-spec(system_terminate/4 :: (_, _, _, gs2_state()) -> no_return()).
--endif.
+-type(millis() :: non_neg_integer()).
%%%=========================================================================
%%% API
%%%=========================================================================
+-callback init(Args :: term()) ->
+ {ok, State :: term()} |
+ {ok, State :: term(), timeout() | hibernate} |
+ {ok, State :: term(), timeout() | hibernate,
+ {backoff, millis(), millis(), millis()}} |
+ ignore |
+ {stop, Reason :: term()}.
+-callback handle_call(Request :: term(), From :: {pid(), Tag :: term()},
+ State :: term()) ->
+ {reply, Reply :: term(), NewState :: term()} |
+ {reply, Reply :: term(), NewState :: term(), timeout() | hibernate} |
+ {noreply, NewState :: term()} |
+ {noreply, NewState :: term(), timeout() | hibernate} |
+ {stop, Reason :: term(),
+ Reply :: term(), NewState :: term()}.
+-callback handle_cast(Request :: term(), State :: term()) ->
+ {noreply, NewState :: term()} |
+ {noreply, NewState :: term(), timeout() | hibernate} |
+ {stop, Reason :: term(), NewState :: term()}.
+-callback handle_info(Info :: term(), State :: term()) ->
+ {noreply, NewState :: term()} |
+ {noreply, NewState :: term(), timeout() | hibernate} |
+ {stop, Reason :: term(), NewState :: term()}.
+-callback terminate(Reason :: (normal | shutdown | {shutdown, term()} | term()),
+ State :: term()) ->
+ ok | term().
+-callback code_change(OldVsn :: (term() | {down, term()}), State :: term(),
+ Extra :: term()) ->
+ {ok, NewState :: term()} | {error, Reason :: term()}.
+
+%% It's not possible to define "optional" -callbacks, so putting specs
+%% for handle_pre_hibernate/1 and handle_post_hibernate/1 will result
+%% in warnings (the same applied for the behaviour_info before).
+
+-else.
+
+-export([behaviour_info/1]).
+
behaviour_info(callbacks) ->
[{init,1},{handle_call,3},{handle_cast,2},{handle_info,2},
{terminate,2},{code_change,3}];
behaviour_info(_Other) ->
undefined.
+-endif.
+
%%% -----------------------------------------------------------------
%%% Starts a generic server.
%%% start(Mod, Args, Options)
diff --git a/src/gm.erl b/src/gm.erl
index 6f9ff564..01300f18 100644
--- a/src/gm.erl
+++ b/src/gm.erl
@@ -57,8 +57,8 @@
%% you wish to be passed into the callback module's functions. The
%% joined/2 function will be called when we have joined the group,
%% with the arguments passed to start_link and a list of the current
-%% members of the group. See the comments in behaviour_info/1 below
-%% for further details of the callback functions.
+%% members of the group. See the callbacks specs and the comments
+%% below for further details of the callback functions.
%%
%% leave/1
%% Provide the Pid. Removes the Pid from the group. The callback
@@ -378,7 +378,9 @@
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
code_change/3, prioritise_info/2]).
+-ifndef(use_specs).
-export([behaviour_info/1]).
+-endif.
-export([table_definitions/0]).
@@ -431,56 +433,63 @@
-spec(confirmed_broadcast/2 :: (pid(), any()) -> 'ok').
-spec(group_members/1 :: (pid()) -> [pid()]).
--endif.
+%% The joined, members_changed and handle_msg callbacks can all
+%% return any of the following terms:
+%%
+%% 'ok' - the callback function returns normally
+%%
+%% {'stop', Reason} - the callback indicates the member should
+%% stop with reason Reason and should leave the group.
+%%
+%% {'become', Module, Args} - the callback indicates that the
+%% callback module should be changed to Module and that the
+%% callback functions should now be passed the arguments
+%% Args. This allows the callback module to be dynamically
+%% changed.
+
+%% Called when we've successfully joined the group. Supplied with
+%% Args provided in start_link, plus current group members.
+-callback joined(Args :: term(), Members :: [pid()]) ->
+ ok | {stop, Reason :: term()} | {become, Module :: atom(), Args :: any()}.
+
+%% Supplied with Args provided in start_link, the list of new
+%% members and the list of members previously known to us that
+%% have since died. Note that if a member joins and dies very
+%% quickly, it's possible that we will never see that member
+%% appear in either births or deaths. However we are guaranteed
+%% that (1) we will see a member joining either in the births
+%% here, or in the members passed to joined/2 before receiving
+%% any messages from it; and (2) we will not see members die that
+%% we have not seen born (or supplied in the members to
+%% joined/2).
+-callback members_changed(Args :: term(), Births :: [pid()],
+ Deaths :: [pid()]) ->
+ ok | {stop, Reason :: term()} | {become, Module :: atom(), Args :: any()}.
+
+%% Supplied with Args provided in start_link, the sender, and the
+%% message. This does get called for messages injected by this
+%% member, however, in such cases, there is no special
+%% significance of this invocation: it does not indicate that the
+%% message has made it to any other members, let alone all other
+%% members.
+-callback handle_msg(Args :: term(), From :: pid(), Message :: term()) ->
+ ok | {stop, Reason :: term()} | {become, Module :: atom(), Args :: any()}.
+
+%% Called on gm member termination as per rules in gen_server,
+%% with the Args provided in start_link plus the termination
+%% Reason.
+-callback terminate(Args :: term(), Reason :: term()) ->
+ ok | term().
+
+-else.
behaviour_info(callbacks) ->
- [
- %% The joined, members_changed and handle_msg callbacks can all
- %% return any of the following terms:
- %%
- %% 'ok' - the callback function returns normally
- %%
- %% {'stop', Reason} - the callback indicates the member should
- %% stop with reason Reason and should leave the group.
- %%
- %% {'become', Module, Args} - the callback indicates that the
- %% callback module should be changed to Module and that the
- %% callback functions should now be passed the arguments
- %% Args. This allows the callback module to be dynamically
- %% changed.
-
- %% Called when we've successfully joined the group. Supplied with
- %% Args provided in start_link, plus current group members.
- {joined, 2},
-
- %% Supplied with Args provided in start_link, the list of new
- %% members and the list of members previously known to us that
- %% have since died. Note that if a member joins and dies very
- %% quickly, it's possible that we will never see that member
- %% appear in either births or deaths. However we are guaranteed
- %% that (1) we will see a member joining either in the births
- %% here, or in the members passed to joined/2 before receiving
- %% any messages from it; and (2) we will not see members die that
- %% we have not seen born (or supplied in the members to
- %% joined/2).
- {members_changed, 3},
-
- %% Supplied with Args provided in start_link, the sender, and the
- %% message. This does get called for messages injected by this
- %% member, however, in such cases, there is no special
- %% significance of this invocation: it does not indicate that the
- %% message has made it to any other members, let alone all other
- %% members.
- {handle_msg, 3},
-
- %% Called on gm member termination as per rules in gen_server,
- %% with the Args provided in start_link plus the termination
- %% Reason.
- {terminate, 2}
- ];
+ [{joined, 2}, {members_changed, 3}, {handle_msg, 3}, {terminate, 2}];
behaviour_info(_Other) ->
undefined.
+-endif.
+
create_tables() ->
create_tables([?TABLE]).
diff --git a/src/mirrored_supervisor.erl b/src/mirrored_supervisor.erl
index a599effa..221f6a87 100644
--- a/src/mirrored_supervisor.erl
+++ b/src/mirrored_supervisor.erl
@@ -120,8 +120,6 @@
delete_child/2, terminate_child/2,
which_children/1, count_children/1, check_childspecs/1]).
--export([behaviour_info/1]).
-
-behaviour(?GEN_SERVER).
-behaviour(?SUPERVISOR).
@@ -142,15 +140,20 @@
-ifdef(use_specs).
--type child() :: pid() | 'undefined'.
--type child_id() :: term().
--type modules() :: [module()] | 'dynamic'.
--type worker() :: 'worker' | 'supervisor'.
--type sup_name() :: {'local', Name :: atom()} | {'global', Name :: atom()}.
--type sup_ref() :: (Name :: atom())
- | {Name :: atom(), Node :: node()}
- | {'global', Name :: atom()}
- | pid().
+%%--------------------------------------------------------------------------
+%% Callback behaviour
+%%--------------------------------------------------------------------------
+
+-callback init(Args :: term()) ->
+ {ok, {{RestartStrategy :: supervisor2:strategy(),
+ MaxR :: non_neg_integer(),
+ MaxT :: non_neg_integer()},
+ [ChildSpec :: supervisor2:child_spec()]}}
+ | ignore.
+
+%%--------------------------------------------------------------------------
+%% Specs
+%%--------------------------------------------------------------------------
-type startlink_err() :: {'already_started', pid()} | 'shutdown' | term().
-type startlink_ret() :: {'ok', pid()} | 'ignore' | {'error', startlink_err()}.
@@ -163,54 +166,26 @@
Args :: term().
-spec start_link(SupName, GroupName, Module, Args) -> startlink_ret() when
- SupName :: sup_name(),
+ SupName :: supervisor2:sup_name(),
GroupName :: group_name(),
Module :: module(),
Args :: term().
--spec start_child(SupRef, ChildSpec) -> supervisor:startchild_ret() when
- SupRef :: sup_ref(),
- ChildSpec :: supervisor:child_spec() | (List :: [term()]).
-
--spec restart_child(SupRef, Id) -> Result when
- SupRef :: sup_ref(),
- Id :: child_id(),
- Result :: {'ok', Child :: child()}
- | {'ok', Child :: child(), Info :: term()}
- | {'error', Error},
- Error :: 'running' | 'not_found' | 'simple_one_for_one' | term().
-
--spec delete_child(SupRef, Id) -> Result when
- SupRef :: sup_ref(),
- Id :: child_id(),
- Result :: 'ok' | {'error', Error},
- Error :: 'running' | 'not_found' | 'simple_one_for_one'.
-
--spec terminate_child(SupRef, Id) -> Result when
- SupRef :: sup_ref(),
- Id :: pid() | child_id(),
- Result :: 'ok' | {'error', Error},
- Error :: 'not_found' | 'simple_one_for_one'.
-
--spec which_children(SupRef) -> [{Id,Child,Type,Modules}] when
- SupRef :: sup_ref(),
- Id :: child_id() | 'undefined',
- Child :: child(),
- Type :: worker(),
- Modules :: modules().
-
--spec check_childspecs(ChildSpecs) -> Result when
- ChildSpecs :: [supervisor:child_spec()],
- Result :: 'ok' | {'error', Error :: term()}.
-
-spec start_internal(Group, ChildSpecs) -> Result when
Group :: group_name(),
- ChildSpecs :: [supervisor:child_spec()],
- Result :: startlink_ret().
+ ChildSpecs :: [supervisor2:child_spec()],
+ Result :: supervisor2:startlink_ret().
-spec create_tables() -> Result when
Result :: 'ok'.
+-else.
+
+-export([behaviour_info/1]).
+
+behaviour_info(callbacks) -> [{init,1}];
+behaviour_info(_Other) -> undefined.
+
-endif.
%%----------------------------------------------------------------------------
@@ -250,9 +225,6 @@ which_children(Sup) -> fold(which_children, Sup, fun lists:append/2).
count_children(Sup) -> fold(count_children, Sup, fun add_proplists/2).
check_childspecs(Specs) -> ?SUPERVISOR:check_childspecs(Specs).
-behaviour_info(callbacks) -> [{init,1}];
-behaviour_info(_Other) -> undefined.
-
call(Sup, Msg) ->
?GEN_SERVER:call(child(Sup, mirroring), Msg, infinity).
diff --git a/src/rabbit_auth_backend.erl b/src/rabbit_auth_backend.erl
index e0e252b8..e89951e7 100644
--- a/src/rabbit_auth_backend.erl
+++ b/src/rabbit_auth_backend.erl
@@ -16,42 +16,57 @@
-module(rabbit_auth_backend).
+-ifdef(use_specs).
+
+%% A description proplist as with auth mechanisms,
+%% exchanges. Currently unused.
+-callback description() -> [proplist:property()].
+
+%% Check a user can log in, given a username and a proplist of
+%% authentication information (e.g. [{password, Password}]).
+%%
+%% Possible responses:
+%% {ok, User}
+%% Authentication succeeded, and here's the user record.
+%% {error, Error}
+%% Something went wrong. Log and die.
+%% {refused, Msg, Args}
+%% Client failed authentication. Log and die.
+-callback check_user_login(rabbit_types:username(), [term()]) ->
+ {'ok', rabbit_types:user()} |
+ {'refused', string(), [any()]} |
+ {'error', any()}.
+
+%% Given #user and vhost, can a user log in to a vhost?
+%% Possible responses:
+%% true
+%% false
+%% {error, Error}
+%% Something went wrong. Log and die.
+-callback check_vhost_access(rabbit_types:user(), rabbit_types:vhost()) ->
+ boolean() | {'error', any()}.
+
+
+%% Given #user, resource and permission, can a user access a resource?
+%%
+%% Possible responses:
+%% true
+%% false
+%% {error, Error}
+%% Something went wrong. Log and die.
+-callback check_resource_access(rabbit_types:user(),
+ rabbit_types:r(atom()),
+ rabbit_access_control:permission_atom()) ->
+ boolean() | {'error', any()}.
+
+-else.
+
-export([behaviour_info/1]).
behaviour_info(callbacks) ->
- [
- %% A description proplist as with auth mechanisms,
- %% exchanges. Currently unused.
- {description, 0},
-
- %% Check a user can log in, given a username and a proplist of
- %% authentication information (e.g. [{password, Password}]).
- %%
- %% Possible responses:
- %% {ok, User}
- %% Authentication succeeded, and here's the user record.
- %% {error, Error}
- %% Something went wrong. Log and die.
- %% {refused, Msg, Args}
- %% Client failed authentication. Log and die.
- {check_user_login, 2},
-
- %% Given #user and vhost, can a user log in to a vhost?
- %% Possible responses:
- %% true
- %% false
- %% {error, Error}
- %% Something went wrong. Log and die.
- {check_vhost_access, 2},
-
- %% Given #user, resource and permission, can a user access a resource?
- %%
- %% Possible responses:
- %% true
- %% false
- %% {error, Error}
- %% Something went wrong. Log and die.
- {check_resource_access, 3}
- ];
+ [{description, 0}, {check_user_login, 2}, {check_vhost_access, 2},
+ {check_resource_access, 3}];
behaviour_info(_Other) ->
undefined.
+
+-endif.
diff --git a/src/rabbit_auth_backend_internal.erl b/src/rabbit_auth_backend_internal.erl
index 3ef81d32..7b9df81e 100644
--- a/src/rabbit_auth_backend_internal.erl
+++ b/src/rabbit_auth_backend_internal.erl
@@ -32,8 +32,6 @@
vhost_perms_info_keys/0, user_perms_info_keys/0,
user_vhost_perms_info_keys/0]).
--include("rabbit_auth_backend_spec.hrl").
-
-ifdef(use_specs).
-type(regexp() :: binary()).
diff --git a/src/rabbit_auth_mechanism.erl b/src/rabbit_auth_mechanism.erl
index 0c8251b8..eda6a743 100644
--- a/src/rabbit_auth_mechanism.erl
+++ b/src/rabbit_auth_mechanism.erl
@@ -16,31 +16,41 @@
-module(rabbit_auth_mechanism).
+-ifdef(use_specs).
+
+%% A description.
+-callback description() -> [proplist:property()].
+
+%% If this mechanism is enabled, should it be offered for a given socket?
+%% (primarily so EXTERNAL can be SSL-only)
+-callback should_offer(rabbit_net:socket()) -> boolean().
+
+%% Called before authentication starts. Should create a state
+%% object to be passed through all the stages of authentication.
+-callback init(rabbit_net:socket()) -> any().
+
+%% Handle a stage of authentication. Possible responses:
+%% {ok, User}
+%% Authentication succeeded, and here's the user record.
+%% {challenge, Challenge, NextState}
+%% Another round is needed. Here's the state I want next time.
+%% {protocol_error, Msg, Args}
+%% Client got the protocol wrong. Log and die.
+%% {refused, Msg, Args}
+%% Client failed authentication. Log and die.
+-callback handle_response(binary(), any()) ->
+ {'ok', rabbit_types:user()} |
+ {'challenge', binary(), any()} |
+ {'protocol_error', string(), [any()]} |
+ {'refused', string(), [any()]}.
+
+-else.
+
-export([behaviour_info/1]).
behaviour_info(callbacks) ->
- [
- %% A description.
- {description, 0},
-
- %% If this mechanism is enabled, should it be offered for a given socket?
- %% (primarily so EXTERNAL can be SSL-only)
- {should_offer, 1},
-
- %% Called before authentication starts. Should create a state
- %% object to be passed through all the stages of authentication.
- {init, 1},
-
- %% Handle a stage of authentication. Possible responses:
- %% {ok, User}
- %% Authentication succeeded, and here's the user record.
- %% {challenge, Challenge, NextState}
- %% Another round is needed. Here's the state I want next time.
- %% {protocol_error, Msg, Args}
- %% Client got the protocol wrong. Log and die.
- %% {refused, Msg, Args}
- %% Client failed authentication. Log and die.
- {handle_response, 2}
- ];
+ [{description, 0}, {should_offer, 1}, {init, 1}, {handle_response, 2}];
behaviour_info(_Other) ->
undefined.
+
+-endif.
diff --git a/src/rabbit_auth_mechanism_amqplain.erl b/src/rabbit_auth_mechanism_amqplain.erl
index 3de6e7a6..c0d86cd1 100644
--- a/src/rabbit_auth_mechanism_amqplain.erl
+++ b/src/rabbit_auth_mechanism_amqplain.erl
@@ -21,8 +21,6 @@
-export([description/0, should_offer/1, init/1, handle_response/2]).
--include("rabbit_auth_mechanism_spec.hrl").
-
-rabbit_boot_step({?MODULE,
[{description, "auth mechanism amqplain"},
{mfa, {rabbit_registry, register,
diff --git a/src/rabbit_auth_mechanism_cr_demo.erl b/src/rabbit_auth_mechanism_cr_demo.erl
index 64b01d8e..5df1d5d7 100644
--- a/src/rabbit_auth_mechanism_cr_demo.erl
+++ b/src/rabbit_auth_mechanism_cr_demo.erl
@@ -21,8 +21,6 @@
-export([description/0, should_offer/1, init/1, handle_response/2]).
--include("rabbit_auth_mechanism_spec.hrl").
-
-rabbit_boot_step({?MODULE,
[{description, "auth mechanism cr-demo"},
{mfa, {rabbit_registry, register,
diff --git a/src/rabbit_auth_mechanism_plain.erl b/src/rabbit_auth_mechanism_plain.erl
index 19fb5875..423170e1 100644
--- a/src/rabbit_auth_mechanism_plain.erl
+++ b/src/rabbit_auth_mechanism_plain.erl
@@ -21,8 +21,6 @@
-export([description/0, should_offer/1, init/1, handle_response/2]).
--include("rabbit_auth_mechanism_spec.hrl").
-
-rabbit_boot_step({?MODULE,
[{description, "auth mechanism plain"},
{mfa, {rabbit_registry, register,
diff --git a/src/rabbit_backing_queue.erl b/src/rabbit_backing_queue.erl
index 42627aae..6cc1c3fd 100644
--- a/src/rabbit_backing_queue.erl
+++ b/src/rabbit_backing_queue.erl
@@ -16,164 +16,200 @@
-module(rabbit_backing_queue).
+-ifdef(use_specs).
+
+%% We can't specify a per-queue ack/state with callback signatures
+-type(ack() :: any()).
+-type(state() :: any()).
+
+-type(fetch_result(Ack) ::
+ ('empty' |
+ %% Message, IsDelivered, AckTag, Remaining_Len
+ {rabbit_types:basic_message(), boolean(), Ack, non_neg_integer()})).
+-type(is_durable() :: boolean()).
+-type(attempt_recovery() :: boolean()).
+-type(purged_msg_count() :: non_neg_integer()).
+-type(confirm_required() :: boolean()).
+-type(async_callback() :: fun ((atom(), fun ((atom(), state()) -> state())) -> 'ok')).
+-type(duration() :: ('undefined' | 'infinity' | number())).
+
+-type(msg_fun() :: fun((rabbit_types:basic_message(), ack()) -> 'ok') |
+ 'undefined').
+
+%% Called on startup with a list of durable queue names. The queues
+%% aren't being started at this point, but this call allows the
+%% backing queue to perform any checking necessary for the consistency
+%% of those queues, or initialise any other shared resources.
+-callback start([rabbit_amqqueue:name()]) -> 'ok'.
+
+%% Called to tear down any state/resources. NB: Implementations should
+%% not depend on this function being called on shutdown and instead
+%% should hook into the rabbit supervision hierarchy.
+-callback stop() -> 'ok'.
+
+%% Initialise the backing queue and its state.
+%%
+%% Takes
+%% 1. the amqqueue record
+%% 2. a boolean indicating whether the queue is an existing queue that
+%% should be recovered
+%% 3. an asynchronous callback which accepts a function of type
+%% backing-queue-state to backing-queue-state. This callback
+%% function can be safely invoked from any process, which makes it
+%% useful for passing messages back into the backing queue,
+%% especially as the backing queue does not have control of its own
+%% mailbox.
+-callback init(rabbit_types:amqqueue(), attempt_recovery(),
+ async_callback()) -> state().
+
+%% Called on queue shutdown when queue isn't being deleted.
+-callback terminate(any(), state()) -> state().
+
+%% Called when the queue is terminating and needs to delete all its
+%% content.
+-callback delete_and_terminate(any(), state()) -> state().
+
+%% Remove all messages in the queue, but not messages which have been
+%% fetched and are pending acks.
+-callback purge(state()) -> {purged_msg_count(), state()}.
+
+%% Publish a message.
+-callback publish(rabbit_types:basic_message(),
+ rabbit_types:message_properties(), pid(), state()) ->
+ state().
+
+%% Called for messages which have already been passed straight
+%% out to a client. The queue will be empty for these calls
+%% (i.e. saves the round trip through the backing queue).
+-callback publish_delivered(true, rabbit_types:basic_message(),
+ rabbit_types:message_properties(), pid(), state())
+ -> {ack(), state()};
+ (false, rabbit_types:basic_message(),
+ rabbit_types:message_properties(), pid(), state())
+ -> {undefined, state()}.
+
+%% Return ids of messages which have been confirmed since the last
+%% invocation of this function (or initialisation).
+%%
+%% Message ids should only appear in the result of drain_confirmed
+%% under the following circumstances:
+%%
+%% 1. The message appears in a call to publish_delivered/4 and the
+%% first argument (ack_required) is false; or
+%% 2. The message is fetched from the queue with fetch/2 and the first
+%% argument (ack_required) is false; or
+%% 3. The message is acked (ack/2 is called for the message); or
+%% 4. The message is fully fsync'd to disk in such a way that the
+%% recovery of the message is guaranteed in the event of a crash of
+%% this rabbit node (excluding hardware failure).
+%%
+%% In addition to the above conditions, a message id may only appear
+%% in the result of drain_confirmed if
+%% #message_properties.needs_confirming = true when the msg was
+%% published (through whichever means) to the backing queue.
+%%
+%% It is legal for the same message id to appear in the results of
+%% multiple calls to drain_confirmed, which means that the backing
+%% queue is not required to keep track of which messages it has
+%% already confirmed. The confirm will be issued to the publisher the
+%% first time the message id appears in the result of
+%% drain_confirmed. All subsequent appearances of that message id will
+%% be ignored.
+-callback drain_confirmed(state()) -> {[rabbit_guid:guid()], state()}.
+
+%% Drop messages from the head of the queue while the supplied
+%% predicate returns true. A callback function is supplied allowing
+%% callers access to messages that are about to be dropped.
+-callback dropwhile(fun ((rabbit_types:message_properties()) -> boolean()), msg_fun(),
+ state())
+ -> state().
+
+%% Produce the next message.
+-callback fetch(true, state()) -> {fetch_result(ack()), state()};
+ (false, state()) -> {fetch_result(undefined), state()}.
+
+%% Acktags supplied are for messages which can now be forgotten
+%% about. Must return 1 msg_id per Ack, in the same order as Acks.
+-callback ack([ack()], state()) -> {[rabbit_guid:guid()], state()}.
+
+%% Acktags supplied are for messages which should be processed. The
+%% provided callback function is called with each message.
+-callback fold(msg_fun(), state(), [ack()]) -> state().
+
+%% Reinsert messages into the queue which have already been delivered
+%% and were pending acknowledgement.
+-callback requeue([ack()], state()) -> {[rabbit_guid:guid()], state()}.
+
+%% How long is my queue?
+-callback len(state()) -> non_neg_integer().
+
+%% Is my queue empty?
+-callback is_empty(state()) -> boolean().
+
+%% For the next three functions, the assumption is that you're
+%% monitoring something like the ingress and egress rates of the
+%% queue. The RAM duration is thus the length of time represented by
+%% the messages held in RAM given the current rates. If you want to
+%% ignore all of this stuff, then do so, and return 0 in
+%% ram_duration/1.
+
+%% The target is to have no more messages in RAM than indicated by the
+%% duration and the current queue rates.
+-callback set_ram_duration_target(duration(), state()) -> state().
+
+%% Optionally recalculate the duration internally (likely to be just
+%% update your internal rates), and report how many seconds the
+%% messages in RAM represent given the current rates of the queue.
+-callback ram_duration(state()) -> {duration(), state()}.
+
+%% Should 'timeout' be called as soon as the queue process can manage
+%% (either on an empty mailbox, or when a timer fires)?
+-callback needs_timeout(state()) -> 'false' | 'timed' | 'idle'.
+
+%% Called (eventually) after needs_timeout returns 'idle' or 'timed'.
+%% Note this may be called more than once for each 'idle' or 'timed'
+%% returned from needs_timeout
+-callback timeout(state()) -> state().
+
+%% Called immediately before the queue hibernates.
+-callback handle_pre_hibernate(state()) -> state().
+
+%% Exists for debugging purposes, to be able to expose state via
+%% rabbitmqctl list_queues backing_queue_status
+-callback status(state()) -> [{atom(), any()}].
+
+%% Passed a function to be invoked with the relevant backing queue's
+%% state. Useful for when the backing queue or other components need
+%% to pass functions into the backing queue.
+-callback invoke(atom(), fun ((atom(), A) -> A), state()) -> state().
+
+%% Called prior to a publish or publish_delivered call. Allows the BQ
+%% to signal that it's already seen this message (and in what capacity
+%% - i.e. was it published previously or discarded previously) and
+%% thus the message should be dropped.
+-callback is_duplicate(rabbit_types:basic_message(), state())
+ -> {'false'|'published'|'discarded', state()}.
+
+%% Called to inform the BQ about messages which have reached the
+%% queue, but are not going to be further passed to BQ for some
+%% reason. Note that this is may be invoked for messages for which
+%% BQ:is_duplicate/2 has already returned {'published' | 'discarded',
+%% BQS}.
+-callback discard(rabbit_types:basic_message(), pid(), state()) -> state().
+
+-else.
+
-export([behaviour_info/1]).
behaviour_info(callbacks) ->
- [
- %% Called on startup with a list of durable queue names. The
- %% queues aren't being started at this point, but this call
- %% allows the backing queue to perform any checking necessary for
- %% the consistency of those queues, or initialise any other
- %% shared resources.
- {start, 1},
-
- %% Called to tear down any state/resources. NB: Implementations
- %% should not depend on this function being called on shutdown
- %% and instead should hook into the rabbit supervision hierarchy.
- {stop, 0},
-
- %% Initialise the backing queue and its state.
- %%
- %% Takes
- %% 1. the amqqueue record
- %% 2. a boolean indicating whether the queue is an existing queue
- %% that should be recovered
- %% 3. an asynchronous callback which accepts a function of type
- %% backing-queue-state to backing-queue-state. This callback
- %% function can be safely invoked from any process, which
- %% makes it useful for passing messages back into the backing
- %% queue, especially as the backing queue does not have
- %% control of its own mailbox.
- {init, 3},
-
- %% Called on queue shutdown when queue isn't being deleted.
- {terminate, 2},
-
- %% Called when the queue is terminating and needs to delete all
- %% its content.
- {delete_and_terminate, 2},
-
- %% Remove all messages in the queue, but not messages which have
- %% been fetched and are pending acks.
- {purge, 1},
-
- %% Publish a message.
- {publish, 4},
-
- %% Called for messages which have already been passed straight
- %% out to a client. The queue will be empty for these calls
- %% (i.e. saves the round trip through the backing queue).
- {publish_delivered, 5},
-
- %% Return ids of messages which have been confirmed since
- %% the last invocation of this function (or initialisation).
- %%
- %% Message ids should only appear in the result of
- %% drain_confirmed under the following circumstances:
- %%
- %% 1. The message appears in a call to publish_delivered/4 and
- %% the first argument (ack_required) is false; or
- %% 2. The message is fetched from the queue with fetch/2 and the
- %% first argument (ack_required) is false; or
- %% 3. The message is acked (ack/2 is called for the message); or
- %% 4. The message is fully fsync'd to disk in such a way that the
- %% recovery of the message is guaranteed in the event of a
- %% crash of this rabbit node (excluding hardware failure).
- %%
- %% In addition to the above conditions, a message id may only
- %% appear in the result of drain_confirmed if
- %% #message_properties.needs_confirming = true when the msg was
- %% published (through whichever means) to the backing queue.
- %%
- %% It is legal for the same message id to appear in the results
- %% of multiple calls to drain_confirmed, which means that the
- %% backing queue is not required to keep track of which messages
- %% it has already confirmed. The confirm will be issued to the
- %% publisher the first time the message id appears in the result
- %% of drain_confirmed. All subsequent appearances of that message
- %% id will be ignored.
- {drain_confirmed, 1},
-
- %% Drop messages from the head of the queue while the supplied
- %% predicate returns true. A callback function is supplied
- %% allowing callers access to messages that are about to be
- %% dropped.
- {dropwhile, 3},
-
- %% Produce the next message.
- {fetch, 2},
-
- %% Acktags supplied are for messages which can now be forgotten
- %% about. Must return 1 msg_id per Ack, in the same order as
- %% Acks.
- {ack, 2},
-
- %% Acktags supplied are for messages which should be
- %% processed. The provided callback function is called with each
- %% message.
- {fold, 3},
-
- %% Reinsert messages into the queue which have already been
- %% delivered and were pending acknowledgement.
- {requeue, 2},
-
- %% How long is my queue?
- {len, 1},
-
- %% Is my queue empty?
- {is_empty, 1},
-
- %% For the next three functions, the assumption is that you're
- %% monitoring something like the ingress and egress rates of the
- %% queue. The RAM duration is thus the length of time represented
- %% by the messages held in RAM given the current rates. If you
- %% want to ignore all of this stuff, then do so, and return 0 in
- %% ram_duration/1.
-
- %% The target is to have no more messages in RAM than indicated
- %% by the duration and the current queue rates.
- {set_ram_duration_target, 2},
-
- %% Optionally recalculate the duration internally (likely to be
- %% just update your internal rates), and report how many seconds
- %% the messages in RAM represent given the current rates of the
- %% queue.
- {ram_duration, 1},
-
- %% Should 'timeout' be called as soon as the queue process
- %% can manage (either on an empty mailbox, or when a timer
- %% fires)?
- {needs_timeout, 1},
-
- %% Called (eventually) after needs_timeout returns 'idle' or
- %% 'timed'. Note this may be called more than once for each
- %% 'idle' or 'timed' returned from needs_timeout.
- {timeout, 1},
-
- %% Called immediately before the queue hibernates.
- {handle_pre_hibernate, 1},
-
- %% Exists for debugging purposes, to be able to expose state via
- %% rabbitmqctl list_queues backing_queue_status
- {status, 1},
-
- %% Passed a function to be invoked with the relevant backing
- %% queue's state. Useful for when the backing queue or other
- %% components need to pass functions into the backing queue.
- {invoke, 3},
-
- %% Called prior to a publish or publish_delivered call. Allows
- %% the BQ to signal that it's already seen this message (and in
- %% what capacity - i.e. was it published previously or discarded
- %% previously) and thus the message should be dropped.
- {is_duplicate, 2},
-
- %% Called to inform the BQ about messages which have reached the
- %% queue, but are not going to be further passed to BQ for some
- %% reason. Note that this is may be invoked for messages for
- %% which BQ:is_duplicate/2 has already returned {'published' |
- %% 'discarded', BQS}.
- {discard, 3}
- ];
+ [{start, 1}, {stop, 0}, {init, 3}, {terminate, 2},
+ {delete_and_terminate, 2}, {purge, 1}, {publish, 4},
+ {publish_delivered, 5}, {drain_confirmed, 1}, {dropwhile, 3},
+ {fetch, 2}, {ack, 2}, {fold, 3}, {requeue, 2}, {len, 1},
+ {is_empty, 1}, {set_ram_duration_target, 2}, {ram_duration, 1},
+ {needs_timeout, 1}, {timeout, 1}, {handle_pre_hibernate, 1},
+ {status, 1}, {invoke, 3}, {is_duplicate, 2}, {discard, 3}];
behaviour_info(_Other) ->
undefined.
+
+-endif.
diff --git a/src/rabbit_exchange_type.erl b/src/rabbit_exchange_type.erl
index 44a08e24..1027570c 100644
--- a/src/rabbit_exchange_type.erl
+++ b/src/rabbit_exchange_type.erl
@@ -16,39 +16,57 @@
-module(rabbit_exchange_type).
--export([behaviour_info/1]).
+-ifdef(use_specs).
-behaviour_info(callbacks) ->
- [
- {description, 0},
+-type(tx() :: 'transaction' | 'none').
+-type(serial() :: pos_integer() | tx()).
+
+-callback description() -> [proplist:property()].
+
+%% Should Rabbit ensure that all binding events that are
+%% delivered to an individual exchange can be serialised? (they
+%% might still be delivered out of order, but there'll be a
+%% serial number).
+-callback serialise_events() -> boolean().
- %% Should Rabbit ensure that all binding events that are
- %% delivered to an individual exchange can be serialised? (they
- %% might still be delivered out of order, but there'll be a
- %% serial number).
- {serialise_events, 0},
+%% The no_return is there so that we can have an "invalid" exchange
+%% type (see rabbit_exchange_type_invalid).
+-callback route(rabbit_types:exchange(), rabbit_types:delivery()) ->
+ rabbit_router:match_result().
- {route, 2},
+%% called BEFORE declaration, to check args etc; may exit with #amqp_error{}
+-callback validate(rabbit_types:exchange()) -> 'ok'.
- %% called BEFORE declaration, to check args etc; may exit with #amqp_error{}
- {validate, 1},
+%% called after declaration and recovery
+-callback create(tx(), rabbit_types:exchange()) -> 'ok'.
- %% called after declaration and recovery
- {create, 2},
+%% called after exchange (auto)deletion.
+-callback delete(tx(), rabbit_types:exchange(), [rabbit_types:binding()]) ->
+ 'ok'.
- %% called after exchange (auto)deletion.
- {delete, 3},
+%% called after a binding has been added or recovered
+-callback add_binding(serial(), rabbit_types:exchange(),
+ rabbit_types:binding()) -> 'ok'.
- %% called after a binding has been added or recovered
- {add_binding, 3},
+%% called after bindings have been deleted.
+-callback remove_bindings(serial(), rabbit_types:exchange(),
+ [rabbit_types:binding()]) -> 'ok'.
- %% called after bindings have been deleted.
- {remove_bindings, 3},
+%% called when comparing exchanges for equivalence - should return ok or
+%% exit with #amqp_error{}
+-callback assert_args_equivalence (rabbit_types:exchange(),
+ rabbit_framing:amqp_table()) ->
+ 'ok' | rabbit_types:connection_exit().
- %% called when comparing exchanges for equivalence - should return ok or
- %% exit with #amqp_error{}
- {assert_args_equivalence, 2}
+-else.
- ];
+-export([behaviour_info/1]).
+
+behaviour_info(callbacks) ->
+ [{description, 0}, {serialise_events, 0}, {route, 2}, {validate, 1},
+ {create, 2}, {delete, 3}, {add_binding, 3}, {remove_bindings, 3},
+ {assert_args_equivalence, 2}];
behaviour_info(_Other) ->
undefined.
+
+-endif.
diff --git a/src/rabbit_exchange_type_direct.erl b/src/rabbit_exchange_type_direct.erl
index 4bce42d4..cdec1cb9 100644
--- a/src/rabbit_exchange_type_direct.erl
+++ b/src/rabbit_exchange_type_direct.erl
@@ -22,7 +22,6 @@
-export([description/0, serialise_events/0, route/2]).
-export([validate/1, create/2, delete/3,
add_binding/3, remove_bindings/3, assert_args_equivalence/2]).
--include("rabbit_exchange_type_spec.hrl").
-rabbit_boot_step({?MODULE,
[{description, "exchange type direct"},
diff --git a/src/rabbit_exchange_type_fanout.erl b/src/rabbit_exchange_type_fanout.erl
index cc3fb87c..a64f2c29 100644
--- a/src/rabbit_exchange_type_fanout.erl
+++ b/src/rabbit_exchange_type_fanout.erl
@@ -22,7 +22,6 @@
-export([description/0, serialise_events/0, route/2]).
-export([validate/1, create/2, delete/3, add_binding/3,
remove_bindings/3, assert_args_equivalence/2]).
--include("rabbit_exchange_type_spec.hrl").
-rabbit_boot_step({?MODULE,
[{description, "exchange type fanout"},
diff --git a/src/rabbit_exchange_type_headers.erl b/src/rabbit_exchange_type_headers.erl
index de9979b4..61917d8f 100644
--- a/src/rabbit_exchange_type_headers.erl
+++ b/src/rabbit_exchange_type_headers.erl
@@ -23,7 +23,6 @@
-export([description/0, serialise_events/0, route/2]).
-export([validate/1, create/2, delete/3, add_binding/3,
remove_bindings/3, assert_args_equivalence/2]).
--include("rabbit_exchange_type_spec.hrl").
-rabbit_boot_step({?MODULE,
[{description, "exchange type headers"},
diff --git a/src/rabbit_exchange_type_invalid.erl b/src/rabbit_exchange_type_invalid.erl
index 8f60f7d8..82d27960 100644
--- a/src/rabbit_exchange_type_invalid.erl
+++ b/src/rabbit_exchange_type_invalid.erl
@@ -22,7 +22,6 @@
-export([description/0, serialise_events/0, route/2]).
-export([validate/1, create/2, delete/3,
add_binding/3, remove_bindings/3, assert_args_equivalence/2]).
--include("rabbit_exchange_type_spec.hrl").
description() ->
[{name, <<"invalid">>},
diff --git a/src/rabbit_exchange_type_topic.erl b/src/rabbit_exchange_type_topic.erl
index 84f4f8a9..3160fdf4 100644
--- a/src/rabbit_exchange_type_topic.erl
+++ b/src/rabbit_exchange_type_topic.erl
@@ -23,7 +23,6 @@
-export([description/0, serialise_events/0, route/2]).
-export([validate/1, create/2, delete/3, add_binding/3,
remove_bindings/3, assert_args_equivalence/2]).
--include("rabbit_exchange_type_spec.hrl").
-rabbit_boot_step({?MODULE,
[{description, "exchange type topic"},
diff --git a/src/rabbit_mirror_queue_master.erl b/src/rabbit_mirror_queue_master.erl
index 5db0fa2f..04b7514f 100644
--- a/src/rabbit_mirror_queue_master.erl
+++ b/src/rabbit_mirror_queue_master.erl
@@ -59,10 +59,6 @@
known_senders :: set()
}).
--type(ack() :: non_neg_integer()).
--type(state() :: master_state()).
--include("rabbit_backing_queue_spec.hrl").
-
-spec(promote_backing_queue_state/6 ::
(pid(), atom(), any(), pid(), dict(), [pid()]) -> master_state()).
-spec(sender_death_fun/0 :: () -> death_fun()).
diff --git a/src/rabbit_msg_store_ets_index.erl b/src/rabbit_msg_store_ets_index.erl
index 9c31439f..3defeaaf 100644
--- a/src/rabbit_msg_store_ets_index.erl
+++ b/src/rabbit_msg_store_ets_index.erl
@@ -16,6 +16,8 @@
-module(rabbit_msg_store_ets_index).
+-include("rabbit_msg_store.hrl").
+
-behaviour(rabbit_msg_store_index).
-export([new/1, recover/1,
@@ -25,8 +27,6 @@
-define(MSG_LOC_NAME, rabbit_msg_store_ets_index).
-define(FILENAME, "msg_store_index.ets").
--include("rabbit_msg_store_index.hrl").
-
-record(state, { table, dir }).
new(Dir) ->
diff --git a/src/rabbit_msg_store_index.erl b/src/rabbit_msg_store_index.erl
index 2f36256c..6cc0b2a7 100644
--- a/src/rabbit_msg_store_index.erl
+++ b/src/rabbit_msg_store_index.erl
@@ -16,6 +16,31 @@
-module(rabbit_msg_store_index).
+-include("rabbit_msg_store.hrl").
+
+-ifdef(use_specs).
+
+-type(dir() :: any()).
+-type(index_state() :: any()).
+-type(keyvalue() :: any()).
+-type(fieldpos() :: non_neg_integer()).
+-type(fieldvalue() :: any()).
+
+-callback new(dir()) -> index_state().
+-callback recover(dir()) -> rabbit_types:ok_or_error2(index_state(), any()).
+-callback lookup(rabbit_types:msg_id(), index_state()) -> ('not_found' | keyvalue()).
+-callback insert(keyvalue(), index_state()) -> 'ok'.
+-callback update(keyvalue(), index_state()) -> 'ok'.
+-callback update_fields(rabbit_types:msg_id(), ({fieldpos(), fieldvalue()} |
+ [{fieldpos(), fieldvalue()}]),
+ index_state()) -> 'ok'.
+-callback delete(rabbit_types:msg_id(), index_state()) -> 'ok'.
+-callback delete_object(keyvalue(), index_state()) -> 'ok'.
+-callback delete_by_file(fieldvalue(), index_state()) -> 'ok'.
+-callback terminate(index_state()) -> any().
+
+-else.
+
-export([behaviour_info/1]).
behaviour_info(callbacks) ->
@@ -30,3 +55,5 @@ behaviour_info(callbacks) ->
{terminate, 1}];
behaviour_info(_Other) ->
undefined.
+
+-endif.
diff --git a/src/rabbit_variable_queue.erl b/src/rabbit_variable_queue.erl
index 64d3b05c..0bfec2fd 100644
--- a/src/rabbit_variable_queue.erl
+++ b/src/rabbit_variable_queue.erl
@@ -351,7 +351,7 @@
durable :: boolean(),
transient_threshold :: non_neg_integer(),
- async_callback :: async_callback(),
+ async_callback :: rabbit_backing_queue:async_callback(),
len :: non_neg_integer(),
persistent_count :: non_neg_integer(),
@@ -370,8 +370,6 @@
ack_in_counter :: non_neg_integer(),
ack_rates :: rates() }).
--include("rabbit_backing_queue_spec.hrl").
-
-spec(multiple_routing_keys/0 :: () -> 'ok').
-endif.
diff --git a/src/supervisor2.erl b/src/supervisor2.erl
index 8dd8aba8..f1b74878 100644
--- a/src/supervisor2.erl
+++ b/src/supervisor2.erl
@@ -81,8 +81,6 @@
which_children/1, find_child/2,
check_childspecs/1]).
--export([behaviour_info/1]).
-
%% Internal exports
-export([init/1, handle_call/3, handle_info/2, terminate/2, code_change/3]).
-export([handle_cast/2]).
@@ -112,11 +110,144 @@
-define(is_terminate_simple(State),
State#state.strategy =:= simple_one_for_one_terminate).
+-ifdef(use_specs).
+
+%%--------------------------------------------------------------------------
+%% Types
+%%--------------------------------------------------------------------------
+
+-export_type([child_spec/0, startchild_ret/0, strategy/0, sup_name/0]).
+
+-type child() :: 'undefined' | pid().
+-type child_id() :: term().
+-type mfargs() :: {M :: module(), F :: atom(), A :: [term()] | undefined}.
+-type modules() :: [module()] | 'dynamic'.
+-type delay() :: non_neg_integer().
+-type restart() :: 'permanent' | 'transient' | 'temporary' | 'intrinsic'
+ | {'permanent', delay()} | {'transient', delay()}
+ | {'intrinsic', delay()}.
+-type shutdown() :: 'brutal_kill' | timeout().
+-type worker() :: 'worker' | 'supervisor'.
+-type sup_name() :: {'local', Name :: atom()} | {'global', Name :: atom()}.
+-type sup_ref() :: (Name :: atom())
+ | {Name :: atom(), Node :: node()}
+ | {'global', Name :: atom()}
+ | pid().
+-type child_spec() :: {Id :: child_id(),
+ StartFunc :: mfargs(),
+ Restart :: restart(),
+ Shutdown :: shutdown(),
+ Type :: worker(),
+ Modules :: modules()}.
+
+
+-type strategy() :: 'one_for_all' | 'one_for_one'
+ | 'rest_for_one' | 'simple_one_for_one'
+ | 'simple_one_for_one_terminate'.
+
+-type child_rec() :: #child{pid :: child() | {restarting,pid()} | [pid()],
+ name :: child_id(),
+ mfa :: mfargs(),
+ restart_type :: restart(),
+ shutdown :: shutdown(),
+ child_type :: worker(),
+ modules :: modules()}.
+
+-type state() :: #state{strategy :: strategy(),
+ children :: [child_rec()],
+ dynamics :: ?DICT(),
+ intensity :: non_neg_integer(),
+ period :: pos_integer()}.
+
+%%--------------------------------------------------------------------------
+%% Callback behaviour
+%%--------------------------------------------------------------------------
+
+-callback init(Args :: term()) ->
+ {ok, {{RestartStrategy :: strategy(),
+ MaxR :: non_neg_integer(),
+ MaxT :: non_neg_integer()},
+ [ChildSpec :: child_spec()]}}
+ | ignore.
+
+%%--------------------------------------------------------------------------
+%% Specs
+%%--------------------------------------------------------------------------
+
+-type startchild_err() :: 'already_present'
+ | {'already_started', Child :: child()} | term().
+-type startchild_ret() :: {'ok', Child :: child()}
+ | {'ok', Child :: child(), Info :: term()}
+ | {'error', startchild_err()}.
+
+-spec start_child(SupRef, ChildSpec) -> startchild_ret() when
+ SupRef :: sup_ref(),
+ ChildSpec :: child_spec() | (List :: [term()]).
+
+-spec restart_child(SupRef, Id) -> Result when
+ SupRef :: sup_ref(),
+ Id :: child_id(),
+ Result :: {'ok', Child :: child()}
+ | {'ok', Child :: child(), Info :: term()}
+ | {'error', Error},
+ Error :: 'running' | 'not_found' | 'simple_one_for_one' | term().
+
+-spec delete_child(SupRef, Id) -> Result when
+ SupRef :: sup_ref(),
+ Id :: child_id(),
+ Result :: 'ok' | {'error', Error},
+ Error :: 'running' | 'not_found' | 'simple_one_for_one'.
+
+-spec terminate_child(SupRef, Id) -> Result when
+ SupRef :: sup_ref(),
+ Id :: pid() | child_id(),
+ Result :: 'ok' | {'error', Error},
+ Error :: 'not_found' | 'simple_one_for_one'.
+
+-spec which_children(SupRef) -> [{Id,Child,Type,Modules}] when
+ SupRef :: sup_ref(),
+ Id :: child_id() | 'undefined',
+ Child :: child(),
+ Type :: worker(),
+ Modules :: modules().
+
+-spec check_childspecs(ChildSpecs) -> Result when
+ ChildSpecs :: [child_spec()],
+ Result :: 'ok' | {'error', Error :: term()}.
+
+-type init_sup_name() :: sup_name() | 'self'.
+
+-type stop_rsn() :: 'shutdown' | {'bad_return', {module(),'init', term()}}
+ | {'bad_start_spec', term()} | {'start_spec', term()}
+ | {'supervisor_data', term()}.
+
+-spec init({init_sup_name(), module(), [term()]}) ->
+ {'ok', state()} | 'ignore' | {'stop', stop_rsn()}.
+
+-type call() :: 'which_children'.
+-spec handle_call(call(), term(), state()) -> {'reply', term(), state()}.
+
+-spec handle_cast('null', state()) -> {'noreply', state()}.
+
+-spec handle_info(term(), state()) ->
+ {'noreply', state()} | {'stop', 'shutdown', state()}.
+
+-spec terminate(term(), state()) -> 'ok'.
+
+-spec code_change(term(), state(), term()) ->
+ {'ok', state()} | {'error', term()}.
+
+-else.
+
+-export([behaviour_info/1]).
+
behaviour_info(callbacks) ->
[{init,1}];
behaviour_info(_Other) ->
undefined.
+-endif.
+
%%% ---------------------------------------------------
%%% This is a general process supervisor built upon gen_server.erl.
%%% Servers/processes should/could also be built using gen_server.erl.