Hotswap

classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|

Hotswap

Jay Nelson
Peter wrote:
 > -module(simple_server).

 > server() ->
 >     receive
 >        {tagA,Data} ->     %% do A ...
 >                server();      % <<<<<<<<<<<<<<<< case A
 >        {tagB,Data} ->      %% do B ...
 >                simple_server:server(); %<<< case B
 >      end.

Does the entire module simple_server get loaded?

If not, what about new functions that server() might call
in the new version?

If so, why does Chris say that
the interface must stay the same -- wouldn't loading
the whole module introduce a potentially new interface?

jay



Reply | Threaded
Open this post in threaded view
|

Hotswap

Michał Ptaszek
You reminded me I need to add the -export([server/0]) and a number of
other things, oops!

And I think there lies the answer to your question: internally the
module may change radically, but if you inconsiderately change the
exported function signatures, you can expect the server to throw an
exception, which hopefully the program writer will catch with another
linked supervisor process, which may potentially diagnose the error and
revert to a previous version. I'm speculating here, I haven't actually
done this before, but the explanation on error handling and robust
applications in the Concurrent Programming in Erlang book is quite easy
to grasp. I highly recommend this (rare) book!

This doesn't prevent the new version from *enhancing* the exported
interface, or adding new exported functions, which highlights another
strength of Erlang as a prototyping tool. You could potentially write
the code to enable the change from one module design to a totally
different one, by proceeding in stages to switch the server loop from
one tail recursive function to another in the new module.

I'm going to attempt a functioning example of switching code within a
running server process in the next hour (work permitting) and hopefully
follow this up on the mailing list. It's a good toy project and will
solidify my understanding too.

Pete.


Jay Nelson wrote:

> Peter wrote:
>  > -module(simple_server).
>
>  > server() ->
>  >     receive
>  >        {tagA,Data} ->     %% do A ...
>  >                server();      % <<<<<<<<<<<<<<<< case A
>  >        {tagB,Data} ->      %% do B ...
>  >                simple_server:server(); %<<< case B
>  >      end.
>
> Does the entire module simple_server get loaded?
>
> If not, what about new functions that server() might call
> in the new version?
>
> If so, why does Chris say that
> the interface must stay the same -- wouldn't loading
> the whole module introduce a potentially new interface?
>
> jay
>
>
>





Reply | Threaded
Open this post in threaded view
|

Hotswap

Michał Ptaszek
Okay, here's my example:

I do the following in the shell:

   8> c(counter).
   {ok,counter}
   9> counter:start(100).
   {ok,100}
   10> counter:test().
   incr
   decr
   decr
   decr
   reset (previous value=98)
   get_value => 10
   ok

All is well. Without issuing counter:stop() I modify the code by
uncommenting the new code and commenting out the old. I recompile and
run counter:test again:

   11> c(counter).
   {ok,counter}
   12> counter:test().
   incr
   **** switching NOW! ****
   decr
   decr
   decr
   reset (previous value=8)
   get_value => {10,new_parameter}
   ok
   13> counter:stop().
   10

Et voila! I've modified the loop by litterally switching from one tail
recursive function to another (and modified the API for the sake of the
demo) with very little effort and without stopping anything.

