Clone wiki

pymoult / A simple Pymoult tutorial

Prerequisites

This tutorial requires a working installation of Pymoult. You can follow
the instructions
here to install
it.

Or you can download a Virtual
Machine

with Pymoult pre-installed and ready to use. If chose this option, make
sure Pymoult is up to date following the instructions on the VM’s page.

The Tutorial

For each exercise, you can find the solution in a solution.py file. It
provides an answer to the exercise. Keep in mind that there can be more
than one way to apply the updates. To execute the solution, run
./test.sh solution in the proper directory. The documentation of
Pymoult can be found
here
and examples of use of mechanisms can be found in the directory
pymoult/examples/tests.

Step 1: Using the High-level API

The first step of our tutorial will show how to use the predefined
updates classes provided by the high-level API of Pymoult. The following
exercises can be found in the step1 folder.

Exercise 1: Hello World

Our first update will update a small hello world program. Look at the
application code: a loop calls the hello function every 2 seconds.

Now, open the update.py file. See how it begins with #parsed. This
keyword tells Pymoult that this is an update file. Notice also how a
manager is started during the update.

Complete the update.py file by defining a hello_v2 function that
prints hello <your name>. Then create an update object using the
SafeRedefineUpdate class from pymoult.highlevel.updates and send to
the manager by adding
manager.add_update(<name of your update object>).

When you think your update is ready, run ./test.sh and look at the
result.

Exercise 2: Tic toc, goes the clock

In this exercise, use what you learned in the previous exercise to
update the functions tic and tac of the application.

Open the application.py, this application calls tic then tac each
second. Note that the application starts a manager before calling its
main function. You can use that manager when updating by calling\ main.manager.add_update(<update>) where main is the module captured
by sys.modules[__main__].

Now, create an update.py file (you can copy the update file from
previous example) and create two functions tic_v2 and tac_v2. Then
using two instances of SafeRedefineUpdate, update tic and tac to
tic_v2 and tac_v2.

Run ./test.sh when your update is ready

Exercice 3: Updating Data

In this exercise, you will use an instance of EagerConversionUpdate to
update the class Data of the application.

Create an update.py file and write a new version of the Data class
where it has an origin attribute. When an instance of Data_v2 is
printed, it should display &lt;value&gt; from &lt;origin&gt;.

Then, write a tranformer(data) function that takes an instance of
Data (old version) and adds a origin attribute to it so that it
becomes compatible with Data_v2. After that, you can create an
instance of EagerConversionUpdate and send it to the manager to update
Data.

Step 2: Combining update classes

The second step of our tutorial shows how to combine predefined update
classes to design more complex updates. The following exercises can be
found in the step2 folder.

Exercise 1: Back to updating Data

This exercise uses the same Data class as last exercise. The
application maintains a list of Data following the principle of the
Fibonacci sequence: the new element of the list is the sum of the two
last elements of the list.

As in the previous exercise, origin is added to the Data class, which
requires modifying the sum function. Open update.py and use the
update classes of the High-level API of Pymoult to update Data and
sum.

Notice that in Data_v2, the origin argument of the constructor is
optional. This is because Data and sum are updated separately: the
old version of sum may create an instance of Data_v2 without
supplying the origin argument.

Exercise 2: Series of integer

This application generates ten thousand integers then creates a serie of
5 randomly picked integers every two seconds.

Write an update that applies two modifications to the application:

  1. Update the Integer class so that all integers are multiplied by 2.

  2. Redefine the __str__ method of Serie so that it shuffles the
    integers before returning its content.

Since there are a lot of integers in the application, use the Lazy
strategy for updating them.

Hint: you can shuffle a list by calling random.shuffle(<list>).

Step 3: Developing custom update classes

The third step of our tutorial shows how to develop custom update
classes by combining mechanisms from the Low-level API of Pymoult. The
following exercises can be found in the step3 folder.

Exercice 1: Hello again

