aboutsummaryrefslogtreecommitdiffstats
path: root/system/doc/design_principles/appup_cookbook.xml
diff options
context:
space:
mode:
Diffstat (limited to 'system/doc/design_principles/appup_cookbook.xml')
-rw-r--r--system/doc/design_principles/appup_cookbook.xml627
1 files changed, 627 insertions, 0 deletions
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>
+