diff options
Diffstat (limited to 'system/doc/design_principles')
-rw-r--r-- | system/doc/design_principles/applications.xml | 270 | ||||
-rw-r--r-- | system/doc/design_principles/appup_cookbook.xml | 372 | ||||
-rw-r--r-- | system/doc/design_principles/des_princ.xml | 113 | ||||
-rw-r--r-- | system/doc/design_principles/distributed_applications.xml | 182 | ||||
-rw-r--r-- | system/doc/design_principles/events.xml | 95 | ||||
-rw-r--r-- | system/doc/design_principles/fsm.xml | 168 | ||||
-rw-r--r-- | system/doc/design_principles/gen_server_concepts.xml | 160 | ||||
-rw-r--r-- | system/doc/design_principles/included_applications.xml | 67 | ||||
-rw-r--r-- | system/doc/design_principles/release_handling.xml | 628 | ||||
-rw-r--r-- | system/doc/design_principles/release_structure.xml | 190 | ||||
-rw-r--r-- | system/doc/design_principles/spec_proc.xml | 248 | ||||
-rw-r--r-- | system/doc/design_principles/sup_princ.xml | 338 |
12 files changed, 1516 insertions, 1315 deletions
diff --git a/system/doc/design_principles/applications.xml b/system/doc/design_principles/applications.xml index 7b030115df..9d3a204999 100644 --- a/system/doc/design_principles/applications.xml +++ b/system/doc/design_principles/applications.xml @@ -29,55 +29,63 @@ <file>applications.xml</file> </header> <marker id="appl"></marker> - <p>This chapter should be read in conjunction with <c>app(4)</c> and - <c>application(3)</c>.</p> + <p>This section is to be read with the <c>app(4)</c> and + <c>application(3)</c> manual pages in Kernel.</p> <section> <title>Application Concept</title> - <p>When we have written code implementing some specific - functionality, we might want to make the code into an - <em>application</em>, that is a component that can be started and - stopped as a unit, and which can be re-used in other systems as - well.</p> - <p>To do this, we create an - <seealso marker="#callback_module">application callback module</seealso>, where we describe how the application should - be started and stopped.</p> + <p>When you have written code implementing some specific functionality + you might want to make the code into an <em>application</em>, + that is, a component that can be started and stopped as a unit, + and which can also be reused in other systems.</p> + <p>To do this, create an + <seealso marker="#callback_module">application callback module</seealso>, + and describe how the application is to be started and stopped.</p> <p>Then, an <em>application specification</em> is needed, which is - put in an <seealso marker="#appl_res_file">application resource file</seealso>. Among other things, we specify which - modules the application consists of and the name of the callback - module.</p> - <p>If we use <c>systools</c>, the Erlang/OTP tools for packaging code + put in an + <seealso marker="#appl_res_file">application resource file</seealso>. + Among other things, this file specifies which modules the application + consists of and the name of the callback module.</p> + <p>If you use <c>systools</c>, the Erlang/OTP tools for packaging code (see <seealso marker="release_structure">Releases</seealso>), - the code for each application is placed in a separate directory - following a pre-defined <seealso marker="#app_dir">directory structure</seealso>.</p> + the code for each application is placed in a + separate directory following a pre-defined + <seealso marker="#app_dir">directory structure</seealso>.</p> </section> <section> <marker id="callback_module"></marker> <title>Application Callback Module</title> - <p>How to start and stop the code for the application, i.e. + <p>How to start and stop the code for the application, that is, the supervision tree, is described by two callback functions:</p> <code type="none"> start(StartType, StartArgs) -> {ok, Pid} | {ok, Pid, State} -stop(State)</code> - <p><c>start</c> is called when starting the application and should - create the supervision tree by starting the top supervisor. - It is expected to return the pid of the top supervisor and an - optional term <c>State</c>, which defaults to []. This term is - passed as-is to <c>stop</c>.</p> - <p><c>StartType</c> is usually the atom <c>normal</c>. It has other +stop(State) + </code> + <list type="bulleted"> + <item><c>start</c> is called when starting the application and is to + create the supervision tree by starting the top supervisor. It is + expected to return the pid of the top supervisor and an optional + term, <c>State</c>, which defaults to <c>[]</c>. This term is passed + as is to <c>stop</c>.</item> + <item><c>StartType</c> is usually the atom <c>normal</c>. It has other values only in the case of a takeover or failover, see - <seealso marker="distributed_applications">Distributed Applications</seealso>. <c>StartArgs</c> is defined by the key - <c>mod</c> in the <seealso marker="#appl_res_file">application resource file</seealso> file.</p> - <p><c>stop/1</c> is called <em>after</em> the application has been - stopped and should do any necessary cleaning up. Note that - the actual stopping of the application, that is the shutdown of - the supervision tree, is handled automatically as described in - <seealso marker="#stopping">Starting and Stopping Applications</seealso>.</p> + <seealso marker="distributed_applications">Distributed Applications</seealso>. + </item> + <item><c>StartArgs</c> is defined by the key <c>mod</c> in the + <seealso marker="#appl_res_file">application + resource file</seealso>.</item> + <item><c>stop/1</c> is called <em>after</em> the application has been + stopped and is to do any necessary cleaning up. The actual stopping of + the application, that is, the shutdown of the supervision tree, is + handled automatically as described in + <seealso marker="#stopping">Starting and Stopping Applications</seealso>. + </item> + </list> <marker id="ch_app"></marker> <p>Example of an application callback module for packaging the supervision tree from - the <seealso marker="sup_princ#ex">Supervisor</seealso> chapter:</p> + <seealso marker="sup_princ#ex">Supervisor Behaviour</seealso>:</p> <code type="none"> -module(ch_app). -behaviour(application). @@ -89,44 +97,48 @@ start(_Type, _Args) -> stop(_State) -> ok.</code> - <p>A library application, which can not be started or stopped, - does not need any application callback module.</p> + <p>A library application that cannot be started or stopped, does not + need any application callback module.</p> </section> <section> <marker id="appl_res_file"></marker> <title>Application Resource File</title> - <p>To define an application, we create an <em>application specification</em> which is put in an <em>application resource file</em>, or in short <c>.app</c> file:</p> + <p>To define an application, an <em>application specification</em> is + created, which is put in an <em>application resource file</em>, or in + short an <c>.app</c> file:</p> <code type="none"> {application, Application, [Opt1,...,OptN]}.</code> - <p><c>Application</c>, an atom, is the name of the application. - The file must be named <c>Application.app</c>.</p> - <p>Each <c>Opt</c> is a tuple <c>{Key, Value}</c> which define a +<list> + <item><c>Application</c>, an atom, is the name of the application. + The file must be named <c>Application.app</c>.</item> + <item>Each <c>Opt</c> is a tuple <c>{Key,Value}</c>, which define a certain property of the application. All keys are optional. - Default values are used for any omitted keys.</p> + Default values are used for any omitted keys.</item> +</list> <p>The contents of a minimal <c>.app</c> file for a library - application <c>libapp</c> looks like this:</p> + application <c>libapp</c> looks as follows:</p> <code type="none"> {application, libapp, []}.</code> <p>The contents of a minimal <c>.app</c> file <c>ch_app.app</c> for - a supervision tree application like <c>ch_app</c> looks like this:</p> + a supervision tree application like <c>ch_app</c> looks as follows:</p> <code type="none"> {application, ch_app, [{mod, {ch_app,[]}}]}.</code> - <p>The key <c>mod</c> defines the callback module and start - argument of the application, in this case <c>ch_app</c> and - [], respectively. This means that</p> + <p>The key <c>mod</c> defines the callback module and start argument of + the application, in this case <c>ch_app</c> and <c>[]</c>, respectively. + This means that the following is called when the application is to be + started:</p> <code type="none"> ch_app:start(normal, [])</code> - <p>will be called when the application should be started and</p> + <p>The following is called when the application is stopped.</p> <code type="none"> ch_app:stop([])</code> - <p>will be called when the application has been stopped.</p> <p>When using <c>systools</c>, the Erlang/OTP tools for packaging - code (see <seealso marker="release_structure">Releases</seealso>), - the keys <c>description</c>, <c>vsn</c>, <c>modules</c>, - <c>registered</c> and <c>applications</c> should also be - specified:</p> + code (see Section + <seealso marker="release_structure">Releases</seealso>), the keys + <c>description</c>, <c>vsn</c>, <c>modules</c>, <c>registered</c>, + and <c>applications</c> are also to be specified:</p> <code type="none"> {application, ch_app, [{description, "Channel allocator"}, @@ -136,67 +148,54 @@ ch_app:stop([])</code> {applications, [kernel, stdlib, sasl]}, {mod, {ch_app,[]}} ]}.</code> - <taglist> - <tag><c>description</c></tag> - <item>A short description, a string. Defaults to "".</item> - <tag><c>vsn</c></tag> - <item>Version number, a string. Defaults to "".</item> - <tag><c>modules</c></tag> - <item>All modules <em>introduced</em> by this application. - <c>systools</c> uses this list when generating boot scripts and - tar files. A module must be defined in one and only one - application. Defaults to [].</item> - <tag><c>registered</c></tag> - <item>All names of registered processes in the application. - <c>systools</c> uses this list to detect name clashes - between applications. Defaults to [].</item> - <tag><c>applications</c></tag> - <item>All applications which must be started before this - application is started. <c>systools</c> uses this list to - generate correct boot scripts. Defaults to [], but note that - all applications have dependencies to at least <c>kernel</c> - and <c>stdlib</c>.</item> - </taglist> - <note><p>The syntax and contents of of the application resource file - are described in detail in the<seealso marker="kernel:app"> - Application resource file reference</seealso>.</p></note> + <list> + <item><c>description</c> - A short description, a string. Defaults to + "".</item> + <item><c>vsn</c> - Version number, a string. Defaults to "".</item> + <item><c>modules</c> - All modules <em>introduced</em> by this + application. <c>systools</c> uses this list when generating boot scripts + and tar files. A module must be defined in only one application. + Defaults to <c>[]</c>.</item> + <item><c>registered</c> - All names of registered processes in the + application. <c>systools</c> uses this list to detect name clashes + between applications. Defaults to <c>[]</c>.</item> + <item><c>applications</c> - All applications that must be + started before this application is started. <c>systools</c> uses this + list to generate correct boot scripts. Defaults to <c>[]</c>. Notice + that all applications have dependencies to at least Kernel + and STDLIB.</item> + </list> + <note><p>For details about the syntax and contents of the application + resource file, see the <seealso marker="kernel:app">app</seealso> + manual page in Kernel.</p></note> </section> <section> <marker id="app_dir"></marker> <title>Directory Structure</title> <p>When packaging code using <c>systools</c>, the code for each - application is placed in a separate directory + application is placed in a separate directory, <c>lib/Application-Vsn</c>, where <c>Vsn</c> is the version number.</p> - <p>This may be useful to know, even if <c>systools</c> is not used, - since Erlang/OTP itself is packaged according to the OTP principles + <p>This can be useful to know, even if <c>systools</c> is not used, + since Erlang/OTP is packaged according to the OTP principles and thus comes with this directory structure. The code server - (see <c>code(3)</c>) will automatically use code from - the directory with the highest version number, if there are - more than one version of an application present.</p> - <p>The application directory structure can of course be used in - the development environment as well. The version number may then + (see the <c>code(3)</c> manual page in Kernel) automatically + uses code from + the directory with the highest version number, if more than one + version of an application is present.</p> + <p>The application directory structure can also be used in the + development environment. The version number can then be omitted from the name.</p> - <p>The application directory have the following sub-directories:</p> + <p>The application directory has the following sub-directories:</p> <list type="bulleted"> - <item><c>src</c></item> - <item><c>ebin</c></item> - <item><c>priv</c></item> - <item><c>include</c></item> + <item><c>src</c> - Contains the Erlang source code.</item> + <item><c>ebin</c> - Contains the Erlang object code, the + <c>beam</c> files. The <c>.app</c> file is also placed here.</item> + <item><c>priv</c> - Used for application specific files. For + example, C executables are placed here. The function + <c>code:priv_dir/1</c> is to be used to access this directory.</item> + <item><c>include</c> - Used for include files.</item> </list> - <taglist> - <tag><c>src</c></tag> - <item>Contains the Erlang source code.</item> - <tag><c>ebin</c></tag> - <item>Contains the Erlang object code, the <c>beam</c> files. - The <c>.app</c> file is also placed here.</item> - <tag><c>priv</c></tag> - <item>Used for application specific files. For example, C - executables are placed here. The function <c>code:priv_dir/1</c> - should be used to access this directory.</item> - <tag><c>include</c></tag> - <item>Used for include files.</item> - </taglist> </section> <section> @@ -207,17 +206,17 @@ ch_app:stop([])</code> processes is the <em>application controller</em> process, registered as <c>application_controller</c>.</p> <p>All operations on applications are coordinated by the application - controller. It is interfaced through the functions in - the module <c>application</c>, see <c>application(3)</c>. - In particular, applications can be loaded, unloaded, started and - stopped.</p> + controller. It is interacted through the functions in + the module <c>application</c>, see the <c>application(3)</c> + manual page in Kernel. In particular, applications can be + loaded, unloaded, started, and stopped.</p> </section> <section> <title>Loading and Unloading Applications</title> <p>Before an application can be started, it must be <em>loaded</em>. The application controller reads and stores the information from - the <c>.app</c> file.</p> + the <c>.app</c> file:</p> <pre> 1> <input>application:load(ch_app).</input> ok @@ -236,7 +235,7 @@ ok {stdlib,"ERTS CXC 138 10","1.11.4.3"}]</pre> <note> <p>Loading/unloading an application does not load/unload the code - used by the application. Code loading is done the usual way.</p> + used by the application. Code loading is done the usual way.</p> </note> </section> @@ -252,13 +251,14 @@ ok {stdlib,"ERTS CXC 138 10","1.11.4.3"}, {ch_app,"Channel allocator","1"}]</pre> <p>If the application is not already loaded, the application - controller will first load it using <c>application:load/1</c>. It - will check the value of the <c>applications</c> key, to ensure - that all applications that should be started before this + controller first loads it using <c>application:load/1</c>. It + checks the value of the <c>applications</c> key, to ensure + that all applications that are to be started before this application are running.</p> <marker id="application_master"></marker> - <p>The application controller then creates an <em>application master</em> for the application. The application master is - the group leader of all the processes in the application. + <p>The application controller then creates an + <em>application master</em> for the application. The application master + is the group leader of all the processes in the application. The application master starts the application by calling the application callback function <c>start/2</c> in the module, and with the start argument, defined by the <c>mod</c> key in @@ -268,8 +268,8 @@ ok 7> <input>application:stop(ch_app).</input> ok</pre> <p>The application master stops the application by telling the top - supervisor to shutdown. The top supervisor tells all its child - processes to shutdown etc. and the entire tree is terminated in + supervisor to shut down. The top supervisor tells all its child + processes to shut down, and so on; the entire tree is terminated in reversed start order. The application master then calls the application callback function <c>stop/1</c> in the module defined by the <c>mod</c> key.</p> @@ -277,8 +277,10 @@ ok</pre> <section> <title>Configuring an Application</title> - <p>An application can be configured using <em>configuration parameters</em>. These are a list of <c>{Par, Val}</c> tuples - specified by a key <c>env</c> in the <c>.app</c> file.</p> + <p>An application can be configured using + <em>configuration parameters</em>. These are a list of + <c>{Par,Val}</c> tuples + specified by a key <c>env</c> in the <c>.app</c> file:</p> <code type="none"> {application, ch_app, [{description, "Channel allocator"}, @@ -289,11 +291,12 @@ ok</pre> {mod, {ch_app,[]}}, {env, [{file, "/usr/local/log"}]} ]}.</code> - <p><c>Par</c> should be an atom, <c>Val</c> is any term. + <p><c>Par</c> is to be an atom. <c>Val</c> is any term. The application can retrieve the value of a configuration parameter by calling <c>application:get_env(App, Par)</c> or a - number of similar functions, see <c>application(3)</c>.</p> - <p>Example:</p> + number of similar functions, see the <c>application(3)</c> + manual page in Kernel.</p> + <p><em>Example:</em></p> <pre> % <input>erl</input> Erlang (BEAM) emulator version 5.2.3.6 [hipe] [threads:0] @@ -304,20 +307,21 @@ ok 2> <input>application:get_env(ch_app, file).</input> {ok,"/usr/local/log"}</pre> <p>The values in the <c>.app</c> file can be overridden by values - in a <em>system configuration file</em>. This is a file which + in a <em>system configuration file</em>. This is a file that contains configuration parameters for relevant applications:</p> <code type="none"> [{Application1, [{Par11,Val11},...]}, ..., {ApplicationN, [{ParN1,ValN1},...]}].</code> - <p>The system configuration should be called <c>Name.config</c> and - Erlang should be started with the command line argument - <c>-config Name</c>. See <c>config(4)</c> for more information.</p> - <p>Example: A file <c>test.config</c> is created with the following - contents:</p> + <p>The system configuration is to be called <c>Name.config</c> and + Erlang is to be started with the command-line argument + <c>-config Name</c>. For details, see the <c>config(4)</c> + manual page in Kernel.</p> + <p><em>Example:</em></p> + <p>A file <c>test.config</c> is created with the following contents:</p> <code type="none"> [{ch_app, [{file, "testlog"}]}].</code> - <p>The value of <c>file</c> will override the value of <c>file</c> + <p>The value of <c>file</c> overrides the value of <c>file</c> as defined in the <c>.app</c> file:</p> <pre> % <input>erl -config test</input> @@ -330,14 +334,14 @@ ok {ok,"testlog"}</pre> <p>If <seealso marker="release_handling#sys">release handling</seealso> - is used, exactly one system configuration file should be used and - that file should be called <c>sys.config</c></p> - <p>The values in the <c>.app</c> file, as well as the values in a - system configuration file, can be overridden directly from + is used, exactly one system configuration file is to be used and + that file is to be called <c>sys.config</c>.</p> + <p>The values in the <c>.app</c> file and the values in a + system configuration file can be overridden directly from the command line:</p> <pre> % <input>erl -ApplName Par1 Val1 ... ParN ValN</input></pre> - <p>Example:</p> + <p><em>Example:</em></p> <pre> % <input>erl -ch_app file '"testlog"'</input> Erlang (BEAM) emulator version 5.2.3.6 [hipe] [threads:0] @@ -368,10 +372,10 @@ application:start(Application, Type)</code> <item>If a temporary application terminates, this is reported but no other applications are terminated.</item> </list> - <p>It is always possible to stop an application explicitly by + <p>An application can always be stopped explicitly by calling <c>application:stop/1</c>. Regardless of the mode, no - other applications will be affected.</p> - <p>Note that transient mode is of little practical use, since when + other applications are affected.</p> + <p>The transient mode is of little practical use, since when a supervision tree terminates, the reason is set to <c>shutdown</c>, not <c>normal</c>.</p> </section> diff --git a/system/doc/design_principles/appup_cookbook.xml b/system/doc/design_principles/appup_cookbook.xml index 70c34a5a06..63adea8a5c 100644 --- a/system/doc/design_principles/appup_cookbook.xml +++ b/system/doc/design_principles/appup_cookbook.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2003</year><year>2013</year> + <year>2003</year><year>2014</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -28,15 +28,15 @@ <rev></rev> <file>appup_cookbook.xml</file> </header> - <p>This chapter contains examples of <c>.appup</c> files for - typical cases of upgrades/downgrades done in run-time.</p> + <marker id="appup cookbook"></marker> + <p>This section includes examples of <c>.appup</c> files for + typical cases of upgrades/downgrades done in runtime.</p> <section> <title>Changing a Functional Module</title> - <p>When a change has been made to a functional module, for example + <p>When a functional module has been changed, for example, if a new function has been added or a bug has been corrected, - simple code replacement is sufficient.</p> - <p>Example:</p> + simple code replacement is sufficient, for example:</p> <code type="none"> {"2", [{"1", [{load_module, m}]}], @@ -46,29 +46,31 @@ <section> <title>Changing a Residence Module</title> - <p>In a system implemented according to the OTP Design Principles, + <p>In a system implemented according to the OTP design principles, all processes, except system processes and special processes, reside in one of the behaviours <c>supervisor</c>, - <c>gen_server</c>, <c>gen_fsm</c> or <c>gen_event</c>. These + <c>gen_server</c>, <c>gen_fsm</c>, or <c>gen_event</c>. These belong to the STDLIB application and upgrading/downgrading normally requires an emulator restart.</p> - <p>OTP thus provides no support for changing residence modules - except in the case of <seealso marker="#spec">special processes</seealso>.</p> + <p>OTP thus provides no support for changing residence modules except + in the case of <seealso marker="#spec">special processes</seealso>.</p> </section> <section> <title>Changing a Callback Module</title> - <p>A callback module is a functional module, and for code + <p>A callback module is a functional module, and for code extensions simple code replacement is sufficient.</p> - <p>Example: When adding a function to <c>ch3</c> as described in - the example in <seealso marker="release_handling#appup">Release Handling</seealso>, <c>ch_app.appup</c> looks as follows:</p> + <p><em>Example:</em> When adding a function to <c>ch3</c>, + as described in the example in + <seealso marker="release_handling#appup">Release Handling</seealso>, + <c>ch_app.appup</c> looks as follows:</p> <code type="none"> {"2", [{"1", [{load_module, ch3}]}], [{"1", [{load_module, ch3}]}] }.</code> <p>OTP also supports changing the internal state of behaviour - processes, see <seealso marker="#int_state">Changing Internal State</seealso> below.</p> + processes, see <seealso marker="#int_state">Changing Internal State</seealso>.</p> </section> <section> @@ -77,26 +79,28 @@ <p>In this case, simple code replacement is not sufficient. The process must explicitly transform its state using the callback function <c>code_change</c> before switching to the new version - of the callback module. Thus synchronized code replacement is + of the callback module. Thus, synchronized code replacement is used.</p> - <p>Example: Consider the gen_server <c>ch3</c> from the chapter - about the <seealso marker="gen_server_concepts#ex">gen_server behaviour</seealso>. The internal state is a term <c>Chs</c> - representing the available channels. Assume we want add a counter - <c>N</c> which keeps track of the number of <c>alloc</c> requests - so far. This means we need to change the format to + <p><em>Example:</em> Consider <c>gen_server</c> <c>ch3</c> from + <seealso marker="gen_server_concepts#ex">gen_server Behaviour</seealso>. + The internal state is a term <c>Chs</c> + representing the available channels. Assume you want to add a counter + <c>N</c>, which keeps track of the number of <c>alloc</c> requests + so far. This means that the format must be changed to <c>{Chs,N}</c>.</p> - <p>The <c>.appup</c> file could look as follows:</p> + <p>The <c>.appup</c> file can look as follows:</p> <code type="none"> {"2", [{"1", [{update, ch3, {advanced, []}}]}], [{"1", [{update, ch3, {advanced, []}}]}] }.</code> <p>The third element of the <c>update</c> instruction is a tuple - <c>{advanced,Extra}</c> which says that the affected processes - should do a state transformation before loading the new version + <c>{advanced,Extra}</c>, which says that the affected processes + are to do a state transformation before loading the new version of the module. This is done by the processes calling the callback - function <c>code_change</c> (see <c>gen_server(3)</c>). The term - <c>Extra</c>, in this case [], is passed as-is to the function:</p> + function <c>code_change</c> (see the <c>gen_server(3)</c> manual + page in STDLIB). The term <c>Extra</c>, in this case + <c>[]</c>, is passed as is to the function:</p> <marker id="code_change"></marker> <code type="none"> -module(ch3). @@ -107,40 +111,41 @@ code_change({down, _Vsn}, {Chs, N}, _Extra) -> {ok, Chs}; code_change(_Vsn, Chs, _Extra) -> {ok, {Chs, 0}}.</code> - <p>The first argument is <c>{down,Vsn}</c> in case of a downgrade, - or <c>Vsn</c> in case of an upgrade. The term <c>Vsn</c> is - fetched from the 'original' version of the module, i.e. - the version we are upgrading from, or downgrading to.</p> + <p>The first argument is <c>{down,Vsn}</c> if there is a downgrade, + or <c>Vsn</c> if there is a upgrade. The term <c>Vsn</c> is + fetched from the 'original' version of the module, that is, + the version you are upgrading from, or downgrading to.</p> <p>The version is defined by the module attribute <c>vsn</c>, if any. There is no such attribute in <c>ch3</c>, so in this case - the version is the checksum (a huge integer) of the BEAM file, an - uninteresting value which is ignored.</p> - <p>(The other callback functions of <c>ch3</c> need to be modified - as well and perhaps a new interface function added, this is not - shown here).</p> + the version is the checksum (a huge integer) of the beam file, an + uninteresting value, which is ignored.</p> + <p>The other callback functions of <c>ch3</c> must also be modified + and perhaps a new interface function must be added, but this is not + shown here.</p> </section> <section> <title>Module Dependencies</title> - <p>Assume we extend a module by adding a new interface function, as - in the example in <seealso marker="release_handling#appup">Release Handling</seealso>, where a function <c>available/0</c> is - added to <c>ch3</c>.</p> - <p>If we also add a call to this function, say in the module - <c>m1</c>, a run-time error could occur during release upgrade if + <p>Assume that a module is extended by adding an interface function, + as in the example in + <seealso marker="release_handling#appup">Release Handling</seealso>, + where a function <c>available/0</c> is added to <c>ch3</c>.</p> + <p>If a call is added to this function, say in module + <c>m1</c>, a runtime error could can occur during release upgrade if the new version of <c>m1</c> is loaded first and calls <c>ch3:available/0</c> before the new version of <c>ch3</c> is loaded.</p> - <p>Thus, <c>ch3</c> must be loaded before <c>m1</c> is, in - the upgrade case, and vice versa in the downgrade case. We say - that <c>m1</c><em>is dependent on</em><c>ch3</c>. In a release - handling instruction, this is expressed by the element - <c>DepMods</c>:</p> + <p>Thus, <c>ch3</c> must be loaded before <c>m1</c>, in + the upgrade case, and conversely in the downgrade case. + <c>m1</c> is said to be <em>dependent on</em> <c>ch3</c>. In a release + handling instruction, this is expressed by the + <c>DepMods</c> element:</p> <code type="none"> {load_module, Module, DepMods} {update, Module, {advanced, Extra}, DepMods}</code> <p><c>DepMods</c> is a list of modules, on which <c>Module</c> is dependent.</p> - <p>Example: The module <c>m1</c> in the application <c>myapp</c> is + <p><em>Example:</em> The module <c>m1</c> in application <c>myapp</c> is dependent on <c>ch3</c> when upgrading from "1" to "2", or downgrading from "2" to "1":</p> <code type="none"> @@ -157,8 +162,8 @@ ch_app.appup: [{"1", [{load_module, ch3}]}], [{"1", [{load_module, ch3}]}] }.</code> - <p>If <c>m1</c> and <c>ch3</c> had belonged to the same application, - the <c>.appup</c> file could have looked like this:</p> + <p>If instead <c>m1</c> and <c>ch3</c> belong to the same application, + the <c>.appup</c> file can look as follows:</p> <code type="none"> {"2", [{"1", @@ -168,48 +173,48 @@ ch_app.appup: [{load_module, ch3}, {load_module, m1, [ch3]}]}] }.</code> - <p>Note that it is <c>m1</c> that is dependent on <c>ch3</c> also + <p><c>m1</c> is dependent on <c>ch3</c> also when downgrading. <c>systools</c> knows the difference between - up- and downgrading and will generate a correct <c>relup</c>, - where <c>ch3</c> is loaded before <c>m1</c> when upgrading but + up- and downgrading and generates a correct <c>relup</c>, + where <c>ch3</c> is loaded before <c>m1</c> when upgrading, but <c>m1</c> is loaded before <c>ch3</c> when downgrading.</p> </section> <section> <marker id="spec"></marker> - <title>Changing Code For a Special Process</title> + <title>Changing Code for a Special Process</title> <p>In this case, simple code replacement is not sufficient. When a new version of a residence module for a special process is loaded, the process must make a fully qualified call to - its loop function to switch to the new code. Thus synchronized + its loop function to switch to the new code. Thus, synchronized code replacement must be used.</p> <note> <p>The name(s) of the user-defined residence module(s) must be listed in the <c>Modules</c> part of the child specification - for the special process, in order for the release handler to + for the special process. Otherwise the release handler cannot find the process.</p> </note> - <p>Example. Consider the example <c>ch4</c> from the chapter about + <p><em>Example:</em> Consider the example <c>ch4</c> in <seealso marker="spec_proc#ex">sys and proc_lib</seealso>. - When started by a supervisor, the child specification could look - like this:</p> + When started by a supervisor, the child specification can look + as follows:</p> <code type="none"> {ch4, {ch4, start_link, []}, permanent, brutal_kill, worker, [ch4]}</code> <p>If <c>ch4</c> is part of the application <c>sp_app</c> and a new - version of the module should be loaded when upgrading from - version "1" to "2" of this application, <c>sp_app.appup</c> could - look like this:</p> + version of the module is to be loaded when upgrading from + version "1" to "2" of this application, <c>sp_app.appup</c> can + look as follows:</p> <code type="none"> {"2", [{"1", [{update, ch4, {advanced, []}}]}], [{"1", [{update, ch4, {advanced, []}}]}] }.</code> <p>The <c>update</c> instruction must contain the tuple - <c>{advanced,Extra}</c>. The instruction will make the special + <c>{advanced,Extra}</c>. The instruction makes the special process call the callback function <c>system_code_change/4</c>, a function the user must implement. The term <c>Extra</c>, in this - case [], is passed as-is to <c>system_code_change/4</c>:</p> + case <c>[]</c>, is passed as is to <c>system_code_change/4</c>:</p> <code type="none"> -module(ch4). ... @@ -218,39 +223,43 @@ ch_app.appup: system_code_change(Chs, _Module, _OldVsn, _Extra) -> {ok, Chs}.</code> - <p>The first argument is the internal state <c>State</c> passed from - the function <c>sys:handle_system_msg(Request, From, Parent, Module, Deb, State)</c>, called by the special process when - a system message is received. In <c>ch4</c>, the internal state is - the set of available channels <c>Chs</c>.</p> - <p>The second argument is the name of the module (<c>ch4</c>).</p> - <p>The third argument is <c>Vsn</c> or <c>{down,Vsn}</c> as - described for - <seealso marker="#code_change">gen_server:code_change/3</seealso>.</p> + <list type="bulleted"> + <item>The first argument is the internal state <c>State</c>, + passed from function + <c>sys:handle_system_msg(Request, From, Parent, Module, Deb, State)</c>, + and called by the special process when a system message is received. + In <c>ch4</c>, the internal state is the set of available channels + <c>Chs</c>.</item> + <item>The second argument is the name of the module + (<c>ch4</c>).</item> + <item>The third argument is <c>Vsn</c> or <c>{down,Vsn}</c>, as + described for <c>gen_server:code_change/3</c> in + <seealso marker="#code_change">Changing Internal State</seealso>.</item> + </list> <p>In this case, all arguments but the first are ignored and the function simply returns the internal state again. This is - enough if the code only has been extended. If we had wanted to - change the internal state (similar to the example in + enough if the code only has been extended. If instead the + internal state is changed (similar to the example in <seealso marker="#int_state">Changing Internal State</seealso>), - it would have been done in this function and - <c>{ok,Chs2}</c> returned.</p> + this is done in this function and <c>{ok,Chs2}</c> returned.</p> </section> <section> <marker id="sup"></marker> <title>Changing a Supervisor</title> <p>The supervisor behaviour supports changing the internal state, - i.e. changing restart strategy and maximum restart frequency - properties, as well as changing existing child specifications.</p> - <p>Adding and deleting child processes are also possible, but not + that is, changing the restart strategy and maximum restart frequency + properties, as well as changing the existing child specifications.</p> + <p>Child processes can be added or deleted, but this is not handled automatically. Instructions must be given by in the <c>.appup</c> file.</p> <section> <title>Changing Properties</title> - <p>Since the supervisor should change its internal state, + <p>Since the supervisor is to change its internal state, synchronized code replacement is required. However, a special <c>update</c> instruction must be used.</p> - <p>The new version of the callback module must be loaded first + <p>First, the new version of the callback module must be loaded, both in the case of upgrade and downgrade. Then the new return value of <c>init/1</c> can be checked and the internal state be changed accordingly.</p> @@ -258,16 +267,17 @@ system_code_change(Chs, _Module, _OldVsn, _Extra) -> supervisors:</p> <code type="none"> {update, Module, supervisor}</code> - <p>Example: Assume we want to change the restart strategy of - <c>ch_sup</c> from the <seealso marker="sup_princ#ex">Supervisor Behaviour</seealso> chapter from one_for_one to one_for_all. - We change the callback function <c>init/1</c> in - <c>ch_sup.erl</c>:</p> + <p><em>Example:</em> To change the restart strategy of + <c>ch_sup</c> (from + <seealso marker="sup_princ#ex">Supervisor Behaviour</seealso>) + from <c>one_for_one</c> to <c>one_for_all</c>, change the callback + function <c>init/1</c> in <c>ch_sup.erl</c>:</p> <code type="none"> -module(ch_sup). ... init(_Args) -> - {ok, {{one_for_all, 1, 60}, ...}}.</code> + {ok, {#{strategy => one_for_all, ...}, ...}}.</code> <p>The file <c>ch_app.appup</c>:</p> <code type="none"> {"2", @@ -280,7 +290,7 @@ init(_Args) -> <title>Changing Child Specifications</title> <p>The instruction, and thus the <c>.appup</c> file, when changing an existing child specification, is the same as when - changing properties as described above:</p> + changing properties as described earlier:</p> <code type="none"> {"2", [{"1", [{update, ch_sup, supervisor}]}], @@ -288,25 +298,25 @@ init(_Args) -> }.</code> <p>The changes do not affect existing child processes. For example, changing the start function only specifies how - the child process should be restarted, if needed later on.</p> - <p>Note that the id of the child specification cannot be changed.</p> - <p>Note also that changing the <c>Modules</c> field of the child - specification may affect the release handling process itself, + the child process is to be restarted, if needed later on.</p> + <p>The id of the child specification cannot be changed.</p> + <p>Changing the <c>Modules</c> field of the child + specification can affect the release handling process itself, as this field is used to identify which processes are affected when doing a synchronized code replacement.</p> </section> <marker id="sup_add"></marker> <section> - <title>Adding And Deleting Child Processes</title> - <p>As stated above, changing child specifications does not affect + <title>Adding and Deleting Child Processes</title> + <p>As stated earlier, changing child specifications does not affect existing child processes. New child specifications are - automatically added, but not deleted. Also, child processes are - not automatically started or terminated. Instead, this must be - done explicitly using <c>apply</c> instructions.</p> - <p>Example: Assume we want to add a new child process <c>m1</c> to - <c>ch_sup</c> when upgrading <c>ch_app</c> from "1" to "2". - This means <c>m1</c> should be deleted when downgrading from + automatically added, but not deleted. Child processes are + not automatically started or terminated, this must be + done using <c>apply</c> instructions.</p> + <p><em>Example:</em> Assume a new child process <c>m1</c> is to be + added to <c>ch_sup</c> when upgrading <c>ch_app</c> from "1" to "2". + This means <c>m1</c> is to be deleted when downgrading from "2" to "1":</p> <code type="none"> {"2", @@ -320,13 +330,13 @@ init(_Args) -> {update, ch_sup, supervisor} ]}] }.</code> - <p>Note that the order of the instructions is important.</p> - <p>Note also that the supervisor must be registered as + <p>The order of the instructions is important.</p> + <p>The supervisor must be registered as <c>ch_sup</c> for the script to work. If the supervisor is not registered, it cannot be accessed directly from the script. Instead a help function that finds the pid of the supervisor - and calls <c>supervisor:restart_child</c> etc. must be written, - and it is this function that should be called from the script + and calls <c>supervisor:restart_child</c>, and so on, must be + written. This function is then to be called from the script using the <c>apply</c> instruction.</p> <p>If the module <c>m1</c> is introduced in version "2" of <c>ch_app</c>, it must also be loaded when upgrading and @@ -345,18 +355,18 @@ init(_Args) -> {delete_module, m1} ]}] }.</code> - <p>Note again that the order of the instructions is important. - When upgrading, <c>m1</c> must be loaded and the supervisor's + <p>As stated earlier, the order of the instructions is important. + When upgrading, <c>m1</c> must be loaded, and the supervisor child specification changed, before the new child process can be started. When downgrading, the child process must be - terminated before child specification is changed and the module + terminated before the child specification is changed and the module is deleted.</p> </section> </section> <section> <title>Adding or Deleting a Module</title> - <p>Example: A new functional module <c>m</c> is added to + <p><em>Example:</em> A new functional module <c>m</c> is added to <c>ch_app</c>:</p> <code type="none"> {"2", @@ -367,15 +377,16 @@ init(_Args) -> <section> <title>Starting or Terminating a Process</title> <p>In a system structured according to the OTP design principles, - any process would be a child process belonging to a supervisor, - see <seealso marker="#sup_add">Adding and Deleting Child Processes</seealso> above.</p> + any process would be a child process belonging to a supervisor, see + <seealso marker="#sup_add">Adding and Deleting Child Processes</seealso> + in Changing a Supervisor.</p> </section> <section> <title>Adding or Removing an Application</title> <p>When adding or removing an application, no <c>.appup</c> file is needed. When generating <c>relup</c>, the <c>.rel</c> files - are compared and <c>add_application</c> and + are compared and the <c>add_application</c> and <c>remove_application</c> instructions are added automatically.</p> </section> @@ -383,11 +394,11 @@ init(_Args) -> <title>Restarting an Application</title> <p>Restarting an application is useful when a change is too complicated to be made without restarting the processes, for - example if the supervisor hierarchy has been restructured.</p> - <p>Example: When adding a new child <c>m1</c> to <c>ch_sup</c>, as - in the <seealso marker="#sup_add">example above</seealso>, an - alternative to updating the supervisor is to restart the entire - application:</p> + example, if the supervisor hierarchy has been restructured.</p> + <p><em>Example:</em> When adding a child <c>m1</c> to <c>ch_sup</c>, as in + <seealso marker="#sup_add">Adding and Deleting Child Processes</seealso> + in Changing a Supervisor, an alternative to updating + the supervisor is to restart the entire application:</p> <code type="none"> {"2", [{"1", [{restart_application, ch_app}]}], @@ -400,7 +411,7 @@ init(_Args) -> <title>Changing an Application Specification</title> <p>When installing a release, the application specifications are automatically updated before evaluating the <c>relup</c> script. - Hence, no instructions are needed in the <c>.appup</c> file:</p> + Thus, no instructions are needed in the <c>.appup</c> file:</p> <pre> {"2", [{"1", []}], @@ -412,28 +423,29 @@ init(_Args) -> <title>Changing Application Configuration</title> <p>Changing an application configuration by updating the <c>env</c> key in the <c>.app</c> file is an instance of changing an - application specification, <seealso marker="#app_spec">see above</seealso>.</p> + application specification, see the previous section.</p> <p>Alternatively, application configuration parameters can be added or updated in <c>sys.config</c>.</p> </section> <section> <title>Changing Included Applications</title> - <p>The release handling instructions for adding, removing and + <p>The release handling instructions for adding, removing, and restarting applications apply to primary applications only. There are no corresponding instructions for included applications. However, since an included application is really a supervision tree with a topmost supervisor, started as a child process to a supervisor in the including application, a <c>relup</c> file can be manually created.</p> - <p>Example: Assume we have a release containing an application - <c>prim_app</c> which have a supervisor <c>prim_sup</c> in its + <p><em>Example:</em> Assume there is a release containing an application + <c>prim_app</c>, which have a supervisor <c>prim_sup</c> in its supervision tree.</p> - <p>In a new version of the release, our example application - <c>ch_app</c> should be included in <c>prim_app</c>. That is, - its topmost supervisor <c>ch_sup</c> should be started as a child + <p>In a new version of the release, the application <c>ch_app</c> + is to be included in <c>prim_app</c>. That is, + its topmost supervisor <c>ch_sup</c> is to be started as a child process to <c>prim_sup</c>.</p> - <p>1) Edit the code for <c>prim_sup</c>:</p> + <p>The workflow is as follows:</p> + <p><em>Step 1)</em> Edit the code for <c>prim_sup</c>:</p> <code type="none"> init(...) -> {ok, {...supervisor flags..., @@ -441,7 +453,7 @@ init(...) -> {ch_sup, {ch_sup,start_link,[]}, permanent,infinity,supervisor,[ch_sup]}, ...]}}.</code> - <p>2) Edit the <c>.app</c> file for <c>prim_app</c>:</p> + <p><em>Step 2)</em> Edit the <c>.app</c> file for <c>prim_app</c>:</p> <code type="none"> {application, prim_app, [..., @@ -450,27 +462,29 @@ init(...) -> {included_applications, [ch_app]}, ... ]}.</code> - <p>3) Create a new <c>.rel</c> file, including <c>ch_app</c>:</p> + <p><em>Step 3)</em> Create a new <c>.rel</c> file, including + <c>ch_app</c>:</p> <code type="none"> {release, ..., [..., {prim_app, "2"}, {ch_app, "1"}]}.</code> + <p>The included application can be started in two ways. + This is described in the next two sections.</p> <section> <title>Application Restart</title> - <p>4a) One way to start the included application is to restart - the entire <c>prim_app</c> application. Normally, we would then - use the <c>restart_application</c> instruction in - the <c>.appup</c> file for <c>prim_app</c>.</p> - <p>However, if we did this and then generated a <c>relup</c> file, - not only would it contain instructions for restarting (i.e. + <p><em>Step 4a)</em> One way to start the included application is to + restart the entire <c>prim_app</c> application. Normally, the + <c>restart_application</c> instruction in the <c>.appup</c> file + for <c>prim_app</c> would be used.</p> + <p>However, if this is done and a <c>relup</c> file is generated, + not only would it contain instructions for restarting (that is, removing and adding) <c>prim_app</c>, it would also contain instructions for starting <c>ch_app</c> (and stopping it, in - the case of downgrade). This is due to the fact that - <c>ch_app</c> is included in the new <c>.rel</c> file, but not - in the old one.</p> + the case of downgrade). This is because <c>ch_app</c> is included + in the new <c>.rel</c> file, but not in the old one.</p> <p>Instead, a correct <c>relup</c> file can be created manually, either from scratch or by editing the generated version. The instructions for starting/stopping <c>ch_app</c> are @@ -512,7 +526,8 @@ init(...) -> <section> <title>Supervisor Change</title> - <p>4b) Another way to start the included application (or stop it + <p><em>Step 4b)</em> Another way to start the included + application (or stop it in the case of downgrade) is by combining instructions for adding and removing child processes to/from <c>prim_sup</c> with instructions for loading/unloading all <c>ch_app</c> code and @@ -521,7 +536,7 @@ init(...) -> scratch or by editing a generated version. Load all code for <c>ch_app</c> first, and also load the application specification, before <c>prim_sup</c> is updated. When - downgrading, <c>prim_sup</c> should be updated first, before + downgrading, <c>prim_sup</c> is to updated first, before the code for <c>ch_app</c> and its application specification are unloaded.</p> <code type="none"> @@ -560,10 +575,10 @@ init(...) -> <section> <title>Changing Non-Erlang Code</title> <p>Changing code for a program written in another programming - language than Erlang, for example a port program, is very - application dependent and OTP provides no special support for it.</p> - <p>Example, changing code for a port program: Assume that - the Erlang process controlling the port is a gen_server + language than Erlang, for example, a port program, is + application-dependent and OTP provides no special support for it.</p> + <p><em>Example:</em> When changing code for a port program, assume that + the Erlang process controlling the port is a <c>gen_server</c> <c>portc</c> and that the port is opened in the callback function <c>init/1</c>:</p> <code type="none"> @@ -573,10 +588,11 @@ init(...) -> Port = open_port({spawn,PortPrg}, [...]), ..., {ok, #state{port=Port, ...}}.</code> - <p>If the port program should be updated, we can extend the code for - the gen_server with a <c>code_change</c> function which closes - the old port and opens a new port. (If necessary, the gen_server - may first request data that needs to be saved from the port + <p>If the port program is to be updated, the code for the + <c>gen_server</c> can be extended with a <c>code_change</c> function, + which closes the old port and opens a new port. + (If necessary, the <c>gen_server</c> can + first request data that must be saved from the port program and pass this data to the new port):</p> <code type="none"> code_change(_OldVsn, State, port) -> @@ -595,8 +611,8 @@ code_change(_OldVsn, State, port) -> [{"1", [{update, portc, {advanced,port}}]}], [{"1", [{update, portc, {advanced,port}}]}] ].</code> - <p>Make sure the <c>priv</c> directory where the C program is - located is included in the new release package:</p> + <p>Ensure that the <c>priv</c> directory, where the C program is + located, is included in the new release package:</p> <pre> 1> <input>systools:make_tar("my_release", [{dirs,[priv]}]).</input> ...</pre> @@ -604,28 +620,29 @@ code_change(_OldVsn, State, port) -> <section> <title>Emulator Restart and Upgrade</title> - <p>There are two upgrade instructions that will restart the emulator:</p> - <taglist> - <tag><c>restart_new_emulator</c></tag> - <item>Intended for when erts, kernel, stdlib or sasl is - upgraded. It is automatically added when the relup file is - generated by <c>systools:make_relup/3,4</c>. It is executed - before all other upgrade instructions. See - <seealso marker="release_handling#restart_new_emulator_instr">Release - Handling</seealso> for more information about this - instruction.</item> - <tag><c>restart_emulator</c></tag> - <item>Used when a restart of the emulator is required after all - other upgrade instructions are executed. See - <seealso marker="release_handling#restart_emulator_instr">Release - Handling</seealso> for more information about this - instruction.</item> - </taglist> - + <p>Two upgrade instructions restart the emulator:</p> + <list type="bulleted"> + <item><p><c>restart_new_emulator</c></p> + <p>Intended when ERTS, Kernel, STDLIB, or + SASL is upgraded. It is automatically added when the + <c>relup</c> file is generated by <c>systools:make_relup/3,4</c>. + It is executed before all other upgrade instructions. + For more information about this instruction, see + restart_new_emulator (Low-Level) in + <seealso marker="release_handling#restart_new_emulator_instr">Release Handling Instructions</seealso>. + </p></item> + <item><p><c>restart_emulator</c></p> + <p>Used when a restart of the emulator is required after all + other upgrade instructions are executed. + For more information about this instruction, see + restart_emulator (Low-Level) in + <seealso marker="release_handling#restart_emulator_instr">Release Handling Instructions</seealso>. + </p></item> + </list> <p>If an emulator restart is necessary and no upgrade instructions - are needed, i.e. if the restart itself is enough for the - upgraded applications to start running the new versions, a very - simple <c>.relup</c> file can be created manually:</p> + are needed, that is, if the restart itself is enough for the + upgraded applications to start running the new versions, a + simple <c>relup</c> file can be created manually:</p> <code type="none"> {"B", [{"A", @@ -637,26 +654,27 @@ code_change(_OldVsn, State, port) -> }.</code> <p>In this case, the release handler framework with automatic packing and unpacking of release packages, automatic path - updates etc. can be used without having to specify <c>.appup</c> - files.</p> + updates, and so on, can be used without having to specify + <c>.appup</c> files.</p> </section> <section> - <title>Emulator Upgrade from pre OTP R15</title> + <title>Emulator Upgrade From Pre OTP R15</title> <p>From OTP R15, an emulator upgrade is performed by restarting the emulator with new versions of the core applications - (<c>kernel</c>, <c>stdlib</c> and <c>sasl</c>) before loading code + (Kernel, STDLIB, and SASL) before loading code and running upgrade instruction for other applications. For this - to work, the release to upgrade from must includes OTP R15 or - later. For the case where the release to upgrade from includes an - earlier emulator version, <c>systools:make_relup</c> will create a + to work, the release to upgrade from must include OTP R15 or + later.</p> + <p>For the case where the release to upgrade from includes an + earlier emulator version, <c>systools:make_relup</c> creates a backwards compatible relup file. This means that all upgrade - instructions will be executed before the emulator is - restarted. The new application code will therefore be loaded into + instructions are executed before the emulator is + restarted. The new application code is therefore loaded into the old emulator. If the new code is compiled with the new - emulator, there might be cases where the beam format has changed - and beam files can not be loaded. To overcome this problem, the - new code should be compiled with the old emulator.</p> + emulator, there can be cases where the beam format has changed + and beam files cannot be loaded. To overcome this problem, compile + the new code with the old emulator.</p> </section> </chapter> diff --git a/system/doc/design_principles/des_princ.xml b/system/doc/design_principles/des_princ.xml index e8f289b905..77c61eafb0 100644 --- a/system/doc/design_principles/des_princ.xml +++ b/system/doc/design_principles/des_princ.xml @@ -28,50 +28,52 @@ <rev></rev> <file>des_princ.xml</file> </header> - <p>The <em>OTP Design Principles</em> is a set of principles for how - to structure Erlang code in terms of processes, modules and - directories.</p> + <marker id="otp design principles"></marker> + <p>The <em>OTP design principles</em> define how to + structure Erlang code in terms of processes, modules, + and directories.</p> <section> <title>Supervision Trees</title> <p>A basic concept in Erlang/OTP is the <em>supervision tree</em>. This is a process structuring model based on the idea of - <em>workers</em> and <em>supervisors</em>.</p> + <em>workers</em> and <em>supervisors</em>:</p> <list type="bulleted"> - <item>Workers are processes which perform computations, that is, + <item>Workers are processes that perform computations, that is, they do the actual work.</item> - <item>Supervisors are processes which monitor the behaviour of + <item>Supervisors are processes that monitor the behaviour of workers. A supervisor can restart a worker if something goes wrong.</item> <item>The supervision tree is a hierarchical arrangement of - code into supervisors and workers, making it possible to + code into supervisors and workers, which makes it possible to design and program fault-tolerant software.</item> </list> + <p>In the following figure, square boxes represents supervisors and + circles represent workers:</p> <marker id="sup6"></marker> <image file="../design_principles/sup6.gif"> <icaption>Supervision Tree</icaption> </image> - <p>In the figure above, square boxes represents supervisors and - circles represent workers.</p> </section> <section> <title>Behaviours</title> <p>In a supervision tree, many of the processes have similar structures, they follow similar patterns. For example, - the supervisors are very similar in structure. The only difference - between them is which child processes they supervise. Also, many - of the workers are servers in a server-client relation, finite - state machines, or event handlers such as error loggers.</p> + the supervisors are similar in structure. The only difference + between them is which child processes they supervise. Many + of the workers are servers in a server-client relation, + finite-state machines, or event handlers such as error loggers.</p> <p><em>Behaviours</em> are formalizations of these common patterns. The idea is to divide the code for a process in a generic part - (a behaviour module) and a specific part (a <em>callback module</em>).</p> + (a behaviour module) and a specific part (a + <em>callback module</em>).</p> <p>The behaviour module is part of Erlang/OTP. To implement a process such as a supervisor, the user only has to implement - the callback module which should export a pre-defined set of + the callback module which is to export a pre-defined set of functions, the <em>callback functions</em>.</p> - <p>An example to illustrate how code can be divided into a generic - and a specific part: Consider the following code (written in + <p>The following example illustrate how code can be divided into a + generic and a specific part. Consider the following code (written in plain Erlang) for a simple server, which keeps track of a number of "channels". Other processes can allocate and free the channels by calling the functions <c>alloc/0</c> and <c>free/1</c>, @@ -149,7 +151,7 @@ loop(Mod, State) -> State2 = Mod:handle_cast(Req, State), loop(Mod, State2) end.</code> - <p>and a callback module <c>ch2.erl</c>:</p> + <p>And a callback module <c>ch2.erl</c>:</p> <code type="none"> -module(ch2). -export([start/0]). @@ -173,27 +175,27 @@ handle_call(alloc, Chs) -> handle_cast({free, Ch}, Chs) -> free(Ch, Chs). % => Chs2</code> - <p>Note the following:</p> + <p>Notice the following:</p> <list type="bulleted"> - <item>The code in <c>server</c> can be re-used to build many + <item>The code in <c>server</c> can be reused to build many different servers.</item> - <item>The name of the server, in this example the atom - <c>ch2</c>, is hidden from the users of the client functions. - This means the name can be changed without affecting them.</item> + <item>The server name, in this example the atom + <c>ch2</c>, is hidden from the users of the client functions. This + means that the name can be changed without affecting them.</item> <item>The protcol (messages sent to and received from the server) - is hidden as well. This is good programming practice and allows - us to change the protocol without making changes to code using + is also hidden. This is good programming practice and allows + one to change the protocol without changing the code using the interface functions.</item> - <item>We can extend the functionality of <c>server</c>, without + <item>The functionality of <c>server</c> can be extended without having to change <c>ch2</c> or any other callback module.</item> </list> - <p>(In <c>ch1.erl</c> and <c>ch2.erl</c> above, the implementation - of <c>channels/0</c>, <c>alloc/1</c> and <c>free/2</c> has been + <p>In <c>ch1.erl</c> and <c>ch2.erl</c> above, the implementation + of <c>channels/0</c>, <c>alloc/1</c>, and <c>free/2</c> has been intentionally left out, as it is not relevant to the example. For completeness, one way to write these functions are given - below. Note that this is an example only, a realistic + below. This is an example only, a realistic implementation must be able to handle situations like running out - of channels to allocate etc.)</p> + of channels to allocate, and so on.</p> <code type="none"> channels() -> {_Allocated = [], _Free = lists:seq(1,100)}. @@ -208,30 +210,30 @@ free(Ch, {Alloc, Free} = Channels) -> false -> Channels end. </code> - <p>Code written without making use of behaviours may be more - efficient, but the increased efficiency will be at the expense of + <p>Code written without using behaviours can be more + efficient, but the increased efficiency is at the expense of generality. The ability to manage all applications in the system - in a consistent manner is very important.</p> + in a consistent manner is important.</p> <p>Using behaviours also makes it easier to read and understand - code written by other programmers. Ad hoc programming structures, + code written by other programmers. Improvised programming structures, while possibly more efficient, are always more difficult to understand.</p> - <p>The module <c>server</c> corresponds, greatly simplified, + <p>The <c>server</c> module corresponds, greatly simplified, to the Erlang/OTP behaviour <c>gen_server</c>.</p> <p>The standard Erlang/OTP behaviours are:</p> - <taglist> - <tag><seealso marker="gen_server_concepts">gen_server</seealso></tag> - <item>For implementing the server of a client-server relation.</item> - <tag><seealso marker="fsm">gen_fsm</seealso></tag> - <item>For implementing finite state machines.</item> - <tag><seealso marker="events">gen_event</seealso></tag> - <item>For implementing event handling functionality.</item> - <tag><seealso marker="sup_princ">supervisor</seealso></tag> - <item>For implementing a supervisor in a supervision tree.</item> - </taglist> + <list type="bulleted"> + <item><p><seealso marker="gen_server_concepts">gen_server</seealso></p> + <p>For implementing the server of a client-server relation</p></item> + <item><p><seealso marker="fsm">gen_fsm</seealso></p> + <p>For implementing finite-state machines</p></item> + <item><p><seealso marker="events">gen_event</seealso></p> + <p>For implementing event handling functionality</p></item> + <item><p><seealso marker="sup_princ">supervisor</seealso></p> + <p>For implementing a supervisor in a supervision tree</p></item> + </list> <p>The compiler understands the module attribute <c>-behaviour(Behaviour)</c> and issues warnings about - missing callback functions. Example:</p> + missing callback functions, for example:</p> <code type="none"> -module(chs3). -behaviour(gen_server). @@ -248,13 +250,17 @@ free(Ch, {Alloc, Free} = Channels) -> some specific functionality. Components are with Erlang/OTP terminology called <em>applications</em>. Examples of Erlang/OTP applications are Mnesia, which has everything needed for - programming database services, and Debugger which is used to - debug Erlang programs. The minimal system based on Erlang/OTP - consists of the applications Kernel and STDLIB.</p> + programming database services, and Debugger, which is used + to debug Erlang programs. The minimal system based on Erlang/OTP + consists of the following two applications:</p> + <list type="bulleted"> + <item>Kernel - Functionality necessary to run Erlang</item> + <item>STDLIB - Erlang standard libraries</item> + </list> <p>The application concept applies both to program structure (processes) and directory structure (modules).</p> - <p>The simplest kind of application does not have any processes, - but consists of a collection of functional modules. Such an + <p>The simplest applications do not have any processes, + but consist of a collection of functional modules. Such an application is called a <em>library application</em>. An example of a library application is STDLIB.</p> <p>An application with processes is easiest implemented as a @@ -266,12 +272,11 @@ free(Ch, {Alloc, Free} = Channels) -> <section> <title>Releases</title> <p>A <em>release</em> is a complete system made out from a subset of - the Erlang/OTP applications and a set of user-specific - applications.</p> + Erlang/OTP applications and a set of user-specific applications.</p> <p>How to program releases is described in <seealso marker="release_structure">Releases</seealso>.</p> <p>How to install a release in a target environment is described - in the chapter about Target Systems in System Principles.</p> + in the section about target systems in Section 2 System Principles.</p> </section> <section> diff --git a/system/doc/design_principles/distributed_applications.xml b/system/doc/design_principles/distributed_applications.xml index 2886f06b53..f40a24fdf5 100644 --- a/system/doc/design_principles/distributed_applications.xml +++ b/system/doc/design_principles/distributed_applications.xml @@ -28,71 +28,73 @@ <rev></rev> <file>distributed_applications.xml</file> </header> + <marker id="distributed appl"></marker> <section> - <title>Definition</title> - <p>In a distributed system with several Erlang nodes, there may be - a need to control applications in a distributed manner. If + <title>Introduction</title> + <p>In a distributed system with several Erlang nodes, it can be + necessary to control applications in a distributed manner. If the node, where a certain application is running, goes down, - the application should be restarted at another node.</p> + the application is to be restarted at another node.</p> <p>Such an application is called a <em>distributed application</em>. - Note that it is the control of the application which is - distributed, all applications can of course be distributed in - the sense that they, for example, use services on other nodes.</p> - <p>Because a distributed application may move between nodes, some + Notice that it is the control of the application that is distributed. + All applications can be distributed in the sense that they, + for example, use services on other nodes.</p> + <p>Since a distributed application can move between nodes, some addressing mechanism is required to ensure that it can be addressed by other applications, regardless on which node it currently executes. This issue is not addressed here, but the - Kernel module <c>global</c> or STDLIB module <c>pg</c> can be - used for this purpose.</p> + <c>global</c> or <c>pg2</c> modules in Kernel + can be used for this purpose.</p> </section> <section> <title>Specifying Distributed Applications</title> <p>Distributed applications are controlled by both the application - controller and a distributed application controller process, - <c>dist_ac</c>. Both these processes are part of the <c>kernel</c> - application. Therefore, distributed applications are specified by - configuring the <c>kernel</c> application, using the following - configuration parameter (see also <c>kernel(6)</c>):</p> - <taglist> - <tag><c>distributed = [{Application, [Timeout,] NodeDesc}]</c></tag> - <item> - <p>Specifies where the application <c>Application = atom()</c> - may execute. <c>NodeDesc = [Node | {Node,...,Node}]</c> is - a list of node names in priority order. The order between - nodes in a tuple is undefined.</p> - <p><c>Timeout = integer()</c> specifies how many milliseconds to - wait before restarting the application at another node. - Defaults to 0.</p> - </item> - </taglist> + controller and a distributed application controller process, + <c>dist_ac</c>. Both these processes are part of the Kernel + application. Distributed applications are thus specified by + configuring the Kernel application, using the following + configuration parameter (see also <c>kernel(6)</c>):</p> + <p><c>distributed = [{Application, [Timeout,] NodeDesc}]</c></p> + <list type="bulleted"> + <item>Specifies where the application <c>Application = atom()</c> + can execute.</item> + <item>><c>NodeDesc = [Node | {Node,...,Node}]</c> is a list of + node names in priority order. The order between nodes in a tuple + is undefined.</item> + <item><c>Timeout = integer()</c> specifies how many milliseconds + to wait before restarting the application at another node. It + defaults to 0.</item> + </list> <p>For distribution of application control to work properly, - the nodes where a distributed application may run must contact + the nodes where a distributed application can run must contact each other and negotiate where to start the application. This is - done using the following <c>kernel</c> configuration parameters:</p> - <taglist> - <tag><c>sync_nodes_mandatory = [Node]</c></tag> - <item>Specifies which other nodes must be started (within - the timeout specified by <c>sync_nodes_timeout</c>.</item> - <tag><c>sync_nodes_optional = [Node]</c></tag> - <item>Specifies which other nodes can be started (within - the timeout specified by <c>sync_nodes_timeout</c>.</item> - <tag><c>sync_nodes_timeout = integer() | infinity</c></tag> - <item>Specifies how many milliseconds to wait for the other nodes - to start.</item> - </taglist> - <p>When started, the node will wait for all nodes specified by + done using the following configuration parameters in + Kernel:</p> + <list type="bulleted"> + <item><c>sync_nodes_mandatory = [Node]</c> - Specifies which + other nodes must be started (within the time-out specified by + <c>sync_nodes_timeout</c>).</item> + <item><c>sync_nodes_optional = [Node]</c> - Specifies which + other nodes can be started (within the time-out specified by + <c>sync_nodes_timeout</c>).</item> + <item><c>sync_nodes_timeout = integer() | infinity</c> - + Specifies how many milliseconds to wait for the other nodes to + start.</item> + </list> + <p>When started, the node waits for all nodes specified by <c>sync_nodes_mandatory</c> and <c>sync_nodes_optional</c> to - come up. When all nodes have come up, or when all mandatory nodes - have come up and the time specified by <c>sync_nodes_timeout</c> - has elapsed, all applications will be started. If not all - mandatory nodes have come up, the node will terminate.</p> - <p>Example: An application <c>myapp</c> should run at the node - <c>cp1@cave</c>. If this node goes down, <c>myapp</c> should + come up. When all nodes are up, or when all mandatory nodes + are up and the time specified by <c>sync_nodes_timeout</c> + has elapsed, all applications start. If not all + mandatory nodes are up, the node terminates.</p> + <p><em>Example:</em></p> + <p>An application <c>myapp</c> is to run at the node + <c>cp1@cave</c>. If this node goes down, <c>myapp</c> is to be restarted at <c>cp2@cave</c> or <c>cp3@cave</c>. A system - configuration file <c>cp1.config</c> for <c>cp1@cave</c> could - look like:</p> + configuration file <c>cp1.config</c> for <c>cp1@cave</c> can + look as follows:</p> <code type="none"> [{kernel, [{distributed, [{myapp, 5000, [cp1@cave, {cp2@cave, cp3@cave}]}]}, @@ -103,13 +105,13 @@ ].</code> <p>The system configuration files for <c>cp2@cave</c> and <c>cp3@cave</c> are identical, except for the list of mandatory - nodes which should be <c>[cp1@cave, cp3@cave]</c> for + nodes, which is to be <c>[cp1@cave, cp3@cave]</c> for <c>cp2@cave</c> and <c>[cp1@cave, cp2@cave]</c> for <c>cp3@cave</c>.</p> <note> <p>All involved nodes must have the same value for - <c>distributed</c> and <c>sync_nodes_timeout</c>, or - the behaviour of the system is undefined.</p> + <c>distributed</c> and <c>sync_nodes_timeout</c>. + Otherwise the system behaviour is undefined.</p> </note> </section> @@ -117,28 +119,29 @@ <title>Starting and Stopping Distributed Applications</title> <p>When all involved (mandatory) nodes have been started, the distributed application can be started by calling - <c>application:start(Application)</c> at <em>all of these nodes.</em></p> - <p>It is of course also possible to use a boot script (see - <seealso marker="release_structure">Releases</seealso>) which - automatically starts the application.</p> - <p>The application will be started at the first node, specified - by the <c>distributed</c> configuration parameter, which is up - and running. The application is started as usual. That is, an - application master is created and calls the application callback - function:</p> + <c>application:start(Application)</c> at <em>all of these + nodes.</em></p> + <p>A boot script (see + <seealso marker="release_structure">Releases</seealso>) + can be used that automatically starts the application.</p> + <p>The application is started at the first operational node that + is listed in the list of nodes in the <c>distributed</c> + configuration parameter. The application is started as usual. + That is, an application master is created and calls the + application callback function:</p> <code type="none"> Module:start(normal, StartArgs)</code> - <p>Example: Continuing the example from the previous section, - the three nodes are started, specifying the system configuration - file:</p> + <p>Example:</p> + <p>Continuing the example from the previous section, the three nodes + are started, specifying the system configuration file:</p> <pre> > <input>erl -sname cp1 -config cp1</input> > <input>erl -sname cp2 -config cp2</input> > <input>erl -sname cp3 -config cp3</input></pre> - <p>When all nodes are up and running, <c>myapp</c> can be started. + <p>When all nodes are operational, <c>myapp</c> can be started. This is achieved by calling <c>application:start(myapp)</c> at all three nodes. It is then started at <c>cp1</c>, as shown in - the figure below.</p> + the following figure:</p> <marker id="dist1"></marker> <image file="../design_principles/dist1.gif"> <icaption>Application myapp - Situation 1</icaption> @@ -150,31 +153,33 @@ Module:start(normal, StartArgs)</code> <section> <title>Failover</title> <p>If the node where the application is running goes down, - the application is restarted (after the specified timeout) at - the first node, specified by the <c>distributed</c> configuration - parameter, which is up and running. This is called a + the application is restarted (after the specified time-out) at + the first operational node that is listed in the list of nodes + in the <c>distributed</c> configuration parameter. This is called a <em>failover</em>.</p> <p>The application is started the normal way at the new node, that is, by the application master calling:</p> <code type="none"> Module:start(normal, StartArgs)</code> - <p>Exception: If the application has the <c>start_phases</c> key - defined (see <seealso marker="included_applications">Included Applications</seealso>), then the application is instead started - by calling:</p> + <p>An exception is if the application has the <c>start_phases</c> + key defined + (see <seealso marker="included_applications">Included Applications</seealso>). + The application is then instead started by calling:</p> <code type="none"> Module:start({failover, Node}, StartArgs)</code> - <p>where <c>Node</c> is the terminated node.</p> - <p>Example: If <c>cp1</c> goes down, the system checks which one of + <p>Here <c>Node</c> is the terminated node.</p> + <p><em>Example:</em></p> + <p> If <c>cp1</c> goes down, the system checks which one of the other nodes, <c>cp2</c> or <c>cp3</c>, has the least number of running applications, but waits for 5 seconds for <c>cp1</c> to restart. If <c>cp1</c> does not restart and <c>cp2</c> runs fewer - applications than <c>cp3,</c> then <c>myapp</c> is restarted on + applications than <c>cp3</c>, <c>myapp</c> is restarted on <c>cp2</c>.</p> <marker id="dist2"></marker> <image file="../design_principles/dist2.gif"> <icaption>Application myapp - Situation 2</icaption> </image> - <p>Suppose now that <c>cp2</c> goes down as well and does not + <p>Suppose now that <c>cp2</c> goes also down and does not restart within 5 seconds. <c>myapp</c> is now restarted on <c>cp3</c>.</p> <marker id="dist3"></marker> @@ -186,28 +191,29 @@ Module:start({failover, Node}, StartArgs)</code> <section> <title>Takeover</title> <p>If a node is started, which has higher priority according - to <c>distributed</c>, than the node where a distributed - application is currently running, the application will be - restarted at the new node and stopped at the old node. This is + to <c>distributed</c> than the node where a distributed + application is running, the application is restarted at the + new node and stopped at the old node. This is called a <em>takeover</em>.</p> <p>The application is started by the application master calling:</p> <code type="none"> Module:start({takeover, Node}, StartArgs)</code> - <p>where <c>Node</c> is the old node.</p> - <p>Example: If <c>myapp</c> is running at <c>cp3</c>, and if - <c>cp2</c> now restarts, it will not restart <c>myapp</c>, - because the order between nodes <c>cp2</c> and <c>cp3</c> is + <p>Here <c>Node</c> is the old node.</p> + <p><em>Example: </em></p> + <p>If <c>myapp</c> is running at <c>cp3</c>, and if + <c>cp2</c> now restarts, it does not restart <c>myapp</c>, + as the order between the <c>cp2</c> and <c>cp3</c> nodes is undefined.</p> <marker id="dist4"></marker> <image file="../design_principles/dist4.gif"> <icaption>Application myapp - Situation 4</icaption> </image> - <p>However, if <c>cp1</c> restarts as well, the function + <p>However, if <c>cp1</c> also restarts, the function <c>application:takeover/2</c> moves <c>myapp</c> to <c>cp1</c>, - because <c>cp1</c> has a higher priority than <c>cp3</c> for this - application. In this case, - <c>Module:start({takeover, cp3@cave}, StartArgs)</c> is executed - at <c>cp1</c> to start the application.</p> + as <c>cp1</c> has a higher priority than <c>cp3</c> for this + application. In this case, + <c>Module:start({takeover, cp3@cave}, StartArgs)</c> is + executed at <c>cp1</c> to start the application.</p> <marker id="dist5"></marker> <image file="../design_principles/dist5.gif"> <icaption>Application myapp - Situation 5</icaption> diff --git a/system/doc/design_principles/events.xml b/system/doc/design_principles/events.xml index 529e12c216..6e5afb939e 100644 --- a/system/doc/design_principles/events.xml +++ b/system/doc/design_principles/events.xml @@ -21,7 +21,7 @@ </legalnotice> - <title>Gen_Event Behaviour</title> + <title>gen_event Behaviour</title> <prepared></prepared> <docno></docno> <date></date> @@ -29,35 +29,36 @@ <file>events.xml</file> </header> <marker id="gen_event"></marker> - <p>This chapter should be read in conjunction with - <c>gen_event(3)</c>, where all interface functions and callback - functions are described in detail.</p> + <p>This section is to be read with the <c>gen_event(3)</c> manual + page in STDLIB, where all interface functions and callback + functions are described in detail.</p> <section> <title>Event Handling Principles</title> <p>In OTP, an <em>event manager</em> is a named object to which - events can be sent. An <em>event</em> could be, for example, - an error, an alarm or some information that should be logged.</p> - <p>In the event manager, zero, one or several <em>event handlers</em> are installed. When the event manager is notified - about an event, the event will be processed by all the installed + events can be sent. An <em>event</em> can be, for example, + an error, an alarm, or some information that is to be logged.</p> + <p>In the event manager, zero, one, or many <em>event handlers</em> + are installed. When the event manager is notified + about an event, the event is processed by all the installed event handlers. For example, an event manager for handling errors - can by default have a handler installed which writes error + can by default have a handler installed, which writes error messages to the terminal. If the error messages during a certain - period should be saved to a file as well, the user adds another - event handler which does this. When logging to file is no longer - necessary, this event handler is deleted.</p> + period is to be saved to a file as well, the user adds another + event handler that does this. When logging to the file is no + longer necessary, this event handler is deleted.</p> <p>An event manager is implemented as a process and each event handler is implemented as a callback module.</p> <p>The event manager essentially maintains a list of <c>{Module, State}</c> pairs, where each <c>Module</c> is an - event handler, and <c>State</c> the internal state of that event - handler.</p> + event handler, and <c>State</c> is the internal state of that + event handler.</p> </section> <section> <title>Example</title> <p>The callback module for the event handler writing error messages - to the terminal could look like:</p> + to the terminal can look as follows:</p> <code type="none"> -module(terminal_logger). -behaviour(gen_event). @@ -74,7 +75,7 @@ handle_event(ErrorMsg, State) -> terminate(_Args, _State) -> ok.</code> <p>The callback module for the event handler writing error messages - to a file could look like:</p> + to a file can look as follows:</p> <code type="none"> -module(file_logger). -behaviour(gen_event). @@ -98,29 +99,28 @@ terminate(_Args, Fd) -> <marker id="mgr"></marker> <title>Starting an Event Manager</title> <p>To start an event manager for handling errors, as described in - the example above, call the following function:</p> + the previous example, call the following function:</p> <code type="none"> gen_event:start_link({local, error_man})</code> <p>This function spawns and links to a new process, an event manager.</p> - <p>The argument, <c>{local, error_man}</c> specifies the name. In - this case, the event manager will be locally registered as - <c>error_man</c>.</p> + <p>The argument, <c>{local, error_man}</c> specifies the name. The + event manager is then locally registered as <c>error_man</c>.</p> <p>If the name is omitted, the event manager is not registered. - Instead its pid must be used. The name could also be given + Instead its pid must be used. The name can also be given as <c>{global, Name}</c>, in which case the event manager is registered using <c>global:register_name/2</c>.</p> <p><c>gen_event:start_link</c> must be used if the event manager is - part of a supervision tree, i.e. is started by a supervisor. - There is another function <c>gen_event:start</c> to start a - stand-alone event manager, i.e. an event manager which is not + part of a supervision tree, that is, started by a supervisor. + There is another function, <c>gen_event:start</c>, to start a + standalone event manager, that is, an event manager that is not part of a supervision tree.</p> </section> <section> <title>Adding an Event Handler</title> - <p>Here is an example using the shell on how to start an event - manager and add an event handler to it:</p> + <p>The following example shows how to start an event manager and + add an event handler to it by using the shell:</p> <pre> 1> <input>gen_event:start({local, error_man}).</input> {ok,<0.31.0>} @@ -128,16 +128,16 @@ gen_event:start_link({local, error_man})</code> ok</pre> <p>This function sends a message to the event manager registered as <c>error_man</c>, telling it to add the event handler - <c>terminal_logger</c>. The event manager will call the callback - function <c>terminal_logger:init([])</c>, where the argument [] - is the third argument to <c>add_handler</c>. <c>init</c> is - expected to return <c>{ok, State}</c>, where <c>State</c> is + <c>terminal_logger</c>. The event manager calls the callback + function <c>terminal_logger:init([])</c>, where the argument + <c>[]</c> is the third argument to <c>add_handler</c>. <c>init</c> + is expected to return <c>{ok, State}</c>, where <c>State</c> is the internal state of the event handler.</p> <code type="none"> init(_Args) -> {ok, []}.</code> <p>Here, <c>init</c> does not need any input data and ignores its - argument. Also, for <c>terminal_logger</c> the internal state is + argument. For <c>terminal_logger</c>, the internal state is not used. For <c>file_logger</c>, the internal state is used to save the open file descriptor.</p> <code type="none"> @@ -147,7 +147,7 @@ init(File) -> </section> <section> - <title>Notifying About Events</title> + <title>Notifying about Events</title> <pre> 3> <input>gen_event:notify(error_man, no_reply).</input> ***Error*** no_reply @@ -158,7 +158,7 @@ ok</pre> When the event is received, the event manager calls <c>handle_event(Event, State)</c> for each installed event handler, in the same order as they were added. The function is - expected to return a tuple <c>{ok, State1}</c>, where + expected to return a tuple <c>{ok,State1}</c>, where <c>State1</c> is a new value for the state of the event handler.</p> <p>In <c>terminal_logger</c>:</p> <code type="none"> @@ -179,17 +179,17 @@ handle_event(ErrorMsg, Fd) -> ok</pre> <p>This function sends a message to the event manager registered as <c>error_man</c>, telling it to delete the event handler - <c>terminal_logger</c>. The event manager will call the callback + <c>terminal_logger</c>. The event manager calls the callback function <c>terminal_logger:terminate([], State)</c>, where - the argument [] is the third argument to <c>delete_handler</c>. - <c>terminate</c> should be the opposite of <c>init</c> and do any + the argument <c>[]</c> is the third argument to <c>delete_handler</c>. + <c>terminate</c> is to be the opposite of <c>init</c> and do any necessary cleaning up. Its return value is ignored.</p> <p>For <c>terminal_logger</c>, no cleaning up is necessary:</p> <code type="none"> terminate(_Args, _State) -> ok.</code> <p>For <c>file_logger</c>, the file descriptor opened in <c>init</c> - needs to be closed:</p> + must be closed:</p> <code type="none"> terminate(_Args, Fd) -> file:close(Fd).</code> @@ -197,20 +197,22 @@ terminate(_Args, Fd) -> <section> <title>Stopping</title> - <p>When an event manager is stopped, it will give each of + <p>When an event manager is stopped, it gives each of the installed event handlers the chance to clean up by calling <c>terminate/2</c>, the same way as when deleting a handler.</p> <section> <title>In a Supervision Tree</title> <p>If the event manager is part of a supervision tree, no stop - function is needed. The event manager will automatically be + function is needed. The event manager is automatically terminated by its supervisor. Exactly how this is done is - defined by a <seealso marker="sup_princ#shutdown">shutdown strategy</seealso> set in the supervisor.</p> + defined by a + <seealso marker="sup_princ#shutdown">shutdown strategy</seealso> + set in the supervisor.</p> </section> <section> - <title>Stand-Alone Event Managers</title> + <title>Standalone Event Managers</title> <p>An event manager can also be stopped by calling:</p> <pre> > <input>gen_event:stop(error_man).</input> @@ -219,16 +221,17 @@ ok</pre> </section> <section> <title>Handling Other Messages</title> - <p>If the gen_event should be able to receive other messages than - events, the callback function <c>handle_info(Info, StateName, StateData)</c> - must be implemented to handle them. Examples of - other messages are exit messages, if the gen_event is linked to + <p>If the <c>gen_event</c> is to be able to receive other messages + than events, the callback function + <c>handle_info(Info, StateName, StateData)</c> + must be implemented to handle them. Examples of other + messages are exit messages, if the <c>gen_event</c> is linked to other processes (than the supervisor) and trapping exit signals.</p> <code type="none"> handle_info({'EXIT', Pid, Reason}, State) -> ..code to handle exits here.. {ok, NewState}.</code> - <p>The code_change method also has to be implemented.</p> + <p>The <c>code_change</c> method must also be implemented.</p> <code type="none"> code_change(OldVsn, State, Extra) -> ..code to convert state (and more) during code change diff --git a/system/doc/design_principles/fsm.xml b/system/doc/design_principles/fsm.xml index 9dce159dca..ef961f5fad 100644 --- a/system/doc/design_principles/fsm.xml +++ b/system/doc/design_principles/fsm.xml @@ -21,32 +21,33 @@ </legalnotice> - <title>Gen_Fsm Behaviour</title> + <title>gen_fsm Behaviour</title> <prepared></prepared> <docno></docno> <date></date> <rev></rev> <file>fsm.xml</file> </header> - <p>This chapter should be read in conjunction with <c>gen_fsm(3)</c>, - where all interface functions and callback functions are described - in detail.</p> + <marker id="gen_fsm behaviour"></marker> + <p>This section is to be read with the <c>gen_fsm(3)</c> manual page + in STDLIB, where all interface functions and callback + functions are described in detail.</p> <section> - <title>Finite State Machines</title> - <p>A finite state machine, FSM, can be described as a set of + <title>Finite-State Machines</title> + <p>A Finite-State Machine (FSM) can be described as a set of relations of the form:</p> <pre> State(S) x Event(E) -> Actions(A), State(S')</pre> <p>These relations are interpreted as meaning:</p> <quote> - <p>If we are in state <c>S</c> and the event <c>E</c> occurs, we - should perform the actions <c>A</c> and make a transition to - the state <c>S'</c>.</p> + <p>If we are in state <c>S</c> and event <c>E</c> occurs, we + are to perform actions <c>A</c> and make a transition to + state <c>S'</c>.</p> </quote> <p>For an FSM implemented using the <c>gen_fsm</c> behaviour, the state transition rules are written as a number of Erlang - functions which conform to the following convention:</p> + functions, which conform to the following convention:</p> <pre> StateName(Event, StateData) -> .. code for actions here ... @@ -55,16 +56,16 @@ StateName(Event, StateData) -> <section> <title>Example</title> - <p>A door with a code lock could be viewed as an FSM. Initially, + <p>A door with a code lock can be viewed as an FSM. Initially, the door is locked. Anytime someone presses a button, this generates an event. Depending on what buttons have been pressed - before, the sequence so far may be correct, incomplete or wrong.</p> - <p>If it is correct, the door is unlocked for 30 seconds (30000 ms). + before, the sequence so far can be correct, incomplete, or wrong.</p> + <p>If it is correct, the door is unlocked for 30 seconds (30,000 ms). If it is incomplete, we wait for another button to be pressed. If it is is wrong, we start all over, waiting for a new button sequence.</p> <p>Implementing the code lock FSM using <c>gen_fsm</c> results in - this callback module:</p> + the following callback module:</p> <marker id="ex"></marker> <code type="none"><![CDATA[ -module(code_lock). @@ -101,85 +102,88 @@ open(timeout, State) -> </section> <section> - <title>Starting a Gen_Fsm</title> - <p>In the example in the previous section, the gen_fsm is started by - calling <c>code_lock:start_link(Code)</c>:</p> + <title>Starting gen_fsm</title> + <p>In the example in the previous section, the <c>gen_fsm</c> is + started by calling <c>code_lock:start_link(Code)</c>:</p> <code type="none"> start_link(Code) -> gen_fsm:start_link({local, code_lock}, code_lock, lists:reverse(Code), []). </code> - <p><c>start_link</c> calls the function <c>gen_fsm:start_link/4</c>. - This function spawns and links to a new process, a gen_fsm.</p> + <p><c>start_link</c> calls the function <c>gen_fsm:start_link/4</c>, + which spawns and links to a new process, a <c>gen_fsm</c>.</p> <list type="bulleted"> <item> - <p>The first argument <c>{local, code_lock}</c> specifies - the name. In this case, the gen_fsm will be locally registered - as <c>code_lock</c>.</p> - <p>If the name is omitted, the gen_fsm is not registered. - Instead its pid must be used. The name could also be given as - <c>{global, Name}</c>, in which case the gen_fsm is registered - using <c>global:register_name/2</c>.</p> + <p>The first argument, <c>{local, code_lock}</c>, specifies + the name. In this case, the <c>gen_fsm</c> is locally + registered as <c>code_lock</c>.</p> + <p>If the name is omitted, the <c>gen_fsm</c> is not registered. + Instead its pid must be used. The name can also be given + as <c>{global, Name}</c>, in which case the <c>gen_fsm</c> is + registered using <c>global:register_name/2</c>.</p> </item> <item> <p>The second argument, <c>code_lock</c>, is the name of - the callback module, that is the module where the callback + the callback module, that is, the module where the callback functions are located.</p> - <p>In this case, the interface functions (<c>start_link</c> and - <c>button</c>) are located in the same module as the callback - functions (<c>init</c>, <c>locked</c> and <c>open</c>). This + <p>The interface functions (<c>start_link</c> and <c>button</c>) + are then located in the same module as the callback + functions (<c>init</c>, <c>locked</c>, and <c>open</c>). This is normally good programming practice, to have the code corresponding to one process contained in one module.</p> </item> <item> - <p>The third argument, <c>Code</c>, is a list of digits which is passed - reversed to the callback function <c>init</c>. Here, <c>init</c> + <p>The third argument, <c>Code</c>, is a list of digits that + which is passed reversed to the callback function <c>init</c>. + Here, <c>init</c> gets the correct code for the lock as indata.</p> </item> <item> - <p>The fourth argument, [], is a list of options. See - <c>gen_fsm(3)</c> for available options.</p> + <p>The fourth argument, <c>[]</c>, is a list of options. See + the <c>gen_fsm(3)</c> manual page for available options.</p> </item> </list> - <p>If name registration succeeds, the new gen_fsm process calls + <p>If name registration succeeds, the new <c>gen_fsm</c> process calls the callback function <c>code_lock:init(Code)</c>. This function is expected to return <c>{ok, StateName, StateData}</c>, where - <c>StateName</c> is the name of the initial state of the gen_fsm. - In this case <c>locked</c>, assuming the door is locked to begin - with. <c>StateData</c> is the internal state of the gen_fsm. (For - gen_fsms, the internal state is often referred to 'state data' to + <c>StateName</c> is the name of the initial state of the + <c>gen_fsm</c>. In this case <c>locked</c>, assuming the door is + locked to begin with. <c>StateData</c> is the internal state of + the <c>gen_fsm</c>. (For <c>gen_fsm</c>, the internal state is + often referred to 'state data' to distinguish it from the state as in states of a state machine.) In this case, the state data is the button sequence so far (empty to begin with) and the correct code of the lock.</p> <code type="none"> init(Code) -> {ok, locked, {[], Code}}.</code> - <p>Note that <c>gen_fsm:start_link</c> is synchronous. It does not - return until the gen_fsm has been initialized and is ready to + <p><c>gen_fsm:start_link</c> is synchronous. It does not return until + the <c>gen_fsm</c> has been initialized and is ready to receive notifications.</p> - <p><c>gen_fsm:start_link</c> must be used if the gen_fsm is part of - a supervision tree, i.e. is started by a supervisor. There is - another function <c>gen_fsm:start</c> to start a stand-alone - gen_fsm, i.e. a gen_fsm which is not part of a supervision tree.</p> + <p><c>gen_fsm:start_link</c> must be used if the <c>gen_fsm</c> is + part of a supervision tree, that is, started by a supervisor. There + is another function, <c>gen_fsm:start</c>, to start a standalone + <c>gen_fsm</c>, that is, a <c>gen_fsm</c> that is not part of a + supervision tree.</p> </section> <section> - <title>Notifying About Events</title> + <title>Notifying about Events</title> <p>The function notifying the code lock about a button event is implemented using <c>gen_fsm:send_event/2</c>:</p> <code type="none"> button(Digit) -> gen_fsm:send_event(code_lock, {button, Digit}).</code> - <p><c>code_lock</c> is the name of the gen_fsm and must agree with - the name used to start it. <c>{button, Digit}</c> is the actual - event.</p> - <p>The event is made into a message and sent to the gen_fsm. When - the event is received, the gen_fsm calls - <c>StateName(Event, StateData)</c> which is expected to return a - tuple <c>{next_state, StateName1, StateData1}</c>. + <p><c>code_lock</c> is the name of the <c>gen_fsm</c> and must + agree with the name used to start it. + <c>{button, Digit}</c> is the actual event.</p> + <p>The event is made into a message and sent to the <c>gen_fsm</c>. + When the event is received, the <c>gen_fsm</c> calls + <c>StateName(Event, StateData)</c>, which is expected to return a + tuple <c>{next_state,StateName1,StateData1}</c>. <c>StateName</c> is the name of the current state and <c>StateName1</c> is the name of the next state to go to. <c>StateData1</c> is a new value for the state data of - the gen_fsm.</p> + the <c>gen_fsm</c>.</p> <code type="none"><![CDATA[ locked({button, Digit}, {SoFar, Code}) -> case [Digit|SoFar] of @@ -198,20 +202,21 @@ open(timeout, State) -> <p>If the door is locked and a button is pressed, the complete button sequence so far is compared with the correct code for the lock and, depending on the result, the door is either unlocked - and the gen_fsm goes to state <c>open</c>, or the door remains in - state <c>locked</c>.</p> + and the <c>gen_fsm</c> goes to state <c>open</c>, or the door + remains in state <c>locked</c>.</p> </section> <section> - <title>Timeouts</title> + <title>Time-Outs</title> <p>When a correct code has been given, the door is unlocked and the following tuple is returned from <c>locked/2</c>:</p> <code type="none"> {next_state, open, {[], Code}, 30000};</code> - <p>30000 is a timeout value in milliseconds. After 30000 ms, i.e. - 30 seconds, a timeout occurs. Then <c>StateName(timeout, StateData)</c> is called. In this case, the timeout occurs when - the door has been in state <c>open</c> for 30 seconds. After that - the door is locked again:</p> + <p>30,000 is a time-out value in milliseconds. After this time, + that is, 30 seconds, a time-out occurs. Then, + <c>StateName(timeout, StateData)</c> is called. The time-out + then occurs when the door has been in state <c>open</c> for 30 + seconds. After that the door is locked again:</p> <code type="none"> open(timeout, State) -> do_lock(), @@ -220,7 +225,7 @@ open(timeout, State) -> <section> <title>All State Events</title> - <p>Sometimes an event can arrive at any state of the gen_fsm. + <p>Sometimes an event can arrive at any state of the <c>gen_fsm</c>. Instead of sending the message with <c>gen_fsm:send_event/2</c> and writing one clause handling the event for each state function, the message can be sent with <c>gen_fsm:send_all_state_event/2</c> @@ -245,15 +250,16 @@ handle_event(stop, _StateName, StateData) -> <section> <title>In a Supervision Tree</title> - <p>If the gen_fsm is part of a supervision tree, no stop function - is needed. The gen_fsm will automatically be terminated by its - supervisor. Exactly how this is done is defined by a - <seealso marker="sup_princ#shutdown">shutdown strategy</seealso> + <p>If the <c>gen_fsm</c> is part of a supervision tree, no stop + function is needed. The <c>gen_fsm</c> is automatically + terminated by its supervisor. Exactly how this is done is + defined by a + <seealso marker="sup_princ#shutdown">shutdown strategy</seealso> set in the supervisor.</p> <p>If it is necessary to clean up before termination, the shutdown - strategy must be a timeout value and the gen_fsm must be set to - trap exit signals in the <c>init</c> function. When ordered - to shutdown, the gen_fsm will then call the callback function + strategy must be a time-out value and the <c>gen_fsm</c> must be + set to trap exit signals in the <c>init</c> function. When ordered + to shutdown, the <c>gen_fsm</c> then calls the callback function <c>terminate(shutdown, StateName, StateData)</c>:</p> <code type="none"> init(Args) -> @@ -270,9 +276,9 @@ terminate(shutdown, StateName, StateData) -> </section> <section> - <title>Stand-Alone Gen_Fsms</title> - <p>If the gen_fsm is not part of a supervision tree, a stop - function may be useful, for example:</p> + <title>Standalone gen_fsm</title> + <p>If the <c>gen_fsm</c> is not part of a supervision tree, a stop + function can be useful, for example:</p> <code type="none"> ... -export([stop/0]). @@ -290,26 +296,28 @@ handle_event(stop, _StateName, StateData) -> terminate(normal, _StateName, _StateData) -> ok.</code> <p>The callback function handling the <c>stop</c> event returns a - tuple <c>{stop,normal,StateData1}</c>, where <c>normal</c> + tuple, <c>{stop,normal,StateData1}</c>, where <c>normal</c> specifies that it is a normal termination and <c>StateData1</c> - is a new value for the state data of the gen_fsm. This will - cause the gen_fsm to call + is a new value for the state data of the <c>gen_fsm</c>. This + causes the <c>gen_fsm</c> to call <c>terminate(normal,StateName,StateData1)</c> and then - terminate gracefully:</p> + it terminates gracefully:</p> </section> </section> <section> <title>Handling Other Messages</title> - <p>If the gen_fsm should be able to receive other messages than - events, the callback function <c>handle_info(Info, StateName, StateData)</c> must be implemented to handle them. Examples of - other messages are exit messages, if the gen_fsm is linked to + <p>If the <c>gen_fsm</c> is to be able to receive other messages + than events, the callback function + <c>handle_info(Info, StateName, StateData)</c> must be implemented + to handle them. Examples of + other messages are exit messages, if the <c>gen_fsm</c> is linked to other processes (than the supervisor) and trapping exit signals.</p> <code type="none"> handle_info({'EXIT', Pid, Reason}, StateName, StateData) -> ..code to handle exits here.. {next_state, StateName1, StateData1}.</code> - <p>The code_change method also has to be implemented.</p> + <p>The code_change method must also be implemented.</p> <code type="none"> code_change(OldVsn, StateName, StateData, Extra) -> ..code to convert state (and more) during code change diff --git a/system/doc/design_principles/gen_server_concepts.xml b/system/doc/design_principles/gen_server_concepts.xml index d24d87aa03..d721845c6d 100644 --- a/system/doc/design_principles/gen_server_concepts.xml +++ b/system/doc/design_principles/gen_server_concepts.xml @@ -21,7 +21,7 @@ </legalnotice> - <title>Gen_Server Behaviour</title> + <title>gen_server Behaviour</title> <prepared></prepared> <docno></docno> <date></date> @@ -29,16 +29,16 @@ <file>gen_server_concepts.xml</file> </header> <marker id="gen_server"></marker> - <p>This chapter should be read in conjunction with - <seealso marker="stdlib:gen_server">gen_server(3)</seealso>, - where all interface functions and callback - functions are described in detail.</p> + <p>This section is to be read with the + <seealso marker="stdlib:gen_server">gen_server(3)</seealso> + manual page in <c>stdblib</c>, where all interface functions and + callback functions are described in detail.</p> <section> <title>Client-Server Principles</title> <p>The client-server model is characterized by a central server and an arbitrary number of clients. The client-server model is - generally used for resource management operations, where several + used for resource management operations, where several different clients want to share a common resource. The server is responsible for managing this resource.</p> <marker id="clientserver"></marker> @@ -49,9 +49,10 @@ <section> <title>Example</title> - <p>An example of a simple server written in plain Erlang was - given in <seealso marker="des_princ#ch1">Overview</seealso>. - The server can be re-implemented using <c>gen_server</c>, + <p>An example of a simple server written in plain Erlang is + provided in + <seealso marker="des_princ#ch1">Overview</seealso>. + The server can be reimplemented using <c>gen_server</c>, resulting in this callback module:</p> <marker id="ex"></marker> <code type="none"> @@ -86,61 +87,60 @@ handle_cast({free, Ch}, Chs) -> <section> <title>Starting a Gen_Server</title> - <p>In the example in the previous section, the gen_server is started - by calling <c>ch3:start_link()</c>:</p> + <p>In the example in the previous section, <c>gen_server</c> is + started by calling <c>ch3:start_link()</c>:</p> <code type="none"> start_link() -> gen_server:start_link({local, ch3}, ch3, [], []) => {ok, Pid}</code> - <p><c>start_link</c> calls the function - <c>gen_server:start_link/4</c>. This function spawns and links to - a new process, a gen_server.</p> + <p><c>start_link</c> calls function <c>gen_server:start_link/4</c>. + This function spawns and links to a new process, a + <c>gen_server</c>.</p> <list type="bulleted"> <item> - <p>The first argument <c>{local, ch3}</c> specifies the name. In - this case, the gen_server will be locally registered as - <c>ch3</c>.</p> - <p>If the name is omitted, the gen_server is not registered. - Instead its pid must be used. The name could also be given - as <c>{global, Name}</c>, in which case the gen_server is + <p>The first argument, <c>{local, ch3}</c>, specifies the name. + The gen_server is then locally registered as <c>ch3</c>.</p> + <p>If the name is omitted, the <c>gen_server</c> is not registered. + Instead its pid must be used. The name can also be given + as <c>{global, Name}</c>, in which case the <c>gen_server</c> is registered using <c>global:register_name/2</c>.</p> </item> <item> <p>The second argument, <c>ch3</c>, is the name of the callback - module, that is the module where the callback functions are + module, that is, the module where the callback functions are located.</p> - <p>In this case, the interface functions (<c>start_link</c>, - <c>alloc</c> and <c>free</c>) are located in the same module - as the callback functions (<c>init</c>, <c>handle_call</c> and + <p>The interface functions (<c>start_link</c>, <c>alloc</c>, + and <c>free</c>) are then located in the same module + as the callback functions (<c>init</c>, <c>handle_call</c>, and <c>handle_cast</c>). This is normally good programming practice, to have the code corresponding to one process contained in one module.</p> </item> <item> - <p>The third argument, [], is a term which is passed as-is to - the callback function <c>init</c>. Here, <c>init</c> does not + <p>The third argument, <c>[]</c>, is a term that is passed as is + to the callback function <c>init</c>. Here, <c>init</c> does not need any indata and ignores the argument.</p> </item> <item> - <p>The fourth argument, [], is a list of options. See - <c>gen_server(3)</c> for available options.</p> + <p>The fourth argument, <c>[]</c>, is a list of options. See the + <c>gen_server(3)</c> manual page for available options.</p> </item> </list> - <p>If name registration succeeds, the new gen_server process calls - the callback function <c>ch3:init([])</c>. <c>init</c> is expected - to return <c>{ok, State}</c>, where <c>State</c> is the internal - state of the gen_server. In this case, the state is the available - channels.</p> + <p>If name registration succeeds, the new <c>gen_server</c> process + calls the callback function <c>ch3:init([])</c>. <c>init</c> is + expected to return <c>{ok, State}</c>, where <c>State</c> is the + internal state of the <c>gen_server</c>. In this case, the state + is the available channels.</p> <code type="none"> init(_Args) -> {ok, channels()}.</code> - <p>Note that <c>gen_server:start_link</c> is synchronous. It does - not return until the gen_server has been initialized and is ready + <p><c>gen_server:start_link</c> is synchronous. It does not return + until the <c>gen_server</c> has been initialized and is ready to receive requests.</p> - <p><c>gen_server:start_link</c> must be used if the gen_server is - part of a supervision tree, i.e. is started by a supervisor. - There is another function <c>gen_server:start</c> to start a - stand-alone gen_server, i.e. a gen_server which is not part of a - supervision tree.</p> + <p><c>gen_server:start_link</c> must be used if the <c>gen_server</c> + is part of a supervision tree, that is, started by a supervisor. + There is another function, <c>gen_server:start</c>, to start a + standalone <c>gen_server</c>, that is, a <c>gen_server</c> that + is not part of a supervision tree.</p> </section> <section> @@ -150,14 +150,17 @@ init(_Args) -> <code type="none"> alloc() -> gen_server:call(ch3, alloc).</code> - <p><c>ch3</c> is the name of the gen_server and must agree with - the name used to start it. <c>alloc</c> is the actual request.</p> - <p>The request is made into a message and sent to the gen_server. - When the request is received, the gen_server calls - <c>handle_call(Request, From, State)</c> which is expected to - return a tuple <c>{reply, Reply, State1}</c>. <c>Reply</c> is - the reply which should be sent back to the client, and - <c>State1</c> is a new value for the state of the gen_server.</p> + <p><c>ch3</c> is the name of the <c>gen_server</c> and must agree + with the name used to start it. <c>alloc</c> is the actual + request.</p> + <p>The request is made into a message and sent to the + <c>gen_server</c>. When the request is received, the + <c>gen_server</c> calls + <c>handle_call(Request, From, State)</c>, which is expected to + return a tuple <c>{reply,Reply,State1}</c>. <c>Reply</c> is + the reply that is to be sent back to the client, and + <c>State1</c> is a new value for the state of the + <c>gen_server</c>.</p> <code type="none"> handle_call(alloc, _From, Chs) -> {Ch, Chs2} = alloc(Chs), @@ -166,8 +169,8 @@ handle_call(alloc, _From, Chs) -> the new state is the set of remaining available channels <c>Chs2</c>.</p> <p>Thus, the call <c>ch3:alloc()</c> returns the allocated channel - <c>Ch</c> and the gen_server then waits for new requests, now - with an updated list of available channels.</p> + <c>Ch</c> and the <c>gen_server</c> then waits for new requests, + now with an updated list of available channels.</p> </section> <section> @@ -177,20 +180,21 @@ handle_call(alloc, _From, Chs) -> <code type="none"> free(Ch) -> gen_server:cast(ch3, {free, Ch}).</code> - <p><c>ch3</c> is the name of the gen_server. <c>{free, Ch}</c> is - the actual request.</p> - <p>The request is made into a message and sent to the gen_server. + <p><c>ch3</c> is the name of the <c>gen_server</c>. + <c>{free, Ch}</c> is the actual request.</p> + <p>The request is made into a message and sent to the + <c>gen_server</c>. <c>cast</c>, and thus <c>free</c>, then returns <c>ok</c>.</p> - <p>When the request is received, the gen_server calls - <c>handle_cast(Request, State)</c> which is expected to - return a tuple <c>{noreply, State1}</c>. <c>State1</c> is a new - value for the state of the gen_server.</p> + <p>When the request is received, the <c>gen_server</c> calls + <c>handle_cast(Request, State)</c>, which is expected to + return a tuple <c>{noreply,State1}</c>. <c>State1</c> is a new + value for the state of the <c>gen_server</c>.</p> <code type="none"> handle_cast({free, Ch}, Chs) -> Chs2 = free(Ch, Chs), {noreply, Chs2}.</code> <p>In this case, the new state is the updated list of available - channels <c>Chs2</c>. The gen_server is now ready for new + channels <c>Chs2</c>. The <c>gen_server</c> is now ready for new requests.</p> </section> @@ -199,15 +203,17 @@ handle_cast({free, Ch}, Chs) -> <section> <title>In a Supervision Tree</title> - <p>If the gen_server is part of a supervision tree, no stop - function is needed. The gen_server will automatically be + <p>If the <c>gen_server</c> is part of a supervision tree, no stop + function is needed. The <c>gen_server</c> is automatically terminated by its supervisor. Exactly how this is done is - defined by a <seealso marker="sup_princ#shutdown">shutdown strategy</seealso> set in the supervisor.</p> + defined by a + <seealso marker="sup_princ#shutdown">shutdown strategy</seealso> + set in the supervisor.</p> <p>If it is necessary to clean up before termination, the shutdown - strategy must be a timeout value and the gen_server must be set - to trap exit signals in the <c>init</c> function. When ordered - to shutdown, the gen_server will then call the callback function - <c>terminate(shutdown, State)</c>:</p> + strategy must be a time-out value and the <c>gen_server</c> must + be set to trap exit signals in function <c>init</c>. When ordered + to shutdown, the <c>gen_server</c> then calls the callback + function <c>terminate(shutdown, State)</c>:</p> <code type="none"> init(Args) -> ..., @@ -223,9 +229,9 @@ terminate(shutdown, State) -> </section> <section> - <title>Stand-Alone Gen_Servers</title> - <p>If the gen_server is not part of a supervision tree, a stop - function may be useful, for example:</p> + <title>Standalone Gen_Servers</title> + <p>If the <c>gen_server</c> is not part of a supervision tree, a + stop function can be useful, for example:</p> <code type="none"> ... export([stop/0]). @@ -245,26 +251,26 @@ handle_cast({free, Ch}, State) -> terminate(normal, State) -> ok.</code> <p>The callback function handling the <c>stop</c> request returns - a tuple <c>{stop, normal, State1}</c>, where <c>normal</c> + a tuple <c>{stop,normal,State1}</c>, where <c>normal</c> specifies that it is a normal termination and <c>State1</c> is - a new value for the state of the gen_server. This will cause - the gen_server to call <c>terminate(normal,State1)</c> and then - terminate gracefully.</p> + a new value for the state of the <c>gen_server</c>. This causes + the <c>gen_server</c> to call <c>terminate(normal, State1)</c> + and then it terminates gracefully.</p> </section> </section> <section> <title>Handling Other Messages</title> - <p>If the gen_server should be able to receive other messages than - requests, the callback function <c>handle_info(Info, State)</c> + <p>If the <c>gen_server</c> is to be able to receive other messages + than requests, the callback function <c>handle_info(Info, State)</c> must be implemented to handle them. Examples of other messages - are exit messages, if the gen_server is linked to other processes - (than the supervisor) and trapping exit signals.</p> + are exit messages, if the <c>gen_server</c> is linked to other + processes (than the supervisor) and trapping exit signals.</p> <code type="none"> handle_info({'EXIT', Pid, Reason}, State) -> ..code to handle exits here.. {noreply, State1}.</code> - <p>The code_change method also has to be implemented.</p> + <p>The <c>code_change</c> method must also be implemented.</p> <code type="none"> code_change(OldVsn, State, Extra) -> ..code to convert state (and more) during code change diff --git a/system/doc/design_principles/included_applications.xml b/system/doc/design_principles/included_applications.xml index 3aa43fd595..7f139edf76 100644 --- a/system/doc/design_principles/included_applications.xml +++ b/system/doc/design_principles/included_applications.xml @@ -28,35 +28,36 @@ <rev></rev> <file>included_applications.xml</file> </header> + <marker id="included appl"></marker> <section> - <title>Definition</title> + <title>Introduction</title> <p>An application can <em>include</em> other applications. An <em>included application</em> has its own application directory and <c>.app</c> file, but it is started as part of the supervisor tree of another application.</p> <p>An application can only be included by one other application.</p> <p>An included application can include other applications.</p> - <p>An application which is not included by any other application is + <p>An application that is not included by any other application is called a <em>primary application</em>.</p> <marker id="inclappls"></marker> <image file="../design_principles/inclappls.gif"> - <icaption>Primary Application and Included Applications.</icaption> + <icaption>Primary Application and Included Applications</icaption> </image> - <p>The application controller will automatically load any included - applications when loading a primary application, but not start + <p>The application controller automatically loads any included + applications when loading a primary application, but does not start them. Instead, the top supervisor of the included application must be started by a supervisor in the including application.</p> <p>This means that when running, an included application is in fact - part of the primary application and a process in an included - application will consider itself belonging to the primary + part of the primary application, and a process in an included + application considers itself belonging to the primary application.</p> </section> <section> <title>Specifying Included Applications</title> <p>Which applications to include is defined by - the <c>included_applications</c> key in the <c>.app</c> file.</p> + the <c>included_applications</c> key in the <c>.app</c> file:</p> <pre> {application, prim_app, [{description, "Tree application"}, @@ -71,7 +72,7 @@ </section> <section> - <title>Synchronizing Processes During Startup</title> + <title>Synchronizing Processes during Startup</title> <p>The supervisor tree of an included application is started as part of the supervisor tree of the including application. If there is a need for synchronization between processes in @@ -79,12 +80,12 @@ by using <em>start phases</em>.</p> <p>Start phases are defined by the <c>start_phases</c> key in the <c>.app</c> file as a list of tuples <c>{Phase,PhaseArgs}</c>, - where <c>Phase</c> is an atom and <c>PhaseArgs</c> is a term. - Also, the value of the <c>mod</c> key of the including application + where <c>Phase</c> is an atom and <c>PhaseArgs</c> is a term.</p> + <p>The value of the <c>mod</c> key of the including application must be set to <c>{application_starter,[Module,StartArgs]}</c>, - where <c>Module</c> as usual is the application callback module - and <c>StartArgs</c> a term provided as argument to the callback - function <c>Module:start/2</c>.</p> + where <c>Module</c> as usual is the application callback module. + <c>StartArgs</c> is a term provided as argument to the callback + function <c>Module:start/2</c>:</p> <code type="none"> {application, prim_app, [{description, "Tree application"}, @@ -108,36 +109,38 @@ {mod, {incl_app_cb,[]}} ]}.</code> <p>When starting a primary application with included applications, - the primary application is started the normal way: - The application controller creates an application master for - the application, and the application master calls + the primary application is started the normal way, that is:</p> + <list type="bulleted"> + <item>The application controller creates an application master for + the application</item> + <item>The application master calls <c>Module:start(normal, StartArgs)</c> to start the top - supervisor.</p> + supervisor.</item> + </list> <p>Then, for the primary application and each included application in top-down, left-to-right order, the application master calls <c>Module:start_phase(Phase, Type, PhaseArgs)</c> for each phase - defined for for the primary application, in that order. - Note that if a phase is not defined for an included application, + defined for the primary application, in that order. If a phase + is not defined for an included application, the function is not called for this phase and application.</p> <p>The following requirements apply to the <c>.app</c> file for an included application:</p> <list type="bulleted"> - <item>The <c>{mod, {Module,StartArgs}}</c> option must be - included. This option is used to find the callback module - <c>Module</c> of the application. <c>StartArgs</c> is ignored, - as <c>Module:start/2</c> is called only for the primary - application.</item> + <item>The <c>{mod, {Module,StartArgs}}</c> option must be included. + This option is used to find the callback module <c>Module</c> of the + application. <c>StartArgs</c> is ignored, as <c>Module:start/2</c> + is called only for the primary application.</item> <item>If the included application itself contains included - applications, instead the option - <c>{mod, {application_starter, [Module,StartArgs]}}</c> must be - included.</item> + applications, instead the + <c>{mod, {application_starter, [Module,StartArgs]}}</c> option + must be included.</item> <item>The <c>{start_phases, [{Phase,PhaseArgs}]}</c> option must - be included, and the set of specified phases must be a subset - of the set of phases specified for the primary application.</item> + be included, and the set of specified phases must be a subset + of the set of phases specified for the primary application.</item> </list> <p>When starting <c>prim_app</c> as defined above, the application - controller will call the following callback functions, before - <c>application:start(prim_app)</c> returns a value:</p> + controller calls the following callback functions before + <c>application:start(prim_app)</c> returns a value:</p> <code type="none"> application:start(prim_app) => prim_app_cb:start(normal, []) diff --git a/system/doc/design_principles/release_handling.xml b/system/doc/design_principles/release_handling.xml index 9d1e2c8669..eeb71125b6 100644 --- a/system/doc/design_principles/release_handling.xml +++ b/system/doc/design_principles/release_handling.xml @@ -28,128 +28,126 @@ <rev></rev> <file>release_handling.xml</file> </header> + <marker id="release handling"></marker> <section> <title>Release Handling Principles</title> <p>An important feature of the Erlang programming language is - the ability to change module code in run-time, <em>code replacement</em>, as described in <em>Erlang Reference Manual</em>.</p> + the ability to change module code in runtime, + <em>code replacement</em>, as described in the Erlang + Reference Manual.</p> <p>Based on this feature, the OTP application SASL provides a framework for upgrading and downgrading between different - versions of an entire release in run-time. This is what we call + versions of an entire release in runtime. This is called <em>release handling</em>.</p> - <p>The framework consists of off-line support (<c>systools</c>) for - generating scripts and building release packages, and on-line - support (<c>release_handler</c>) for unpacking and installing - release packages.</p> - <p>Note that the minimal system based on Erlang/OTP, enabling - release handling, thus consists of Kernel, STDLIB and SASL.</p> - <list type="ordered"> - <item> - <p>A release is created as described in the previous chapter - <seealso marker="release_structure">Releases</seealso>. - The release is transferred to and installed at target - environment. Refer to <em>System Principles</em> for - information of how to install the first target system.</p> - </item> - <item> - <p>Modifications, for example error corrections, are made to - the code in the development environment.</p> - </item> - <item> - <p>At some point it is time to make a new version of release. - The relevant <c>.app</c> files are updated and a new - <c>.rel</c> file is written.</p> - </item> - <item> - <p>For each modified application, an - <seealso marker="#appup">application upgrade file</seealso>, - <c>.appup</c>, is created. In this file, it is described how - to upgrade and/or downgrade between the old and new version of - the application.</p> - </item> - <item> - <p>Based on the <c>.appup</c> files, a - <seealso marker="#relup">release upgrade file</seealso> called - <c>relup</c>, is created. This file describes how to upgrade - and/or downgrade between the old and new version of - the entire release.</p> - </item> - <item> - <p>A new release package is made and transferred to - the target system.</p> - </item> - <item> - <p>The new release package is unpacked using the release - handler.</p> - </item> - <item> - <p>The new version of the release is installed, also using - the release handler. This is done by evaluating - the instructions in <c>relup</c>. Modules may be added, - deleted or re-loaded, applications may be started, stopped or - re-started etc. In some cases, it is even necessary to restart - the entire emulator.</p> - <p>If the installation fails, the system may be rebooted. - The old release version is then automatically used.</p> - </item> - <item> - <p>If the installation succeeds, the new version is made - the default version, which should now be used in case of a - system reboot.</p> - </item> - </list> - <p>The next chapter, <seealso marker="appup_cookbook">Appup Cookbook</seealso>, contains examples of <c>.appup</c> files - for typical cases of upgrades/downgrades that are normally easy - to handle in run-time. However, there are a many aspects that can - make release handling complicated. To name a few examples:</p> + <p>The framework consists of:</p> <list type="bulleted"> - <item> - <p>Complicated or circular dependencies can make it difficult - or even impossible to decide in which order things must be - done without risking run-time errors during an upgrade or - downgrade. Dependencies may be:</p> - <list type="bulleted"> - <item>between nodes,</item> - <item>between processes, and</item> - <item>between modules.</item> - </list> - </item> - <item> - <p>During release handling, non-affected processes continue - normal execution. This may lead to timeouts or other problems. - For example, new processes created in the time window between - suspending processes using a certain module and loading a new - version of this module, may execute old code.</p> - </item> + <item>Offline support - <c>systools</c> for generating scripts + and building release packages</item> + <item>Online support - <c>release_handler</c> for unpacking and + installing release packages</item> </list> - <p>It is therefore recommended that code is changed in as small + <p>The minimal system based on Erlang/OTP, enabling release handling, + thus consists of the Kernel, STDLIB, and SASL + applications.</p> + + <section> + <title>Release Handling Workflow</title> + <p><em>Step 1</em>) A release is created as described in + <seealso marker="release_structure">Releases</seealso>.</p> + <p><em>Step 2</em>) The release is transferred to and installed at + target environment. For information of how to install the first + target system, see System Principles.</p> + <p><em>Step 3</em>) Modifications, for example, error corrections, + are made to the code in the development environment.</p> + <p><em>Step 4</em>) At some point, it is time to make a new version + of release. The relevant <c>.app</c> files are updated and a new + <c>.rel</c> file is written.</p> + <p><em>Step 5</em>) For each modified application, an + <seealso marker="#appup">application upgrade file</seealso>, + <c>.appup</c>, is created. In this file, it is described how to + upgrade and/or downgrade between the old and new version of the + application.</p> + <p><em>Step 6</em>) Based on the <c>.appup</c> files, a + <seealso marker="#relup">release upgrade file</seealso> called + <c>relup</c>, is created. This file describes how to upgrade and/or + downgrade between the old and new version of the entire release.</p> + <p><em>Step 7</em>) A new release package is made and transferred to + the target system.</p> + <p><em>Step 8</em>) The new release package is unpacked using the + release handler.</p> + <p><em>Step 9</em>) The new version of the release is installed, + also using the release handler. This is done by evaluating the + instructions in <c>relup</c>. Modules can be added, deleted, or + reloaded, applications can be started, stopped, or restarted, and so + on. In some cases, it is even necessary to restart the entire + emulator.</p> + <list type="bulleted"> + <item>If the installation fails, the system can be rebooted. + The old release version is then automatically used.</item> + <item>If the installation succeeds, the new version is made + the default version, which is to now be used if there is a + system reboot.</item> + </list> + </section> + + <section> + <title>Release Handling Aspects</title> + <p><seealso marker="appup_cookbook">Appup Cookbook</seealso>, + contains examples of <c>.appup</c> files + for typical cases of upgrades/downgrades that are normally easy to + handle in runtime. However, many aspects can make release handling + complicated, for example:</p> + <list type="bulleted"> + <item> + <p>Complicated or circular dependencies can make it difficult + or even impossible to decide in which order things must be + done without risking runtime errors during an upgrade or + downgrade. Dependencies can be:</p> + <list type="bulleted"> + <item>Between nodes</item> + <item>Between processes</item> + <item>Between modules</item> + </list> + </item> + <item> + <p>During release handling, non-affected processes continue + normal execution. This can lead to time-outs or other problems. + For example, new processes created in the time window between + suspending processes using a certain module, and loading a new + version of this module, can execute old code.</p> + </item> + </list> + <p>It is thus recommended that code is changed in as small steps as possible, and always kept backwards compatible.</p> + </section> </section> <section> <marker id="req"></marker> <title>Requirements</title> - <p>For release handling to work properly, the runtime system needs - to have knowledge about which release it is currently running. It - must also be able to change (in run-time) which boot script and - system configuration file should be used if the system is - rebooted, for example by <c>heart</c> after a failure. - Therefore, Erlang must be started as an embedded system, see - <em>Embedded System</em> for information on how to do this.</p> + <p>For release handling to work properly, the runtime system must + have knowledge about which release it is running. It + must also be able to change (in runtime) which boot script and + system configuration file to use if the system is + rebooted, for example, by <c>heart</c> after a failure. + Thus, Erlang must be started as an embedded system; for + information on how to do this, see Embedded System.</p> <p>For system reboots to work properly, it is also required that - the system is started with heart beat monitoring, see - <c>erl(1)</c> and <c>heart(3)</c>.</p> + the system is started with heartbeat monitoring, see the + <c>erl(1)</c> manual page in ERTS and the <c>heart(3)</c> + manual page in Kernel</p> <p>Other requirements:</p> <list type="bulleted"> <item> <p>The boot script included in a release package must be generated from the same <c>.rel</c> file as the release package itself.</p> - <p>Information about applications are fetched from the script + <p>Information about applications is fetched from the script when an upgrade or downgrade is performed.</p> </item> <item> - <p>The system must be configured using one and only one system + <p>The system must be configured using only one system configuration file, called <c>sys.config</c>.</p> <p>If found, this file is automatically included when a release package is created.</p> @@ -165,13 +163,13 @@ <section> <title>Distributed Systems</title> - <p>If the system consists of several Erlang nodes, each node may use + <p>If the system consists of several Erlang nodes, each node can use its own version of the release. The release handler is a locally registered process and must be called at each node where an - upgrade or downgrade is required. There is a release handling - instruction that can be used to synchronize the release handler - processes at a number of nodes: <c>sync_nodes</c>. See - <c>appup(4)</c>.</p> + upgrade or downgrade is required. A release handling + instruction, <c>sync_nodes</c>, can be used to synchronize the + release handler processes at a number of nodes, see the + <c>appup(4)</c> manual page in SASL.</p> </section> <section> @@ -183,31 +181,26 @@ instructions. To make it easier for the user, there are also a number of <em>high-level</em> instructions, which are translated to low-level instructions by <c>systools:make_relup</c>.</p> - <p>Here, some of the most frequently used instructions are - described. The complete list of instructions can be found in - <c>appup(4)</c>.</p> + <p>Some of the most frequently used instructions are described in + this section. The complete list of instructions is included in the + <c>appup(4)</c> manual page in SASL.</p> <p>First, some definitions:</p> - <taglist> - <tag><em>Residence module</em></tag> - <item> - <p>The module where a process has its tail-recursive loop - function(s). If the tail-recursive loop functions are - implemented in several modules, all those modules are residence - modules for the process.</p> - </item> - <tag><em>Functional module</em></tag> - <item> - <p>A module which is not a residence module for any process.</p> - </item> - </taglist> - <p>Note that for a process implemented using an OTP behaviour, - the behaviour module is the residence module for that process. - The callback module is a functional module.</p> + <list type="bulleted"> + <item><em>Residence module</em> - The module where a process has + its tail-recursive loop function(s). If these functions are + implemented in several modules, all those modules are residence + modules for the process.</item> + <item><em>Functional module</em> - A module that is not a + residence module for any process.</item> + </list> + <p>For a process implemented using an OTP behaviour, the behaviour + module is the residence module for that process. + The callback module is a functional module.</p> <section> <title>load_module</title> <p>If a simple extension has been made to a functional module, it - is sufficient to simply load the new version of the module into + is sufficient to load the new version of the module into the system, and remove the old version. This is called <em>simple code replacement</em> and for this the following instruction is used:</p> @@ -217,44 +210,50 @@ <section> <title>update</title> - <p>If a more complex change has been made, for example a change - to the format of the internal state of a gen_server, simple code - replacement is not sufficient. Instead it is necessary to - suspend the processes using the module (to avoid that they try - to handle any requests before the code replacement is - completed), ask them to transform the internal state format and - switch to the new version of the module, remove the old version - and last, resume the processes. This is called <em>synchronized code replacement</em> and for this the following instructions - are used:</p> + <p>If a more complex change has been made, for example, a change + to the format of the internal state of a <c>gen_server</c>, simple + code replacement is not sufficient. Instead, it is necessary to:</p> + <list type="bulleted"> + <item>Suspend the processes using the module (to avoid that + they try to handle any requests before the code replacement is + completed).</item> + <item>Ask them to transform the internal state format and + switch to the new version of the module.</item> + <item>Remove the old version.</item> + <item>Resume the processes.</item> + </list> + <p>This is called <em>synchronized code replacement</em> and for + this the following instructions are used:</p> <code type="none"> {update, Module, {advanced, Extra}} {update, Module, supervisor}</code> <p><c>update</c> with argument <c>{advanced,Extra}</c> is used when changing the internal state of a behaviour as described - above. It will cause behaviour processes to call the callback + above. It causes behaviour processes to call the callback function <c>code_change</c>, passing the term <c>Extra</c> and - some other information as arguments. See the man pages for + some other information as arguments. See the manual pages for the respective behaviours and - <seealso marker="appup_cookbook#int_state">Appup Cookbook</seealso>.</p> + <seealso marker="appup_cookbook#int_state">Appup Cookbook</seealso>.</p> <p><c>update</c> with argument <c>supervisor</c> is used when changing the start specification of a supervisor. See - <seealso marker="appup_cookbook#sup">Appup Cookbook</seealso>.</p> + <seealso marker="appup_cookbook#sup">Appup Cookbook</seealso>.</p> <p>When a module is to be updated, the release handler finds which processes that are <em>using</em> the module by traversing the supervision tree of each running application and checking all the child specifications:</p> <code type="none"> {Id, StartFunc, Restart, Shutdown, Type, Modules}</code> - <p>A process is using a module if the name is listed in + <p>A process uses a module if the name is listed in <c>Modules</c> in the child specification for the process.</p> <p>If <c>Modules=dynamic</c>, which is the case for event managers, the event manager process informs the release handler - about the list of currently installed event handlers (gen_fsm) - and it is checked if the module name is in this list instead.</p> + about the list of currently installed event handlers + (<c>gen_fsm</c>), and it is checked if the module name is in + this list instead.</p> <p>The release handler suspends, asks for code change, and resumes processes by calling the functions - <c>sys:suspend/1,2</c>, <c>sys:change_code/4,5</c> and - <c>sys:resume/1,2</c> respectively.</p> + <c>sys:suspend/1,2</c>, <c>sys:change_code/4,5</c>, and + <c>sys:resume/1,2</c>, respectively.</p> </section> <section> @@ -263,39 +262,39 @@ used:</p> <code type="none"> {add_module, Module}</code> - <p>The instruction loads the module and is absolutely necessary + <p>The instruction loads the module and is necessary when running Erlang in embedded mode. It is not strictly required when running Erlang in interactive (default) mode, since the code server then automatically searches for and loads unloaded modules.</p> - <p>The opposite of <c>add_module</c> is <c>delete_module</c> which + <p>The opposite of <c>add_module</c> is <c>delete_module</c>, which unloads a module:</p> <code type="none"> {delete_module, Module}</code> - <p>Note that any process, in any application, with <c>Module</c> + <p>Any process, in any application, with <c>Module</c> as residence module, is killed when the instruction is - evaluated. The user should therefore ensure that all such + evaluated. The user must therefore ensure that all such processes are terminated before deleting the module, to avoid - a possible situation with failing supervisor restarts.</p> + a situation with failing supervisor restarts.</p> </section> <section> <title>Application Instructions</title> - <p>Instruction for adding an application:</p> + <p>The following is the instruction for adding an application:</p> <code type="none"> {add_application, Application}</code> <p>Adding an application means that the modules defined by the <c>modules</c> key in the <c>.app</c> file are loaded using - a number of <c>add_module</c> instructions, then the application + a number of <c>add_module</c> instructions, and then the application is started.</p> - <p>Instruction for removing an application:</p> + <p>The following is the instruction for removing an application:</p> <code type="none"> {remove_application, Application}</code> <p>Removing an application means that the application is stopped, the modules are unloaded using a number of <c>delete_module</c> - instructions and then the application specification is unloaded + instructions, and then the application specification is unloaded from the application controller.</p> - <p>Instruction for restarting an application:</p> + <p>The following is the instruction for restarting an application:</p> <code type="none"> {restart_application, Application}</code> <p>Restarting an application means that the application is stopped @@ -305,46 +304,48 @@ </section> <section> - <title>apply (low-level)</title> + <title>apply (Low-Level)</title> <p>To call an arbitrary function from the release handler, the following instruction is used:</p> <code type="none"> {apply, {M, F, A}}</code> - <p>The release handler will evaluate <c>apply(M, F, A)</c>.</p> + <p>The release handler evalutes <c>apply(M, F, A)</c>.</p> </section> <section> <marker id="restart_new_emulator_instr"></marker> - <title>restart_new_emulator (low-level)</title> + <title>restart_new_emulator (Low-Level)</title> <p>This instruction is used when changing to a new emulator - version, or when any of the core applications kernel, stdlib - or sasl is upgraded. If a system reboot is needed for some - other reason, the <c>restart_emulator</c> instruction should - be used instead.</p> - <p>Requires that the system is started with heart beat - monitoring, see <c>erl(1)</c> and <c>heart(3)</c>.</p> - <p>The <c>restart_new_emulator</c> instruction shall always be - the very first instruction in a relup. If the relup is - generated by <c>systools:make_relup/3,4</c> this is + version, or when any of the core applications Kernel, + STDLIB, or SASL is upgraded. If a system reboot + is needed for another reason, the <c>restart_emulator</c> + instruction is to be used instead.</p> + <p>This instruction requires that the system is started with + heartbeat monitoring, see the <c>erl(1)</c> manual page in + ERTS and the <c>heart(3)</c> manual page in Kernel.</p> + <p>The <c>restart_new_emulator</c> instruction must always be + the first instruction in a relup. If the relup is + generated by <c>systools:make_relup/3,4</c>, this is automatically ensured.</p> <p>When the release handler encounters the instruction, it first generates a temporary boot file, which starts the new versions of the emulator and the core applications, and the old version of all other applications. Then it shuts down - the current emulator by calling <c>init:reboot()</c>, see - <c>init(3)</c>. All processes are terminated gracefully and - the system is rebooted by the heart program, using the + the current emulator by calling <c>init:reboot()</c>, see the + <c>init(3)</c> manual page in Kernel. + All processes are terminated gracefully and + the system is rebooted by the <c>heart</c> program, using the temporary boot file. After the reboot, the rest of the relup instructions are executed. This is done as a part of the temporary boot script.</p> <warning> - <p>Since this mechanism causes the new versions of the - emulator and core applications to run with the old version of - other applications during startup, extra care must be taken to + <p>This mechanism causes the new versions of the emulator and + core applications to run with the old version of other + applications during startup. Thus, take extra care to avoid incompatibility. Incompatible changes in the core - applications may in some situations be necessary. If possible, + applications can in some situations be necessary. If possible, such changes are preceded by deprecation over two major - releases before the actual change. To make sure your + releases before the actual change. To ensure the application is not crashed by an incompatible change, always remove any call to deprecated functions as soon as possible.</p> @@ -352,35 +353,36 @@ <p>An info report is written when the upgrade is completed. To programmatically find out if the upgrade is complete, call <c>release_handler:which_releases(current)</c> and check - if it returns the expected (i.e. the new) release.</p> + if it returns the expected (that is, the new) release.</p> <p>The new release version must be made permanent when the new - emulator is up and running. Otherwise, the old version will be - used in case of a new system reboot.</p> - <p>On UNIX, the release handler tells the heart program which - command to use to reboot the system. Note that the environment - variable <c>HEART_COMMAND</c>, normally used by the heart - program, in this case is ignored. The command instead defaults - to <c>$ROOT/bin/start</c>. Another command can be set - by using the SASL configuration parameter <c>start_prg</c>, see - <c>sasl(6)</c>.</p> + emulator is operational. Otherwise, the old version will be + used if there is a new system reboot.</p> + <p>On UNIX, the release handler tells the <c>heart</c> program + which command to use to reboot the system. The environment + variable <c>HEART_COMMAND</c>, normally used by the <c>heart</c> + program, is ignored in this case. The command instead defaults + to <c>$ROOT/bin/start</c>. Another command can be set by using + the SASL configuration parameter <c>start_prg</c>, see + the <c>sasl(6)</c> manual page.</p> </section> <section> <marker id="restart_emulator_instr"></marker> - <title>restart_emulator (low-level)</title> - <p>This instruction is not related to upgrades of erts or any of - the core applications. It can be used by any application to + <title>restart_emulator (Low-Level)</title> + <p>This instruction is not related to upgrades of ERTS or any + of the core applications. It can be used by any application to force a restart of the emulator after all upgrade instructions are executed.</p> - <p>There can only be one <c>restart_emulator</c> instruction in - a relup script, and it shall always be placed at the end. If - the relup is generated by <c>systools:make_relup/3,4</c> this + <p>A relup script can only have one <c>restart_emulator</c> + instruction and it must always be placed at the end. If + the relup is generated by <c>systools:make_relup/3,4</c>, this is automatically ensured.</p> <p>When the release handler encounters the instruction, it shuts - down the emulator by calling <c>init:reboot()</c>, see - <c>init(3)</c>. All processes are terminated gracefully and - the system can then be rebooted by the heart program using the - new release version. No more upgrade instruction will be + down the emulator by calling <c>init:reboot()</c>, see the + <c>init(3)</c> manual page in Kernel. + All processes are terminated gracefully and the system + can then be rebooted by the <c>heart</c> program using the + new release version. No more upgrade instruction is executed after the restart.</p> </section> </section> @@ -389,10 +391,11 @@ <marker id="appup"></marker> <title>Application Upgrade File</title> <p>To define how to upgrade/downgrade between the current version - and previous versions of an application, we create an - <em>application upgrade file</em>, or in short <c>.appup</c> file. - The file should be called <c>Application.appup</c>, where - <c>Application</c> is the name of the application:</p> + and previous versions of an application, an + <em>application upgrade file</em>, or in short an <c>.appup</c> + file is created. + The file is to be called <c>Application.appup</c>, where + <c>Application</c> is the application name:</p> <code type="none"> {Vsn, [{UpFromVsn1, InstructionsU1}, @@ -401,24 +404,27 @@ [{DownToVsn1, InstructionsD1}, ..., {DownToVsnK, InstructionsDK}]}.</code> - <p><c>Vsn</c>, a string, is the current version of the application, - as defined in the <c>.app</c> file. Each <c>UpFromVsn</c> - is a previous version of the application to upgrade from, and each - <c>DownToVsn</c> is a previous version of the application to - downgrade to. Each <c>Instructions</c> is a list of release - handling instructions.</p> - <p>The syntax and contents of the <c>appup</c> file are described - in detail in <c>appup(4)</c>.</p> - <p>In the chapter <seealso marker="appup_cookbook">Appup Cookbook</seealso>, examples of <c>.appup</c> files for typical - upgrade/downgrade cases are given.</p> - <p>Example: Consider the release <c>ch_rel-1</c> from - the <seealso marker="release_structure#ch_rel">Releases</seealso> - chapter. Assume we want to add a function <c>available/0</c> to - the server <c>ch3</c> which returns the number of available - channels:</p> - <p>(Hint: When trying out the example, make the changes in a copy of - the original directory, so that the first versions are still - available.)</p> + <list type="bulleted"> + <item><c>Vsn</c>, a string, is the current version of the application, + as defined in the <c>.app</c> file.</item> + <item>Each <c>UpFromVsn</c> is a previous version of the application + to upgrade from.</item> + <item>Each <c>DownToVsn</c> is a previous version of the application + to downgrade to.</item> + <item>Each <c>Instructions</c> is a list of release handling + instructions.</item> + </list> + <p>For information about the syntax and contents of the <c>.appup</c> + file, see the <c>appup(4)</c> manual page in SASL.</p> + <p><seealso marker="appup_cookbook">Appup Cookbook</seealso> + includes examples of <c>.appup</c> files for typical upgrade/downgrade + cases.</p> + <p><em>Example:</em> Consider the release <c>ch_rel-1</c> from + <seealso marker="release_structure#ch_rel">Releases</seealso>. + Assume you want to add a function <c>available/0</c> to server + <c>ch3</c>, which returns the number of available channels (when + trying out the example, change in a copy of the original + directory, so that the first versions are still available):</p> <code type="none"> -module(ch3). -behaviour(gen_server). @@ -465,9 +471,9 @@ handle_cast({free, Ch}, Chs) -> {mod, {ch_app,[]}} ]}.</code> <p>To upgrade <c>ch_app</c> from <c>"1"</c> to <c>"2"</c> (and - to downgrade from <c>"2"</c> to <c>"1"</c>), we simply need to + to downgrade from <c>"2"</c> to <c>"1"</c>), you only need to load the new (old) version of the <c>ch3</c> callback module. - We create the application upgrade file <c>ch_app.appup</c> in + Create the application upgrade file <c>ch_app.appup</c> in the <c>ebin</c> directory:</p> <code type="none"> {"2", @@ -480,25 +486,25 @@ handle_cast({free, Ch}, Chs) -> <marker id="relup"></marker> <title>Release Upgrade File</title> <p>To define how to upgrade/downgrade between the new version and - previous versions of a release, we create a <em>release upgrade file</em>, or in short <c>relup</c> file.</p> + previous versions of a release, a <em>release upgrade file</em>, + or in short <c>relup</c> file, is to be created.</p> <p>This file does not need to be created manually, it can be generated by <c>systools:make_relup/3,4</c>. The relevant versions - of the <c>.rel</c> file, <c>.app</c> files and <c>.appup</c> files - are used as input. It is deducted which applications should be - added and deleted, and which applications that need to be upgraded - and/or downgraded. The instructions for this is fetched from + of the <c>.rel</c> file, <c>.app</c> files, and <c>.appup</c> files + are used as input. It is deducted which applications are to be + added and deleted, and which applications that must be upgraded + and/or downgraded. The instructions for this are fetched from the <c>.appup</c> files and transformed into a single list of low-level instructions in the right order.</p> <p>If the <c>relup</c> file is relatively simple, it can be created - manually. Remember that it should only contain low-level - instructions.</p> - <p>The syntax and contents of the release upgrade file are - described in detail in <c>relup(4)</c>.</p> - <p>Example, continued from the previous section. We have a new - version "2" of <c>ch_app</c> and an <c>.appup</c> file. We also - need a new version of the <c>.rel</c> file. This time the file is - called <c>ch_rel-2.rel</c> and the release version string is - changed changed from "A" to "B":</p> + manually. It it only to contain low-level instructions.</p> + <p>For details about the syntax and contents of the release upgrade + file, see the <c>relup(4)</c> manual page in SASL.</p> + <p><em>Example, continued from the previous section:</em> You have a + new version "2" of <c>ch_app</c> and an <c>.appup</c> file. A new + version of the <c>.rel</c> file is also needed. This time the file + is called <c>ch_rel-2.rel</c> and the release version string is + changed from "A" to "B":</p> <code type="none"> {release, {"ch_rel", "B"}, @@ -512,13 +518,13 @@ handle_cast({free, Ch}, Chs) -> <pre> 1> <input>systools:make_relup("ch_rel-2", ["ch_rel-1"], ["ch_rel-1"]).</input> ok</pre> - <p>This will generate a <c>relup</c> file with instructions for + <p>This generates a <c>relup</c> file with instructions for how to upgrade from version "A" ("ch_rel-1") to version "B" ("ch_rel-2") and how to downgrade from version "B" to version "A".</p> - <p>Note that both the old and new versions of the <c>.app</c> and - <c>.rel</c> files must be in the code path, as well as - the <c>.appup</c> and (new) <c>.beam</c> files. It is possible - to extend the code path by using the option <c>path</c>:</p> + <p>Both the old and new versions of the <c>.app</c> and + <c>.rel</c> files must be in the code path, as well as the + <c>.appup</c> and (new) <c>.beam</c> files. The code path can be + extended by using the option <c>path</c>:</p> <pre> 1> <input>systools:make_relup("ch_rel-2", ["ch_rel-1"], ["ch_rel-1"],</input> <input>[{path,["../ch_rel-1",</input> @@ -529,31 +535,34 @@ ok</pre> <section> <marker id="rel_handler"></marker> <title>Installing a Release</title> - <p>When we have made a new version of a release, a release package + <p>When you have made a new version of a release, a release package can be created with this new version and transferred to the target environment.</p> - <p>To install the new version of the release in run-time, + <p>To install the new version of the release in runtime, the <em>release handler</em> is used. This is a process belonging - to the SASL application, that handles unpacking, installation, - and removal of release packages. It is interfaced through - the module <c>release_handler</c>, which is described in detail in - <c>release_handler(3)</c>.</p> - <p>Assuming there is a target system up and running with + to the SASL application, which handles unpacking, installation, + and removal of release packages. It is communicated through + the <c>release_handler</c> module. For details, see the + <c>release_handler(3)</c> manual page in SASL.</p> + <p>Assuming there is an operational target system with installation root directory <c>$ROOT</c>, the release package with - the new version of the release should be copied to + the new version of the release is to be copied to <c>$ROOT/releases</c>.</p> - <p>The first action is to <em>unpack</em> the release package, - the files are then extracted from the package:</p> + <p>First, <em>unpack</em> the release package. + The files are then extracted from the package:</p> <code type="none"> release_handler:unpack_release(ReleaseName) => {ok, Vsn}</code> - <p><c>ReleaseName</c> is the name of the release package except - the <c>.tar.gz</c> extension. <c>Vsn</c> is the version of - the unpacked release, as defined in its <c>.rel</c> file.</p> - <p>A directory <c>$ROOT/lib/releases/Vsn</c> will be created, where + <list type="bulleted"> + <item><c>ReleaseName</c> is the name of the release package except + the <c>.tar.gz</c> extension.</item> + <item><c>Vsn</c> is the version of the unpacked release, as + defined in its <c>.rel</c> file.</item> + </list> + <p>A directory <c>$ROOT/lib/releases/Vsn</c> is created, where the <c>.rel</c> file, the boot script <c>start.boot</c>, - the system configuration file <c>sys.config</c> and <c>relup</c> + the system configuration file <c>sys.config</c>, and <c>relup</c> are placed. For applications with new version numbers, - the application directories will be placed under <c>$ROOT/lib</c>. + the application directories are placed under <c>$ROOT/lib</c>. Unchanged applications are not affected.</p> <p>An unpacked release can be <em>installed</em>. The release handler then evaluates the instructions in <c>relup</c>, step by @@ -563,11 +572,11 @@ release_handler:install_release(Vsn) => {ok, FromVsn, []}</code> <p>If an error occurs during the installation, the system is rebooted using the old version of the release. If installation succeeds, the system is afterwards using the new version of - the release, but should anything happen and the system is - rebooted, it would start using the previous version again. To be - made the default version, the newly installed release must be made - <em>permanent</em>, which means the previous version becomes - <em>old</em>:</p> + the release, but if anything happens and the system is + rebooted, it starts using the previous version again.</p> + <p>To be made the default version, the newly installed release + must be made <em>permanent</em>, which means the previous + version becomes <em>old</em>:</p> <code type="none"> release_handler:make_permanent(Vsn) => ok</code> <p>The system keeps information about which versions are old and @@ -579,41 +588,44 @@ release_handler:make_permanent(Vsn) => ok</code> release_handler:install_release(FromVsn) => {ok, Vsn, []}</code> <p>An installed, but not permanent, release can be <em>removed</em>. Information about the release is then deleted from - <c>$ROOT/releases/RELEASES</c> and the release specific code, - that is the new application directories and + <c>$ROOT/releases/RELEASES</c> and the release-specific code, + that is, the new application directories and the <c>$ROOT/releases/Vsn</c> directory, are removed.</p> <code type="none"> release_handler:remove_release(Vsn) => ok</code> - <p>Example, continued from the previous sections:</p> - <p>1) Create a target system as described in <em>System Principles</em> of the first version <c>"A"</c> of <c>ch_rel</c> - from - the <seealso marker="release_structure#ch_rel">Releases</seealso> - chapter. This time <c>sys.config</c> must be included in - the release package. If no configuration is needed, the file - should contain the empty list:</p> - <code type="none"> + + <section> + <title>Example (continued from the previous sections)</title> + <p><em>Step 1)</em> Create a target system as described in + System Principles of the first version <c>"A"</c> + of <c>ch_rel</c> from + <seealso marker="release_structure#ch_rel">Releases</seealso>. + This time <c>sys.config</c> must be included in the release package. + If no configuration is needed, the file is to contain the empty + list:</p> + <code type="none"> [].</code> - <p>2) Start the system as a simple target system. Note that in - reality, it should be started as an embedded system. However, - using <c>erl</c> with the correct boot script and config file is - enough for illustration purposes:</p> - <pre> + <p><em>Step 2)</em> Start the system as a simple target system. In + reality, it is to be started as an embedded system. However, using + <c>erl</c> with the correct boot script and config file is enough for + illustration purposes:</p> + <pre> % <input>cd $ROOT</input> % <input>bin/erl -boot $ROOT/releases/A/start -config $ROOT/releases/A/sys</input> ...</pre> <p><c>$ROOT</c> is the installation directory of the target system.</p> - <p>3) In another Erlang shell, generate start scripts and create a - release package for the new version <c>"B"</c>. Remember to - include (a possible updated) <c>sys.config</c> and - the <c>relup</c> file, see <seealso marker="#relup">Release Upgrade File</seealso> above.</p> - <pre> + <p><em>Step 3)</em> In another Erlang shell, generate start scripts and + create a release package for the new version <c>"B"</c>. Remember to + include (a possible updated) <c>sys.config</c> and the <c>relup</c> file, + see <seealso marker="#relup">Release Upgrade File</seealso>.</p> + <pre> 1> <input>systools:make_script("ch_rel-2").</input> ok 2> <input>systools:make_tar("ch_rel-2").</input> ok</pre> - <p>The new release package now contains version "2" of <c>ch_app</c> - and the <c>relup</c> file as well:</p> - <code type="none"> + <p>The new release package now also contains version "2" of <c>ch_app</c> + and the <c>relup</c> file:</p> + <code type="none"> % tar tf ch_rel-2.tar lib/kernel-2.9/ebin/kernel.app lib/kernel-2.9/ebin/application.beam @@ -633,28 +645,30 @@ releases/B/relup releases/B/sys.config releases/B/ch_rel-2.rel releases/ch_rel-2.rel</code> - <p>4) Copy the release package <c>ch_rel-2.tar.gz</c> to - the <c>$ROOT/releases</c> directory.</p> - <p>5) In the running target system, unpack the release package:</p> - <pre> + <p><em>Step 4)</em> Copy the release package <c>ch_rel-2.tar.gz</c> + to the <c>$ROOT/releases</c> directory.</p> + <p><em>Step 5)</em> In the running target system, unpack the release + package:</p> + <pre> 1> <input>release_handler:unpack_release("ch_rel-2").</input> {ok,"B"}</pre> <p>The new application version <c>ch_app-2</c> is installed under <c>$ROOT/lib</c> next to <c>ch_app-1</c>. The <c>kernel</c>, - <c>stdlib</c> and <c>sasl</c> directories are not affected, as + <c>stdlib</c>, and <c>sasl</c> directories are not affected, as they have not changed.</p> <p>Under <c>$ROOT/releases</c>, a new directory <c>B</c> is created, containing <c>ch_rel-2.rel</c>, <c>start.boot</c>, - <c>sys.config</c> and <c>relup</c>.</p> - <p>6) Check if the function <c>ch3:available/0</c> is available:</p> - <pre> + <c>sys.config</c>, and <c>relup</c>.</p> + <p><em>Step 6)</em> Check if the function <c>ch3:available/0</c> is + available:</p> + <pre> 2> <input>ch3:available().</input> ** exception error: undefined function ch3:available/0</pre> - <p>7) Install the new release. The instructions in + <p><em>Step 7)</em> Install the new release. The instructions in <c>$ROOT/releases/B/relup</c> are executed one by one, resulting in the new version of <c>ch3</c> being loaded. The function <c>ch3:available/0</c> is now available:</p> - <pre> + <pre> 3> <input>release_handler:install_release("B").</input> {ok,"A",[]} 4> <input>ch3:available().</input> @@ -663,15 +677,16 @@ releases/ch_rel-2.rel</code> ".../lib/ch_app-2/ebin/ch3.beam" 6> <input>code:which(ch_sup).</input> ".../lib/ch_app-1/ebin/ch_sup.beam"</pre> - <p>Note that processes in <c>ch_app</c> for which code have not - been updated, for example the supervisor, are still evaluating + <p>Processes in <c>ch_app</c> for which code have not + been updated, for example, the supervisor, are still evaluating code from <c>ch_app-1</c>.</p> - <p>8) If the target system is now rebooted, it will use version "A" - again. The "B" version must be made permanent, in order to be + <p><em>Step 8)</em> If the target system is now rebooted, it uses + version "A" again. The "B" version must be made permanent, to be used when the system is rebooted.</p> - <pre> + <pre> 7> <input>release_handler:make_permanent("B").</input> ok</pre> + </section> </section> <section> @@ -681,37 +696,40 @@ ok</pre> specifications are automatically updated for all loaded applications.</p> <note> - <p>The information about the new application specifications are + <p>The information about the new application specifications is fetched from the boot script included in the release package. - It is therefore important that the boot script is generated from + Thus, it is important that the boot script is generated from the same <c>.rel</c> file as is used to build the release package itself.</p> </note> <p>Specifically, the application configuration parameters are automatically updated according to (in increasing priority order):</p> - <list type="ordered"> + <list type="bulleted"> <item>The data in the boot script, fetched from the new application resource file <c>App.app</c></item> <item>The new <c>sys.config</c></item> - <item>Command line arguments <c>-App Par Val</c></item> + <item>Command-line arguments <c>-App Par Val</c></item> </list> <p>This means that parameter values set in the other system - configuration files, as well as values set using - <c>application:set_env/3</c>, are disregarded.</p> + configuration files and values set using + <c>application:set_env/3</c> are disregarded.</p> <p>When an installed release is made permanent, the system process <c>init</c> is set to point out the new <c>sys.config</c>.</p> - <p>After the installation, the application controller will compare + <p>After the installation, the application controller compares the old and new configuration parameters for all running applications and call the callback function:</p> <code type="none"> Module:config_change(Changed, New, Removed)</code> - <p><c>Module</c> is the application callback module as defined by - the <c>mod</c> key in the <c>.app</c> file. <c>Changed</c> and - <c>New</c> are lists of <c>{Par,Val}</c> for all changed and - added configuration parameters, respectively. <c>Removed</c> is - a list of all parameters <c>Par</c> that have been removed.</p> - <p>The function is optional and may be omitted when implementing an + <list type="bulleted"> + <item><c>Module</c> is the application callback module as defined + by the <c>mod</c> key in the <c>.app</c> file.</item> + <item><c>Changed</c> and <c>New</c> are lists of <c>{Par,Val}</c> for + all changed and added configuration parameters, respectively.</item> + <item><c>Removed</c> is a list of all parameters <c>Par</c> that have + been removed.</item> + </list> + <p>The function is optional and can be omitted when implementing an application callback module.</p> </section> </chapter> diff --git a/system/doc/design_principles/release_structure.xml b/system/doc/design_principles/release_structure.xml index cec33f42e3..aa04f5e6a3 100644 --- a/system/doc/design_principles/release_structure.xml +++ b/system/doc/design_principles/release_structure.xml @@ -28,21 +28,23 @@ <rev></rev> <file>release_structure.xml</file> </header> - <p>This chapter should be read in conjuction with <c>rel(4)</c>, - <c>systools(3)</c> and <c>script(4)</c>.</p> + <marker id="releases section"></marker> + <p>This section is to be read with the <c>rel(4)</c>, <c>systools(3)</c>, + and <c>script(4)</c> manual pages in SASL.</p> <section> <title>Release Concept</title> - <p>When we have written one or more applications, we might want to - create a complete system consisting of these applications and a + <p>When you have written one or more applications, you might want + to create a complete system with these applications and a subset of the Erlang/OTP applications. This is called a <em>release</em>.</p> - <p>To do this, we create a <seealso marker="#res_file">release resource file</seealso> which defines which applications - are included in the release.</p> + <p>To do this, create a + <seealso marker="#res_file">release resource file</seealso> that + defines which applications are included in the release.</p> <p>The release resource file is used to generate <seealso marker="#boot">boot scripts</seealso> and <seealso marker="#pack">release packages</seealso>. A system - which is transfered to and installed at another site is called a + that is transferred to and installed at another site is called a <em>target system</em>. How to use a release package to create a target system is described in System Principles.</p> </section> @@ -50,29 +52,30 @@ <section> <marker id="res_file"></marker> <title>Release Resource File</title> - <p>To define a release, we create a <em>release resource file</em>, - or in short <c>.rel</c> file, where we specify the name and - version of the release, which ERTS version it is based on, and - which applications it consists of:</p> + <p>To define a release, create a <em>release resource file</em>, + or in short a <c>.rel</c> file. In the file, specify the name and + version of the release, which ERTS version it is based on, + and which applications it consists of:</p> <code type="none"> {release, {Name,Vsn}, {erts, EVsn}, [{Application1, AppVsn1}, ... {ApplicationN, AppVsnN}]}.</code> + <p><c>Name</c>, <c>Vsn</c>, <c>EVsn</c>, and <c>AppVsn</c> are + strings.</p> <p>The file must be named <c>Rel.rel</c>, where <c>Rel</c> is a unique name.</p> - <p><c>Name</c>, <c>Vsn</c> and <c>EVsn</c> are strings.</p> - <p>Each <c>Application</c> (atom) and <c>AppVsn</c> (string) is + <p>Each <c>Application</c> (atom) and <c>AppVsn</c> is the name and version of an application included in the release. - Note that the minimal release based on Erlang/OTP consists of - the <c>kernel</c> and <c>stdlib</c> applications, so these + The minimal release based on Erlang/OTP consists of + the Kernel and STDLIB applications, so these applications must be included in the list.</p> <p>If the release is to be upgraded, it must also include - the <c>sasl</c> application.</p> + the SASL application.</p> <marker id="ch_rel"></marker> - <p>Example: We want to make a release of <c>ch_app</c> from - the <seealso marker="applications#ch_app">Applications</seealso> - chapter. It has the following <c>.app</c> file:</p> + <p><em>Example: </em> A release of <c>ch_app</c> from + <seealso marker="applications#ch_app">Applications</seealso> + has the following <c>.app</c> file:</p> <code type="none"> {application, ch_app, [{description, "Channel allocator"}, @@ -83,8 +86,8 @@ {mod, {ch_app,[]}} ]}.</code> <p>The <c>.rel</c> file must also contain <c>kernel</c>, - <c>stdlib</c> and <c>sasl</c>, since these applications are - required by <c>ch_app</c>. We call the file <c>ch_rel-1.rel</c>:</p> + <c>stdlib</c>, and <c>sasl</c>, as these applications are required + by <c>ch_app</c>. The file is called <c>ch_rel-1.rel</c>:</p> <code type="none"> {release, {"ch_rel", "A"}, @@ -99,24 +102,28 @@ <section> <marker id="boot"></marker> <title>Generating Boot Scripts</title> - <p>There are tools in the SASL module <c>systools</c> available to - build and check releases. The functions read the <c>.rel</c> and + <p><c>systools</c> in the SASL application includes tools to + build and check releases. The functions read the <c>rel</c> and <c>.app</c> files and performs syntax and dependency checks. - The function <c>systools:make_script/1,2</c> is used to generate - a boot script (see System Principles).</p> + The <c>systools:make_script/1,2</c> function is used to generate + a boot script (see System Principles):</p> <pre> 1> <input>systools:make_script("ch_rel-1", [local]).</input> ok</pre> - <p>This creates a boot script, both the readable version - <c>ch_rel-1.script</c> and the binary version used by the runtime - system, <c>ch_rel-1.boot</c>. <c>"ch_rel-1"</c> is the name of - the <c>.rel</c> file, minus the extension. <c>local</c> is an - option that means that the directories where the applications are - found are used in the boot script, instead of <c>$ROOT/lib</c>. - (<c>$ROOT</c> is the root directory of the installed release.) - This is a useful way to test a generated boot script locally.</p> + <p>This creates a boot script, both the readable version, + <c>ch_rel-1.script</c>, and the binary version, <c>ch_rel-1.boot</c>, + used by the runtime system.</p> + <list type="bulleted"> + <item><c>"ch_rel-1"</c> is the name of the <c>.rel</c> file, + minus the extension.</item> + <item><c>local</c> is an option that means that the directories + where the applications are found are used in the boot script, + instead of <c>$ROOT/lib</c> (<c>$ROOT</c> is the root directory + of the installed release).</item> + </list> + <p> This is a useful way to test a generated boot script locally.</p> <p>When starting Erlang/OTP using the boot script, all applications - from the <c>.rel</c> file are automatically loaded and started:</p> + from the <c>.rel</c> file are automatically loaded and started:</p> <pre> % <input>erl -boot ch_rel-1</input> Erlang (BEAM) emulator version 5.3 @@ -147,18 +154,24 @@ Eshell V5.3 (abort with ^G) <section> <marker id="pack"></marker> <title>Creating a Release Package</title> - <p>There is a function <c>systools:make_tar/1,2</c> which takes - a <c>.rel</c> file as input and creates a zipped tar-file with - the code for the specified applications, a <em>release package</em>.</p> + <p>The <c>systools:make_tar/1,2</c> function takes a <c>.rel</c> file + as input and creates a zipped tar file with the code for the specified + applications, a <em>release package</em>:</p> <pre> 1> <input>systools:make_script("ch_rel-1").</input> ok 2> <input>systools:make_tar("ch_rel-1").</input> ok</pre> - <p>The release package by default contains the <c>.app</c> files and - object code for all applications, structured according to - the <seealso marker="applications#app_dir">application directory structure</seealso>, the binary boot script renamed to - <c>start.boot</c>, and the <c>.rel</c> file.</p> + <p>The release package by default contains:</p> + <list type="bulleted"> + <item>The <c>.app</c> files</item> + <item>The <c>.rel</c> file</item> + <item>The object code for all applications, structured according + to the + <seealso marker="applications#app_dir">application directory + structure</seealso></item> + <item>The binary boot script renamed to <c>start.boot</c></item> + </list> <pre> % <input>tar tf ch_rel-1.tar</input> lib/kernel-2.9/ebin/kernel.app @@ -177,40 +190,39 @@ lib/ch_app-1/ebin/ch3.beam releases/A/start.boot releases/A/ch_rel-1.rel releases/ch_rel-1.rel</pre> - <p>Note that a new boot script was generated, without + <p>A new boot script was generated, without the <c>local</c> option set, before the release package was made. In the release package, all application directories are placed - under <c>lib</c>. Also, we do not know where the release package - will be installed, so we do not want any hardcoded absolute paths - in the boot script here.</p> + under <c>lib</c>. You do not know where the release package + will be installed, so no hard-coded absolute paths are allowed.</p> <p>The release resource file <c>mysystem.rel</c> is duplicated in the tar file. Originally, this file was only stored in - the <c>releases</c> directory in order to make it possible for + the <c>releases</c> directory to make it possible for the <c>release_handler</c> to extract this file separately. After unpacking the tar file, <c>release_handler</c> would automatically copy the file to <c>releases/FIRST</c>. However, sometimes the tar file is - unpacked without involving the <c>release_handler</c> (e.g. when - unpacking the first target system) and therefore the file is now - instead duplicated in the tar file so no manual copying is - necessary.</p> + unpacked without involving the <c>release_handler</c> (for + example, when unpacking the first target system) and the file + is therefore now instead duplicated in the tar file so no manual + copying is necessary.</p> <p>If a <c>relup</c> file and/or a system configuration file called - <c>sys.config</c> is found, these files are included in - the release package as well. See + <c>sys.config</c> is found, these files are also included in + the release package. See <seealso marker="release_handling#req">Release Handling</seealso>.</p> <p>Options can be set to make the release package include source code and the ERTS binary as well.</p> - <p>Refer to System Principles for how to install the first target - system, using a release package, and to - <seealso marker="release_handling">Release Handling</seealso> for - how to install a new release package in an existing system.</p> + <p>For information on how to install the first target system, using + a release package, see System Principles. For information + on how to install a new release package in an existing system, see + <seealso marker="release_handling">Release Handling</seealso>.</p> </section> <section> <marker id="reldir"></marker> <title>Directory Structure</title> - <p>Directory structure for the code installed by the release handler - from a release package:</p> + <p>The directory structure for the code installed by the release handler + from a release package is as follows:</p> <code type="none"> $ROOT/lib/App1-AVsn1/ebin /priv @@ -222,24 +234,18 @@ $ROOT/lib/App1-AVsn1/ebin /erts-EVsn/bin /releases/Vsn /bin</code> - <taglist> - <tag><c>lib</c></tag> - <item>Application directories.</item> - <tag><c>erts-EVsn/bin</c></tag> - <item>Erlang runtime system executables.</item> - <tag><c>releases/Vsn</c></tag> - <item><c>.rel</c> file and boot script <c>start.boot</c>. <br></br> - - If present in the release package, <br></br> -<c>relup</c> and/or <c>sys.config</c>.</item> - <tag><c>bin</c></tag> - <item>Top level Erlang runtime system executables.</item> - </taglist> - <p>Applications are not required to be located under the - <c>$ROOT/lib</c> directory. Accordingly, several installation - directories may exist which contain different parts of a - system. For example, the previous example could be extended as - follows:</p> + <list type="bulleted"> + <item><c>lib</c> - Application directories</item> + <item><c>erts-EVsn/bin</c> - Erlang runtime system executables</item> + <item><c>releases/Vsn</c> - <c>.rel</c> file and boot script + <c>start.boot</c>; if present in the release package, <c>relup</c> + and/or <c>sys.config</c></item> + <item><c>bin</c> - Top-level Erlang runtime system executables</item> + </list> + <p>Applications are not required to be located under directory + <c>$ROOT/lib</c>. Several installation directories, which contain + different parts of a system, can thus exist. + For example, the previous example can be extended as follows:</p> <pre> $SECOND_ROOT/.../SApp1-SAVsn1/ebin /priv @@ -256,24 +262,24 @@ $THIRD_ROOT/TApp1-TAVsn1/ebin ... /TAppN-TAVsnN/ebin /priv</pre> - <p>The <c>$SECOND_ROOT</c> and <c>$THIRD_ROOT</c> are introduced as + <p><c>$SECOND_ROOT</c> and <c>$THIRD_ROOT</c> are introduced as <c>variables</c> in the call to the <c>systools:make_script/2</c> function.</p> <section> <title>Disk-Less and/or Read-Only Clients</title> - <p>If a complete system consists of some disk-less and/or - read-only client nodes, a <c>clients</c> directory should be - added to the <c>$ROOT</c> directory. By a read-only node we - mean a node with a read-only file system.</p> - <p>The <c>clients</c> directory should have one sub-directory + <p>If a complete system consists of disk-less and/or + read-only client nodes, a <c>clients</c> directory is to be + added to the <c>$ROOT</c> directory. A read-only node is + a node with a read-only file system.</p> + <p>The <c>clients</c> directory is to have one subdirectory per supported client node. The name of each client directory - should be the name of the corresponding client node. As a - minimum, each client directory should contain the <c>bin</c> and - <c>releases</c> sub-directories. These directories are used to + is to be the name of the corresponding client node. As a + minimum, each client directory is to contain the <c>bin</c> and + <c>releases</c> subdirectories. These directories are used to store information about installed releases and to appoint the - current release to the client. Accordingly, the <c>$ROOT</c> - directory contains the following:</p> + current release to the client. The <c>$ROOT</c> + directory thus contains the following:</p> <code type="none"> $ROOT/... /clients/ClientName1/bin @@ -283,14 +289,14 @@ $ROOT/... ... /ClientNameN/bin /releases/Vsn</code> - <p>This structure should be used if all clients are running + <p>This structure is to be used if all clients are running the same type of Erlang machine. If there are clients running different types of Erlang machines, or on different operating - systems, the <c>clients</c> directory could be divided into one - sub-directory per type of Erlang machine. Alternatively, you - can set up one <c>$ROOT</c> per type of machine. For each + systems, the <c>clients</c> directory can be divided into one + subdirectory per type of Erlang machine. Alternatively, one + <c>$ROOT</c> can be set up per type of machine. For each type, some of the directories specified for the <c>$ROOT</c> - directory should be included:</p> + directory are to be included:</p> <code type="none"> $ROOT/... /clients/Type1/lib diff --git a/system/doc/design_principles/spec_proc.xml b/system/doc/design_principles/spec_proc.xml index e4fb5fdca7..aceb5ba99e 100644 --- a/system/doc/design_principles/spec_proc.xml +++ b/system/doc/design_principles/spec_proc.xml @@ -21,30 +21,31 @@ </legalnotice> - <title>Sys and Proc_Lib</title> + <title>sys and proc_lib</title> <prepared></prepared> <docno></docno> <date></date> <rev></rev> <file>spec_proc.xml</file> </header> - <p>The module <c>sys</c> contains functions for simple debugging of - processes implemented using behaviours.</p> - <p>There are also functions that, together with functions in - the module <c>proc_lib</c>, can be used to implement a - <em>special process</em>, a process which comply to the OTP design - principles without making use of a standard behaviour. They can - also be used to implement user defined (non-standard) behaviours.</p> - <p>Both <c>sys</c> and <c>proc_lib</c> belong to the STDLIB - application.</p> + <marker id="sys and proc_lib"></marker> + <p>The <c>sys</c> module has functions for simple debugging of + processes implemented using behaviours. It also has functions that, + together with functions in the <c>proc_lib</c> module, can be used + to implement a <em>special process</em> that complies to the OTP + design principles without using a standard behaviour. These + functions can also be used to implement user-defined (non-standard) + behaviours.</p> + <p>Both <c>sys</c> and <c>proc_lib</c> belong to the STDLIB + application.</p> <section> <title>Simple Debugging</title> - <p>The module <c>sys</c> contains some functions for simple debugging - of processes implemented using behaviours. We use the - <c>code_lock</c> example from - the <seealso marker="fsm#ex">gen_fsm</seealso> chapter to - illustrate this:</p> + <p>The <c>sys</c> module has functions for simple debugging of + processes implemented using behaviours. The <c>code_lock</c> + example from + <seealso marker="fsm#ex">gen_fsm Behaviour</seealso> + is used to illustrate this:</p> <pre> % <input>erl</input> Erlang (BEAM) emulator version 5.2.3.6 [hipe] [threads:0] @@ -102,16 +103,18 @@ ok <section> <title>Special Processes</title> - <p>This section describes how to write a process which comply to - the OTP design principles, without making use of a standard - behaviour. Such a process should:</p> + <p>This section describes how to write a process that complies to + the OTP design principles, without using a standard behaviour. + Such a process is to:</p> <list type="bulleted"> - <item>be started in a way that makes the process fit into a - supervision tree,</item> - <item>support the <c>sys</c> <seealso marker="#debug">debug facilities</seealso>, and</item> - <item>take care of <seealso marker="#msg">system messages</seealso>.</item> + <item>Be started in a way that makes the process fit into a + supervision tree</item> + <item>Support the <c>sys</c> + <seealso marker="#debug">debug facilities</seealso></item> + <item>Take care of + <seealso marker="#msg">system messages</seealso>.</item> </list> - <p>System messages are messages with special meaning, used in + <p>System messages are messages with a special meaning, used in the supervision tree. Typical system messages are requests for trace output, and requests to suspend or resume process execution (used during release handling). Processes implemented using @@ -120,9 +123,9 @@ ok <section> <title>Example</title> <p>The simple server from - the <seealso marker="des_princ#ch1">Overview</seealso> chapter, - implemented using <c>sys</c> and <c>proc_lib</c> so it fits into - a supervision tree:</p> + <seealso marker="des_princ#ch1">Overview</seealso>, + implemented using <c>sys</c> and <c>proc_lib</c> so it fits into a + supervision tree:</p> <marker id="ex"></marker> <pre> -module(ch4). @@ -190,8 +193,8 @@ system_replace_state(StateFun, Chs) -> write_debug(Dev, Event, Name) -> io:format(Dev, "~p event = ~p~n", [Name, Event]).</pre> - <p>Example on how the simple debugging functions in <c>sys</c> can - be used for <c>ch4</c> as well:</p> + <p>Example on how the simple debugging functions in the <c>sys</c> + module can also be used for <c>ch4</c>:</p> <pre> % <input>erl</input> Erlang (BEAM) emulator version 5.2.3.6 [hipe] [threads:0] @@ -230,31 +233,32 @@ ok <section> <title>Starting the Process</title> - <p>A function in the <c>proc_lib</c> module should be used to - start the process. There are several possible functions, for - example <c>spawn_link/3,4</c> for asynchronous start and + <p>A function in the <c>proc_lib</c> module is to be used to + start the process. Several functions are available, for + example, <c>spawn_link/3,4</c> for asynchronous start and <c>start_link/3,4,5</c> for synchronous start.</p> - <p>A process started using one of these functions will store - information that is needed for a process in a supervision tree, - for example about the ancestors and initial call.</p> - <p>Also, if the process terminates with another reason than - <c>normal</c> or <c>shutdown</c>, a crash report (see SASL - User's Guide) is generated.</p> - <p>In the example, synchronous start is used. The process is - started by calling <c>ch4:start_link()</c>:</p> + <p>A process started using one of these functions stores + information (for example, about the ancestors and initial call) + that is needed for a process in a supervision tree.</p> + <p>If the process terminates with another reason than + <c>normal</c> or <c>shutdown</c>, a crash report is generated. + For more information about the crash report, see the SASL + User's Guide.</p> + <p>In the example, synchronous start is used. The process + starts by calling <c>ch4:start_link()</c>:</p> <code type="none"> start_link() -> proc_lib:start_link(ch4, init, [self()]).</code> <p><c>ch4:start_link</c> calls the function <c>proc_lib:start_link</c>. This function takes a module name, - a function name and an argument list as arguments and spawns + a function name, and an argument list as arguments, spawns, and links to a new process. The new process starts by executing - the given function, in this case <c>ch4:init(Pid)</c>, where - <c>Pid</c> is the pid (<c>self()</c>) of the first process, that - is the parent process.</p> - <p>In <c>init</c>, all initialization including name registration - is done. The new process must also acknowledge that it has been - started to the parent:</p> + the given function, here <c>ch4:init(Pid)</c>, where + <c>Pid</c> is the pid (<c>self()</c>) of the first process, + which is the parent process.</p> + <p>All initialization, including name registration, is done in + <c>init</c>. The new process must also acknowledge that it has + been started to the parent:</p> <code type="none"> init(Parent) -> ... @@ -267,8 +271,8 @@ init(Parent) -> <section> <marker id="debug"></marker> <title>Debugging</title> - <p>To support the debug facilites in <c>sys</c>, we need a - <em>debug structure</em>, a term <c>Deb</c> which is + <p>To support the debug facilites in <c>sys</c>, a + <em>debug structure</em> is needed. The <c>Deb</c> term is initialized using <c>sys:debug_options/1</c>:</p> <code type="none"> init(Parent) -> @@ -278,50 +282,41 @@ init(Parent) -> loop(Chs, Parent, Deb).</code> <p><c>sys:debug_options/1</c> takes a list of options as argument. Here the list is empty, which means no debugging is enabled - initially. See <c>sys(3)</c> for information about possible - options.</p> - <p>Then for each <em>system event</em> that we want to be logged - or traced, the following function should be called.</p> + initially. For information about the possible options, see the + <c>sys(3)</c> manual page in STDLIB.</p> + <p>Then, for each <em>system event</em> to be logged + or traced, the following function is to be called.</p> <code type="none"> sys:handle_debug(Deb, Func, Info, Event) => Deb1</code> +<p>Here:</p> <list type="bulleted"> - <item> - <p><c>Deb</c> is the debug structure.</p> - </item> - <item> - <p><c>Func</c> is a fun specifying - a (user defined) function used to format + <item><c>Deb</c> is the debug structure.</item> + <item><c>Func</c> is a fun specifying + a (user-defined) function used to format trace output. For each system event, the format function is - called as <c>Func(Dev, Event, Info)</c>, where:</p> + called as <c>Func(Dev, Event, Info)</c>, where: <list type="bulleted"> - <item> - <p><c>Dev</c> is the IO device to which the output should - be printed. See <c>io(3)</c>.</p> - </item> - <item> - <p><c>Event</c> and <c>Info</c> are passed as-is from - <c>handle_debug</c>.</p> - </item> + <item><c>Dev</c> is the I/O device to which the output is to + be printed. See the <c>io(3)</c> manual page in + STDLIB.</item> + <item><c>Event</c> and <c>Info</c> are passed as is from + <c>handle_debug</c>.</item> </list> </item> - <item> - <p><c>Info</c> is used to pass additional information to - <c>Func</c>, it can be any term and is passed as-is.</p> - </item> - <item> - <p><c>Event</c> is the system event. It is up to the user to - define what a system event is and how it should be - represented, but typically at least incoming and outgoing + <item><c>Info</c> is used to pass more information to + <c>Func</c>. It can be any term and is passed as is.</item> + <item><c>Event</c> is the system event. It is up to the user to + define what a system event is and how it is to be + represented. Typically at least incoming and outgoing messages are considered system events and represented by the tuples <c>{in,Msg[,From]}</c> and <c>{out,Msg,To}</c>, - respectively.</p> - </item> + respectively.</item> </list> <p><c>handle_debug</c> returns an updated debug structure <c>Deb1</c>.</p> <p>In the example, <c>handle_debug</c> is called for each incoming and outgoing message. The format function <c>Func</c> is - the function <c>ch4:write_debug/3</c> which prints the message + the function <c>ch4:write_debug/3</c>, which prints the message using <c>io:format/3</c>.</p> <code type="none"> loop(Chs, Parent, Deb) -> @@ -354,22 +349,22 @@ write_debug(Dev, Event, Name) -> {system, From, Request}</code> <p>The content and meaning of these messages do not need to be interpreted by the process. Instead the following function - should be called:</p> + is to be called:</p> <code type="none"> sys:handle_system_msg(Request, From, Parent, Module, Deb, State)</code> - <p>This function does not return. It will handle the system - message and then call:</p> + <p>This function does not return. It handles the system + message and then either calls the following if process execution is + to continue:</p> <code type="none"> Module:system_continue(Parent, Deb, State)</code> - <p>if process execution should continue, or:</p> + <p>Or calls the following if the process is to terminate:</p> <code type="none"> Module:system_terminate(Reason, Parent, Deb, State)</code> - <p>if the process should terminate. Note that a process in a - supervision tree is expected to terminate with the same reason as - its parent.</p> + <p>A process in a supervision tree is expected to terminate with + the same reason as its parent.</p> <list type="bulleted"> - <item><c>Request</c> and <c>From</c> should be passed as-is from - the system message to the call to <c>handle_system_msg</c>.</item> + <item><c>Request</c> and <c>From</c> are to be passed as is from + the system message to the call to <c>handle_system_msg</c>.</item> <item><c>Parent</c> is the pid of the parent.</item> <item><c>Module</c> is the name of the module.</item> <item><c>Deb</c> is the debug structure.</item> @@ -377,10 +372,12 @@ Module:system_terminate(Reason, Parent, Deb, State)</code> is passed to <c>system_continue</c>/<c>system_terminate</c>/ <c>system_get_state</c>/<c>system_replace_state</c>.</item> </list> - <p>If the process should return its state <c>handle_system_msg</c> will call:</p> + <p>If the process is to return its state, <c>handle_system_msg</c> + calls:</p> <code type="none"> Module:system_get_state(State)</code> - <p>or if the process should replace its state using the fun <c>StateFun</c>:</p> + <p>If the process is to replace its state using the fun <c>StateFun</c>, + <c>handle_system_msg</c> calls:</p> <code type="none"> Module:system_replace_state(StateFun, State)</code> <p>In the example:</p> @@ -407,9 +404,9 @@ system_replace_state(StateFun, Chs) -> NChs = StateFun(Chs), {ok, NChs, NChs}. </code> - <p>If the special process is set to trap exits, note that if - the parent process terminates, the expected behavior is to - terminate with the same reason:</p> + <p>If the special process is set to trap exits and if the parent + process terminates, the expected behavior is to terminate with + the same reason:</p> <code type="none"> init(...) -> ..., @@ -431,43 +428,74 @@ loop(...) -> <section> <title>User-Defined Behaviours</title> - <p><marker id="behaviours"/>To implement a user-defined behaviour, write code similar to - code for a special process but calling functions in a callback + <p><marker id="behaviours"/>To implement a user-defined behaviour, + write code similar to + code for a special process, but call functions in a callback module for handling specific tasks.</p> - <p>If it is desired that the compiler should warn for missing callback - functions, as it does for the OTP behaviours, add <c>-callback</c> attributes in the + <p>If the compiler is to warn for missing callback functions, as it + does for the OTP behaviours, add <c>-callback</c> attributes in the behaviour module to describe the expected callbacks:</p> <code type="none"> -callback Name1(Arg1_1, Arg1_2, ..., Arg1_N1) -> Res1. -callback Name2(Arg2_1, Arg2_2, ..., Arg2_N2) -> Res2. ... -callback NameM(ArgM_1, ArgM_2, ..., ArgM_NM) -> ResM.</code> - <p>where <c>NameX</c> are the names of the expected callbacks and - <c>ArgX_Y</c>, <c>ResX</c> are types as they are described in Specifications - for functions in <seealso marker="../reference_manual/typespec">Types and - Function Specifications</seealso>. The whole syntax of <c>-spec</c> attribute is - supported by <c>-callback</c> attribute.</p> - <p>Alternatively you may directly implement and export the function:</p> + <p><c>NameX</c> are the names of the expected callbacks. + <c>ArgX_Y</c> and <c>ResX</c> are types as they are described in + <seealso marker="../reference_manual/typespec">Types and + Function Specifications</seealso>. The whole syntax of the <c>-spec</c> + attribute is supported by the <c>-callback</c> attribute.</p> + <p>Callback functions that are optional for the user of the + behaviour to implement are specified by use of the + <c>-optional_callbacks</c> attribute:</p> + +<code type="none"> +-optional_callbacks([OptName1/OptArity1, ..., OptNameK/OptArityK]).</code> + + <p>where each <c>OptName/OptArity</c> specifies the name and arity + of a callback function. Note that the <c>-optional_callbacks</c> + attribute is to be used together with the <c>-callback</c> + attribute; it cannot be combined with the + <c>behaviour_info()</c> function described below.</p> + <p>Tools that need to know about optional callback functions can + call <c>Behaviour:behaviour_info(optional_callbacks)</c> to get + a list of all optional callback functions.</p> + + <note><p>We recommend using the <c>-callback</c> attribute rather + than the <c>behaviour_info()</c> function. The reason is that + the extra type information can be used by tools to produce + documentation or find discrepancies.</p></note> + + <p>As an alternative to the <c>-callback</c> and + <c>-optional_callbacks</c> attributes you may directly implement + and export <c>behaviour_info()</c>:</p> + <code type="none"> behaviour_info(callbacks) -> [{Name1, Arity1},...,{NameN, ArityN}].</code> - <p>where each <c>{Name, Arity}</c> specifies the name and arity of a callback - function. This function is otherwise automatically generated by the compiler - using the <c>-callback</c> attributes.</p> + + <p>where each <c>{Name, Arity}</c> specifies the name and arity of + a callback function. This function is otherwise automatically + generated by the compiler using the <c>-callback</c> + attributes.</p> <p>When the compiler encounters the module attribute - <c>-behaviour(Behaviour).</c> in a module <c>Mod</c>, it will call - <c>Behaviour:behaviour_info(callbacks)</c> and compare the result with the - set of functions actually exported from <c>Mod</c>, and issue a warning if - any callback function is missing.</p> + <c>-behaviour(Behaviour).</c> in a module <c>Mod</c>, it + calls <c>Behaviour:behaviour_info(callbacks)</c> and compares the + result with the set of functions actually exported from + <c>Mod</c>, and issues a warning if any callback function is + missing.</p> <p>Example:</p> <code type="none"> %% User-defined behaviour module -module(simple_server). --export([start_link/2,...]). +-export([start_link/2, init/3, ...]). -callback init(State :: term()) -> 'ok'. -callback handle_req(Req :: term(), State :: term()) -> {'ok', Reply :: term()}. -callback terminate() -> 'ok'. +-callback format_state(State :: term()) -> term(). + +-optional_callbacks([format_state/1]). %% Alternatively you may define: %% diff --git a/system/doc/design_principles/sup_princ.xml b/system/doc/design_principles/sup_princ.xml index 11ef3813d6..9583ca5c55 100644 --- a/system/doc/design_principles/sup_princ.xml +++ b/system/doc/design_principles/sup_princ.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>1997</year><year>2013</year> + <year>1997</year><year>2014</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -28,15 +28,16 @@ <rev></rev> <file>sup_princ.xml</file> </header> - <p>This section should be read in conjunction with - <c>supervisor(3)</c>, where all details about the supervisor + <p>This section should be read with the + <seealso marker="stdlib:supervisor">supervisor(3)</seealso> manual page + in STDLIB, where all details about the supervisor behaviour is given.</p> <section> <title>Supervision Principles</title> - <p>A supervisor is responsible for starting, stopping and + <p>A supervisor is responsible for starting, stopping, and monitoring its child processes. The basic idea of a supervisor is - that it should keep its child processes alive by restarting them + that it is to keep its child processes alive by restarting them when necessary.</p> <p>Which child processes to start and monitor is specified by a list of <seealso marker="#spec">child specifications</seealso>. @@ -47,8 +48,8 @@ <section> <title>Example</title> <p>The callback module for a supervisor starting the server from - the <seealso marker="gen_server_concepts#ex">gen_server chapter</seealso> - could look like this:</p> + <seealso marker="gen_server_concepts#ex">gen_server Behaviour</seealso> + can look as follows:</p> <marker id="ex"></marker> <code type="none"> -module(ch_sup). @@ -61,18 +62,60 @@ start_link() -> supervisor:start_link(ch_sup, []). init(_Args) -> - {ok, {{one_for_one, 1, 60}, - [{ch3, {ch3, start_link, []}, - permanent, brutal_kill, worker, [ch3]}]}}.</code> - <p><c>one_for_one</c> is the <seealso marker="#strategy">restart strategy</seealso>.</p> - <p>1 and 60 defines the <seealso marker="#frequency">maximum restart frequency</seealso>.</p> - <p>The tuple <c>{ch3, ...}</c> is a <seealso marker="#spec">child specification</seealso>.</p> + SupFlags = #{strategy => one_for_one, intensity => 1, period => 5}, + ChildSpecs = [#{id => ch3, + start => {ch3, start_link, []}, + restart => permanent, + shutdown => brutal_kill, + type => worker, + modules => [cg3]}], + {ok, {SupFlags, ChildSpecs}}.</code> + <p>The <c>SupFlags</c> variable in the return value + from <c>init/1</c> represents + the <seealso marker="#flags">supervisor flags</seealso>.</p> + <p>The <c>ChildSpecs</c> variable in the return value + from <c>init/1</c> is a list of <seealso marker="#spec">child + specifications</seealso>.</p> + </section> + + <section> + <title>Supervisor Flags</title> + <marker id="flags"/> + <p>This is the type definition for the supervisor flags:</p> + <code type="none"><![CDATA[ +sup_flags() = #{strategy => strategy(), % optional + intensity => non_neg_integer(), % optional + period => pos_integer()} % optional + strategy() = one_for_all + | one_for_one + | rest_for_one + | simple_one_for_one]]></code> + <list type="bulleted"> + <item> + <p><c>strategy</c> specifies + the <seealso marker="#strategy">restart + strategy</seealso>.</p> + </item> + <item> + <p><c>intensity</c> and <c>period</c> specify + the <seealso marker="#max_intensity">maximum restart + intensity</seealso>.</p> + </item> + </list> </section> <section> <marker id="strategy"></marker> <title>Restart Strategy</title> + <p> The restart strategy is specified by + the <c>strategy</c> key in the supervisor flags map returned by + the callback function <c>init</c>:</p> + <code type="none"> +SupFlags = #{strategy => Strategy, ...}</code> + <p>The <c>strategy</c> key is optional in this map. If it is not + given, it defaults to <c>one_for_one</c>.</p> + <section> <title>one_for_one</title> <p>If a child process terminates, only that process is restarted.</p> @@ -85,7 +128,7 @@ init(_Args) -> <section> <title>one_for_all</title> <p>If a child process terminates, all other child processes are - terminated and then all child processes, including + terminated, and then all child processes, including the terminated one, are restarted.</p> <marker id="sup5"></marker> <image file="../design_principles/sup5.gif"> @@ -95,165 +138,208 @@ init(_Args) -> <section> <title>rest_for_one</title> - <p>If a child process terminates, the 'rest' of the child - processes -- i.e. the child processes after the terminated - process in start order -- are terminated. Then the terminated + <p>If a child process terminates, the rest of the child + processes (that is, the child processes after the terminated + process in start order) are terminated. Then the terminated child process and the rest of the child processes are restarted.</p> </section> + + <section> + <title>simple_one_for_one</title> + <p>See <seealso marker="#simple">simple-one-for-one + supervisors</seealso>.</p> + </section> </section> <section> - <marker id="frequency"></marker> - <title>Maximum Restart Frequency</title> + <marker id="max_intensity"></marker> + <title>Maximum Restart Intensity</title> <p>The supervisors have a built-in mechanism to limit the number of restarts which can occur in a given time interval. This is - determined by the values of the two parameters <c>MaxR</c> and - <c>MaxT</c> in the start specification returned by the callback - function <c>init</c>:</p> + specified by the two keys <c>intensity</c> and + <c>period</c> in the supervisor flags map returned by the + callback function <c>init</c>:</p> <code type="none"> -init(...) -> - {ok, {{RestartStrategy, MaxR, MaxT}, - [ChildSpec, ...]}}.</code> +SupFlags = #{intensity => MaxR, period => MaxT, ...}</code> <p>If more than <c>MaxR</c> number of restarts occur in the last - <c>MaxT</c> seconds, then the supervisor terminates all the child + <c>MaxT</c> seconds, the supervisor terminates all the child processes and then itself.</p> - <p>When the supervisor terminates, then the next higher level + <p>When the supervisor terminates, then the next higher-level supervisor takes some action. It either restarts the terminated - supervisor, or terminates itself.</p> + supervisor or terminates itself.</p> <p>The intention of the restart mechanism is to prevent a situation where a process repeatedly dies for the same reason, only to be restarted again.</p> + <p>The keys <c>intensity</c> and <c>period</c> are optional in the + supervisor flags map. If they are not given, they default + to <c>1</c> and <c>5</c>, respectively.</p> </section> <section> <marker id="spec"></marker> <title>Child Specification</title> - <p>This is the type definition for a child specification:</p> + <p>The type definition for a child specification is as follows:</p> <code type="none"><![CDATA[ -{Id, StartFunc, Restart, Shutdown, Type, Modules} - Id = term() - StartFunc = {M, F, A} - M = F = atom() - A = [term()] - Restart = permanent | transient | temporary - Shutdown = brutal_kill | integer()>0 | infinity - Type = worker | supervisor - Modules = [Module] | dynamic - Module = atom()]]></code> +child_spec() = #{id => child_id(), % mandatory + start => mfargs(), % mandatory + restart => restart(), % optional + shutdown => shutdown(), % optional + type => worker(), % optional + modules => modules()} % optional + child_id() = term() + mfargs() = {M :: module(), F :: atom(), A :: [term()]} + modules() = [module()] | dynamic + restart() = permanent | transient | temporary + shutdown() = brutal_kill | timeout() + worker() = worker | supervisor]]></code> <list type="bulleted"> <item> - <p><c>Id</c> is a name that is used to identify the child + <p><c>id</c> is used to identify the child specification internally by the supervisor.</p> + <p>The <c>id</c> key is mandatory.</p> + <p>Note that this identifier occasionally has been called + "name". As far as possible, the terms "identifier" or "id" + are now used but in order to keep backwards compatibility, + some occurences of "name" can still be found, for example + in error messages.</p> </item> <item> - <p><c>StartFunc</c> defines the function call used to start + <p><c>start</c> defines the function call used to start the child process. It is a module-function-arguments tuple used as <c>apply(M, F, A)</c>.</p> - <p>It should be (or result in) a call to - <c>supervisor:start_link</c>, <c>gen_server:start_link</c>, - <c>gen_fsm:start_link</c> or <c>gen_event:start_link</c>. - (Or a function compliant with these functions, see - <c>supervisor(3)</c> for details.</p> + <p>It is to be (or result in) a call to any of the following:</p> + <list type="bulleted"> + <item><c>supervisor:start_link</c></item> + <item><c>gen_server:start_link</c></item> + <item><c>gen_fsm:start_link</c></item> + <item><c>gen_event:start_link</c></item> + <item>A function compliant with these functions. For details, + see the <c>supervisor(3)</c> manual page.</item> + </list> + <p>The <c>start</c> key is mandatory.</p> </item> <item> - <p><c>Restart</c> defines when a terminated child process should + <p><c>restart</c> defines when a terminated child process is to be restarted.</p> <list type="bulleted"> <item>A <c>permanent</c> child process is always restarted.</item> <item>A <c>temporary</c> child process is never restarted - (not even when the supervisor's restart strategy - is <c>rest_for_one</c> or <c>one_for_all</c> and a sibling's + (not even when the supervisor restart strategy + is <c>rest_for_one</c> or <c>one_for_all</c> and a sibling death causes the temporary process to be terminated).</item> <item>A <c>transient</c> child process is restarted only if it - terminates abnormally, i.e. with another exit reason than - <c>normal</c>, <c>shutdown</c> or <c>{shutdown,Term}</c>.</item> + terminates abnormally, that is, with another exit reason than + <c>normal</c>, <c>shutdown</c>, or <c>{shutdown,Term}</c>.</item> </list> + <p>The <c>restart</c> key is optional. If it is not given, the + default value <c>permanent</c> will be used.</p> </item> <item> <marker id="shutdown"></marker> - <p><c>Shutdown</c> defines how a child process should be + <p><c>shutdown</c> defines how a child process is to be terminated.</p> <list type="bulleted"> - <item><c>brutal_kill</c> means the child process is + <item><c>brutal_kill</c> means that the child process is unconditionally terminated using <c>exit(Child, kill)</c>.</item> - <item>An integer timeout value means that the supervisor tells + <item>An integer time-out value means that the supervisor tells the child process to terminate by calling <c>exit(Child, shutdown)</c> and then waits for an exit signal back. If no exit signal is received within the specified time, the child process is unconditionally terminated using <c>exit(Child, kill)</c>.</item> - <item>If the child process is another supervisor, it should be + <item>If the child process is another supervisor, it is to be set to <c>infinity</c> to give the subtree enough time to - shutdown. It is also allowed to set it to <c>infinity</c>, if the - child process is a worker.</item> + shut down. It is also allowed to set it to <c>infinity</c>, + if the child process is a worker. See the warning below:</item> </list> <warning> - <p>Be careful by setting the <c>Shutdown</c> strategy to + <p>Be careful when setting the shutdown time to <c>infinity</c> when the child process is a worker. Because, in this situation, the termination of the supervision tree depends on the - child process, it must be implemented in a safe way and its cleanup + child process; it must be implemented in a safe way and its cleanup procedure must always return.</p> </warning> + <p>The <c>shutdown</c> key is optional. If it is not given, + and the child is of type <c>worker</c>, the default value + <c>5000</c> will be used; if the child is of type + <c>supervisor</c>, the default value <c>infinity</c> will be + used.</p> </item> <item> - <p><c>Type</c> specifies if the child process is a supervisor or + <p><c>type</c> specifies if the child process is a supervisor or a worker.</p> + <p>The <c>type</c> key is optional. If it is not given, the + default value <c>worker</c> will be used.</p> </item> <item> - <p><c>Modules</c> should be a list with one element + <p><c>modules</c> are to be a list with one element <c>[Module]</c>, where <c>Module</c> is the name of the callback module, if the child process is a supervisor, gen_server or gen_fsm. If the child process is a gen_event, - <c>Modules</c> should be <c>dynamic</c>.</p> + the value shall be <c>dynamic</c>.</p> <p>This information is used by the release handler during upgrades and downgrades, see <seealso marker="release_handling">Release Handling</seealso>.</p> + <p>The <c>modules</c> key is optional. If it is not given, it + defaults to <c>[M]</c>, where <c>M</c> comes from the + child's start <c>{M,F,A}</c>.</p> </item> </list> - <p>Example: The child specification to start the server <c>ch3</c> - in the example above looks like:</p> + <p><em>Example:</em> The child specification to start the server + <c>ch3</c> in the previous example look as follows:</p> + <code type="none"> +#{id => ch3, + start => {ch3, start_link, []}, + restart => permanent, + shutdown => brutal_kill, + type => worker, + modules => [ch3]}</code> + <p>or simplified, relying on the default values:</p> <code type="none"> -{ch3, - {ch3, start_link, []}, - permanent, brutal_kill, worker, [ch3]}</code> +#{id => ch3, + start => {ch3, start_link, []} + shutdown => brutal_kill}</code> <p>Example: A child specification to start the event manager from the chapter about <seealso marker="events#mgr">gen_event</seealso>:</p> <code type="none"> -{error_man, - {gen_event, start_link, [{local, error_man}]}, - permanent, 5000, worker, dynamic}</code> - <p>Both the server and event manager are registered processes which - can be expected to be accessible at all times, thus they are +#{id => error_man, + start => {gen_event, start_link, [{local, error_man}]}, + modules => dynamic}</code> + <p>Both server and event manager are registered processes which + can be expected to be always accessible. Thus they are specified to be <c>permanent</c>.</p> <p><c>ch3</c> does not need to do any cleaning up before - termination, thus no shutdown time is needed but - <c>brutal_kill</c> should be sufficient. <c>error_man</c> may + termination. Thus, no shutdown time is needed, but + <c>brutal_kill</c> is sufficient. <c>error_man</c> can need some time for the event handlers to clean up, thus - <c>Shutdown</c> is set to 5000 ms.</p> + the shutdown time is set to 5000 ms (which is the default + value).</p> <p>Example: A child specification to start another supervisor:</p> <code type="none"> -{sup, - {sup, start_link, []}, - transient, infinity, supervisor, [sup]}</code> +#{id => sup, + start => {sup, start_link, []}, + restart => transient, + type => supervisor} % will cause default shutdown=>infinity</code> </section> <section> <marker id="super_tree"></marker> <title>Starting a Supervisor</title> - <p>In the example above, the supervisor is started by calling + <p>In the previous example, the supervisor is started by calling <c>ch_sup:start_link()</c>:</p> <code type="none"> start_link() -> supervisor:start_link(ch_sup, []).</code> - <p><c>ch_sup:start_link</c> calls the function - <c>supervisor:start_link/2</c>. This function spawns and links to - a new process, a supervisor.</p> + <p><c>ch_sup:start_link</c> calls function + <c>supervisor:start_link/2</c>, which spawns and links to a new + process, a supervisor.</p> <list type="bulleted"> <item>The first argument, <c>ch_sup</c>, is the name of - the callback module, that is the module where the <c>init</c> + the callback module, that is, the module where the <c>init</c> callback function is located.</item> - <item>The second argument, [], is a term which is passed as-is to + <item>The second argument, <c>[]</c>, is a term that is passed + as is to the callback function <c>init</c>. Here, <c>init</c> does not need any indata and ignores the argument.</item> </list> @@ -262,34 +348,37 @@ start_link() -> <c>supervisor:start_link({local, Name}, Module, Args)</c> or <c>supervisor:start_link({global, Name}, Module, Args)</c>.</p> <p>The new supervisor process calls the callback function - <c>ch_sup:init([])</c>. <c>init</c> is expected to return - <c>{ok, StartSpec}</c>:</p> + <c>ch_sup:init([])</c>. <c>init</c> shall return + <c>{ok, {SupFlags, ChildSpecs}}</c>:</p> <code type="none"> init(_Args) -> - {ok, {{one_for_one, 1, 60}, - [{ch3, {ch3, start_link, []}, - permanent, brutal_kill, worker, [ch3]}]}}.</code> + SupFlags = #{}, + ChildSpecs = [#{id => ch3, + start => {ch3, start_link, []}, + shutdown => brutal_kill}], + {ok, {SupFlags, ChildSpecs}}.</code> <p>The supervisor then starts all its child processes according to the child specifications in the start specification. In this case there is one child process, <c>ch3</c>.</p> - <p>Note that <c>supervisor:start_link</c> is synchronous. It does + <p><c>supervisor:start_link</c> is synchronous. It does not return until all child processes have been started.</p> </section> <section> <title>Adding a Child Process</title> - <p>In addition to the static supervision tree, we can also add - dynamic child processes to an existing supervisor with - the following call:</p> + <p>In addition to the static supervision tree, dynamic child + processes can be added to an existing supervisor with the following + call:</p> <code type="none"> supervisor:start_child(Sup, ChildSpec)</code> <p><c>Sup</c> is the pid, or name, of the supervisor. - <c>ChildSpec</c> is a <seealso marker="#spec">child specification</seealso>.</p> + <c>ChildSpec</c> is a + <seealso marker="#spec">child specification</seealso>.</p> <p>Child processes added using <c>start_child/2</c> behave in - the same manner as the other child processes, with the following - important exception: If a supervisor dies and is re-created, then - all child processes which were dynamically added to the supervisor - will be lost.</p> + the same way as the other child processes, with the an important + exception: if a supervisor dies and is recreated, then + all child processes that were dynamically added to the supervisor + are lost.</p> </section> <section> @@ -303,18 +392,21 @@ supervisor:terminate_child(Sup, Id)</code> <code type="none"> supervisor:delete_child(Sup, Id)</code> <p><c>Sup</c> is the pid, or name, of the supervisor. - <c>Id</c> is the id specified in the <seealso marker="#spec">child specification</seealso>.</p> + <c>Id</c> is the value associated with the <c>id</c> key in + the <seealso marker="#spec">child specification</seealso>.</p> <p>As with dynamically added child processes, the effects of deleting a static child process is lost if the supervisor itself restarts.</p> </section> + <marker id="simple"/> <section> - <title>Simple-One-For-One Supervisors</title> + <title>Simplified one_for_one Supervisors</title> <p>A supervisor with restart strategy <c>simple_one_for_one</c> is - a simplified one_for_one supervisor, where all child processes are - dynamically added instances of the same process.</p> - <p>Example of a callback module for a simple_one_for_one supervisor:</p> + a simplified <c>one_for_one</c> supervisor, where all child + processes are dynamically added instances of the same process.</p> + <p>The following is an example of a callback module for a + <c>simple_one_for_one</c> supervisor:</p> <code type="none"> -module(simple_sup). -behaviour(supervisor). @@ -326,45 +418,49 @@ start_link() -> supervisor:start_link(simple_sup, []). init(_Args) -> - {ok, {{simple_one_for_one, 0, 1}, - [{call, {call, start_link, []}, - temporary, brutal_kill, worker, [call]}]}}.</code> - <p>When started, the supervisor will not start any child processes. + SupFlags = #{strategy => simple_one_for_one, + intensity => 0, + period => 1}, + ChildSpecs = [#{id => call, + start => {call, start_link, []}, + shutdown => brutal_kill}], + {ok, {SupFlags, ChildSpecs}}.</code> + <p>When started, the supervisor does not start any child processes. Instead, all child processes are added dynamically by calling:</p> <code type="none"> supervisor:start_child(Sup, List)</code> <p><c>Sup</c> is the pid, or name, of the supervisor. - <c>List</c> is an arbitrary list of terms which will be added to + <c>List</c> is an arbitrary list of terms, which are added to the list of arguments specified in the child specification. If - the start function is specified as <c>{M, F, A}</c>, then + the start function is specified as <c>{M, F, A}</c>, the child process is started by calling <c>apply(M, F, A++List)</c>.</p> <p>For example, adding a child to <c>simple_sup</c> above:</p> <code type="none"> supervisor:start_child(Pid, [id1])</code> - <p>results in the child process being started by calling + <p>The result is that the child process is started by calling <c>apply(call, start_link, []++[id1])</c>, or actually:</p> <code type="none"> call:start_link(id1)</code> - <p>A child under a <c>simple_one_for_one</c> supervisor can be terminated - with</p> + <p>A child under a <c>simple_one_for_one</c> supervisor can be + terminated with the following:</p> <code type="none"> supervisor:terminate_child(Sup, Pid)</code> - <p>where <c>Sup</c> is the pid, or name, of the supervisor and + <p><c>Sup</c> is the pid, or name, of the supervisor and <c>Pid</c> is the pid of the child.</p> - <p>Because a <c>simple_one_for_one</c> supervisor could have many children, - it shuts them all down at same time. So, order in which they are stopped is - not defined. For the same reason, it could have an overhead with regards to - the <c>Shutdown</c> strategy.</p> + <p>Because a <c>simple_one_for_one</c> supervisor can have many + children, it shuts them all down asynchronously. This means that + the children will do their cleanup in parallel and therefore the + order in which they are stopped is not defined.</p> </section> <section> <title>Stopping</title> - <p>Since the supervisor is part of a supervision tree, it will - automatically be terminated by its supervisor. When asked to - shutdown, it will terminate all child processes in reversed start + <p>Since the supervisor is part of a supervision tree, it is + automatically terminated by its supervisor. When asked to + shut down, it terminates all child processes in reversed start order according to the respective shutdown specifications, and - then terminate itself.</p> + then terminates itself.</p> </section> </chapter> |