Wiki

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 <value> from <origin>.

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