diff options
Diffstat (limited to 'system/doc/design_principles')
49 files changed, 7065 insertions, 0 deletions
diff --git a/system/doc/design_principles/Makefile b/system/doc/design_principles/Makefile new file mode 100644 index 0000000000..b3fe136644 --- /dev/null +++ b/system/doc/design_principles/Makefile @@ -0,0 +1,115 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include $(ERL_TOP)/erts/vsn.mk + +APPLICATION=otp-system-documentation +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/doc/design_principles + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +XML_PART_FILES = part.xml + +include xmlfiles.mk + +XML_CHAPTER_FILES=$(DESIGN_PRINCIPLES_CHAPTER_FILES) + +TOPDOCDIR=.. + +BOOK_FILES = book.xml + +GIF_FILES = \ + note.gif \ + clientserver.gif \ + dist1.gif \ + dist2.gif \ + dist3.gif \ + dist4.gif \ + dist5.gif \ + inclappls.gif \ + sup4.gif \ + sup5.gif \ + sup6.gif + +XML_FILES = \ + $(BOOK_FILES) $(XML_CHAPTER_FILES) \ + $(XML_PART_FILES) + +# ---------------------------------------------------- + +HTML_FILES = \ + $(XML_PART_FILES:%.xml=%.html) + +HTMLDIR = ../html/design_principles + +HTML_UG_FILE = $(HTMLDIR)/users_guide.html + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +XML_FLAGS += +DVIPS_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +$(HTMLDIR)/%.gif: %.gif + $(INSTALL_DATA) $< $@ + +docs: html + +local_docs: PDFDIR=../../pdf + +html: $(HTML_UG_FILE) gifs + +gifs: $(GIF_FILES:%=$(HTMLDIR)/%) + +debug opt: + +clean clean_docs: + rm -rf $(HTMLDIR) + rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) + rm -f errs core *~ + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_docs_spec: docs +# $(INSTALL_DIR) $(RELEASE_PATH)/pdf +# $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf + $(INSTALL_DIR) $(RELSYSDIR) + $(INSTALL_DATA) $(GIF_FILES) $(HTMLDIR)/*.html \ + $(RELSYSDIR) + + +release_spec: + + diff --git a/system/doc/design_principles/applications.xml b/system/doc/design_principles/applications.xml new file mode 100644 index 0000000000..121c0179c6 --- /dev/null +++ b/system/doc/design_principles/applications.xml @@ -0,0 +1,378 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Applications</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <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> + + <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>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 + (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> + </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. + 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 + 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> + <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> + <code type="none"> +-module(ch_app). +-behaviour(application). + +-export([start/2, stop/1]). + +start(_Type, _Args) -> + ch_sup:start_link(). + +stop(_State) -> + ok.</code> + <p>A library application, which can not 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> + <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 + certain property of the application. All keys are optional. + Default values are used for any omitted keys.</p> + <p>The contents of a minimal <c>.app</c> file for a library + application <c>libapp</c> looks like this:</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> + <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> + <code type="none"> +ch_app:start(normal, [])</code> + <p>will be called when the application should be started and</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 type="none"> +{application, ch_app, + [{description, "Channel allocator"}, + {vsn, "1"}, + {modules, [ch_app, ch_sup, ch3]}, + {registered, [ch3]}, + {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> + <p>The syntax and contents of of the application resource file + are described in detail in <c>app(4)</c>.</p> + </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 + <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 + 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 + be omitted from the name.</p> + <p>The application directory have 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> + </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> + <marker id="application_controller"></marker> + <title>Application Controller</title> + <p>When an Erlang runtime system is started, a number of processes + are started as part of the Kernel application. One of these + 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> + </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> + <pre> +1> <input>application:load(ch_app).</input> +ok +2> <input>application:loaded_applications().</input> +[{kernel,"ERTS CXC 138 10","2.8.1.3"}, + {stdlib,"ERTS CXC 138 10","1.11.4.3"}, + {ch_app,"Channel allocator","1"}]</pre> + <p>An application that has been stopped, or has never been started, + can be unloaded. The information about the application is + erased from the internal database of the application controller.</p> + <pre> +3> <input>application:unload(ch_app).</input> +ok +4> <input>application:loaded_applications().</input> +[{kernel,"ERTS CXC 138 10","2.8.1.3"}, + {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> + </note> + </section> + + <section> + <marker id="stopping"></marker> + <title>Starting and Stopping Applications</title> + <p>An application is started by calling:</p> + <pre> +5> <input>application:start(ch_app).</input> +ok +6> <input>application:which_applications().</input> +[{kernel,"ERTS CXC 138 10","2.8.1.3"}, + {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 + 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. + 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 + the <c>.app</c> file.</p> + <p>An application is stopped, but not unloaded, by calling:</p> + <pre> +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 + 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> + </section> + + <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> + <code type="none"> +{application, ch_app, + [{description, "Channel allocator"}, + {vsn, "1"}, + {modules, [ch_app, ch_sup, ch3]}, + {registered, [ch3]}, + {applications, [kernel, stdlib, sasl]}, + {mod, {ch_app,[]}}, + {env, [{file, "/usr/local/log"}]} + ]}.</code> + <p><c>Par</c> should 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> + <pre> +% <input>erl</input> +Erlang (BEAM) emulator version 5.2.3.6 [hipe] [threads:0] + +Eshell V5.2.3.6 (abort with ^G) +1> <input>application:start(ch_app).</input> +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 + 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> + <code type="none"> +[{ch_app, [{file, "testlog"}]}].</code> + <p>The value of <c>file</c> will override the value of <c>file</c> + as defined in the <c>.app</c> file:</p> + <pre> +% <input>erl -config test</input> +Erlang (BEAM) emulator version 5.2.3.6 [hipe] [threads:0] + +Eshell V5.2.3.6 (abort with ^G) +1> <input>application:start(ch_app).</input> +ok +2> <input>application:get_env(ch_app, file).</input> +{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 + the command line:</p> + <pre> +% <input>erl -ApplName Par1 Val1 ... ParN ValN</input></pre> + <p>Example:</p> + <pre> +% <input>erl -ch_app file '"testlog"'</input> +Erlang (BEAM) emulator version 5.2.3.6 [hipe] [threads:0] + +Eshell V5.2.3.6 (abort with ^G) +1> <input>application:start(ch_app).</input> +ok +2> <input>application:get_env(ch_app, file).</input> +{ok,"testlog"}</pre> + </section> + + <section> + <title>Application Start Types</title> + <p>A <em>start type</em> is defined when starting the application:</p> + <code type="none"> +application:start(Application, Type)</code> + <p><c>application:start(Application)</c> is the same as calling + <c>application:start(Application, temporary)</c>. The type can + also be <c>permanent</c> or <c>transient</c>:</p> + <list type="bulleted"> + <item>If a permanent application terminates, all other + applications and the runtime system are also terminated.</item> + <item>If a transient application terminates with reason + <c>normal</c>, this is reported but no other applications are + terminated. If a transient application terminates abnormally, + that is with any other reason than <c>normal</c>, all other + applications and the runtime system are also terminated.</item> + <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 + 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 + a supervision tree terminates, the reason is set to + <c>shutdown</c>, not <c>normal</c>.</p> + </section> +</chapter> + diff --git a/system/doc/design_principles/appup_cookbook.xml b/system/doc/design_principles/appup_cookbook.xml new file mode 100644 index 0000000000..bc61578953 --- /dev/null +++ b/system/doc/design_principles/appup_cookbook.xml @@ -0,0 +1,627 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Appup Cookbook</title> + <prepared></prepared> + <docno></docno> + <date></date> + <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> + + <section> + <title>Changing a Functional Module</title> + <p>When a change has been made to a functional module, for example + if a new function has been added or a bug has been corrected, + simple code replacement is sufficient.</p> + <p>Example:</p> + <code type="none"> +{"2", + [{"1", [{load_module, m}]}], + [{"1", [{load_module, m}]}] +}.</code> + </section> + + <section> + <title>Changing a Residence Module</title> + <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 + 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> + </section> + + <section> + <title>Changing a Callback Module</title> + <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> + <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> + </section> + + <section> + <marker id="int_state"></marker> + <title>Changing Internal State</title> + <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 + 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 + <c>{Chs,N}</c>.</p> + <p>The <c>.appup</c> file could 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 + 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> + <marker id="code_change"></marker> + <code type="none"> +-module(ch3). +... +-export([code_change/3]). +... +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 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> + </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 + 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> + <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 + dependent on <c>ch3</c> when upgrading from "1" to "2", or + downgrading from "2" to "1":</p> + <code type="none"> +myapp.appup: + +{"2", + [{"1", [{load_module, m1, [ch3]}]}], + [{"1", [{load_module, m1, [ch3]}]}] +}. + +ch_app.appup: + +{"2", + [{"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> + <code type="none"> +{"2", + [{"1", + [{load_module, ch3}, + {load_module, m1, [ch3]}]}], + [{"1", + [{load_module, ch3}, + {load_module, m1, [ch3]}]}] +}.</code> + <p>Note that it is <c>m1</c> that 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 + <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> + <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 + 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 + find the process.</p> + </note> + <p>Example. Consider the example <c>ch4</c> from the chapter about + <seealso marker="spec_proc#ex">sys and proc_lib</seealso>. + When started by a supervisor, the child specification could look + like this:</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> + <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 + 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> + <code type="none"> +-module(ch4). +... +-export([system_code_change/4]). +... + +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> + <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 + <seealso marker="#int_state">Changing Internal State</seealso>), + it would have been 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 + 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, + 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 + 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> + <p>The following <c>upgrade</c> instruction is used for + 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> + <code type="none"> +-module(ch_sup). +... + +init(_Args) -> + {ok, {{one_for_all, 1, 60}, ...}}.</code> + <p>The file <c>ch_app.appup</c>:</p> + <code type="none"> +{"2", + [{"1", [{update, ch_sup, supervisor}]}], + [{"1", [{update, ch_sup, supervisor}]}] +}.</code> + </section> + + <section> + <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> + <code type="none"> +{"2", + [{"1", [{update, ch_sup, supervisor}]}], + [{"1", [{update, ch_sup, supervisor}]}] +}.</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, + 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 + 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 + "2" to "1":</p> + <code type="none"> +{"2", + [{"1", + [{update, ch_sup, supervisor}, + {apply, {supervisor, restart_child, [ch_sup, m1]}} + ]}], + [{"1", + [{apply, {supervisor, terminate_child, [ch_sup, m1]}}, + {apply, {supervisor, delete_child, [ch_sup, m1]}}, + {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 + <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 + 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 + deleted when downgrading:</p> + <code type="none"> +{"2", + [{"1", + [{add_module, m1}, + {update, ch_sup, supervisor}, + {apply, {supervisor, restart_child, [ch_sup, m1]}} + ]}], + [{"1", + [{apply, {supervisor, terminate_child, [ch_sup, m1]}}, + {apply, {supervisor, delete_child, [ch_sup, m1]}}, + {update, ch_sup, supervisor}, + {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 + 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 + 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 + <c>ch_app</c>:</p> + <code type="none"> +{"2", + [{"1", [{add_module, m}]}], + [{"1", [{delete_module, m}]}]</code> + </section> + + <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> + </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 + <c>remove_application</c> instructions are added automatically.</p> + </section> + + <section> + <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> + <code type="none"> +{"2", + [{"1", [{restart_application, ch_app}]}], + [{"1", [{restart_application, ch_app}]}] +}.</code> + </section> + + <section> + <marker id="app_spec"></marker> + <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> + <pre> +{"2", + [{"1", []}], + [{"1", []}] +}.</pre> + </section> + + <section> + <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> + <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 + 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 + 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 + process to <c>prim_sup</c>.</p> + <p>1) Edit the code for <c>prim_sup</c>:</p> + <code type="none"> +init(...) -> + {ok, {...supervisor flags..., + [..., + {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> + <code type="none"> +{application, prim_app, + [..., + {vsn, "2"}, + ..., + {included_applications, [ch_app]}, + ... + ]}.</code> + <p>3) Create a new <c>.rel</c> file, including <c>ch_app</c>:</p> + <code type="none"> +{release, + ..., + [..., + {prim_app, "2"}, + {ch_app, "1"}]}.</code> + + <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. + 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> + <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 + replaced by instructions for loading/unloading the application:</p> + <code type="none"> +{"B", + [{"A", + [], + [{load_object_code,{ch_app,"1",[ch_sup,ch3]}}, + {load_object_code,{prim_app,"2",[prim_app,prim_sup]}}, + point_of_no_return, + {apply,{application,stop,[prim_app]}}, + {remove,{prim_app,brutal_purge,brutal_purge}}, + {remove,{prim_sup,brutal_purge,brutal_purge}}, + {purge,[prim_app,prim_sup]}, + {load,{prim_app,brutal_purge,brutal_purge}}, + {load,{prim_sup,brutal_purge,brutal_purge}}, + {load,{ch_sup,brutal_purge,brutal_purge}}, + {load,{ch3,brutal_purge,brutal_purge}}, + {apply,{application,load,[ch_app]}}, + {apply,{application,start,[prim_app,permanent]}}]}], + [{"A", + [], + [{load_object_code,{prim_app,"1",[prim_app,prim_sup]}}, + point_of_no_return, + {apply,{application,stop,[prim_app]}}, + {apply,{application,unload,[ch_app]}}, + {remove,{ch_sup,brutal_purge,brutal_purge}}, + {remove,{ch3,brutal_purge,brutal_purge}}, + {purge,[ch_sup,ch3]}, + {remove,{prim_app,brutal_purge,brutal_purge}}, + {remove,{prim_sup,brutal_purge,brutal_purge}}, + {purge,[prim_app,prim_sup]}, + {load,{prim_app,brutal_purge,brutal_purge}}, + {load,{prim_sup,brutal_purge,brutal_purge}}, + {apply,{application,start,[prim_app,permanent]}}]}] +}.</code> + </section> + + <section> + <title>Supervisor Change</title> + <p>4b) 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 + its application specification.</p> + <p>Again, the <c>relup</c> file is created manually. Either from + 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 + the code for <c>ch_app</c> and its application specification + are unloaded.</p> + <code type="none"> +{"B", + [{"A", + [], + [{load_object_code,{ch_app,"1",[ch_sup,ch3]}}, + {load_object_code,{prim_app,"2",[prim_sup]}}, + point_of_no_return, + {load,{ch_sup,brutal_purge,brutal_purge}}, + {load,{ch3,brutal_purge,brutal_purge}}, + {apply,{application,load,[ch_app]}}, + {suspend,[prim_sup]}, + {load,{prim_sup,brutal_purge,brutal_purge}}, + {code_change,up,[{prim_sup,[]}]}, + {resume,[prim_sup]}, + {apply,{supervisor,restart_child,[prim_sup,ch_sup]}}]}], + [{"A", + [], + [{load_object_code,{prim_app,"1",[prim_sup]}}, + point_of_no_return, + {apply,{supervisor,terminate_child,[prim_sup,ch_sup]}}, + {apply,{supervisor,delete_child,[prim_sup,ch_sup]}}, + {suspend,[prim_sup]}, + {load,{prim_sup,brutal_purge,brutal_purge}}, + {code_change,down,[{prim_sup,[]}]}, + {resume,[prim_sup]}, + {remove,{ch_sup,brutal_purge,brutal_purge}}, + {remove,{ch3,brutal_purge,brutal_purge}}, + {purge,[ch_sup,ch3]}, + {apply,{application,unload,[ch_app]}}]}] +}.</code> + </section> + </section> + + <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 + <c>portc</c> and that the port is opened in the callback function + <c>init/1</c>:</p> + <code type="none"> +init(...) -> + ..., + PortPrg = filename:join(code:priv_dir(App), "portc"), + 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 + program and pass this data to the new port):</p> + <code type="none"> +code_change(_OldVsn, State, port) -> + State#state.port ! close, + receive + {Port,close} -> + true + end, + PortPrg = filename:join(code:priv_dir(App), "portc"), + Port = open_port({spawn,PortPrg}, [...]), + {ok, #state{port=Port, ...}}.</code> + <p>Update the application version number in the <c>.app</c> file + and write an <c>.appup</c> file:</p> + <code type="none"> +["2", + [{"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> + <pre> +1> <input>systools:make_tar("my_release", [{dirs,[priv]}]).</input> +...</pre> + </section> + + <section> + <title>Emulator Restart</title> + <p>If the emulator can or should be restarted, the very simple + <c>.relup</c> file can be created manually:</p> + <code type="none"> +{"B", + [{"A", + [], + [restart_new_emulator]}], + [{"A", + [], + [restart_new_emulator]}] +}.</code> + <p>This way, 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> + <p>If some transformation of persistent data, for example database + contents, needs to be done before installing the new release + version, instructions for this can be added to the <c>.relup</c> + file as well.</p> + </section> +</chapter> + diff --git a/system/doc/design_principles/book.xml b/system/doc/design_principles/book.xml new file mode 100644 index 0000000000..615722ac12 --- /dev/null +++ b/system/doc/design_principles/book.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE book SYSTEM "book.dtd"> + +<book xmlns:xi="http://www.w3.org/2001/XInclude"> + <header titlestyle="normal"> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>OTP Design Principles</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <insidecover> + </insidecover> + <pagetext>OTP Design Principles</pagetext> + <preamble> + <contents level="2"></contents> + </preamble> + <parts lift="no"> + <xi:include href="part.xml"/> + </parts> + <listofterms></listofterms> + <index></index> +</book> + diff --git a/system/doc/design_principles/clientserver.fig b/system/doc/design_principles/clientserver.fig new file mode 100644 index 0000000000..5854169ced --- /dev/null +++ b/system/doc/design_principles/clientserver.fig @@ -0,0 +1,40 @@ +#FIG 3.1 +Landscape +Center +Inches +1200 2 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 3150 750 404 404 3150 750 3300 1125 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 2175 2025 404 404 2175 2025 2325 2400 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 1650 3525 404 404 1650 3525 1800 3900 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 5025 2925 404 404 5025 2925 5175 3300 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 3375 1275 4575 2550 +2 1 1 1 -1 7 0 0 -1 4.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 4725 2325 3600 1125 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 2550 2400 4275 2925 +2 1 1 1 -1 7 0 0 -1 4.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 4275 2700 2700 2175 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 2175 3300 4125 3150 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 1 + 3975 3300 +2 1 1 1 -1 7 0 0 -1 4.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 4050 3300 2250 3450 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 5475 525 7050 525 +2 1 1 1 -1 7 0 0 -1 4.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 6975 1125 5550 1125 +4 0 -1 0 0 2 14 0.0000 4 150 645 5700 3075 Server\001 +4 0 -1 0 0 2 14 0.0000 4 150 675 900 1200 Clients\001 +4 0 -1 0 0 2 14 0.0000 4 195 570 5850 300 Query\001 +4 0 -1 0 0 2 14 0.0000 4 195 570 5850 975 Reply\001 +4 0 -1 0 0 2 14 0.0000 4 150 2370 2400 4500 The Client-server model\001 diff --git a/system/doc/design_principles/clientserver.gif b/system/doc/design_principles/clientserver.gif Binary files differnew file mode 100644 index 0000000000..371ece4c12 --- /dev/null +++ b/system/doc/design_principles/clientserver.gif diff --git a/system/doc/design_principles/clientserver.ps b/system/doc/design_principles/clientserver.ps new file mode 100644 index 0000000000..7e4e98152e --- /dev/null +++ b/system/doc/design_principles/clientserver.ps @@ -0,0 +1,199 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: clientserver.fig +%%Creator: fig2dev Version 3.1 Patchlevel 2 +%%CreationDate: Thu May 15 12:48:28 1997 +%%For: jocke@akvavit (Joakim Greben|,ETX/B/DUP) +%Magnification: 1.00 +%%Orientation: Portrait +%%BoundingBox: 0 0 370 264 +%%Pages: 0 +%%BeginSetup +%%IncludeFeature: *PageSize A4 +%%EndSetup +%%EndComments +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +-54.0 272.0 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def + /DrawEllipse { + /endangle exch def + /startangle exch def + /yrad exch def + /xrad exch def + /y exch def + /x exch def + /savematrix mtrx currentmatrix def + x y tr xrad yrad sc 0 0 1 startangle endangle arc + closepath + savematrix setmatrix + } def + +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def +%%EndProlog + +$F2psBegin +10 setmiterlimit +n 0 842 m 0 0 l 595 0 l 595 842 l cp clip + 0.06000 0.06000 sc +7.500 slw +% Ellipse +n 3150 750 404 404 0 360 DrawEllipse gs col-1 s gr + +% Ellipse +n 2175 2025 404 404 0 360 DrawEllipse gs col-1 s gr + +% Ellipse +n 1650 3525 404 404 0 360 DrawEllipse gs col-1 s gr + +% Ellipse +n 5025 2925 404 404 0 360 DrawEllipse gs col-1 s gr + +% Polyline +gs clippath +4496 2422 m 4556 2530 l 4452 2464 l 4563 2581 l 4607 2540 l cp clip +n 3375 1275 m 4575 2550 l gs col-1 s gr gr + +% arrowhead +n 4496 2422 m 4556 2530 l 4452 2464 l 4474 2443 l 4496 2422 l cp gs 0.00 setgray ef gr col-1 s +% Polyline + [66.7] 0 sd +gs clippath +3679 1253 m 3618 1144 l 3722 1212 l 3612 1094 l 3568 1135 l cp clip +n 4725 2325 m 3600 1125 l gs col-1 s gr gr + [] 0 sd +% arrowhead +n 3679 1253 m 3618 1144 l 3722 1212 l 3701 1232 l 3679 1253 l cp gs 0.00 setgray ef gr col-1 s +% Polyline +gs clippath +4143 2853 m 4249 2917 l 4126 2911 l 4281 2958 l 4298 2901 l cp clip +n 2550 2400 m 4275 2925 l gs col-1 s gr gr + +% arrowhead +n 4143 2853 m 4249 2917 l 4126 2911 l 4134 2882 l 4143 2853 l cp gs 0.00 setgray ef gr col-1 s +% Polyline + [66.7] 0 sd +gs clippath +2830 2250 m 2725 2183 l 2849 2193 l 2695 2142 l 2676 2199 l cp clip +n 4275 2700 m 2700 2175 l gs col-1 s gr gr + [] 0 sd +% arrowhead +n 2830 2250 m 2725 2183 l 2849 2193 l 2839 2221 l 2830 2250 l cp gs 0.00 setgray ef gr col-1 s +% Polyline +gs clippath +3976 3131 m 4098 3152 l 3981 3191 l 4142 3179 l 4138 3119 l cp clip +n 2175 3300 m 4125 3150 l gs col-1 s gr gr + +% arrowhead +n 3976 3131 m 4098 3152 l 3981 3191 l 3978 3161 l 3976 3131 l cp gs 0.00 setgray ef gr col-1 s +% Polyline +n 3975 3300 m 3975 3300 l gs col-1 s gr +% Polyline + [66.7] 0 sd +gs clippath +2399 3468 m 2276 3447 l 2394 3408 l 2233 3421 l 2238 3481 l cp clip +n 4050 3300 m 2250 3450 l gs col-1 s gr gr + [] 0 sd +% arrowhead +n 2399 3468 m 2276 3447 l 2394 3408 l 2396 3438 l 2399 3468 l cp gs 0.00 setgray ef gr col-1 s +% Polyline +gs clippath +6903 495 m 7023 525 l 6903 555 l 7065 555 l 7065 495 l cp clip +n 5475 525 m 7050 525 l gs col-1 s gr gr + +% arrowhead +n 6903 495 m 7023 525 l 6903 555 l 6903 525 l 6903 495 l cp gs 0.00 setgray ef gr col-1 s +% Polyline + [66.7] 0 sd +gs clippath +5697 1155 m 5577 1125 l 5697 1095 l 5535 1095 l 5535 1155 l cp clip +n 6975 1125 m 5550 1125 l gs col-1 s gr gr + [] 0 sd +% arrowhead +n 5697 1155 m 5577 1125 l 5697 1095 l 5697 1125 l 5697 1155 l cp gs 0.00 setgray ef gr col-1 s +/Times-Bold ff 210.00 scf sf +5700 3075 m +gs 1 -1 sc (Server) col-1 sh gr +/Times-Bold ff 210.00 scf sf +900 1200 m +gs 1 -1 sc (Clients) col-1 sh gr +/Times-Bold ff 210.00 scf sf +5850 300 m +gs 1 -1 sc (Query) col-1 sh gr +/Times-Bold ff 210.00 scf sf +5850 975 m +gs 1 -1 sc (Reply) col-1 sh gr +/Times-Bold ff 210.00 scf sf +2400 4500 m +gs 1 -1 sc (The Client-server model) col-1 sh gr +$F2psEnd +rs diff --git a/system/doc/design_principles/des_princ.xml b/system/doc/design_principles/des_princ.xml new file mode 100644 index 0000000000..977eda49b5 --- /dev/null +++ b/system/doc/design_principles/des_princ.xml @@ -0,0 +1,285 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Overview</title> + <prepared></prepared> + <docno></docno> + <date></date> + <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> + + <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> + <list type="bulleted"> + <item>Workers are processes which perform computations, that is, + they do the actual work.</item> + <item>Supervisors are processes which 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 + design and program fault-tolerant software.</item> + </list> + <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> + <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> + <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 + 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 + 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>, + respectively.</p> + <marker id="ch1"></marker> + <code type="none"> +-module(ch1). +-export([start/0]). +-export([alloc/0, free/1]). +-export([init/0]). + +start() -> + spawn(ch1, init, []). + +alloc() -> + ch1 ! {self(), alloc}, + receive + {ch1, Res} -> + Res + end. + +free(Ch) -> + ch1 ! {free, Ch}, + ok. + +init() -> + register(ch1, self()), + Chs = channels(), + loop(Chs). + +loop(Chs) -> + receive + {From, alloc} -> + {Ch, Chs2} = alloc(Chs), + From ! {ch1, Ch}, + loop(Chs2); + {free, Ch} -> + Chs2 = free(Ch, Chs), + loop(Chs2) + end.</code> + <p>The code for the server can be rewritten into a generic part + <c>server.erl</c>:</p> + <code type="none"> +-module(server). +-export([start/1]). +-export([call/2, cast/2]). +-export([init/1]). + +start(Mod) -> + spawn(server, init, [Mod]). + +call(Name, Req) -> + Name ! {call, self(), Req}, + receive + {Name, Res} -> + Res + end. + +cast(Name, Req) -> + Name ! {cast, Req}, + ok. + +init(Mod) -> + register(Mod, self()), + State = Mod:init(), + loop(Mod, State). + +loop(Mod, State) -> + receive + {call, From, Req} -> + {Res, State2} = Mod:handle_call(Req, State), + From ! {Mod, Res}, + loop(Mod, State2); + {cast, Req} -> + State2 = Mod:handle_cast(Req, State), + loop(Mod, State2) + end.</code> + <p>and a callback module <c>ch2.erl</c>:</p> + <code type="none"> +-module(ch2). +-export([start/0]). +-export([alloc/0, free/1]). +-export([init/0, handle_call/2, handle_cast/2]). + +start() -> + server:start(ch2). + +alloc() -> + server:call(ch2, alloc). + +free(Ch) -> + server:cast(ch2, {free, Ch}). + +init() -> + channels(). + +handle_call(alloc, Chs) -> + alloc(Chs). % => {Ch,Chs2} + +handle_cast({free, Ch}, Chs) -> + free(Ch, Chs). % => Chs2</code> + <p>Note the following:</p> + <list type="bulleted"> + <item>The code in <c>server</c> can be re-used 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 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 + the interface functions.</item> + <item>We can extend the functionality of <c>server</c>, 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 + 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 + implementation must be able to handle situations like running out + of channels to allocate etc.)</p> + <code type="none"> +channels() -> + {_Allocated = [], _Free = lists:seq(1,100)}. + +alloc({Allocated, [H|T] = _Free}) -> + {H, {[H|Allocated], T}}. + +free(Ch, {Alloc, Free} = Channels) -> + case lists:member(Ch, Alloc) of + true -> + {lists:delete(Ch, Alloc), [Ch|Free]}; + 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 + generality. The ability to manage all applications in the system + in a consistent manner is very important.</p> + <p>Using behaviours also makes it easier to read and understand + code written by other programmers. Ad hoc programming structures, + while possibly more efficient, are always more difficult to + understand.</p> + <p>The module <c>server</c> 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> + <p>The compiler understands the module attribute + <c>-behaviour(Behaviour)</c> and issues warnings about + missing callback functions. Example:</p> + <code type="none"> +-module(chs3). +-behaviour(gen_server). +... + +3> c(chs3). +./chs3.erl:10: Warning: undefined call-back function handle_call/3 +{ok,chs3}</code> + </section> + + <section> + <title>Applications</title> + <p>Erlang/OTP comes with a number of components, each implementing + 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> + <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 + 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 + supervision tree using the standard behaviours.</p> + <p>How to program applications is described in + <seealso marker="applications">Applications</seealso>.</p> + </section> + + <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> + <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> + </section> + + <section> + <title>Release Handling</title> + <p><em>Release handling</em> is upgrading and downgrading between + different versions of a release, in a (possibly) running system. + How to do this is described in + <seealso marker="release_handling">Release Handling</seealso>.</p> + </section> +</chapter> + diff --git a/system/doc/design_principles/dist1.fig b/system/doc/design_principles/dist1.fig new file mode 100644 index 0000000000..ffdb112d71 --- /dev/null +++ b/system/doc/design_principles/dist1.fig @@ -0,0 +1,20 @@ +#FIG 3.1 +Landscape +Center +Inches +1200 2 +6 2025 525 2775 1275 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 2400 900 318 318 2400 900 2625 1125 +4 0 -1 0 0 0 12 0.0000 4 180 255 2272 945 cp2\001 +-6 +6 3375 525 4125 1275 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 3750 900 318 318 3750 900 3975 1125 +4 0 -1 0 0 0 12 0.0000 4 180 255 3622 945 cp3\001 +-6 +6 675 525 1425 1575 +6 675 525 1425 1275 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 1050 900 318 318 1050 900 1275 1125 +4 0 -1 0 0 0 12 0.0000 4 180 255 922 945 cp1\001 +-6 +4 0 -1 0 0 0 12 0.0000 4 135 480 810 1500 myapp\001 +-6 diff --git a/system/doc/design_principles/dist1.gif b/system/doc/design_principles/dist1.gif Binary files differnew file mode 100644 index 0000000000..b2cde85841 --- /dev/null +++ b/system/doc/design_principles/dist1.gif diff --git a/system/doc/design_principles/dist1.ps b/system/doc/design_principles/dist1.ps new file mode 100644 index 0000000000..3b841d2cd4 --- /dev/null +++ b/system/doc/design_principles/dist1.ps @@ -0,0 +1,131 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: dist1.fig +%%Creator: fig2dev Version 3.1 Patchlevel 2 +%%CreationDate: Thu May 15 13:13:44 1997 +%%For: jocke@akvavit (Joakim Greben|,ETX/B/DUP) +%Magnification: 1.00 +%%Orientation: Portrait +%%BoundingBox: 0 0 202 58 +%%Pages: 0 +%%BeginSetup +%%IncludeFeature: *PageSize A4 +%%EndSetup +%%EndComments +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +-43.0 92.0 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def + /DrawEllipse { + /endangle exch def + /startangle exch def + /yrad exch def + /xrad exch def + /y exch def + /x exch def + /savematrix mtrx currentmatrix def + x y tr xrad yrad sc 0 0 1 startangle endangle arc + closepath + savematrix setmatrix + } def + +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def +%%EndProlog + +$F2psBegin +10 setmiterlimit +n 0 842 m 0 0 l 595 0 l 595 842 l cp clip + 0.06000 0.06000 sc +7.500 slw +% Ellipse +n 2400 900 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +2272 945 m +gs 1 -1 sc (cp2) col-1 sh gr +% Ellipse +n 3750 900 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +3622 945 m +gs 1 -1 sc (cp3) col-1 sh gr +% Ellipse +n 1050 900 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +922 945 m +gs 1 -1 sc (cp1) col-1 sh gr +/Times-Roman ff 180.00 scf sf +810 1500 m +gs 1 -1 sc (myapp) col-1 sh gr +$F2psEnd +rs diff --git a/system/doc/design_principles/dist2.fig b/system/doc/design_principles/dist2.fig new file mode 100644 index 0000000000..973cbc4a31 --- /dev/null +++ b/system/doc/design_principles/dist2.fig @@ -0,0 +1,41 @@ +#FIG 3.1 +Landscape +Center +Inches +1200 2 +6 675 525 1425 1575 +6 675 525 1425 1275 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 1050 900 318 318 1050 900 1275 1125 +4 0 -1 0 0 0 12 0.0000 4 180 255 922 945 cp1\001 +-6 +4 0 -1 0 0 0 12 0.0000 4 135 480 810 1500 myapp\001 +-6 +6 2025 525 4125 1275 +6 2025 525 2775 1275 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 2400 900 318 318 2400 900 2625 1125 +4 0 -1 0 0 0 12 0.0000 4 180 255 2272 945 cp2\001 +-6 +6 3375 525 4125 1275 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 3750 900 318 318 3750 900 3975 1125 +4 0 -1 0 0 0 12 0.0000 4 180 255 3622 945 cp3\001 +-6 +-6 +6 2700 3300 3450 4050 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 3075 3675 318 318 3075 3675 3300 3900 +4 0 -1 0 0 0 12 0.0000 4 180 255 2947 3720 cp3\001 +-6 +6 1350 3300 2100 4425 +6 1350 3300 2100 4050 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 1725 3675 318 318 1725 3675 1950 3900 +4 0 -1 0 0 0 12 0.0000 4 180 255 1597 3720 cp2\001 +-6 +4 0 -1 0 0 0 12 0.0000 4 135 480 1485 4350 myapp\001 +-6 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 525 1200 1500 525 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 600 525 1575 1350 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2 + 0 0 1.00 60.00 120.00 + 2325 1725 2325 2850 +4 0 -1 0 0 0 12 0.0000 4 135 480 2550 2325 5 secs.\001 diff --git a/system/doc/design_principles/dist2.gif b/system/doc/design_principles/dist2.gif Binary files differnew file mode 100644 index 0000000000..8351e8b7f0 --- /dev/null +++ b/system/doc/design_principles/dist2.gif diff --git a/system/doc/design_principles/dist2.ps b/system/doc/design_principles/dist2.ps new file mode 100644 index 0000000000..6fe592a4fc --- /dev/null +++ b/system/doc/design_principles/dist2.ps @@ -0,0 +1,160 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: dist2.fig +%%Creator: fig2dev Version 3.1 Patchlevel 2 +%%CreationDate: Thu May 15 13:13:55 1997 +%%For: jocke@akvavit (Joakim Greben|,ETX/B/DUP) +%Magnification: 1.00 +%%Orientation: Portrait +%%BoundingBox: 0 0 215 233 +%%Pages: 0 +%%BeginSetup +%%IncludeFeature: *PageSize A4 +%%EndSetup +%%EndComments +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +-30.0 263.0 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def + /DrawEllipse { + /endangle exch def + /startangle exch def + /yrad exch def + /xrad exch def + /y exch def + /x exch def + /savematrix mtrx currentmatrix def + x y tr xrad yrad sc 0 0 1 startangle endangle arc + closepath + savematrix setmatrix + } def + +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def +%%EndProlog + +$F2psBegin +10 setmiterlimit +n 0 842 m 0 0 l 595 0 l 595 842 l cp clip + 0.06000 0.06000 sc +7.500 slw +% Ellipse +n 1050 900 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +922 945 m +gs 1 -1 sc (cp1) col-1 sh gr +/Times-Roman ff 180.00 scf sf +810 1500 m +gs 1 -1 sc (myapp) col-1 sh gr +% Ellipse +n 2400 900 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +2272 945 m +gs 1 -1 sc (cp2) col-1 sh gr +% Ellipse +n 3750 900 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +3622 945 m +gs 1 -1 sc (cp3) col-1 sh gr +% Ellipse +n 3075 3675 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +2947 3720 m +gs 1 -1 sc (cp3) col-1 sh gr +% Ellipse +n 1725 3675 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +1597 3720 m +gs 1 -1 sc (cp2) col-1 sh gr +/Times-Roman ff 180.00 scf sf +1485 4350 m +gs 1 -1 sc (myapp) col-1 sh gr +% Polyline +n 525 1200 m 1500 525 l gs col-1 s gr +% Polyline +n 600 525 m 1575 1350 l gs col-1 s gr +% Polyline +gs clippath +2355 2703 m 2325 2823 l 2295 2703 l 2295 2865 l 2355 2865 l cp clip +n 2325 1725 m 2325 2850 l gs col-1 s gr gr + +% arrowhead +n 2355 2703 m 2325 2823 l 2295 2703 l col-1 s +/Times-Roman ff 180.00 scf sf +2550 2325 m +gs 1 -1 sc (5 secs.) col-1 sh gr +$F2psEnd +rs diff --git a/system/doc/design_principles/dist3.fig b/system/doc/design_principles/dist3.fig new file mode 100644 index 0000000000..d7e32d0887 --- /dev/null +++ b/system/doc/design_principles/dist3.fig @@ -0,0 +1,33 @@ +#FIG 3.1 +Landscape +Center +Inches +1200 2 +6 1275 300 2325 1125 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 1275 975 2250 300 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 1350 300 2325 1125 +-6 +6 2775 300 3525 1050 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 3150 675 318 318 3150 675 3375 900 +4 0 -1 0 0 0 12 0.0000 4 180 255 3022 720 cp3\001 +-6 +6 1425 300 2175 1425 +6 1425 300 2175 1050 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 1800 675 318 318 1800 675 2025 900 +4 0 -1 0 0 0 12 0.0000 4 180 255 1672 720 cp2\001 +-6 +4 0 -1 0 0 0 12 0.0000 4 135 480 1560 1350 myapp\001 +-6 +6 1950 3225 2700 4350 +6 1950 3225 2700 3975 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 2325 3600 318 318 2325 3600 2550 3825 +4 0 -1 0 0 0 12 0.0000 4 180 255 2197 3645 cp3\001 +-6 +4 0 -1 0 0 0 12 0.0000 4 135 480 2085 4275 myapp\001 +-6 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2 + 0 0 1.00 60.00 120.00 + 2325 1725 2325 2850 +4 0 -1 0 0 0 12 0.0000 4 135 480 2550 2325 5 secs.\001 diff --git a/system/doc/design_principles/dist3.gif b/system/doc/design_principles/dist3.gif Binary files differnew file mode 100644 index 0000000000..e95958cc16 --- /dev/null +++ b/system/doc/design_principles/dist3.gif diff --git a/system/doc/design_principles/dist3.ps b/system/doc/design_principles/dist3.ps new file mode 100644 index 0000000000..3e0e93f5db --- /dev/null +++ b/system/doc/design_principles/dist3.ps @@ -0,0 +1,148 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: dist3.fig +%%Creator: fig2dev Version 3.1 Patchlevel 2 +%%CreationDate: Thu May 15 13:14:01 1997 +%%For: jocke@akvavit (Joakim Greben|,ETX/B/DUP) +%Magnification: 1.00 +%%Orientation: Portrait +%%BoundingBox: 0 0 134 242 +%%Pages: 0 +%%BeginSetup +%%IncludeFeature: *PageSize A4 +%%EndSetup +%%EndComments +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +-75.0 259.0 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def + /DrawEllipse { + /endangle exch def + /startangle exch def + /yrad exch def + /xrad exch def + /y exch def + /x exch def + /savematrix mtrx currentmatrix def + x y tr xrad yrad sc 0 0 1 startangle endangle arc + closepath + savematrix setmatrix + } def + +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def +%%EndProlog + +$F2psBegin +10 setmiterlimit +n 0 842 m 0 0 l 595 0 l 595 842 l cp clip + 0.06000 0.06000 sc +7.500 slw +% Polyline +n 1275 975 m 2250 300 l gs col-1 s gr +% Polyline +n 1350 300 m 2325 1125 l gs col-1 s gr +% Ellipse +n 3150 675 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +3022 720 m +gs 1 -1 sc (cp3) col-1 sh gr +% Ellipse +n 1800 675 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +1672 720 m +gs 1 -1 sc (cp2) col-1 sh gr +/Times-Roman ff 180.00 scf sf +1560 1350 m +gs 1 -1 sc (myapp) col-1 sh gr +% Ellipse +n 2325 3600 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +2197 3645 m +gs 1 -1 sc (cp3) col-1 sh gr +/Times-Roman ff 180.00 scf sf +2085 4275 m +gs 1 -1 sc (myapp) col-1 sh gr +% Polyline +gs clippath +2355 2703 m 2325 2823 l 2295 2703 l 2295 2865 l 2355 2865 l cp clip +n 2325 1725 m 2325 2850 l gs col-1 s gr gr + +% arrowhead +n 2355 2703 m 2325 2823 l 2295 2703 l col-1 s +/Times-Roman ff 180.00 scf sf +2550 2325 m +gs 1 -1 sc (5 secs.) col-1 sh gr +$F2psEnd +rs diff --git a/system/doc/design_principles/dist4.fig b/system/doc/design_principles/dist4.fig new file mode 100644 index 0000000000..d40be27ad6 --- /dev/null +++ b/system/doc/design_principles/dist4.fig @@ -0,0 +1,16 @@ +#FIG 3.1 +Landscape +Center +Inches +1200 2 +6 1425 300 2175 1050 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 1800 675 318 318 1800 675 2025 900 +4 0 -1 0 0 0 12 0.0000 4 180 255 1672 720 cp2\001 +-6 +6 2775 300 3525 1500 +6 2775 300 3525 1050 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 3150 675 318 318 3150 675 3375 900 +4 0 -1 0 0 0 12 0.0000 4 180 255 3022 720 cp3\001 +-6 +4 0 -1 0 0 0 12 0.0000 4 135 480 2910 1425 myapp\001 +-6 diff --git a/system/doc/design_principles/dist4.gif b/system/doc/design_principles/dist4.gif Binary files differnew file mode 100644 index 0000000000..b1d996b861 --- /dev/null +++ b/system/doc/design_principles/dist4.gif diff --git a/system/doc/design_principles/dist4.ps b/system/doc/design_principles/dist4.ps new file mode 100644 index 0000000000..9bcf3dd880 --- /dev/null +++ b/system/doc/design_principles/dist4.ps @@ -0,0 +1,125 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: dist4.fig +%%Creator: fig2dev Version 3.1 Patchlevel 2 +%%CreationDate: Thu May 15 13:14:06 1997 +%%For: jocke@akvavit (Joakim Greben|,ETX/B/DUP) +%Magnification: 1.00 +%%Orientation: Portrait +%%BoundingBox: 0 0 121 67 +%%Pages: 0 +%%BeginSetup +%%IncludeFeature: *PageSize A4 +%%EndSetup +%%EndComments +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +-88.0 88.0 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def + /DrawEllipse { + /endangle exch def + /startangle exch def + /yrad exch def + /xrad exch def + /y exch def + /x exch def + /savematrix mtrx currentmatrix def + x y tr xrad yrad sc 0 0 1 startangle endangle arc + closepath + savematrix setmatrix + } def + +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def +%%EndProlog + +$F2psBegin +10 setmiterlimit +n 0 842 m 0 0 l 595 0 l 595 842 l cp clip + 0.06000 0.06000 sc +7.500 slw +% Ellipse +n 1800 675 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +1672 720 m +gs 1 -1 sc (cp2) col-1 sh gr +% Ellipse +n 3150 675 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +3022 720 m +gs 1 -1 sc (cp3) col-1 sh gr +/Times-Roman ff 180.00 scf sf +2910 1425 m +gs 1 -1 sc (myapp) col-1 sh gr +$F2psEnd +rs diff --git a/system/doc/design_principles/dist5.fig b/system/doc/design_principles/dist5.fig new file mode 100644 index 0000000000..77f2d74c59 --- /dev/null +++ b/system/doc/design_principles/dist5.fig @@ -0,0 +1,40 @@ +#FIG 3.1 +Landscape +Center +Inches +1200 2 +6 750 3000 4200 4050 +6 2100 3000 2850 3750 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 2475 3375 318 318 2475 3375 2700 3600 +4 0 -1 0 0 0 12 0.0000 4 180 255 2347 3420 cp2\001 +-6 +6 3450 3000 4200 3750 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 3825 3375 318 318 3825 3375 4050 3600 +4 0 -1 0 0 0 12 0.0000 4 180 255 3697 3420 cp3\001 +-6 +6 750 3000 1500 4050 +6 750 3000 1500 3750 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 1125 3375 318 318 1125 3375 1350 3600 +4 0 -1 0 0 0 12 0.0000 4 180 255 997 3420 cp1\001 +-6 +4 0 -1 0 0 0 12 0.0000 4 135 480 885 3975 myapp\001 +-6 +-6 +6 2100 300 2850 1050 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 2475 675 318 318 2475 675 2700 900 +4 0 -1 0 0 0 12 0.0000 4 180 255 2347 720 cp2\001 +-6 +6 3450 300 4200 1425 +6 3450 300 4200 1050 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 3825 675 318 318 3825 675 4050 900 +4 0 -1 0 0 0 12 0.0000 4 180 255 3697 720 cp3\001 +-6 +4 0 -1 0 0 0 12 0.0000 4 135 480 3585 1350 myapp\001 +-6 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2 + 0 0 1.00 60.00 120.00 + 2175 2325 1425 2925 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2 + 0 0 1.00 60.00 120.00 + 3600 1350 2775 1950 +4 0 -1 0 0 0 12 0.0000 4 180 3270 750 2175 cp1: application:takeover(myapp, permanent)\001 diff --git a/system/doc/design_principles/dist5.gif b/system/doc/design_principles/dist5.gif Binary files differnew file mode 100644 index 0000000000..3ef5cda3f6 --- /dev/null +++ b/system/doc/design_principles/dist5.gif diff --git a/system/doc/design_principles/dist5.ps b/system/doc/design_principles/dist5.ps new file mode 100644 index 0000000000..daeb56b2b7 --- /dev/null +++ b/system/doc/design_principles/dist5.ps @@ -0,0 +1,165 @@ +%!PS-Adobe-2.0 +%%Title: dist5.fig +%%Creator: fig2dev Version 3.1 Patchlevel 2 +%%CreationDate: Mon Feb 15 08:40:37 1999 +%%For: nibe@gundor (Bengt Nilsson, ETX/DN/SP) +%Magnification: 1.00 +%%Orientation: Portrait +%%BoundingBox: 203 286 408 506 +%%Pages: 1 +%%BeginSetup +%%IncludeFeature: *PageSize Letter +%%EndSetup +%%EndComments +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +158.5 527.0 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def + /DrawEllipse { + /endangle exch def + /startangle exch def + /yrad exch def + /xrad exch def + /y exch def + /x exch def + /savematrix mtrx currentmatrix def + x y tr xrad yrad sc 0 0 1 startangle endangle arc + closepath + savematrix setmatrix + } def + +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def +%%EndProlog + +$F2psBegin +10 setmiterlimit +n 0 792 m 0 0 l 612 0 l 612 792 l cp clip + 0.06000 0.06000 sc +%%Page: 1 1 +7.500 slw +% Ellipse +n 2475 3375 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +2347 3420 m +gs 1 -1 sc (cp2) col-1 sh gr +% Ellipse +n 3825 3375 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +3697 3420 m +gs 1 -1 sc (cp3) col-1 sh gr +% Ellipse +n 1125 3375 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +997 3420 m +gs 1 -1 sc (cp1) col-1 sh gr +/Times-Roman ff 180.00 scf sf +885 3975 m +gs 1 -1 sc (myapp) col-1 sh gr +% Ellipse +n 2475 675 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +2347 720 m +gs 1 -1 sc (cp2) col-1 sh gr +% Ellipse +n 3825 675 318 318 0 360 DrawEllipse gs col-1 s gr + +/Times-Roman ff 180.00 scf sf +3697 720 m +gs 1 -1 sc (cp3) col-1 sh gr +/Times-Roman ff 180.00 scf sf +3585 1350 m +gs 1 -1 sc (myapp) col-1 sh gr +% Polyline +gs clippath +1559 2857 m 1446 2908 l 1521 2810 l 1395 2911 l 1432 2958 l cp clip +n 2175 2325 m 1425 2925 l gs col-1 s gr gr + +% arrowhead +n 1559 2857 m 1446 2908 l 1521 2810 l col-1 s +% Polyline +gs clippath +2912 1888 m 2796 1934 l 2876 1839 l 2745 1935 l 2781 1983 l cp clip +n 3600 1350 m 2775 1950 l gs col-1 s gr gr + +% arrowhead +n 2912 1888 m 2796 1934 l 2876 1839 l col-1 s +/Times-Roman ff 180.00 scf sf +750 2175 m +gs 1 -1 sc (cp1: application:takeover\(myapp, permanent\)) col-1 sh gr +showpage +$F2psEnd +rs diff --git a/system/doc/design_principles/distributed_applications.xml b/system/doc/design_principles/distributed_applications.xml new file mode 100644 index 0000000000..39a24b3598 --- /dev/null +++ b/system/doc/design_principles/distributed_applications.xml @@ -0,0 +1,217 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Distributed Applications</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>distributed_applications.xml</file> + </header> + + <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 + the node, where a certain application is running, goes down, + the application should 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 + 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> + </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> + <p>For distribution of application control to work properly, + the nodes where a distributed application may 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 + <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 + 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> + <code type="none"> +[{kernel, + [{distributed, [{myapp, 5000, [cp1@cave, {cp2@cave, cp3@cave}]}]}, + {sync_nodes_mandatory, [cp2@cave, cp3@cave]}, + {sync_nodes_timeout, 5000} + ] + } +].</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 + <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> + </note> + </section> + + <section> + <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> + <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> + <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. + 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> + <marker id="dist1"></marker> + <image file="../design_principles/dist1.gif"> + <icaption>Application myapp - Situation 1</icaption> + </image> + <p>Similarly, the application must be stopped by calling + <c>application:stop(Application)</c> at all involved nodes.</p> + </section> + + <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 + <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> + <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 + 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 + <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 + restart within 5 seconds. <c>myapp</c> is now restarted on + <c>cp3</c>.</p> + <marker id="dist3"></marker> + <image file="../design_principles/dist3.gif"> + <icaption>Application myapp - Situation 3</icaption> + </image> + </section> + + <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 + 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 + 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 + <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> + <marker id="dist5"></marker> + <image file="../design_principles/dist5.gif"> + <icaption>Application myapp - Situation 5</icaption> + </image> + </section> +</chapter> + diff --git a/system/doc/design_principles/events.xml b/system/doc/design_principles/events.xml new file mode 100644 index 0000000000..5579f1e459 --- /dev/null +++ b/system/doc/design_principles/events.xml @@ -0,0 +1,221 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Gen_Event Behaviour</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <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> + + <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 + event handlers. For example, an event manager for handling errors + 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> + <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> + </section> + + <section> + <title>Example</title> + <p>The callback module for the event handler writing error messages + to the terminal could look like:</p> + <code type="none"> +-module(terminal_logger). +-behaviour(gen_event). + +-export([init/1, handle_event/2, terminate/2]). + +init(_Args) -> + {ok, []}. + +handle_event(ErrorMsg, State) -> + io:format("***Error*** ~p~n", [ErrorMsg]), + {ok, State}. + +terminate(_Args, _State) -> + ok.</code> + <p>The callback module for the event handler writing error messages + to a file could look like:</p> + <code type="none"> +-module(file_logger). +-behaviour(gen_event). + +-export([init/1, handle_event/2, terminate/2]). + +init(File) -> + {ok, Fd} = file:open(File, read), + {ok, Fd}. + +handle_event(ErrorMsg, Fd) -> + io:format(Fd, "***Error*** ~p~n", [ErrorMsg]), + {ok, Fd}. + +terminate(_Args, Fd) -> + file:close(Fd).</code> + <p>The code is explained in the next sections.</p> + </section> + + <section> + <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> + <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>If the name is omitted, the event manager is not registered. + Instead its pid must be used. The name could 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.</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> + <pre> +1> <input>gen_event:start({local, error_man}).</input> +{ok,<0.31.0>} +2> <input>gen_event:add_handler(error_man, terminal_logger, []).</input> +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 + 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 + not used. For <c>file_logger</c>, the internal state is used + to save the open file descriptor.</p> + <code type="none"> +init(File) -> + {ok, Fd} = file:open(File, read), + {ok, Fd}.</code> + </section> + + <section> + <title>Notifying About Events</title> + <pre> +3> <input>gen_event:notify(error_man, no_reply).</input> +***Error*** no_reply +ok</pre> + <p><c>error_man</c> is the name of the event manager and + <c>no_reply</c> is the event.</p> + <p>The event is made into a message and sent to the event manager. + 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 + <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"> +handle_event(ErrorMsg, State) -> + io:format("***Error*** ~p~n", [ErrorMsg]), + {ok, State}.</code> + <p>In <c>file_logger</c>:</p> + <code type="none"> +handle_event(ErrorMsg, Fd) -> + io:format(Fd, "***Error*** ~p~n", [ErrorMsg]), + {ok, Fd}.</code> + </section> + + <section> + <title>Deleting an Event Handler</title> + <pre> +4> <input>gen_event:delete_handler(error_man, terminal_logger, []).</input> +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 + 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 + 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> + <code type="none"> +terminate(_Args, Fd) -> + file:close(Fd).</code> + </section> + + <section> + <title>Stopping</title> + <p>When an event manager is stopped, it will give 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 + 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> + </section> + + <section> + <title>Stand-Alone Event Managers</title> + <p>An event manager can also be stopped by calling:</p> + <pre> +> <input>gen_event:stop(error_man).</input> +ok</pre> + </section> + </section> +</chapter> + diff --git a/system/doc/design_principles/fsm.xml b/system/doc/design_principles/fsm.xml new file mode 100644 index 0000000000..7cdd62057b --- /dev/null +++ b/system/doc/design_principles/fsm.xml @@ -0,0 +1,313 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <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> + + <section> + <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> + </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> + <pre> +StateName(Event, StateData) -> + .. code for actions here ... + {next_state, StateName', StateData'}</pre> + </section> + + <section> + <title>Example</title> + <p>A door with a code lock could 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). + 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> + <marker id="ex"></marker> + <code type="none"><![CDATA[ +-module(code_lock). +-behaviour(gen_fsm). + +-export([start_link/1]). +-export([button/1]). +-export([init/1, locked/2, open/2]). + +start_link(Code) -> + gen_fsm:start_link({local, code_lock}, code_lock, Code, []). + +button(Digit) -> + gen_fsm:send_event(code_lock, {button, Digit}). + +init(Code) -> + {ok, locked, {[], Code}}. + +locked({button, Digit}, {SoFar, Code}) -> + case [Digit|SoFar] of + Code -> + do_unlock(), + {next_state, open, {[], Code}, 3000}; + Incomplete when length(Incomplete)<length(Code) -> + {next_state, locked, {Incomplete, Code}}; + _Wrong -> + {next_state, locked, {[], Code}} + end. + +open(timeout, State) -> + do_lock(), + {next_state, locked, State}.]]></code> + <p>The code is explained in the next sections.</p> + </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> + <code type="none"> +start_link(Code) -> + gen_fsm:start_link({local, code_lock}, code_lock, 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> + <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> + </item> + <item> + <p>The second argument, <c>code_lock</c>, is the name of + 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 + 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 term which is passed + as-is 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> + </item> + </list> + <p>If name registration succeeds, the new gen_fsm 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 + 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 + 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> + </section> + + <section> + <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>. + <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> + <code type="none"><![CDATA[ +locked({button, Digit}, {SoFar, Code}) -> + case [Digit|SoFar] of + Code -> + do_unlock(), + {next_state, open, {[], Code}, 30000}; + Incomplete when length(Incomplete)<length(Code) -> + {next_state, locked, {Incomplete, Code}}; + _Wrong -> + {next_state, locked, {[], Code}}; + end. + +open(timeout, State) -> + do_lock(), + {next_state, locked, State}.]]></code> + <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> + </section> + + <section> + <title>Timeouts</title> + <p>When a correct code has been givened, 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> + <code type="none"> +open(timeout, State) -> + do_lock(), + {next_state, locked, State}.</code> + </section> + + <section> + <title>All State Events</title> + <p>Sometimes an event can arrive at any state of the gen_fsm. + 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> + and handled with <c>Module:handle_event/3</c>:</p> + <code type="none"> +-module(code_lock). +... +-export([stop/0]). +... + +stop() -> + gen_fsm:send_all_state_event(code_lock, stop). + +... + +handle_event(stop, _StateName, StateData) -> + {stop, normal, StateData}.</code> + </section> + + <section> + <title>Stopping</title> + + <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> + 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 + <c>terminate(shutdown, StateName, StateData)</c>:</p> + <code type="none"> +init(Args) -> + ..., + process_flag(trap_exit, true), + ..., + {ok, StateName, StateData}. + +... + +terminate(shutdown, StateName, StateData) -> + ..code for cleaning up here.. + ok.</code> + </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> + <code type="none"> +... +-export([stop/0]). +... + +stop() -> + gen_fsm:send_all_state_event(code_lock, stop). +... + +handle_event(stop, _StateName, StateData) -> + {stop, normal, 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> + 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 + <c>terminate(normal,StateName,StateData1)</c> and then + terminate 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 + 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> + </section> +</chapter> + diff --git a/system/doc/design_principles/gen_server_concepts.xml b/system/doc/design_principles/gen_server_concepts.xml new file mode 100644 index 0000000000..8131c47a69 --- /dev/null +++ b/system/doc/design_principles/gen_server_concepts.xml @@ -0,0 +1,269 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Gen_Server Behaviour</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <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> + + <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 + different clients want to share a common resource. The server is + responsible for managing this resource.</p> + <marker id="clientserver"></marker> + <image file="../design_principles/clientserver.gif"> + <icaption>Client-Server Model</icaption> + </image> + </section> + + <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>, + resulting in this callback module:</p> + <marker id="ex"></marker> + <code type="none"> +-module(ch3). +-behaviour(gen_server). + +-export([start_link/0]). +-export([alloc/0, free/1]). +-export([init/1, handle_call/3, handle_cast/2]). + +start_link() -> + gen_server:start_link({local, ch3}, ch3, [], []). + +alloc() -> + gen_server:call(ch3, alloc). + +free(Ch) -> + gen_server:cast(ch3, {free, Ch}). + +init(_Args) -> + {ok, channels()}. + +handle_call(alloc, _From, Chs) -> + {Ch, Chs2} = alloc(Chs), + {reply, Ch, Chs2}. + +handle_cast({free, Ch}, Chs) -> + Chs2 = free(Ch, Chs), + {noreply, Chs2}.</code> + <p>The code is explained in the next sections.</p> + </section> + + <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> + <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> + <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 + 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 + 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 + <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 + 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> + </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> + <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 + 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> + </section> + + <section> + <title>Synchronous Requests - Call</title> + <p>The synchronous request <c>alloc()</c> is implemented using + <c>gen_server:call/2</c>:</p> + <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> + <code type="none"> +handle_call(alloc, _From, Chs) -> + {Ch, Chs2} = alloc(Chs), + {reply, Ch, Chs2}.</code> + <p>In this case, the reply is the allocated channel <c>Ch</c> and + 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> + </section> + + <section> + <title>Asynchronous Requests - Cast</title> + <p>The asynchronous request <c>free(Ch)</c> is implemented using + <c>gen_server:cast/2</c>:</p> + <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. + <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> + <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 + requests.</p> + </section> + + <section> + <title>Stopping</title> + + <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 + 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_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> + <code type="none"> +init(Args) -> + ..., + process_flag(trap_exit, true), + ..., + {ok, State}. + +... + +terminate(shutdown, State) -> + ..code for cleaning up here.. + ok.</code> + </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> + <code type="none"> +... +export([stop/0]). +... + +stop() -> + gen_server:cast(ch3, stop). +... + +handle_cast(stop, State) -> + {stop, normal, State}; +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> + 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> + </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> + 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> + <code type="none"> +handle_info({'EXIT', Pid, Reason}, State) -> + ..code to handle exits here.. + {noreply, State1}.</code> + </section> +</chapter> + diff --git a/system/doc/design_principles/inclappls.fig b/system/doc/design_principles/inclappls.fig new file mode 100644 index 0000000000..03885c72d6 --- /dev/null +++ b/system/doc/design_principles/inclappls.fig @@ -0,0 +1,33 @@ +#FIG 3.1 +Landscape +Center +Inches +1200 2 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 2700 900 530 530 2700 900 3075 1275 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 750 2400 375 375 750 2400 975 2700 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 1950 2400 375 375 1950 2400 2175 2700 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 3150 2475 375 375 3150 2475 3375 2775 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 4425 2475 375 375 4425 2475 4650 2775 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 5700 2475 375 375 5700 2475 5925 2775 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 3600 3600 375 375 3600 3600 3825 3900 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 2625 3600 375 375 2625 3600 2850 3900 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 675 3600 375 375 675 3600 900 3900 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 975 2100 2250 1200 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 2025 2025 2475 1425 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 3000 2100 2850 1425 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 3150 1275 4125 2250 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 3225 1050 5400 2250 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 675 2775 675 3225 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 3225 2850 3525 3225 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 3075 2850 2700 3225 +4 0 -1 0 0 2 14 0.0000 4 195 1905 3525 975 Primary application \001 +4 0 -1 0 0 2 14 0.0000 4 195 1950 6525 2550 Included applications\001 +4 0 -1 0 0 2 14 0.0000 4 195 1950 6525 3675 Included applications\001 diff --git a/system/doc/design_principles/inclappls.gif b/system/doc/design_principles/inclappls.gif Binary files differnew file mode 100644 index 0000000000..8b88d6d23e --- /dev/null +++ b/system/doc/design_principles/inclappls.gif diff --git a/system/doc/design_principles/inclappls.ps b/system/doc/design_principles/inclappls.ps new file mode 100644 index 0000000000..239be1b3b3 --- /dev/null +++ b/system/doc/design_principles/inclappls.ps @@ -0,0 +1,808 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: (ImageMagick) +%%Title: (./inclappls.tmp.eps) +%%CreationDate: (Tue Jun 12 17:22:15 2001) +%%BoundingBox: 0 20 377 197 +%%DocumentData: Clean7Bit +%%LanguageLevel: 1 +%%Pages: 0 +%%EndComments + +%%BeginDefaults +%%PageOrientation: Portrait +%%EndDefaults + +%%BeginProlog +% +% Display a color image. The image is displayed in color on +% Postscript viewers or printers that support color, otherwise +% it is displayed as grayscale. +% +/buffer 512 string def +/byte 1 string def +/color_packet 3 string def +/pixels 768 string def + +/DirectClassPacket +{ + % + % Get a DirectClass packet. + % + % Parameters: + % red. + % green. + % blue. + % length: number of pixels minus one of this color (optional). + % + currentfile color_packet readhexstring pop pop + compression 0 gt + { + /number_pixels 3 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add 3 mul def + } ifelse + 0 3 number_pixels 1 sub + { + pixels exch color_packet putinterval + } for + pixels 0 number_pixels getinterval +} bind def + +/DirectClassImage +{ + % + % Display a DirectClass image. + % + systemdict /colorimage known + { + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { DirectClassPacket } false 3 colorimage + } + { + % + % No colorimage operator; convert to grayscale. + % + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { GrayDirectClassPacket } image + } ifelse +} bind def + +/GrayDirectClassPacket +{ + % + % Get a DirectClass packet; convert to grayscale. + % + % Parameters: + % red + % green + % blue + % length: number of pixels minus one of this color (optional). + % + currentfile color_packet readhexstring pop pop + color_packet 0 get 0.299 mul + color_packet 1 get 0.587 mul add + color_packet 2 get 0.114 mul add + cvi + /gray_packet exch def + compression 0 gt + { + /number_pixels 1 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add def + } ifelse + 0 1 number_pixels 1 sub + { + pixels exch gray_packet put + } for + pixels 0 number_pixels getinterval +} bind def + +/GrayPseudoClassPacket +{ + % + % Get a PseudoClass packet; convert to grayscale. + % + % Parameters: + % index: index into the colormap. + % length: number of pixels minus one of this color (optional). + % + currentfile byte readhexstring pop 0 get + /offset exch 3 mul def + /color_packet colormap offset 3 getinterval def + color_packet 0 get 0.299 mul + color_packet 1 get 0.587 mul add + color_packet 2 get 0.114 mul add + cvi + /gray_packet exch def + compression 0 gt + { + /number_pixels 1 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add def + } ifelse + 0 1 number_pixels 1 sub + { + pixels exch gray_packet put + } for + pixels 0 number_pixels getinterval +} bind def + +/PseudoClassPacket +{ + % + % Get a PseudoClass packet. + % + % Parameters: + % index: index into the colormap. + % length: number of pixels minus one of this color (optional). + % + currentfile byte readhexstring pop 0 get + /offset exch 3 mul def + /color_packet colormap offset 3 getinterval def + compression 0 gt + { + /number_pixels 3 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add 3 mul def + } ifelse + 0 3 number_pixels 1 sub + { + pixels exch color_packet putinterval + } for + pixels 0 number_pixels getinterval +} bind def + +/PseudoClassImage +{ + % + % Display a PseudoClass image. + % + % Parameters: + % class: 0-PseudoClass or 1-Grayscale. + % + currentfile buffer readline pop + token pop /class exch def pop + class 0 gt + { + currentfile buffer readline pop + token pop /depth exch def pop + /grays columns 8 add depth sub depth mul 8 idiv string def + columns rows depth + [ + columns 0 0 + rows neg 0 rows + ] + { currentfile grays readhexstring pop } image + } + { + % + % Parameters: + % colors: number of colors in the colormap. + % colormap: red, green, blue color packets. + % + currentfile buffer readline pop + token pop /colors exch def pop + /colors colors 3 mul def + /colormap colors string def + currentfile colormap readhexstring pop pop + systemdict /colorimage known + { + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { PseudoClassPacket } false 3 colorimage + } + { + % + % No colorimage operator; convert to grayscale. + % + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { GrayPseudoClassPacket } image + } ifelse + } ifelse +} bind def + +/DisplayImage +{ + % + % Display a DirectClass or PseudoClass image. + % + % Parameters: + % x & y translation. + % x & y scale. + % label pointsize. + % image label. + % image columns & rows. + % class: 0-DirectClass or 1-PseudoClass. + % compression: 0-RunlengthEncodedCompression or 1-NoCompression. + % hex color packets. + % + gsave + currentfile buffer readline pop + token pop /x exch def + token pop /y exch def pop + x y translate + currentfile buffer readline pop + token pop /x exch def + token pop /y exch def pop + currentfile buffer readline pop + token pop /pointsize exch def pop + /Helvetica findfont pointsize scalefont setfont + x y scale + currentfile buffer readline pop + token pop /columns exch def + token pop /rows exch def pop + currentfile buffer readline pop + token pop /class exch def pop + currentfile buffer readline pop + token pop /compression exch def pop + class 0 gt { PseudoClassImage } { DirectClassImage } ifelse + grestore +} bind def +%%EndProlog +%%Page: 1 1 +%%PageBoundingBox: 0 20 377 197 +userdict begin +%%BeginData: +DisplayImage +0 20 +377.000000 177.000000 +12 +566 266 +1 +1 +1 +1 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffffffff +fffffffffffff000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffffffffff +ffffffffff0fff0fffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffffffffffff +fffffff8fffff1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffffffffffffff +ffffe7fffffe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffcffffffffffffffffffffffffffffffffffff +ff9fffffff9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffcfffffffffffffffffffffffffffffffffffffe +7fffffffe7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffcfffffffffffffffffffffffffffffffffffffdff +fffffffbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffcfffffffffffffffffffffffffffffffffffff3ffff +fffffcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffcffffffffffffffffffffffffffffffffffffefffffff +ffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffcffffffffffffffffffffffffffffffffffffdfffffffff +ffbfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffcffffffffffffffffffffffffffffffffffffbfffffffffff +dfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffcffffffffffffffffffffffffffffffffffff7fffffffffffef +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffcfffffffffffffffffffffffffffffffffffefffffffffffff7ff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffcfffffffffffffffffffffffffffffffffffdfffffffffffffbffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffcfffffffffffffffffffffffffffffffffffbfffffffffffffdffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffcfffffffffffffffffffffffffffffffffffbfffffffffffffdffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffcfffffffffffffffffffffffffffffffffff7fffffffffffffeffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffcffffffffffffffffffffffffffffffffffefffffffffffffff7fffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffcffffffffffffffffffffffffffffffffffefffffffffffffff7fffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffcffffffffffffffffffffffffffffffffffdfffffffffffffffbfffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffcffffffffffffffffffffffffffffffffffdfffffffffffffffbfffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fcffffffffffffffffffffffffffffffffffbfffffffffffffffdfffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc +ffffffffffffffffffffffffffffffffffbfffffffffffffffdfffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcff +ffffffffffffffffffffffffffffffff7fffffffffffffffefffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffff +ffffffffffffffffffffffffffffff7fffffffffffffffefffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffff +ffffffffffffffffffffffffffff7fffffffffffffffefffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffff +fffffffffffffffffffffffffefffffffffffffffff7ffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffff +fffffffffffffffffffffffefffffffffffffffff7ffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffff +fffffffffffffffffffffefffffffffffffffff7ffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffff +fffffffffffffffffffefffffffffffffffff7ffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffff +fffffffffffffffffdfffffffffffffffffbffff01fe7ffffffffffffffc4fffff3fffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffff +fffffffffffffffdfffffffffffffffffbffff9cfe7ffffffffffffffe4ffffb3fffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffff +fffffffffffffdfffffffffffffffffbffff9cfffffffffffffffffe7ffff3ffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffff +fffffffffffdfffffffffffffffffbffff9c9062230c813f0c8c8e0f086038623fffffff +fffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffff +fffffffffdfffffffffffffffffbffff9cc871126649be6666664e433333313fffffffff +fffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffffff +fffffffdfffffffffffffffffbffff81ce73326679be6666664e733333333fffffffffff +fffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffffffff +fffffdfffffffffffffffffbffff9fce7333867d7f8666664e7c3333333fffffffffffff +fffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffffffffff +fffdfffffffffffffffffbffff9fce7332667c7e6666664e733333333fffffffffffffff +fffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffffffffffff +fdfffffffffffffffffbffff9fce7332667c7e6626264e233233333fffffffffffffffff +fffffffffffffffffffffffffffffffffffffcfffffffffffffffffffffffffffffffffd +fffffffffffffffffbffff0f842110103efe124e4c07109018611fffffffffffffffffff +fffffffffffffffffffffffffffffffffffcfffffffffffffffffffffffffffffffffdff +fffffffffffffffbfffffffffffffffefffe7e7fffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffcfffffffffffffffffffffffffffffffffdffff +fffffffffffffbfffffffffffffff2fffe7e7fffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffcfffffffffffffffffffffffffffffffffeffffff +fffffffffff7fffffffffffffff1fffc3c3fffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffcfffffffffffffffffffffffffffffffffeffffffff +fffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffcfffffffffffffffffffffffffffffffffeffffffffff +fffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffcfffffffffffffffffffffffffffffffffeffffffffffff +fffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffcffffffffffffffffffffffffffffffffff7fffffffffffff +ffe9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffcffffffffffffffffffffffffffffffffff7fffffffffffffff +ee7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffcffffffffffffffffffffffffffffffffff7fffffffffffffffef +9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffcffffffffffffffffffffffffffffffffffbfffffffffffffffdfe7 +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffcffffffffffffffffffffffffffffffffffbfffffffffffffffdffbff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffcffffffffffffffffffffffffffffffffffdfffffffffffffffbffcffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffcffffffffffffffffffffffffffffffffffdfffffffffffffffbfff3fffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffcffffffffffffffffffffffffffffffffffefffffffffffffff7fffcfffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffcffffffffffffffffffffffffffffffffffefffffffffffffff7ffff3ffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffcffffffffffffffffffffffffffffffffffe7fffffffffffffefffffcffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffcffffffffffffffffffffffffffffffffff9bfffffffffffffdffffff7fffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fcffffffffffffffffffffffffffffffffff7bfffffffffffffdffffff9fffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc +fffffffffffffffffffffffffffffffffefdfffffffffffffbffffffe7ffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcff +fffffffffffffffffffffffffffffff9fefffffffffffff7fffffff9ffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffff +fffffffffffffffffffffffffffff7ff7fffffffffffeefffffffe7fffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffff +ffffffffffffffffffffffffffcfffbfffffffffffdf7fffffffbfffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffff +ffffffffffffffffffffffffbfffdfffffffffffbfbfffffffcfffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffff +fffffffffffffffffffffe7fffefffffffffff7fdffffffff3ffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffff +fffffffffffffffffffdfffff3fffffffffcffeffffffffcffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffff +fffffffffffffffffbfffffdfffffffffbfff7ffffffff3fffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffff +ffffffffffffffe7fffffe7fffffffe7fffbffffffffdfffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffff +ffffffffffffdfffffff9fffffff9ffffdffffffffe7ffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffff +ffffffffff3fffffffe7fffffe7ffffefffffffff9ffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffff +fffffffefffffffff8fffff1ffffff7ffffffffe7fffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffff +fffffdffffffffdf0fff0fffffffbfffffffff9fffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffffff +fff3ffffffffbff000efffffffdfffffffffe7ffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffffffff +efffffffffbfffffefffffffeffffffffffbffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffffffff9f +ffffffff7ffffff7fffffff7fffffffffcffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffffffff7fff +fffffefffffff7fffffffbffffffffff3fffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffcfffffffffffffffffffffffffffcffffff +fffdfffffff7fffffffdffffffffffcfffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffcfffffffffffffffffffffffffffbffffffff +fdfffffff7fffffffefffffffffff3ffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffcfffffffffffffffffffffffffff7fffffffffb +fffffffbffffffff7ffffffffffdffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffcffffffffffffffffffffffffffcffffffffff7ff +fffffbffffffffbffffffffffe7fffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffcffffffffffffffffffffffffffbfffffffffefffff +fffbffffffffdfffffffffff9fffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffcfffffffffffffffffffffffffe7fffffffffefffffff +fbffffffffefffffffffffe7ffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffcfffffffffffffffffffffffffdffffffffffdffffffffb +fffffffff7fffffffffff9ffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffcfffffffffffffffffffffffffbffffffffffbffffffffdff +fffffffbfffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffcffffffffffffffffffffffffe7ffffffffff7ffffffffdffff +fffffdffffffffffff3fffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffcffffffffffffffffffffffffdfffffffffff7ffffffffdffffff +fffeffffffffffffcfffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffcffffffffffffffffffffffff3ffffffffffefffffffffdffffffff +ff7ffffffffffff3ffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffcfffffffffffffffffffffffefffffffffffdfffffffffeffffffffff +bffffffffffffcffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffcfffffffffffffffffffffff9fffffffffffbfffffffffeffffffffffdf +ffffffffffff3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffcfffffffffffffffffffffff7fffffffffffbfffffffffeffffffffffefff +ffffffffffdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffcffffffffffffffffffffffeffffffffffff7fffffffffefffffffffff7ffff +ffffffffe7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffcffffffffffffffffffffff9fffffffffffeffffffffffefffffffffffbffffff +fffffff9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffcffffffffffffffffffffff7fffffffffffdfffffffffff7ffffffffffdffffffff +fffffe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffcfffffffffffffffffffffcffffffffffffdfffffffffff7ffffffffffeffffffffff +ffff9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fcfffffffffffffffffffffbffffffffffffbfffffffffff7fffffffffff7fffffffffff +ffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc +fffffffffffffffffffff7ffffffffffff7fffffffffff7fffffffffffbfffffffffffff +f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcff +ffffffffffffffffffcffffffffffffeffffffffffffbfffffffffffdffffffffffffffc +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffff +ffffffffffffffffbffffffffffffeffffffffffffbfffffffffffefffffffffffffff3f +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffff +fffffffffffffe7ffffffffffffdffffffffffffbffffffffffff7ffffffffffffffcfff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffff +fffffffffffdfffffffffffffbffffffffffffbffffffffffffbfffffffffffffff7ffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffff +fffffffff3fffffffffffff7ffffffffffffbffffffffffffdfffffffffffffff9ffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffff +ffffffeffffffffffffff7ffffffffffffdffffffffffffefffffffffffffffe7fffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffff +ffffdfffffffffffffefffffffffffffdfffffffffffff7fffffffffffffff9fffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffff +ff3fffffffffffffdfffffffffffffdfffffffffffffbfffffffffffffffe7ffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffcfffffffffffffffffe +ffffffffffffffbfffffffffffffdfffffffffffffdffffffffffffffff9ffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffcfffffffffffffffff9ff +ffffffffffffbfffffffffffffefffffffffffffeffffffffffffffffeffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffcfffffffffffffffff7ffff +ffffffffff7fffffffffffffeffffffffffffff7ffffffffffffffff3fffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffefffffff +fffffffeffffffffffffffeffffffffffffffbffffffffffffffffcfffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffff9fffffffff +fffffdffffffffffffffeffffffffffffffdfffffffffffffffff3ffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffcffffffffffffffff7fffffffffff +fffdffffffffffffffeffffffffffffffefffffffffffffffffcffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffcfffffffffffffffcffffffffffffff +fbfffffffffffffff7ffffffffffffff7fffffffffffffffff7fffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffcffffffffe00ffffbffffffffffffe007 +fffffffffffffff7ffffffffffffffbfffffffffffffffff9fffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffcfffffffe1ff0ffe7fffffffffffe1ff0ff +fffffffffffff7ffffffffffffffdfffffffffffffffffe7ffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffcfffffff9ffff3fdffffffffffff9ffff3fff +fffffffffff7ffffffffffffffeffffffffffffffffff9ffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffcffffffe7ffffcfbfffffffffffe7ffffcfffff +fffffffffbfffffffffffffff7fffffffffffffffffe7fffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffcffffff9ffffff27fffffffffff9ffffff3ffffff +fffffffbfffffffffffffffbffffffffffffffffffbfffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffcffffff7ffffffdffffffffffff7ffffffdffffffff +fffffbe00ffffffffffffdffffff007fffffffffcffffffff803ffffffffffffffffffff +fffffffffffffffffffffffffffcfffffefffffffefffffffffffefffffffeffffffffff +fffe1ff0fffffffffffefffff0ff87fffffffff3ffffff87fc3fffffffffffffffffffff +fffffffffffffffffffffffffcfffffdffffffff7ffffffffffdffffffff7fffffffffff +f9ffff3fffffffffff7fffcffff9fffffffffcfffffe7fffcfffffffffffffffffffffff +fffffffffffffffffffffffcfffffbffffffffbffffffffffbffffffffbfffffffffffe7 +ffffcfffffffffffbfff3ffffe7fffffffff3ffff9fffff3ffffffffffffffffffffffff +fffffffffffffffffffffcfffff7ffffffffdffffffffff7ffffffffdfffffffffff9fff +fff3ffffffffffdffcffffff9fffffffffcfffe7fffffcffffffffffffffffffffffffff +fffffffffffffffffffcffffefffffffffefffffffffefffffffffefffffffffff7fffff +fdffffffffffeffbffffffeffffffffff7ffdfffffff7fffffffffffffffffffffffffff +fffffffffffffffffcffffdffffffffff7ffffffffdffffffffff7fffffffffefffffffe +fffffffffff7f7fffffff7fffffffff9ffbfffffffbfffffffffffffffffffffffffffff +fffffffffffffffcffffdffffffffff7ffffffffdffffffffff7fffffffffdffffffff7f +fffffffffbeffffffffbfffffffffe7f7fffffffdfffffffffffffffffffffffffffffff +fffffffffffffcffffbffffffffffbffffffffbffffffffffbfffffffffbffffffffbfff +fffffffddffffffffdffffffffff9effffffffefffffffffffffffffffffffffffffffff +fffffffffffcffffbffffffffffbffffffffbffffffffffbfffffffff7ffffffffdfffff +fffffebffffffffeffffffffffe5fffffffff7ffffffffffffffffffffffffffffffffff +fffffffffcffff7ffffffffffdffffffff7ffffffffffdffffffffefffffffffefffffff +ffff7fffffffff7ffffffffffbfffffffffbffffffffffffffffffffffffffffffffffff +fffffffcffff7ffffffffffdffffffff7ffffffffffdffffffffdffffffffff7ffffffff +feffffffffffbffffffffff7fffffffffdffffffffffffffffffffffffffffffffffffff +fffffcfffefffffffffffefffffffefffffffffffeffffffffdffffffffff7fffffffffe +ffffffffffbffffffffff7fffffffffdffffffffffffffffffffffffffffffffffffffff +fffcfffefffffffffffefffffffefffffffffffeffffffffbffffffffffbfffffffffdff +ffffffffdfffffffffeffffffffffeffffffffffffffffffffffffffffffffffffffffff +fcfffefffffffffffefffffffefffffffffffeffffffffbffffffffffbfffffffffdffff +ffffffdfffffffffeffffffffffefffffffffffffffffffffffffffffffffffffffffffc +fffefffffffffffefffffffefffffffffffeffffffff7ffffffffffdfffffffffbffffff +ffffefffffffffdfffffffffff7ffffffffffffffffffffffffffffffffffffffffffcff +fdffffffffffff7ffffffdffffffffffff7fffffff7ffffffffffdfffffffffbffffffff +ffefffffffffdfffffffffff7ffffffffffffffffffffffffffffffffffffffffffcfffd +ffffffffffff7ffffffdffffffffffff7ffffffefffffffffffefffffffff7ffffffffff +f7ffffffffbfffffffffffbffffffffffffffffffffffffffffffffffffffffffcfffdff +ffffffffff7ffffffdffffffffffff7ffffffefffffffffffefffffffff7fffffffffff7 +ffffffffbfffffffffffbffffffffffffffffffffffffffffffffffffffffffcfffdffff +ffffffff7ffffffdffffffffffff7ffffffefffffffffffefffffffff7fffffffffff7ff +ffffffbfffffffffffbffffffffffffffffffffffffffffffffffffffffffcfffdffffff +ffffff7ffffffdffffffffffff7ffffffefffffffffffefffffffff7fffffffffff7ffff +ffffbfffffffffffbfffffff87ffe3ffc7ff1fffffff13ffffcffffffffcfffdffffffff +ffff7ffffffdffffffffffff7ffffffdffffffffffff7fffffffeffffffffffffbffffff +ff7fffffffffffdfffffffcffff3ffe7ff9fffffff93fffecffffffffcfffdffffffffff +ff7ffffffdffffffffffff7ffffffdffffffffffff7fffffffeffffffffffffbffffffff +7fffffffffffdfffffffcffff3ffe7ff9fffffff9ffffcfffffffffcfffdffffffffffff +7ffffffdffffffffffff7ffffffdffffffffffff7fffffffeffffffffffffbffffffff7f +ffffffffffdfffffffc88e1223270c9fc3232383c2180e188c3ffcfffdffffffffffff7f +fffffdffffffffffff7ffffffdffffffffffff7fffffffeffffffffffffbffffffff7fff +ffffffffdfffffffcc4c933246611f9999999390cccccc49bffcfffefffffffffffeffff +fffefffffffffffefffffffdffffffffffff7fffffffeffffffffffffbffffffff7fffff +ffffffdfffffffccccf33266619f999999939cccccccc8fffcfffefffffffffffeffffff +fefffffffffffefffffffdffffffffffff7fffffffeffffffffffffbffffffff7fffffff +ffffdfffffffccccf33266019fe19999939f0ccccccc3ffcfffefffffffffffefffffffe +fffffffffffefffffffdffffffffffff7fffffffeffffffffffffbffffffff7fffffffff +ffdfffffffccccf33266799f999999939ccccccccf3ffcfffefffffffffffefffffffeff +fffffffffefffffffdffffffffffff7fffffffeffffffffffffbffffffff7fffffffffff +dfffffffcccc532266719f9989899388cc8ccccbbffcffff7ffffffffffdffffffff7fff +fffffffdfffffffdffffffffffff7fffffffeffffffffffffbffffffff7fffffffffffdf +ffffff80462111130c4f84939301c4240618407ffcffff7ffffffffffdffffffff7fffff +fffffdfffffffefffffffffffefffffffff7fffffffffff7ffffffffbfffffffffffbfff +ffffffffffffffffffff9f9ffffffffffffffffcffffbffffffffffbffffffffbfffffff +fffbfffffffefffffffffffefffffffff7fffffffffff7ffffffffbfffffffffffbfffff +ffffffffffffffffff9f9ffffffffffffffffcffffbffffffffffbffffffffbfffffffff +fbfffffffefffffffffffefffffffff7fffffffffff7ffffffffbfffffffffffbfffffff +ffffffffffffffff0f0ffffffffffffffffcffffdffffffffff7ffffffffdffffffffff7 +fffffffefffffffffffefffffffff7fffffffffff7ffffffffbfffffffffffbfffffffff +fffffffffffffffffffffffffffffffffcffffdffffffffff7ffffffffdffffffffff7ff +ffffff7ffffffffffdfffffffffbffffffffffefffffffffdfffffffffff7fffffffffff +fffffffffffffffffffffffffffffffcffffefffffffffefffffffffefffffffffefffff +ffff7ffffffffffdfffffffffbffffffffffefffffffffdfffffffffff7fffffffffffff +fffffffffffffffffffffffffffffcfffff7ffffffffdffffffffff7ffffffffdfffffff +ffbffffffffffbfffffffffdffffffffffdfffffffffeffffffffffeffffffffffffffff +fffffffffffffffffffffffffffcfffffbffffffffbffffffffffbffffffffbfffffffff +bffffffffffbfffffffffdffffffffffdfffffffffeffffffffffeffffffffffffffffff +fffffffffffffffffffffffffcfffffdffffffff7ffffffffffdffffffff7fffffffffdf +fffffffff7fffffffffeffffffffffbffffffffff7fffffffffdffffffffffffffffffff +fffffffffffffffffffffffcfffffefffffffefffffffffffefffffffeffffffffffdfff +fffffff7fffffffffeffffffffffbffffffffff7fffffffffdffffffffffffffffffffff +fffffffffffffffffffffcffffff7ffffffdffffffffffff7ffffffdffffffffffefffff +ffffefffffffffff7fffffffff7ffffffffffbfffffffffbffffffffffffffffffffffff +fffffffffffffffffffcffffff9ffffff3ffffffffffff9ffffff3fffffffffff7ffffff +ffdfffffffffffbffffffffefffffffffffdfffffffff7ffffffffffffffffffffffffff +fffffffffffffffffcffffffe7ffffcfffffffffffffe7ffffcffffffffffffbffffffff +bfffffffffffdffffffffdfffffffffffeffffffffefffffffffffffffffffffffffffff +fffffffffffffffcfffffff9ffff3ffffffffffffff9ffff3ffffffffffffdffffffff7f +ffffffffffeffffffffbffffffffffff7fffffffdfffffffffffffffffffffffffffffff +fffffffffffffcfffffffe1ff0fffffffffffffffe1ff0fffffffffffffefffffffeffff +fffffffff7fffffff7ffffffffffffbfffffffbfffffffffffffffffffffffffffffffff +fffffffffffcffffffffc00fffffffffffffffffe00fffffffffffffff7ffffffdffffff +fffffffbffffffefffffffffffffdfffffff7fffffffffffffffffffffffffffffffffff +fffffffffcffffffffdfffffffffffffffffffffffffffffffffffff9ffffff3ffffffff +fffffcffffff9fffffffffffffe7fffffcffffffffffffffffffffffffffffffffffffff +fffffffcffffffffdfffffffffffffffffffffffffffffffffffffe7ffffcfffffffffff +ffff3ffffe7ffffffffffffff9fffff3ffffffffffffffffffffffffffffffffffffffff +fffffcffffffffdffffffffffffffffffffffffffffffffffffff9ffff3fffffffffffff +ffcffff9fffffffffffffffe7fffcfffffffffffffffffffffffffffffffffffffffffff +fffcffffffffdffffffffffffffffffffffffffffffffffffffe1ff0ffffffffffffffff +f0ff87ffffffffffffffff87fc3fffffffffffffffffffffffffffffffffffffffffffff +fcffffffffdfffffffffffffffffffffffffffffffffffffffc007ffffffffffffffffff +007ffffffffffffffffff803fffffffffffffffffffffffffffffffffffffffffffffffc +ffffffffdfffffffffffffffffffffffffffffffffffffffbffbffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcff +ffffffdfffffffffffffffffffffffffffffffffffffff7ffdffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffff +ffffdffffffffffffffffffffffffffffffffffffffefffdffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffff +ffdffffffffffffffffffffffffffffffffffffffdfffeffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffff +dffffffffffffffffffffffffffffffffffffffbffff7fffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffdf +fffffffffffffffffffffffffffffffffffff7ffffbfffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffdfff +ffffffffffffffffffffffffffffffffffefffffdfffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffdfffff +ffffffffffffffffffffffffffffffffdfffffdfffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffdfffffff +ffffffffffffffffffffffffffffffbfffffefffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffdfffffffff +ffffffffffffffffffffffffffff7ffffff7ffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffdfffffffffff +fffffffffffffffffffffffffefffffffbffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffcffffffffdfffffffffffff +fffffffffffffffffffffffdfffffffdffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffcffffffffdfffffffffffffff +fffffffffffffffffffffbfffffffdffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffcffffffffdfffffffffffffffff +fffffffffffffffffff7fffffffeffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffcffffffffdfffffffffffffffffff +ffffffffffffffffefffffffff7fffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffcffffffffdfffffffffffffffffffff +ffffffffffffffdfffffffffbfffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffcffffffffdfffffffffffffffffffffff +ffffffffffffbfffffffffdfffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffcffffffffdfffffffffffffffffffffffff +ffffffffff7fffffffffdfffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffcffffffffdfffffffffffffffffffffffffff +fffffffeffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffcffffffffdfffffffffffffffffffffffffffff +fffffdfffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffcffffffffdfffffffffffffffffffffffffffffff +fffbfffffffffffbffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffcffffffffdfffffffffffffffffffffffffffffffff +f7fffffffffffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffcffffffffdfffffffffffffffffffffffffffffffffef +fffffffffffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffcffffffffdfffffffffffffffffffffffffffffffffdfff +fffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffcfffffffc01ffffffffffffffffffffffffffffff003fffff +ffffffff003fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffcffffffc3fe1ffffffffffffffffffffffffffff0ff87ffffff +fffff87fc3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffcffffff3fffe7ffffffffffffffffffffffffffcffff9ffffffff +ffe7fffcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffcfffffcfffff9ffffffffffffffffffffffffff3ffffe7fffffffff +9fffff3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffcfffff3fffffe7ffffffffffffffffffffffffcffffff9ffffffffe7f +ffffcfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffcffffefffffffbffffffffffffffffffffffffbffffffeffffffffdffff +fff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffcffffdfffffffdffffffffffffffffffffffff7fffffff7fffffffbffffff +fbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffcffffbfffffffefffffffffffffffffffffffeffffffffbfffffff7fffffffd +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffcffff7ffffffff7ffffffffffffffffffffffdffffffffdffffffeffffffffeff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffcfffefffffffffbffffffffffffffffffffffbffffffffeffffffdfffffffff7fff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffcfffdfffffffffdffffffffffffffffffffff7fffffffff7fffffbfffffffffbfffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fcfffbfffffffffefffffffffffffffffffffeffffffffffbfffff7fffffffffdfffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc +fffbfffffffffefffffffffffffffffffffeffffffffffbfffff7fffffffffdfffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcff +f7ffffffffff7ffffffffffffffffffffdffffffffffdffffeffffffffffefffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfff7 +ffffffffff7ffffffffffffffffffffdffffffffffdffffeffffffffffefffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffefff +ffffffffbffffffffffffffffffffbffffffffffeffffdfffffffffff7ffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffefffff +ffffffbffffffffffffffffffffbffffffffffeffffdfffffffffff7ffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffdfffffff +ffffdffffffffffffffffffff7fffffffffff7fffbfffffffffffbffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffdfffffffff +ffdffffffffffffffffffff7fffffffffff7fffbfffffffffffbffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffdfffffffffff +dffffffffffffffffffff7fffffffffff7fffbfffffffffffbffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffcffdfffffffffffdf +fffffffffffffffffff7fffffffffff7fffbfffffffffffbffffffffffffffffffffffff +ffffffffffffffffff87ffe3ffc7ff1fffffff13ffffcffffffffcffbfffffffffffefff +ffffffffffffffffeffffffffffffbfff7fffffffffffdffffffffffffffffffffffffff +ffffffffffffffffcffff3ffe7ff9fffffff93fffecffffffffcffbfffffffffffefffff +ffffffffffffffeffffffffffffbfff7fffffffffffdffffffffffffffffffffffffffff +ffffffffffffffcffff3ffe7ff9fffffff9ffffcfffffffffcffbfffffffffffefffffff +ffffffffffffeffffffffffffbfff7fffffffffffdffffffffffffffffffffffffffffff +ffffffffffffc88e1223270c9fc3232383c2180e188c3ffcffbfffffffffffefffffffff +ffffffffffeffffffffffffbfff7fffffffffffdffffffffffffffffffffffffffffffff +ffffffffffcc4c933246611f9999999390cccccc49bffcffbfffffffffffefffffffffff +ffffffffeffffffffffffbfff7fffffffffffdffffffffffffffffffffffffffffffffff +ffffffffccccf33266619f999999939cccccccc8fffcffbfffffffffffefffffffffffff +ffffffeffffffffffffbfff7fffffffffffdffffffffffffffffffffffffffffffffffff +ffffffccccf33266019fe19999939f0ccccccc3ffcffbfffffffffffefffffffffffffff +ffffeffffffffffffbfff7fffffffffffdffffffffffffffffffffffffffffffffffffff +ffffccccf33266799f999999939ccccccccf3ffcffbfffffffffffefffffffffffffffff +ffeffffffffffffbfff7fffffffffffdffffffffffffffffffffffffffffffffffffffff +ffcccc532266719f9989899388cc8ccccbbffcffbfffffffffffefffffffffffffffffff +effffffffffffbfff7fffffffffffdffffffffffffffffffffffffffffffffffffffffff +80462111130c4f84939301c4240618407ffcffdfffffffffffdffffffffffffffffffff7 +fffffffffff7fffbfffffffffffbffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffff9f9ffffffffffffffffcffdfffffffffffdffffffffffffffffffff7ff +fffffffff7fffbfffffffffffbffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffff9f9ffffffffffffffffcffdfffffffffffdffffffffffffffffffff7ffff +fffffff7fffbfffffffffffbffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffff0f0ffffffffffffffffcffdfffffffffffdffffffffffffffffffff7ffffff +fffff7fffbfffffffffffbffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffcffefffffffffffbffffffffffffffffffffbffffffff +ffeffffdfffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffcffefffffffffffbffffffffffffffffffffbffffffffff +effffdfffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffcfff7ffffffffff7ffffffffffffffffffffdffffffffffdf +fffeffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffcfff7ffffffffff7ffffffffffffffffffffdffffffffffdfff +feffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffcfffbfffffffffefffffffffffffffffffffeffffffffffbfffff +7fffffffffdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffcfffbfffffffffefffffffffffffffffffffeffffffffffbfffff7f +ffffffffdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffcfffdfffffffffdffffffffffffffffffffff7fffffffff7fffffbfff +ffffffbfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffcfffefffffffffbffffffffffffffffffffffbffffffffeffffffdfffff +ffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffcffff7ffffffff7ffffffffffffffffffffffdffffffffdffffffefffffff +feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffcffffbfffffffefffffffffffffffffffffffeffffffffbfffffff7fffffffd +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffcffffdfffffffdffffffffffffffffffffffff7fffffff7fffffffbfffffffbff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffcffffefffffffbffffffffffffffffffffffffbffffffeffffffffdfffffff7ffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffcfffff3fffffe7ffffffffffffffffffffffffcffffff9ffffffffe7fffffcfffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fcfffffcfffff9ffffffffffffffffffffffffff3ffffe7fffffffff9fffff3fffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc +ffffff3fffe7ffffffffffffffffffffffffffcffff9ffffffffffe7fffcffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcff +ffffc3fe1ffffffffffffffffffffffffffff0ff87fffffffffff87fc3ffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffff +fffc01ffffffffffffffffffffffffffffff007fffffffffffff803fffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffffcffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffffffffffffffffffffffffffffc +%%EndData +end +%%PageTrailer +%%Trailer +%%BoundingBox: 0 20 377 197 +%%EOF diff --git a/system/doc/design_principles/included_applications.xml b/system/doc/design_principles/included_applications.xml new file mode 100644 index 0000000000..3adb27ea08 --- /dev/null +++ b/system/doc/design_principles/included_applications.xml @@ -0,0 +1,150 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Included Applications</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>included_applications.xml</file> + </header> + + <section> + <title>Definition</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 + called a <em>primary application</em>.</p> + <marker id="inclappls"></marker> + <image file="../design_principles/inclappls.gif"> + <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 + 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 + 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> + <pre> +{application, prim_app, + [{description, "Tree application"}, + {vsn, "1"}, + {modules, [prim_app_cb, prim_app_sup, prim_app_server]}, + {registered, [prim_app_server]}, + {included_applications, [incl_app]}, + {applications, [kernel, stdlib, sasl]}, + {mod, {prim_app_cb,[]}}, + {env, [{file, "/usr/local/log"}]} + ]}.</pre> + </section> + + <section> + <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 + the including and included applications, this can be achieved + 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 + 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> + <code type="none"> +{application, prim_app, + [{description, "Tree application"}, + {vsn, "1"}, + {modules, [prim_app_cb, prim_app_sup, prim_app_server]}, + {registered, [prim_app_server]}, + {included_applications, [incl_app]}, + {start_phases, [{init,[]}, {go,[]}]}, + {applications, [kernel, stdlib, sasl]}, + {mod, {application_starter,[prim_app_cb,[]]}}, + {env, [{file, "/usr/local/log"}]} + ]}. + +{application, incl_app, + [{description, "Included application"}, + {vsn, "1"}, + {modules, [incl_app_cb, incl_app_sup, incl_app_server]}, + {registered, []}, + {start_phases, [{go,[]}]}, + {applications, [kernel, stdlib, sasl]}, + {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 + <c>Module:start(normal, StartArgs)</c> to start the top + supervisor.</p> + <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, + 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>If the included application itself contains included + applications, instead the option + <c>{mod, {application_starter, [Module,StartArgs]}}</c> 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> + </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> + <code type="none"> +application:start(prim_app) + => prim_app_cb:start(normal, []) + => prim_app_cb:start_phase(init, normal, []) + => prim_app_cb:start_phase(go, normal, []) + => incl_app_cb:start_phase(go, normal, []) +ok</code> + </section> +</chapter> + diff --git a/system/doc/design_principles/make.dep b/system/doc/design_principles/make.dep new file mode 100644 index 0000000000..05dd2333fb --- /dev/null +++ b/system/doc/design_principles/make.dep @@ -0,0 +1,31 @@ +# ---------------------------------------------------- +# >>>> Do not edit this file <<<< +# This file was automaticly generated by +# /home/gandalf/otp/bin/docdepend +# ---------------------------------------------------- + + +# ---------------------------------------------------- +# TeX files that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: applications.tex appup_cookbook.tex book.tex \ + des_princ.tex distributed_applications.tex \ + events.tex fsm.tex gen_server_concepts.tex \ + included_applications.tex part.tex release_handling.tex \ + release_structure.tex spec_proc.tex sup_princ.tex + +# ---------------------------------------------------- +# Pictures that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: sup6.ps + +book.dvi: dist1.ps dist2.ps dist3.ps dist4.ps dist5.ps + +book.dvi: clientserver.ps + +book.dvi: inclappls.ps + +book.dvi: sup4.ps sup5.ps + diff --git a/system/doc/design_principles/note.gif b/system/doc/design_principles/note.gif Binary files differnew file mode 100644 index 0000000000..6fffe30419 --- /dev/null +++ b/system/doc/design_principles/note.gif diff --git a/system/doc/design_principles/part.xml b/system/doc/design_principles/part.xml new file mode 100644 index 0000000000..d40b7cb23e --- /dev/null +++ b/system/doc/design_principles/part.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE part SYSTEM "part.dtd"> + +<part xmlns:xi="http://www.w3.org/2001/XInclude"> + <header> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>OTP Design Principles</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <xi:include href="des_princ.xml"/> + <xi:include href="gen_server_concepts.xml"/> + <xi:include href="fsm.xml"/> + <xi:include href="events.xml"/> + <xi:include href="sup_princ.xml"/> + <xi:include href="spec_proc.xml"/> + <xi:include href="applications.xml"/> + <xi:include href="included_applications.xml"/> + <xi:include href="distributed_applications.xml"/> + <xi:include href="release_structure.xml"/> + <xi:include href="release_handling.xml"/> + <xi:include href="appup_cookbook.xml"/> +</part> + diff --git a/system/doc/design_principles/release_handling.xml b/system/doc/design_principles/release_handling.xml new file mode 100644 index 0000000000..1d62c242c0 --- /dev/null +++ b/system/doc/design_principles/release_handling.xml @@ -0,0 +1,667 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Release Handling</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>release_handling.xml</file> + </header> + + <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> + <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 + <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> + <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> + </list> + <p>It is therefore recommended that code is changed in as small + steps as possible, and always kept backwards compatible.</p> + </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 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> + <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 + when an upgrade or downgrade is performed.</p> + </item> + <item> + <p>The system must be configured using one and 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> + </item> + <item> + <p>All versions of a release, except the first one, must + contain a <c>relup</c> file.</p> + <p>If found, this file is automatically included when a release + package is created.</p> + </item> + </list> + </section> + + <section> + <title>Distributed Systems</title> + <p>If the system consists of several Erlang nodes, each node may 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> + </section> + + <section> + <marker id="instr"></marker> + <title>Release Handling Instructions</title> + <p>OTP supports a set of <em>release handling instructions</em> + that is used when creating <c>.appup</c> files. The release + handler understands a subset of these, the <em>low-level</em> + 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 is found in + <c>appup(4)</c>.</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> + + <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 + the system, and remove the old version. This is called + <em>simple code replacement</em> and for this the following + instruction is used:</p> + <code type="none"> +{load_module, Module}</code> + </section> + + <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> + <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 + function <c>code_change</c>, passing the term <c>Extra</c> and + some other information as arguments. See the man pages for + the respective behaviours and + <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> + <p>The release handler finds the processes <em>using</em> a module + to update 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 + <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> + <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> + </section> + + <section> + <title>add_module and delete_module</title> + <p>If a new module is introduced, the following instruction is + used:</p> + <code type="none"> +{add_module, Module}</code> + <p>The instruction loads the module and is absolutely necessary + when running Erlang in embedded mode. It is not strictly + required when running Erlang in interactive (default) mode, + since the code server automatically searches for and loads + unloaded modules.</p> + <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> + as residence module, is killed when the instruction is + evaluated. The user should therefore ensure that all such + processes are terminated before deleting the module, to avoid + a possible situation with failing supervisor restarts.</p> + </section> + + <section> + <title>Application Instructions</title> + <p>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 + is started.</p> + <p>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 + from the application controller.</p> + <p>Instruction for removing an application:</p> + <code type="none"> +{restart_application, Application}</code> + <p>Restarting an application means that the application is stopped + and then started again similar to using the instructions + <c>remove_application</c> and <c>add_application</c> in + sequence.</p> + </section> + + <section> + <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 evalute <c>apply(M, F, A)</c>.</p> + </section> + + <section> + <title>restart_new_emulator (low-level)</title> + <p>This instruction is used when changing to a new emulator + version, or if a system reboot is needed for some other reason. + Requires that the system is started with heart beat + monitoring, see <c>erl(1)</c> and <c>heart(3)</c>.</p> + <p>When the release handler encounters the instruction, 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 can then be rebooted by the heart program, using + the new release version. This new version must still be made + permanent when the new emulator is up and running. Otherwise, + the old version is 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> + </section> + </section> + + <section> + <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> + <code type="none"> +{Vsn, + [{UpFromVsn1, InstructionsU1}, + ..., + {UpFromVsnK, InstructionsUK}], + [{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> + <code type="none"> +-module(ch3). +-behaviour(gen_server). + +-export([start_link/0]). +-export([alloc/0, free/1]). +-export([available/0]). +-export([init/1, handle_call/3, handle_cast/2]). + +start_link() -> + gen_server:start_link({local, ch3}, ch3, [], []). + +alloc() -> + gen_server:call(ch3, alloc). + +free(Ch) -> + gen_server:cast(ch3, {free, Ch}). + +available() -> + gen_server:call(ch3, available). + +init(_Args) -> + {ok, channels()}. + +handle_call(alloc, _From, Chs) -> + {Ch, Chs2} = alloc(Chs), + {reply, Ch, Chs2}; +handle_call(available, _From, Chs) -> + N = available(Chs), + {reply, N, Chs}. + +handle_cast({free, Ch}, Chs) -> + Chs2 = free(Ch, Chs), + {noreply, Chs2}.</code> + <p>A new version of the <c>ch_app.app</c> file must now be created, + where the version is updated:</p> + <code type="none"> +{application, ch_app, + [{description, "Channel allocator"}, + {vsn, "2"}, + {modules, [ch_app, ch_sup, ch3]}, + {registered, [ch3]}, + {applications, [kernel, stdlib, sasl]}, + {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 + load the new (old) version of the <c>ch3</c> callback module. + We create the application upgrade file <c>ch_app.appup</c> in + the <c>ebin</c> directory:</p> + <code type="none"> +{"2", + [{"1", [{load_module, ch3}]}], + [{"1", [{load_module, ch3}]}] +}.</code> + </section> + + <section> + <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> + <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 + 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> + <code type="none"> +{release, + {"ch_rel", "B"}, + {erts, "5.3"}, + [{kernel, "2.9"}, + {stdlib, "1.12"}, + {sasl, "1.10"}, + {ch_app, "2"}] +}.</code> + <p>Now the <c>relup</c> file can be generated:</p> + <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 + 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> + <pre> +1> <input>systools:make_relup("ch_rel-2", ["ch_rel-1"], ["ch_rel-1"],</input> +<input>[{path,["../ch_rel-1",</input> +<input>"../ch_rel-1/lib/ch_app-1/ebin"]}]).</input> +ok</pre> + </section> + + <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 + 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, + 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 + installation root directory <c>$ROOT</c>, the release package with + the new version of the release should 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> + <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 + the <c>.rel</c> file, the boot script <c>start.boot</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>. + 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 + step:</p> + <code type="none"> +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> + <code type="none"> +release_handler:make_permanent(Vsn) => ok</code> + <p>The system keeps information about which versions are old and + permanent in the files <c>$ROOT/releases/RELEASES</c> and + <c>$ROOT/releases/start_erl.data</c>.</p> + <p>To downgrade from <c>Vsn</c> to <c>FromVsn</c>, + <c>install_release</c> must be called again:</p> + <code type="none"> +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 + 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"> +[].</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 <c>.config</c> + 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> +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"> +% tar tf ch_rel-2.tar +lib/kernel-2.9/ebin/kernel.app +lib/kernel-2.9/ebin/application.beam +... +lib/stdlib-1.12/ebin/stdlib.app +lib/stdlib-1.12/ebin/beam_lib.beam +... +lib/sasl-1.10/ebin/sasl.app +lib/sasl-1.10/ebin/sasl.beam +... +lib/ch_app-2/ebin/ch_app.app +lib/ch_app-2/ebin/ch_app.beam +lib/ch_app-2/ebin/ch_sup.beam +lib/ch_app-2/ebin/ch3.beam +releases/B/start.boot +releases/B/relup +releases/B/sys.config +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> +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 + 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> +2> <input>ch3:available().</input> +** exception error: undefined function ch3:available/0</pre> + <p>7) 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> +3> <input>release_handler:install_release("B").</input> +{ok,"A",[]} +4> <input>ch3:available().</input> +3 +5> <input>code:which(ch3).</input> +".../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 + 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 + used when the system is rebooted.</p> + <pre> +7> <input>release_handler:make_permanent("B").</input> +ok</pre> + </section> + + <section> + <marker id="sys"></marker> + <title>Updating Application Specifications</title> + <p>When a new version of a release is installed, the application + specifications are automatically updated for all loaded + applications.</p> + <note> + <p>The information about the new application specifications are + fetched from the boot script included in the release package. + It is therefore 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"> + <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> + </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> + <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 + 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 + application callback module.</p> + </section> +</chapter> + diff --git a/system/doc/design_principles/release_structure.xml b/system/doc/design_principles/release_structure.xml new file mode 100644 index 0000000000..2e1daa611a --- /dev/null +++ b/system/doc/design_principles/release_structure.xml @@ -0,0 +1,302 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Releases</title> + <prepared></prepared> + <docno></docno> + <date></date> + <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> + + <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 + 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>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 + <em>target system</em>. How to use a release package to create a + target system is described in System Principles.</p> + </section> + + <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> + <code type="none"> +{release, {Name,Vsn}, {erts, EVsn}, + [{Application1, AppVsn1}, + ... + {ApplicationN, AppVsnN}]}.</code> + <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 + the name and version of an application included in the release. + Note the the minimal release based on Erlang/OTP consists of + the <c>kernel</c> and <c>stdlib</c> applications, so these + applications must be included in the list.</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> + <code type="none"> +{application, ch_app, + [{description, "Channel allocator"}, + {vsn, "1"}, + {modules, [ch_app, ch_sup, ch3]}, + {registered, [ch3]}, + {applications, [kernel, stdlib, sasl]}, + {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> + <code type="none"> +{release, + {"ch_rel", "A"}, + {erts, "5.3"}, + [{kernel, "2.9"}, + {stdlib, "1.12"}, + {sasl, "1.10"}, + {ch_app, "1"}] +}.</code> + </section> + + <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 + <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> + <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>When starting Erlang/OTP using the boot script, all applications + 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 + +Eshell V5.3 (abort with ^G) +1> +=PROGRESS REPORT==== 13-Jun-2003::12:01:15 === + supervisor: {local,sasl_safe_sup} + started: [{pid,<0.33.0>}, + {name,alarm_handler}, + {mfa,{alarm_handler,start_link,[]}}, + {restart_type,permanent}, + {shutdown,2000}, + {child_type,worker}] + +... + +=PROGRESS REPORT==== 13-Jun-2003::12:01:15 === + application: sasl + started_at: nonode@nohost + +... +=PROGRESS REPORT==== 13-Jun-2003::12:01:15 === + application: ch_app + started_at: nonode@nohost</pre> + </section> + + <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> + <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> + <pre> +% <input>tar tf ch_rel-1.tar</input> +lib/kernel-2.9/ebin/kernel.app +lib/kernel-2.9/ebin/application.beam +... +lib/stdlib-1.12/ebin/stdlib.app +lib/stdlib-1.12/ebin/beam_lib.beam +... +lib/sasl-1.10/ebin/sasl.app +lib/sasl-1.10/ebin/sasl.beam +... +lib/ch_app-1/ebin/ch_app.app +lib/ch_app-1/ebin/ch_app.beam +lib/ch_app-1/ebin/ch_sup.beam +lib/ch_app-1/ebin/ch3.beam +releases/A/start.boot +releases/ch_rel-1.rel</pre> + <p>Note that 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> + <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 + <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> + </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> + <code type="none"> +$ROOT/lib/App1-AVsn1/ebin + /priv + /App2-AVsn2/ebin + /priv + ... + /AppN-AVsnN/ebin + /priv + /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> + <pre> +$SECOND_ROOT/.../SApp1-SAVsn1/ebin + /priv + /SApp2-SAVsn2/ebin + /priv + ... + /SAppN-SAVsnN/ebin + /priv + +$THIRD_ROOT/TApp1-TAVsn1/ebin + /priv + /TApp2-TAVsn2/ebin + /priv + ... + /TAppN-TAVsnN/ebin + /priv</pre> + <p>The <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 + 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 + store information about installed releases and to appoint the + current release to the client. Accordingly, the <c>$ROOT</c> + directory contains the following:</p> + <code type="none"> +$ROOT/... + /clients/ClientName1/bin + /releases/Vsn + /ClientName2/bin + /releases/Vsn + ... + /ClientNameN/bin + /releases/Vsn</code> + <p>This structure should 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 + type, some of the directories specified for the <c>$ROOT</c> + directory should be included:</p> + <code type="none"> +$ROOT/... + /clients/Type1/lib + /erts-EVsn + /bin + /ClientName1/bin + /releases/Vsn + /ClientName2/bin + /releases/Vsn + ... + /ClientNameN/bin + /releases/Vsn + ... + /TypeN/lib + /erts-EVsn + /bin + ...</code> + <p>With this structure, the root directory for clients of + <c>Type1</c> is <c>$ROOT/clients/Type1</c>.</p> + </section> + </section> +</chapter> + diff --git a/system/doc/design_principles/spec_proc.xml b/system/doc/design_principles/spec_proc.xml new file mode 100644 index 0000000000..f0f62891b6 --- /dev/null +++ b/system/doc/design_principles/spec_proc.xml @@ -0,0 +1,460 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <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> + + <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_event</seealso> chapter to + illustrate this:</p> + <pre> +% <input>erl</input> +Erlang (BEAM) emulator version 5.2.3.6 [hipe] [threads:0] + +Eshell V5.2.3.6 (abort with ^G) +1> <input>code_lock:start_link([1,2,3,4]).</input> +{ok,<0.32.0>} +2> <input>sys:statistics(code_lock, true).</input> +ok +3> <input>sys:trace(code_lock, true).</input> +ok +4> <input>code_lock:button(4).</input> +*DBG* code_lock got event {button,4} in state closed +ok +*DBG* code_lock switched to state closed +5> <input>code_lock:button(3).</input> +*DBG* code_lock got event {button,3} in state closed +ok +*DBG* code_lock switched to state closed +6> <input>code_lock:button(2).</input> +*DBG* code_lock got event {button,2} in state closed +ok +*DBG* code_lock switched to state closed +7> <input>code_lock:button(1).</input> +*DBG* code_lock got event {button,1} in state closed +ok +OPEN DOOR +*DBG* code_lock switched to state open +*DBG* code_lock got event timeout in state open +CLOSE DOOR +*DBG* code_lock switched to state closed +8> <input>sys:statistics(code_lock, get).</input> +{ok,[{start_time,{{2003,6,12},{14,11,40}}}, + {current_time,{{2003,6,12},{14,12,14}}}, + {reductions,333}, + {messages_in,5}, + {messages_out,0}]} +9> <input>sys:statistics(code_lock, false).</input> +ok +10> <input>sys:trace(code_lock, false).</input> +ok +11> <input>sys:get_status(code_lock).</input> +{status,<0.32.0>, + {module,gen_fsm}, + [[{'$ancestors',[<0.30.0>]}, + {'$initial_call',{gen,init_it, + [gen_fsm,<0.30.0>,<0.30.0>, + {local,code_lock}, + code_lock, + [1,2,3,4], + []]}}], + running,<0.30.0>,[], + [code_lock,closed,{[],[1,2,3,4]},code_lock,infinity]]}</pre> + </section> + + <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> + <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> + </list> + <p>System messages are messages with 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 + standard behaviours automatically understand these messages.</p> + + <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> + <marker id="ex"></marker> + <pre> +-module(ch4). +-export([start_link/0]). +-export([alloc/0, free/1]). +-export([init/1]). +-export([system_continue/3, system_terminate/4, + write_debug/3]). + +start_link() -> + proc_lib:start_link(ch4, init, [self()]). + +alloc() -> + ch4 ! {self(), alloc}, + receive + {ch4, Res} -> + Res + end. + +free(Ch) -> + ch4 ! {free, Ch}, + ok. + +init(Parent) -> + register(ch4, self()), + Chs = channels(), + Deb = sys:debug_options([]), + proc_lib:init_ack(Parent, {ok, self()}), + loop(Chs, Parent, Deb). + +loop(Chs, Parent, Deb) -> + receive + {From, alloc} -> + Deb2 = sys:handle_debug(Deb, {ch4, write_debug}, + ch4, {in, alloc, From}), + {Ch, Chs2} = alloc(Chs), + From ! {ch4, Ch}, + Deb3 = sys:handle_debug(Deb2, {ch4, write_debug}, + ch4, {out, {ch4, Ch}, From}), + loop(Chs2, Parent, Deb3); + {free, Ch} -> + Deb2 = sys:handle_debug(Deb, {ch4, write_debug}, + ch4, {in, {free, Ch}}), + Chs2 = free(Ch, Chs), + loop(Chs2, Parent, Deb2); + + {system, From, Request} -> + sys:handle_system_msg(Request, From, Parent, + ch4, Deb, Chs) + end. + +system_continue(Parent, Deb, Chs) -> + loop(Chs, Parent, Deb). + +system_terminate(Reason, Parent, Deb, Chs) -> + exit(Reason). + +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> + <pre> +% <input>erl</input> +Erlang (BEAM) emulator version 5.2.3.6 [hipe] [threads:0] + +Eshell V5.2.3.6 (abort with ^G) +1> <input>ch4:start_link().</input> +{ok,<0.30.0>} +2> <input>sys:statistics(ch4, true).</input> +ok +3> <input>sys:trace(ch4, true).</input> +ok +4> <input>ch4:alloc().</input> +ch4 event = {in,alloc,<0.25.0>} +ch4 event = {out,{ch4,ch1},<0.25.0>} +ch1 +5> <input>ch4:free(ch1).</input> +ch4 event = {in,{free,ch1}} +ok +6> <input>sys:statistics(ch4, get).</input> +{ok,[{start_time,{{2003,6,13},{9,47,5}}}, + {current_time,{{2003,6,13},{9,47,56}}}, + {reductions,109}, + {messages_in,2}, + {messages_out,1}]} +7> <input>sys:statistics(ch4, false).</input> +ok +8> <input>sys:trace(ch4, false).</input> +ok +9> <input>sys:get_status(ch4).</input> +{status,<0.30.0>, + {module,ch4}, + [[{'$ancestors',[<0.25.0>]},{'$initial_call',{ch4,init,[<0.25.0>]}}], + running,<0.25.0>,[], + [ch1,ch2,ch3]]}</pre> + </section> + + <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 + <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> + <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 + 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> + <code type="none"> +init(Parent) -> + ... + proc_lib:init_ack(Parent, {ok, self()}), + loop(...).</code> + <p><c>proc_lib:start_link</c> is synchronous and does not return + until <c>proc_lib:init_ack</c> has been called.</p> + </section> + + <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 + initialized using <c>sys:debug_options/1</c>:</p> + <code type="none"> +init(Parent) -> + ... + Deb = sys:debug_options([]), + ... + 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> + <code type="none"> +sys:handle_debug(Deb, Func, Info, Event) => Deb1</code> + <list type="bulleted"> + <item> + <p><c>Deb</c> is the debug structure.</p> + </item> + <item> + <p><c>Func</c> is a tuple <c>{Module, Name}</c> (or a fun) and + should specify a (user defined) function used to format + trace output. For each system event, the format function is + called as <c>Module:Name(Dev, Event, Info)</c>, where:</p> + <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> + </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 + messages are considered system events and represented by + the tuples <c>{in,Msg[,From]}</c> and <c>{out,Msg,To}</c>, + respectively.</p> + </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 + using <c>io:format/3</c>.</p> + <code type="none"> +loop(Chs, Parent, Deb) -> + receive + {From, alloc} -> + Deb2 = sys:handle_debug(Deb, {ch4, write_debug}, + ch4, {in, alloc, From}), + {Ch, Chs2} = alloc(Chs), + From ! {ch4, Ch}, + Deb3 = sys:handle_debug(Deb2, {ch4, write_debug}, + ch4, {out, {ch4, Ch}, From}), + loop(Chs2, Parent, Deb3); + {free, Ch} -> + Deb2 = sys:handle_debug(Deb, {ch4, write_debug}, + ch4, {in, {free, Ch}}), + Chs2 = free(Ch, Chs), + loop(Chs2, Parent, Deb2); + ... + end. + +write_debug(Dev, Event, Name) -> + io:format(Dev, "~p event = ~p~n", [Name, Event]).</code> + </section> + + <section> + <marker id="msg"></marker> + <title>Handling System Messages</title> + <p><em>System messages</em> are received as:</p> + <code type="none"> +{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> + <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> + <code type="none"> +Module:system_continue(Parent, Deb, State)</code> + <p>if process execution should continue, or:</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> + <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>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> + <item><c>State</c> is a term describing the internal state and + is passed to <c>system_continue</c>/<c>system_terminate</c>.</item> + </list> + <p>In the example:</p> + <code type="none"> +loop(Chs, Parent, Deb) -> + receive + ... + + {system, From, Request} -> + sys:handle_system_msg(Request, From, Parent, + ch4, Deb, Chs) + end. + +system_continue(Parent, Deb, Chs) -> + loop(Chs, Parent, Deb). + +system_terminate(Reason, Parent, Deb, Chs) -> + exit(Reason).</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> + <code type="none"> +init(...) -> + ..., + process_flag(trap_exit, true), + ..., + loop(...). + +loop(...) -> + receive + ... + + {'EXIT', Parent, Reason} -> + ..maybe some cleaning up here.. + exit(Reason); + ... + end.</code> + </section> + </section> + + <section> + <title>User-Defined Behaviours</title> + <p>To implement a user-defined behaviour, write code similar to + code for a special process but calling 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, implement + and export the function:</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.</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> + <p>Example:</p> + <code type="none"> +%% User-defined behaviour module +-module(simple_server). +-export([start_link/2,...]). +-export([behaviour_info/1]). + +behaviour_info(callbacks) -> + [{init,1}, + {handle_req,1}, + {terminate,0}]. + +start_link(Name, Module) -> + proc_lib:start_link(?MODULE, init, [self(), Name, Module]). + +init(Parent, Name, Module) -> + register(Name, self()), + ..., + Dbg = sys:debug_options([]), + proc_lib:init_ack(Parent, {ok, self()}), + loop(Parent, Module, Deb, ...). + +...</code> + <p>In a callback module:</p> + <code type="none"> +-module(db). +-behaviour(simple_server). + +-export([init/0, handle_req/1, terminate/0]). + +...</code> + </section> +</chapter> + diff --git a/system/doc/design_principles/sup4.fig b/system/doc/design_principles/sup4.fig new file mode 100644 index 0000000000..9127f9797c --- /dev/null +++ b/system/doc/design_principles/sup4.fig @@ -0,0 +1,32 @@ +#FIG 3.1 +Landscape +Center +Inches +1200 2 +6 2100 750 2550 1200 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 2100 750 2550 750 2550 1200 2100 1200 2100 750 +4 0 -1 0 0 2 14 0.0000 4 150 105 2250 1050 1\001 +-6 +1 4 0 1 -1 7 0 0 -1 0.000 1 0.0000 4762 2700 293 293 4575 2475 4950 2925 +1 4 0 1 -1 7 0 0 -1 0.000 1 0.0000 3112 2775 293 293 2925 2550 3300 3000 +1 4 0 1 -1 7 0 0 -1 0.000 1 0.0000 1987 2775 293 293 1800 2550 2175 3000 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 675 2550 1125 2550 1125 3000 675 3000 675 2550 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 900 2550 2250 1200 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 1950 2475 2325 1200 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 2400 1200 3000 2475 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 2475 1200 4500 2550 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 2625 2325 3450 3150 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 2625 3225 3525 2325 +4 0 -1 0 0 2 14 0.0000 4 150 240 1875 2850 P1\001 +4 0 -1 0 0 2 14 0.0000 4 150 240 3000 2850 P2\001 +4 0 -1 0 0 2 14 0.0000 4 150 255 4650 2775 Pn\001 +4 0 -1 0 0 0 14 0.0000 4 195 2025 3450 975 One for one supervision\001 +4 0 -1 0 0 0 14 0.0000 4 195 2490 3450 1200 If any child dies it is restarted\001 diff --git a/system/doc/design_principles/sup4.gif b/system/doc/design_principles/sup4.gif Binary files differnew file mode 100644 index 0000000000..fc099f9b06 --- /dev/null +++ b/system/doc/design_principles/sup4.gif diff --git a/system/doc/design_principles/sup4.ps b/system/doc/design_principles/sup4.ps new file mode 100644 index 0000000000..2507fcc36e --- /dev/null +++ b/system/doc/design_principles/sup4.ps @@ -0,0 +1,153 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: sup4.fig +%%Creator: fig2dev Version 3.1 Patchlevel 2 +%%CreationDate: Thu May 15 12:49:21 1997 +%%For: jocke@akvavit (Joakim Greben|,ETX/B/DUP) +%Magnification: 1.00 +%%Orientation: Portrait +%%BoundingBox: 0 0 322 151 +%%Pages: 0 +%%BeginSetup +%%IncludeFeature: *PageSize A4 +%%EndSetup +%%EndComments +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +-39.0 195.0 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def + /DrawEllipse { + /endangle exch def + /startangle exch def + /yrad exch def + /xrad exch def + /y exch def + /x exch def + /savematrix mtrx currentmatrix def + x y tr xrad yrad sc 0 0 1 startangle endangle arc + closepath + savematrix setmatrix + } def + +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def +%%EndProlog + +$F2psBegin +10 setmiterlimit +n 0 842 m 0 0 l 595 0 l 595 842 l cp clip + 0.06000 0.06000 sc +7.500 slw +% Polyline +n 2100 750 m 2550 750 l 2550 1200 l 2100 1200 l cp gs col-1 s gr +/Times-Bold ff 210.00 scf sf +2250 1050 m +gs 1 -1 sc (1) col-1 sh gr +% Ellipse +n 4762 2700 293 293 0 360 DrawEllipse gs col-1 s gr + +% Ellipse +n 3112 2775 293 293 0 360 DrawEllipse gs col-1 s gr + +% Ellipse +n 1987 2775 293 293 0 360 DrawEllipse gs col-1 s gr + +% Polyline +n 675 2550 m 1125 2550 l 1125 3000 l 675 3000 l cp gs col-1 s gr +% Polyline +n 900 2550 m 2250 1200 l gs col-1 s gr +% Polyline +n 1950 2475 m 2325 1200 l gs col-1 s gr +% Polyline +n 2400 1200 m 3000 2475 l gs col-1 s gr +% Polyline +n 2475 1200 m 4500 2550 l gs col-1 s gr +% Polyline +n 2625 2325 m 3450 3150 l gs col-1 s gr +% Polyline +n 2625 3225 m 3525 2325 l gs col-1 s gr +/Times-Bold ff 210.00 scf sf +1875 2850 m +gs 1 -1 sc (P1) col-1 sh gr +/Times-Bold ff 210.00 scf sf +3000 2850 m +gs 1 -1 sc (P2) col-1 sh gr +/Times-Bold ff 210.00 scf sf +4650 2775 m +gs 1 -1 sc (Pn) col-1 sh gr +/Times-Roman ff 210.00 scf sf +3450 975 m +gs 1 -1 sc (One for one supervision) col-1 sh gr +/Times-Roman ff 210.00 scf sf +3450 1200 m +gs 1 -1 sc (If any child dies it is restarted) col-1 sh gr +$F2psEnd +rs diff --git a/system/doc/design_principles/sup5.fig b/system/doc/design_principles/sup5.fig new file mode 100644 index 0000000000..554ab28ba0 --- /dev/null +++ b/system/doc/design_principles/sup5.fig @@ -0,0 +1,43 @@ +#FIG 3.1 +Landscape +Center +Inches +1200 2 +1 4 0 1 -1 7 0 0 -1 0.000 1 0.0000 4762 2700 293 293 4575 2475 4950 2925 +1 4 0 1 -1 7 0 0 -1 0.000 1 0.0000 3112 2775 293 293 2925 2550 3300 3000 +1 4 0 1 -1 7 0 0 -1 0.000 1 0.0000 1987 2775 293 293 1800 2550 2175 3000 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 675 2550 1125 2550 1125 3000 675 3000 675 2550 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 900 2550 2250 1200 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 1950 2475 2325 1200 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 2400 1200 3000 2475 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 2475 1200 4500 2550 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 2100 750 2550 750 2550 1200 2100 1200 2100 750 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 2775 2325 3450 3225 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 2775 3150 3525 2400 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 4350 3075 5100 2250 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 4425 2175 5100 3150 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 1650 2325 2325 3150 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 1650 3150 2325 2400 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 525 2325 1350 3150 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 525 3150 1350 2325 +4 0 -1 0 0 2 14 0.0000 4 150 240 1875 2850 P1\001 +4 0 -1 0 0 2 14 0.0000 4 150 240 3000 2850 P2\001 +4 0 -1 0 0 2 14 0.0000 4 150 255 4650 2775 Pn\001 +4 0 -1 0 0 0 14 0.0000 4 195 2310 3525 1005 If any child dies all children\001 +4 0 -1 0 0 0 14 0.0000 4 150 3015 3525 1260 are terminated and all are restarted\001 +4 0 -1 0 0 2 14 0.0000 4 105 105 2250 1050 a\001 +4 0 -1 0 0 0 14 0.0000 4 195 2040 3525 750 all-for-one supervision\001 diff --git a/system/doc/design_principles/sup5.gif b/system/doc/design_principles/sup5.gif Binary files differnew file mode 100644 index 0000000000..1197278f63 --- /dev/null +++ b/system/doc/design_principles/sup5.gif diff --git a/system/doc/design_principles/sup5.ps b/system/doc/design_principles/sup5.ps new file mode 100644 index 0000000000..40eb07a132 --- /dev/null +++ b/system/doc/design_principles/sup5.ps @@ -0,0 +1,168 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: sup5.fig +%%Creator: fig2dev Version 3.1 Patchlevel 2 +%%CreationDate: Thu May 15 12:49:29 1997 +%%For: jocke@akvavit (Joakim Greben|,ETX/B/DUP) +%Magnification: 1.00 +%%Orientation: Portrait +%%BoundingBox: 0 0 368 160 +%%Pages: 0 +%%BeginSetup +%%IncludeFeature: *PageSize A4 +%%EndSetup +%%EndComments +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +-30.0 195.0 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def + /DrawEllipse { + /endangle exch def + /startangle exch def + /yrad exch def + /xrad exch def + /y exch def + /x exch def + /savematrix mtrx currentmatrix def + x y tr xrad yrad sc 0 0 1 startangle endangle arc + closepath + savematrix setmatrix + } def + +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def +%%EndProlog + +$F2psBegin +10 setmiterlimit +n 0 842 m 0 0 l 595 0 l 595 842 l cp clip + 0.06000 0.06000 sc +7.500 slw +% Ellipse +n 4762 2700 293 293 0 360 DrawEllipse gs col-1 s gr + +% Ellipse +n 3112 2775 293 293 0 360 DrawEllipse gs col-1 s gr + +% Ellipse +n 1987 2775 293 293 0 360 DrawEllipse gs col-1 s gr + +% Polyline +n 675 2550 m 1125 2550 l 1125 3000 l 675 3000 l cp gs col-1 s gr +% Polyline +n 900 2550 m 2250 1200 l gs col-1 s gr +% Polyline +n 1950 2475 m 2325 1200 l gs col-1 s gr +% Polyline +n 2400 1200 m 3000 2475 l gs col-1 s gr +% Polyline +n 2475 1200 m 4500 2550 l gs col-1 s gr +% Polyline +n 2100 750 m 2550 750 l 2550 1200 l 2100 1200 l cp gs col-1 s gr +% Polyline +n 2775 2325 m 3450 3225 l gs col-1 s gr +% Polyline +n 2775 3150 m 3525 2400 l gs col-1 s gr +% Polyline +n 4350 3075 m 5100 2250 l gs col-1 s gr +% Polyline +n 4425 2175 m 5100 3150 l gs col-1 s gr +% Polyline +n 1650 2325 m 2325 3150 l gs col-1 s gr +% Polyline +n 1650 3150 m 2325 2400 l gs col-1 s gr +% Polyline +n 525 2325 m 1350 3150 l gs col-1 s gr +% Polyline +n 525 3150 m 1350 2325 l gs col-1 s gr +/Times-Bold ff 210.00 scf sf +1875 2850 m +gs 1 -1 sc (P1) col-1 sh gr +/Times-Bold ff 210.00 scf sf +3000 2850 m +gs 1 -1 sc (P2) col-1 sh gr +/Times-Bold ff 210.00 scf sf +4650 2775 m +gs 1 -1 sc (Pn) col-1 sh gr +/Times-Roman ff 210.00 scf sf +3525 1005 m +gs 1 -1 sc (If any child dies all children) col-1 sh gr +/Times-Roman ff 210.00 scf sf +3525 1260 m +gs 1 -1 sc (are terminated and all are restarted) col-1 sh gr +/Times-Bold ff 210.00 scf sf +2250 1050 m +gs 1 -1 sc (a) col-1 sh gr +/Times-Roman ff 210.00 scf sf +3525 750 m +gs 1 -1 sc (all-for-one supervision) col-1 sh gr +$F2psEnd +rs diff --git a/system/doc/design_principles/sup6.fig b/system/doc/design_principles/sup6.fig new file mode 100644 index 0000000000..9947cbb67c --- /dev/null +++ b/system/doc/design_principles/sup6.fig @@ -0,0 +1,46 @@ +#FIG 3.1 +Landscape +Center +Inches +1200 2 +6 2100 750 2550 1200 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 2100 750 2550 750 2550 1200 2100 1200 2100 750 +4 0 -1 0 0 2 14 0.0000 4 150 105 2250 1050 1\001 +-6 +6 1200 1650 1650 2100 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 1200 1650 1650 1650 1650 2100 1200 2100 1200 1650 +4 0 -1 0 0 2 14 0.0000 4 150 105 1350 1950 1\001 +-6 +6 3975 2850 4425 3300 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 3975 2850 4425 2850 4425 3300 3975 3300 3975 2850 +4 0 -1 0 0 2 14 0.0000 4 150 105 4125 3150 1\001 +-6 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 5025 4125 270 270 5025 4125 5175 4350 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 1425 3075 270 270 1425 3075 1575 3300 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 2250 4125 270 270 2250 4125 2400 4350 +1 3 0 1 -1 7 0 0 -1 0.000 1 0.0000 3900 4125 270 270 3900 4125 4050 4350 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 2325 1200 1425 1650 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 2400 1200 3300 1650 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 3300 2100 2550 2850 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 3375 2100 4125 2850 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 2475 3300 2325 3825 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 4200 3300 3900 3825 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 4275 3300 4875 3900 +2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2 + 1425 2775 1425 2100 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 3075 1650 3525 1650 3525 2100 3075 2100 3075 1650 +2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 + 2325 2850 2775 2850 2775 3300 2325 3300 2325 2850 +4 0 -1 0 0 2 14 0.0000 4 105 105 3225 1950 a\001 +4 0 -1 0 0 2 14 0.0000 4 105 105 2475 3150 a\001 diff --git a/system/doc/design_principles/sup6.gif b/system/doc/design_principles/sup6.gif Binary files differnew file mode 100644 index 0000000000..2016f5bf67 --- /dev/null +++ b/system/doc/design_principles/sup6.gif diff --git a/system/doc/design_principles/sup6.ps b/system/doc/design_principles/sup6.ps new file mode 100644 index 0000000000..3e8a8d2ed4 --- /dev/null +++ b/system/doc/design_principles/sup6.ps @@ -0,0 +1,163 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: sup6.fig +%%Creator: fig2dev Version 3.1 Patchlevel 2 +%%CreationDate: Thu May 15 12:49:34 1997 +%%For: jocke@akvavit (Joakim Greben|,ETX/B/DUP) +%Magnification: 1.00 +%%Orientation: Portrait +%%BoundingBox: 0 0 251 221 +%%Pages: 0 +%%BeginSetup +%%IncludeFeature: *PageSize A4 +%%EndSetup +%%EndComments +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +-68.0 265.0 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def + /DrawEllipse { + /endangle exch def + /startangle exch def + /yrad exch def + /xrad exch def + /y exch def + /x exch def + /savematrix mtrx currentmatrix def + x y tr xrad yrad sc 0 0 1 startangle endangle arc + closepath + savematrix setmatrix + } def + +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def +%%EndProlog + +$F2psBegin +10 setmiterlimit +n 0 842 m 0 0 l 595 0 l 595 842 l cp clip + 0.06000 0.06000 sc +7.500 slw +% Polyline +n 2100 750 m 2550 750 l 2550 1200 l 2100 1200 l cp gs col-1 s gr +/Times-Bold ff 210.00 scf sf +2250 1050 m +gs 1 -1 sc (1) col-1 sh gr +% Polyline +n 1200 1650 m 1650 1650 l 1650 2100 l 1200 2100 l cp gs col-1 s gr +/Times-Bold ff 210.00 scf sf +1350 1950 m +gs 1 -1 sc (1) col-1 sh gr +% Polyline +n 3975 2850 m 4425 2850 l 4425 3300 l 3975 3300 l cp gs col-1 s gr +/Times-Bold ff 210.00 scf sf +4125 3150 m +gs 1 -1 sc (1) col-1 sh gr +% Ellipse +n 5025 4125 270 270 0 360 DrawEllipse gs col-1 s gr + +% Ellipse +n 1425 3075 270 270 0 360 DrawEllipse gs col-1 s gr + +% Ellipse +n 2250 4125 270 270 0 360 DrawEllipse gs col-1 s gr + +% Ellipse +n 3900 4125 270 270 0 360 DrawEllipse gs col-1 s gr + +% Polyline +n 2325 1200 m 1425 1650 l gs col-1 s gr +% Polyline +n 2400 1200 m 3300 1650 l gs col-1 s gr +% Polyline +n 3300 2100 m 2550 2850 l gs col-1 s gr +% Polyline +n 3375 2100 m 4125 2850 l gs col-1 s gr +% Polyline +n 2475 3300 m 2325 3825 l gs col-1 s gr +% Polyline +n 4200 3300 m 3900 3825 l gs col-1 s gr +% Polyline +n 4275 3300 m 4875 3900 l gs col-1 s gr +% Polyline +n 1425 2775 m 1425 2100 l gs col-1 s gr +% Polyline +n 3075 1650 m 3525 1650 l 3525 2100 l 3075 2100 l cp gs col-1 s gr +% Polyline +n 2325 2850 m 2775 2850 l 2775 3300 l 2325 3300 l cp gs col-1 s gr +/Times-Bold ff 210.00 scf sf +3225 1950 m +gs 1 -1 sc (a) col-1 sh gr +/Times-Bold ff 210.00 scf sf +2475 3150 m +gs 1 -1 sc (a) col-1 sh gr +$F2psEnd +rs diff --git a/system/doc/design_principles/sup_princ.xml b/system/doc/design_principles/sup_princ.xml new file mode 100644 index 0000000000..067fd31961 --- /dev/null +++ b/system/doc/design_principles/sup_princ.xml @@ -0,0 +1,349 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Supervisor Behaviour</title> + <prepared></prepared> + <docno></docno> + <date></date> + <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 + behaviour is given.</p> + + <section> + <title>Supervision Principles</title> + <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 + when necessary.</p> + <p>Which child processes to start and monitor is specified by a + list of <seealso marker="#spec">child specifications</seealso>. + The child processes are started in the order specified by this + list, and terminated in the reversed order.</p> + </section> + + <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> + <marker id="ex"></marker> + <code type="none"> +-module(ch_sup). +-behaviour(supervisor). + +-export([start_link/0]). +-export([init/1]). + +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> + </section> + + <section> + <marker id="strategy"></marker> + <title>Restart Strategy</title> + + <section> + <title>one_for_one</title> + <p>If a child process terminates, only that process is restarted.</p> + <marker id="sup4"></marker> + <image file="../design_principles/sup4.gif"> + <icaption>One_For_One Supervision</icaption> + </image> + </section> + + <section> + <title>one_for_all</title> + <p>If a child process terminates, all other child processes are + terminated and then all child processes, including + the terminated one, are restarted.</p> + <marker id="sup5"></marker> + <image file="../design_principles/sup5.gif"> + <icaption>One_For_All Supervision</icaption> + </image> + </section> + + <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 + child process and the rest of the child processes are restarted.</p> + </section> + </section> + + <section> + <marker id="frequency"></marker> + <title>Maximum Restart Frequency</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> + <code type="none"> +init(...) -> + {ok, {{RestartStrategy, MaxR, MaxT}, + [ChildSpec, ...]}}.</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 + processes and then itself.</p> + <p>When the supervisor terminates, then the next higher level + supervisor takes some action. It either restarts the terminated + 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> + </section> + + <section> + <marker id="spec"></marker> + <title>Child Specification</title> + <p>This is the type definition for a child specification:</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> + <list type="bulleted"> + <item> + <p><c>Id</c> is a name that is used to identify the child + specification internally by the supervisor.</p> + </item> + <item> + <p><c>StartFunc</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> + </item> + <item> + <p><c>Restart</c> defines when a terminated child process should + 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.</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>.</item> + </list> + </item> + <item> + <marker id="shutdown"></marker> + <p><c>Shutdown</c> defines how a child process should be + terminated.</p> + <list type="bulleted"> + <item><c>brutal_kill</c> means the child process is + unconditionally terminated using <c>exit(Child, kill)</c>.</item> + <item>An integer timeout 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 + set to <c>infinity</c> to give the subtree enough time to + shutdown.</item> + </list> + </item> + <item> + <p><c>Type</c> specifies if the child process is a supervisor or + a worker.</p> + </item> + <item> + <p><c>Modules</c> should 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> + <p>This information is used by the release handler during + upgrades and downgrades, see + <seealso marker="release_handling">Release Handling</seealso>.</p> + </item> + </list> + <p>Example: The child specification to start the server <c>ch3</c> + in the example above looks like:</p> + <code type="none"> +{ch3, + {ch3, start_link, []}, + permanent, brutal_kill, worker, [ch3]}</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 + 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 + need some time for the event handlers to clean up, thus + <c>Shutdown</c> is set to 5000 ms.</p> + <p>Example: A child specification to start another supervisor:</p> + <code type="none"> +{sup, + {sup, start_link, []}, + transient, infinity, supervisor, [sup]}</code> + </section> + + <section> + <marker id="super_tree"></marker> + <title>Starting a Supervisor</title> + <p>In the example above, 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> + <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> + callback function is located.</item> + <item>The second argument, [], is a term which 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> + <p>In this case, the supervisor is not registered. Instead its pid + must be used. A name can be specified by calling + <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> + <code type="none"> +init(_Args) -> + {ok, {{one_for_one, 1, 60}, + [{ch3, {ch3, start_link, []}, + permanent, brutal_kill, worker, [ch3]}]}}.</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 + 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> + <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> + <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> + </section> + + <section> + <title>Stopping a Child Process</title> + <p>Any child process, static or dynamic, can be stopped in + accordance with the shutdown specification:</p> + <code type="none"> +supervisor:terminate_child(Sup, Id)</code> + <p>The child specification for a stopped child process is deleted + with the following call:</p> + <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> + <p>As with dynamically added child processes, the effects of + deleting a static child process is lost if the supervisor itself + restarts.</p> + </section> + + <section> + <title>Simple-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> + <code type="none"> +-module(simple_sup). +-behaviour(supervisor). + +-export([start_link/0]). +-export([init/1]). + +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. + 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 + the list of arguments specified in the child specification. If + the start function is specified as <c>{M, F, A}</c>, then + 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 + <c>apply(call, start_link, []++[id1])</c>, or actually:</p> + <code type="none"> +call:start_link(id1)</code> + </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 + order according to the respective shutdown specifications, and + then terminate itself.</p> + </section> +</chapter> + diff --git a/system/doc/design_principles/warning.gif b/system/doc/design_principles/warning.gif Binary files differnew file mode 100644 index 0000000000..96af52360e --- /dev/null +++ b/system/doc/design_principles/warning.gif diff --git a/system/doc/design_principles/xmlfiles.mk b/system/doc/design_principles/xmlfiles.mk new file mode 100644 index 0000000000..f34d1c9a0f --- /dev/null +++ b/system/doc/design_principles/xmlfiles.mk @@ -0,0 +1,32 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +DESIGN_PRINCIPLES_CHAPTER_FILES = \ + applications.xml \ + appup_cookbook.xml \ + des_princ.xml \ + distributed_applications.xml \ + events.xml \ + fsm.xml \ + gen_server_concepts.xml \ + included_applications.xml \ + release_handling.xml \ + release_structure.xml \ + spec_proc.xml \ + sup_princ.xml |