Stuff that into your C/C++ pipe and smoke it! (-:

Pete.

P.s. I'm an experienced C++ programmer, and I've _never_ found it as
easy as *this* to hot swap code, neither as quick to implement! Yay Erlang!



Peter-Henry Mander wrote:

> You reminded me I need to add the -export([server/0]) and a number of
> other things, oops!
>
> And I think there lies the answer to your question: internally the
> module may change radically, but if you inconsiderately change the
> exported function signatures, you can expect the server to throw an
> exception, which hopefully the program writer will catch with another
> linked supervisor process, which may potentially diagnose the error and
> revert to a previous version. I'm speculating here, I haven't actually
> done this before, but the explanation on error handling and robust
> applications in the Concurrent Programming in Erlang book is quite easy
> to grasp. I highly recommend this (rare) book!
>
> This doesn't prevent the new version from *enhancing* the exported
> interface, or adding new exported functions, which highlights another
> strength of Erlang as a prototyping tool. You could potentially write
> the code to enable the change from one module design to a totally
> different one, by proceeding in stages to switch the server loop from
> one tail recursive function to another in the new module.
>
> I'm going to attempt a functioning example of switching code within a
> running server process in the next hour (work permitting) and hopefully
> follow this up on the mailing list. It's a good toy project and will
> solidify my understanding too.
>
> Pete.
>
>
> Jay Nelson wrote:
>
>> Peter wrote:
>>  > -module(simple_server).
>>
>>  > server() ->
>>  >     receive
>>  >        {tagA,Data} ->     %% do A ...
>>  >                server();      % <<<<<<<<<<<<<<<< case A
>>  >        {tagB,Data} ->      %% do B ...
>>  >                simple_server:server(); %<<< case B
>>  >      end.
>>
>> Does the entire module simple_server get loaded?
>>
>> If not, what about new functions that server() might call
>> in the new version?
>>
>> If so, why does Chris say that
>> the interface must stay the same -- wouldn't loading
>> the whole module introduce a potentially new interface?
>>
>> jay
>>
>>
>>
>
>
>
>
>

-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: counter.erl
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20030403/b10e0e6b/attachment.ksh>

Reply | Threaded
Open this post in threaded view
|

Hotswap

Ulf Wiger-4
In reply to this post by Jay Nelson
On Wed, 2 Apr 2003, Jay Nelson wrote:

>Peter wrote:
> > -module(simple_server).
>
> > server() ->
> >     receive
> >        {tagA,Data} ->     %% do A ...
> >                server();      % <<<<<<<<<<<<<<<< case A
> >        {tagB,Data} ->      %% do B ...
> >                simple_server:server(); %<<< case B
> >      end.
>
>Does the entire module simple_server get loaded?

Yes.

>If not, what about new functions that server() might call
>in the new version?

server() might call other functions in the same module, and
as long as they are not fully qualified
(Module:Function(...)), it will be a "local" call in the
same version of the module.

If it's a fully qualified call, the function has to be part
of the module interface. This is still OK, if that function
acts only on the provided arguments (is side-effect free)
and it's semantics haven't changed in the upgrade.


>If so, why does Chris say that the interface must stay the
>same -- wouldn't loading the whole module introduce a
>potentially new interface?

The interface needs to be backward compatible in the areas
that matter (the functions that can be called by old code
during or after the upgrade). A way around this is to rely
on the OTP code change mechanisms, which allow you to
specify dependencies between processes and modules; this
way, you can suspend processes that might call incompatible
functions or otherwise mess up the upgrade. OTP allows you
to perform a fully synchronized, orderly upgrade of a
complex, multi-node system -- provided you can figure out
how from the documentation, which is no small feat.  (:

/Uffe
--
Ulf Wiger, Senior Specialist,
   / / /   Architecture & Design of Carrier-Class Software
  / / /    Strategic Product & System Management
 / / /     Ericsson AB, Connectivity and Control Nodes




Reply | Threaded
Open this post in threaded view
|

Hotswap

Vance Shipley-2
In reply to this post by Michał Ptaszek

Hot swap is useful for more than constant uptime production
systems.  When you are doing development on a system involving
more than a few modules/processes the startup time can be
significant.  Just starting an erlang node takes a while.  I
generally edit code in one window and then in another I am
running an erlang shell on the system under test in which I
run c(module) which compiles and loads the new module.  You
then test, edit, test, etc.  This iteration is really fast
compared to a cold boot of the erlang node and starting the
processes.

        -Vance


Reply | Threaded
Open this post in threaded view
|

Hotswap

Rick Pettit-2
On Thu, Apr 03, 2003 at 02:39:11PM -0500, Vance Shipley wrote:

> Hot swap is useful for more than constant uptime production
> systems.  When you are doing development on a system involving
> more than a few modules/processes the startup time can be
> significant.  Just starting an erlang node takes a while.  I
> generally edit code in one window and then in another I am
> running an erlang shell on the system under test in which I
> run c(module) which compiles and loads the new module.  You
> then test, edit, test, etc.  This iteration is really fast
> compared to a cold boot of the erlang node and starting the
> processes.

Wow, somehow I hadn't thought of that. This truly is an exciting feature,
and an excellent use of hot swap.  Thanks.

-Rick


Reply | Threaded
Open this post in threaded view
|

Hotswap

Michał Ptaszek
In reply to this post by Vance Shipley-2
Thanks for emphasising a point that I only hinted at.

Yes, prototyping _is_ much faster this way. Only once before I was able
to work on a project that was developed in a similar manner in a
Smalltalk-ish language, and the productivity of the tiny software team
was absolutely blistering! I'm really happy I can work this way again
with Erlang.

I can't imagine how you would do prototyping in C/C++, the
code-compile-load-execute-debug cycle is sooooooooo long!

Pete.

Vance Shipley wrote:

> Hot swap is useful for more than constant uptime production
> systems.  When you are doing development on a system involving
> more than a few modules/processes the startup time can be
> significant.  Just starting an erlang node takes a while.  I
> generally edit code in one window and then in another I am
> running an erlang shell on the system under test in which I
> run c(module) which compiles and loads the new module.  You
> then test, edit, test, etc.  This iteration is really fast
> compared to a cold boot of the erlang node and starting the
> processes.
>
> -Vance
>
>





Reply | Threaded
Open this post in threaded view
|

Hotswap

Tomas Abrahamsson-3
In reply to this post by Vance Shipley-2

> Hot swap is useful for more than constant uptime production
> systems.  When you are doing development on a system involving
> more than a few modules/processes the startup time can be
> significant.  Just starting an erlang node takes a while.  I
> generally edit code in one window and then in another I am
> running an erlang shell on the system under test in which I
> run c(module) which compiles and loads the new module.  You
> then test, edit, test, etc.  This iteration is really fast
> compared to a cold boot of the erlang node and starting the
> processes.

We've built a nifty little tool on top of reshd[*],
that enables us to connect to a running system, compile
and load code directly into all nodes from Emacs by
typing C-c k (instead of the usual C-c C-k).

One hacker here got so addicted to it that he
desperately wants something similar for Java, now that
he has to hack Java for a while :-)

The turn around time from edit to test is really short.


/Tomas

________
[*] See http://www.erlang.org/user.html#reshd-1.2


Reply | Threaded
Open this post in threaded view
|

Hotswap

Ulf Wiger-4
In reply to this post by Vance Shipley-2
On Thu, 3 Apr 2003, Vance Shipley wrote:

>Hot swap is useful for more than constant uptime production
>systems.  When you are doing development on a system
>involving more than a few modules/processes the startup
>time can be significant.  Just starting an erlang node
>takes a while.  I generally edit code in one window and
>then in another I am running an erlang shell on the system
>under test in which I run c(module) which compiles and
>loads the new module.  You then test, edit, test, etc.
>This iteration is really fast compared to a cold boot of
>the erlang node and starting the processes.

Oh, and this feature is a jaw dropper at Interops. I've
heard several accounts where people have brought
erlang-based systems to interops (Megaco, MPLS, etc.), and
have debugged and fixed interoperability problems in minutes
without restarting the system -- sometimes without even
dropping the session!

I also seem to recall occasions where the erlang guys have
helped their competitors debugging _their_ system simply by
being able to follow the communication so much better on the
erlang side. Finally, I've heard accounts of the erlang guys
implementing workarounds to other people's bugs simply
because it was so much easier to do it that way than to wait
for them to get a fix from their design teams.

/Uffe
--
Ulf Wiger, Senior Specialist,
   / / /   Architecture & Design of Carrier-Class Software
  / / /    Strategic Product & System Management
 / / /     Ericsson AB, Connectivity and Control Nodes



Reply | Threaded
Open this post in threaded view
|

Hotswap

Michał Ptaszek
I couldn't let this pass me by without complementing the guys who wrote
the MeGaCo stack. I use Erlang/MeGaCo to test for interop with 3rd party
stacks and the in-house C/C++ implementation. We performed an acceptance
test using it, and pinpointed about a dozen issues with the software we
commisioned from XXX (no names given, but they are stack specialists).
We couldn't do acceptance against our actual product because the C/C++
MeGaCo stack was nowhere near ready. No comment!

I think we embarassed the guy who came over to aid the integration! And
our own MeGaCo team! The current Erlang version of the MeGaCo stack is a
very solid product, it's value is priceless. I can vouch for it.

Pete.


Ulf Wiger wrote:

> On Thu, 3 Apr 2003, Vance Shipley wrote:
>
>
>>Hot swap is useful for more than constant uptime production
>>systems.  When you are doing development on a system
>>involving more than a few modules/processes the startup
>>time can be significant.  Just starting an erlang node
>>takes a while.  I generally edit code in one window and
>>then in another I am running an erlang shell on the system
>>under test in which I run c(module) which compiles and
>>loads the new module.  You then test, edit, test, etc.
>>This iteration is really fast compared to a cold boot of
>>the erlang node and starting the processes.
>
>
> Oh, and this feature is a jaw dropper at Interops. I've
> heard several accounts where people have brought
> erlang-based systems to interops (Megaco, MPLS, etc.), and
> have debugged and fixed interoperability problems in minutes
> without restarting the system -- sometimes without even
> dropping the session!
>
> I also seem to recall occasions where the erlang guys have
> helped their competitors debugging _their_ system simply by
> being able to follow the communication so much better on the
> erlang side. Finally, I've heard accounts of the erlang guys
> implementing workarounds to other people's bugs simply
> because it was so much easier to do it that way than to wait
> for them to get a fix from their design teams.
>
> /Uffe