Wiki
Clone wikipymoult / 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:
-
Update the
Integer
class so that all integers are multiplied by 2. -
Redefine the
__str__
method ofSerie
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 whenhello
is quiescent -
resume_hook
is called when resuming the program -
apply
must redefinehello
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