Here, you will solve the first exercise of the first step again, but by
defining your own update Class.

Open the update.py file. You need to complete the code of the
CustomUpdate by filling up its methods:

  • wait_alterability must return True when hello is quiescent

  • resume_hook is called when resuming the program

  • apply must redefine hello to its new version

Then, create an instance of CustomUpdate and send it manager.

Exercice 2: The return of the Data update

Remember the first exercise of step 2? The new version of the Data had
to define a default value for the origin attribute because the two
parts of the update where independent. In this exercise, you will write
a custom update that will redefine sum and update Data in a single
go.

To update Data, you can use the following mechanisms from the
low-level API:

  • DataAccessor(class,immediate), creates an iterator over all
    instances of class that exist when the data accessor is created.

  • redefineClass(module,class,class_v2), redefines class from
    module to class_v2.

  • updateToClass(obj,class,class_v2,transformer), updates obj of
    class class to class_v2 and applies transformer.

Exercice 3: The clock never stops ticking

In the second exercise of the first step, you used safe redefinition to
update functions tic and tac. While this works, it does not
guarantee that the update won’t happen between calls to tic and tac.

Open the application.py file and notice the static update point placed
at beginning of main’s loop. You will use it as alterability criteria
to ensure that the following trace is not possible:

tic,tac,tic,tac2,tic2,...

Notice that the main function is called in a DSU_Thread. This
Pymoult specific Thread is an extension of the threading.Thread class
of Python. It is required for using static points.

To use the static point as alterability criteria, you will need to call
setupWaitStaticPoints during the first setup step of the update
(method preupdate_setup and ggcleanFailedStaticPoints in the
clean_failed_alterability.

Exercice 4: Rebooting threads

Let’s take the Hello world example and use a different method to
update it. In this exercise, you will use Thread rebooting.

Place a static update point in the code of the application and write an
update that reboots thread to update the hello function.

  • switchMain(thread,new_main) changes the main function of
    DSU_Thread thread to new_main.

  • resetThread(thread) reboots thread (it must be a DSU_Thread)

Step 4: Complex updates

In the last step of our tutorial, you will use everything you learned in
the previous steps to develop complex updates. The following exercises
can be found in the step4 folder.

Exercice 1: Simultaneous update

In this application, a shared variable is read and written by two
functions (write_shared and read_shared). We want to update the
application so that the variable stores the time when it was written.
This requires the two functions to be updates at the same time. Indeed,
if the write_shared write the variable in the new format, the old
version of read_shared would crash when reading it.

In this example, we will use the same strategy as in DynamOS (Dynamic
and Adaptive Updates of Non-Quiescent Subsystems in Commodity Operating
System Kernels, Eurosys 2007): In a first phase, we well redefine
write_shared and read_shared to intermediate functions that can call
both old and new versions:

def interm_write():
    if update:
        <code of write_shared_v2>
    else:
        <code of write_shared>

When both write_shared and read_shared are replaced by their
intermediate version, the global variable update is set to true. The
application will be behave as if it where in its new version. Both
functions can, then, be redefined to write_shared_v2 and
read_shared_v2.

Exercice 2: Web Server

The application here is a web server serving small predefined pages on
localhost:8080. After running ./test.sh, you can go to
http://localhost:8080/hello, http://localhost:8080/banana,
http://localhost:8080/coconut. For this example, the update will not
be summoned until you press a key.

The application uses the server python library (embedded by the Python
interpreter). Before updating, familiarize yourself with the code of the
application.

The update will add authentication to the server. It will require users
to log in and customize the messages in the served pages to the user
currently logged in. All the necessary code for this can be found in the
update.py file.

To apply this update, we advise that you proceed in two steps. As a
first step, update the Page and the Session classes. Then, update
the Webserver class and redefine the do_GET method of the Handler
class. You will need to generate the new version with the
create_new_do_GET function in update.py.

Hint: You may use a static update point to indicate the alterability of
the web server.

Updated