[/Band|c00t] GettingStarted Specification Download Blog About
Fork me on GitHub

Transactions in the Bandicoot

Published by Julius Chrobak on 2011 01 23.

One of the most interesting features of the Bandicoot system is its simple approach for transaction handling. In this blog I would like to show how intuitive and powerfull the transactions are.

Before we move onto the details it's important to note that Bandicoot implements all ACID[1] properties. It's important to keep this in mind when writing applications in the Bandicoot. It'll help you to relax and trust the system.

So, let's start very simple. Look at the following piece of code:

rel Order {
    item: string,
    client: int
}

orders: Order;

fn AddOrder(o: Order)
{
    orders = orders + o;
}

I believe the code is self-explanatory and does not require further comments. The important bit to understand is how the AddOrder function works. The function modifies a global variable and if more than one execution is being performed at a time it requires a synchronization of the assignment. Otherwise, we could end up with corrupted value. Note that this is no different to a general purpose programming language (i.e. Java synchronized blocks [2]). What is different is the fact that the Bandicoot takes care of this on your behalf. Every time you are modifying a global variable you can be sure that there is no-one else doing the same.

But the Bandicoot goes even further. The synchronization is always done on the function level. It never happens just around a single assignment. Let's have a look at the following code:

pending: Order;

fn MovePending()
{
    orders = orders + pending;
    pending = pending - pending;
}

fn MoveOrders()
{
    pending = pending + orders;
    orders = orders - orders;
}

We have introduced another variable, pending orders. We also added functions which modify the same variables but in a different order. Due to the synchronization on the function level this is not a problem and the system will simply execute one function after the other. This also means, there are no deadlocks going to happen regardless of how the code is written.

There is also another important action happening on the function level; commit or rollback. Even though you are able to modify a value of a global variable in the first statement of a function, in reality the new values are not visible until the function execution is finished. This provides a complete isolation and no operation can see partial state of variables. If there is an error during an execution the changes are rolled-back and your variables stay in a consistent state.

This all sounds great, but what about reads? How does it work? Are the read-only functions synchronized as well? No, if you have read-only functions they are executed in parallel with writes and other reads. This is implemented via snapshots in the system. The Bandicoot keeps multiple versions of global variables. The older, not latest, versions are kept as long as there is someone reading them. To be more specific, at a time a function is invoked the system determines what versions, of all variables used in the functions, will be read.

Let's now discuss this more in details with using MovePending and GetAll function as defined below:

fn GetAll(): Order
{
    return orders + pending;
}

If the GetAll and MovePending functions are executed at the same time, the GetAll function will progress and return the result as of the time the function was invoked. Imagine your execution of the GetAll function is in progress and it's just finished reading the orders variable. It is about to read the pending one which in the meanwhile was modified by an execution of the MovePending. The fact that the MovePending was executed while GetAll is running does not have any impact on the results. The version of the pending variable you are going to see is the previous version consistent with the version of the orders variable you have just read.

Summary

To sum up, there are four very important features implied from the way how the Bandicoot implements transactions:

Resources

  1. ACID transactions on wikipedia
  2. Java synchronized block