Skip to content

Instantly share code, notes, and snippets.

@7-fl
Last active May 1, 2017 05:20
Show Gist options
  • Save 7-fl/cf9ea129489b1eeae399f3bda04952d6 to your computer and use it in GitHub Desktop.
Save 7-fl/cf9ea129489b1eeae399f3bda04952d6 to your computer and use it in GitHub Desktop.
Hot code loading with frequency server

original f4.erl:

I changed the original f4.erl server code to contain an additonal clause in loop():

-export([loop/1]).

loop(Frequencies) ->
    receive
        {request, _Pid, switch_code} ->
            f4:loop(Frequencies);

That is straight out of the erlang Compilation and Code Loading docs.


new f4.erl:

The new f4.erl with the inject functionality looks like this:

%% Based on code from 
%%   Erlang Programming
%%   Francecso Cesarini and Simon Thompson
%%   O'Reilly, 2008
%%   http://oreilly.com/catalog/9780596518189/
%%   http://www.erlangprogramming.org/
%%   (c) Francesco Cesarini and Simon Thompson

-module(f4).
-export([start/0,allocate/0,deallocate/1,inject/1,stop/0]).
-export([init/0, loop/1]).

%% These are the start functions used to create and
%% initialize the server.

start() ->
    register(f4,
	     spawn(f4, init, [])).

init() ->
    Frequencies = {get_frequencies(), []},
    loop(Frequencies).

                                                
get_frequencies() -> [10,11].

%% The Main Loop

loop(Frequencies) ->
    receive
        {request, Pid, allocate} ->
            {NewFrequencies, Reply} = allocate(Frequencies, Pid),
            Pid ! {reply, Reply},
            loop(NewFrequencies);
        {request, Pid , {deallocate, Freq}} ->
            NewFrequencies = deallocate(Frequencies, Freq),
            Pid ! {reply, ok},
            loop(NewFrequencies);
        {request, Pid, {inject, AddFreqs}} ->   %<******* ADDED CODE *****
            NewFrequencies = inject(Frequencies, AddFreqs),
            Pid ! {reply, ok},
            loop(NewFrequencies);
        {request, Pid, stop} ->
            Pid ! {reply, stopped}
    end.

%% Functional interface

allocate() -> 
    f4 ! {request, self(), allocate},
    receive 
        {reply, Reply} -> Reply
    end.

deallocate(Freq) -> 
    f4 ! {request, self(), {deallocate, Freq}},
    receive 
        {reply, Reply} -> Reply
    end.

inject(AddFreqs) ->    %<******** ADDED CODE ******
    f4 ! {request, self(), {inject, AddFreqs}},
    receive
        {reply, Reply} -> Reply
    end.

stop() -> 
    f4 ! {request, self(), stop},
    receive 
        {reply, Reply} -> Reply
    end.

%% The Internal Help Functions used to allocate and
%% deallocate frequencies.

allocate({[], Allocated}, _Pid) ->
    {{[], Allocated}, {error, no_frequency}};
allocate({[Freq|Free], Allocated}, Pid) ->
    {{Free, [{Freq, Pid}|Allocated]}, {ok, Freq}}.

deallocate({Free, Allocated}, Freq) ->
    NewAllocated=lists:keydelete(Freq, 1, Allocated),
    {[Freq|Free],  NewAllocated}.

inject({Free, Taken}, AddFreqs) ->   %<****** ADDED CODE ****
    {Free ++ AddFreqs, Taken}.
    

A minimal shell session:

1> c(f4).
{ok,f4}

2> f4:start().
true

3> f4:allocate().
{ok,10}
4> f4:allocate().
{ok,11}
5> f4:allocate().
{ok,12}
6> f4:allocate().
{error,no_frequency}

7> cd("./hotcode").
/Users/me/path/to/hotcode
ok

8> ls().
f4.erl  
ok

9> c(f4).
{ok,f4}

10> f4 ! {request, self(), switch_code}.
{request,<0.32.0>,switch_code}

11> f4:inject([41,42]).
ok

12> f4:allocate().
{ok,41}

13> 

Now, following the steps in the exercise:

1> c(f4).
{ok,f4}

2> f4:start().
true

3> f4:allocate().
{ok,10}
4> f4:allocate().
{ok,11}
5> f4:allocate().
{ok,12}
6> f4:allocate().
{error,no_frequency}

7> cd("./hotcode").
/Users/7stud/erlang_programs/fl_course2/2week/a5/hotcode
ok

8> ls().
f4.beam     f4.erl      
ok

9> c(f4).
{ok,f4}

10> code:load_file(f4).
{error,not_purged}
11> 
=ERROR REPORT==== 30-Apr-2017::11:55:39 ===
Loading of /Users/7stud/erlang_programs/fl_course2/2week/a5/hotcode/f4.beam failed: not_purged

code:soft_purge(f4).
false

12> f4 ! {request, self(), switch_code}.
{request,<0.32.0>,switch_code}

13> code:load_file(f4).

=ERROR REPORT==== 30-Apr-2017::11:56:24 ===
Loading of /Users/7stud/erlang_programs/fl_course2/2week/a5/hotcode/f4.beam failed: not_purged
{error,not_purged}

14> code:soft_purge(f4).
true

15> f4:inject([41,42]).
ok

16> f4:allocate().
{ok,41}

17> 

  • I found it surprising that code:load_file(f4) on line 8 caused an error. Everything I've read says that two versions of a module can exist at the same time, but the error seems to bely those statements. Edit: code:load_file(f4) tries to load the module for the third time, and instead of the original version of the code being purged and all processes using that code being killed, as stated in the lecture, code:load_file(f4) returns an error tuple.

  • Initially, soft_purge() doesn't work because there is still code lingering in the oringinal loop().

  • Sending a switch_code request to the original loop() facilitates the switch to the new version of the code because of the fully qualified call to f4:loop() in the clause handling the switch_code request.

  • Once again, in line 11 f4.beam won't load. Subsequently, soft_purge() worked because execution was not lingering in the orignal version of the code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment