Locksim

Locksim is a simulator for database locking, to try out various locking methods such as two-phase locking. It supports multiple transactions and both binary and read/write locks.

This version of Locksim has been tested on Linux (Ubuntu 20.04 with GCC 9.3.0) and on Windows 10 with Visual Studio Community 2019, and on Mac OS X, but it probably runs on more platforms. It just reads text files and print results as text, and it uses no graphics.

Downloads

Download source code: locksim-0.4-source.tar.gz or locksim-0.4-source.zip

Installing and running

Linux and Mac users can unpack the files, cd to the sub-directory src, and just type make in a command window. (You might need to first install developer tools, such as the compiler, if you haven't already done so.) Then type ./locksim in the command window to run the program.

On Windows it is slightly more complicated. You need Visual Studio or some other C compiler. You can either create your own project and add the source code, or use a prepared project for Visual Studio Community 2019, which might be easier to get started with for Windows Users. Read more in the Windows instructions.

Usage

A scenario with database data and specification of the transactions is written in a text file. Then locksim is started using the command line:
locksim  [ -V ]  [ -v VERBOSITY ]  [ -s SEED ]  [ -r REPS ] SCENARIO-FILE
Explanations:

If you are running Locksim under Linux you probably need to give the command as ./locksim and not just locksim.

If you are running Locksim under Windows you probably want to run it in a command Window, instead of in Visual Studio or by clicking on the icon. Otherwise it will be difficult to specify the command-line arguments. Open a command window (the program cmd.exe), chdir to the directory where your executable (the program Locksim-0.4.exe) is, and run it there.

An example scenario

Lotta and Kalle are friends. They have some money in their bank accounts, and both of them want to give away their money to the other person. Here is a scenario file called swap.txt:
/*  A scenario about Lotta and Kalle
 *  and their bank accounts
 */

Lotta = 100;
Kalle = 50;

// Lotta gives all her money to Kalle
transaction Lotta {
    Read(Lotta);
    Gift = Lotta;
    Lotta = 0;
    Write(Lotta);
    Read(Kalle);
    Kalle = Kalle + Gift;
    Write(Kalle);
}

// Kalle gives all his money to Lotta
transaction Kalle {
    Read(Kalle);
    Gift = Kalle;
    Kalle = 0;
    Write(Kalle);
    Read(Lotta);
    Lotta = Lotta + Gift;
    Write(Lotta);
}
The database contains two data objects, the variables Lotta and Kalle, which are the balances of two bank accounts belonging to Lotta and Kalle. In transaction T1 Lotta gives away her money to Kalle. In transaction T2 Kalle gives away his money to Lotta.

Some explanations of the commands in the file:

If the transactions are run serially, or in a serializable schedule, one person ends up with all the money, and the other none. Either Kalle will first give all his money to Lotta, and Lotta will then give all the money to Kalle, so Kalle ends up with all the money and Lotta none, or Lotta will first give all her money to Kalle, and Kalle will then give all the money to Lotta, so Lotta ends up with all the money and Kalle none,

We run the scenario one million times with this command:

locksim -r 1000000 -v 0 swap.txt 
Since the two transactions concurrently modify the variables without locking, we can get some unexpected results. Here is the output from Locksim:
Tried the scenario in 'swap.txt' 1000000 times.
There were 7 different results:
7780 times: 2 variables: Lotta = 150, Kalle = 0
7857 times: 2 variables: Lotta = 0, Kalle = 150
273523 times: 2 variables: Lotta = 50, Kalle = 100
192036 times: 2 variables: Lotta = 150, Kalle = 100
163699 times: 2 variables: Lotta = 0, Kalle = 100
191644 times: 2 variables: Lotta = 50, Kalle = 150
163461 times: 2 variables: Lotta = 50, Kalle = 0
To avoid these concurrency problems, we can add locking. Here we have used two-phase locking with read/write locks:
Lotta = 100;
Kalle = 50;

transaction Lotta {
    ReadLock(Lotta);
    Read(Lotta);
    Gift = Lotta;
    Lotta = 0;
    WriteLock(Lotta);
    Write(Lotta);
    ReadLock(Kalle);
    Read(Kalle);
    Kalle = Kalle + Gift;
    WriteLock(Kalle);
    Unlock(Lotta);
    Write(Kalle);
    Unlock(Kalle);
}

transaction Kalle {
    ReadLock(Kalle);
    Read(Kalle);
    Gift = Kalle;
    Kalle = 0;
    WriteLock(Kalle);
    Write(Kalle);
    ReadLock(Lotta);
    Read(Lotta);
    Lotta = Lotta + Gift;
    WriteLock(Lotta);
    Unlock(Kalle);
    Write(Lotta);
    Unlock(Lotta);
}

Some explanations of the locking commands:

Now the output from Locksim looks like this:

Tried the scenario in 'swap-rw-2PL.txt' 1000000 times.
There were 5 different results:
940 times: 2 variables: Lotta = 150, Kalle = 0
935 times: 2 variables: Lotta = 0, Kalle = 150
453221 times: *** Deadlock! *** 2 variables: Lotta = 0, Kalle = 0
*** Deadlock! ***
272600 times: *** Deadlock! *** 2 variables: Lotta = 0, Kalle = 50
*** Deadlock! ***
272304 times: *** Deadlock! *** 2 variables: Lotta = 100, Kalle = 0
*** Deadlock! ***
As we can see, this locking schema most often leads to deadlock, but when the scenario is finished without deadlock, we get only the two expected results.

Some notes

Author

Locksim is written by Thomas Padron-McCarthy (thomas.padron-mccarthy@oru.se).

License

Locksim is free software licensed under the GNU General Public License version 2. Share and enjoy. No warranty.


Thomas Padron-McCarthy (thomas.padron-mccarthy@oru.se), January 18, 2021