January 3, 2015

Charging data records or CDRs are generated every time you use the internet on your phone. These records are created by multiple cellular network elements and contain the metadata related to your network activity and determine how you will be billed for your access.

A separate piece of equipment is used to combine matching records from different equipment into a final billable record. This hardware or software device is called a charging gateway function (CGF).

At Atlantic Tele-Network we have created our own CGF using Java to parse the incoming files, load them into a database for matching, and generate the output. Once a complete set of matching records are found, a new record is created in the format required for billing.

Periodically the database needs to be cleaned up and old information needs to be purged, but it’s important that maintenance does not run during the normal execution of the CGF. Since we use shell scripts to start both regular operations and maintenance, I decided to implement the mutual exclusion in Bash.

I only wanted to write the locking code once, so I looked into ways of extracting the functionality into a library. I created a Bash script containing the functions needed to prevent related applications from running at the same time.

Each script that requires mutual exclusion sources the keyway “library”:

#!/usr/bin/env bash source keyway_lib.sh

The area of the script that needs to be protected by a lock (the critical section) is surrounded by keyway lock calls:

acquire_lock_for "example" echo "Executing critical section." release_lock_for "example"

This generates a lock file in ./locks which is the default $LOCK_DIR .

# The lock directory can be customized. LOCK_DIR="./alt-lock-dir"

If the lock is unable to be acquired, the script exits, but if the script should wait to enter the critical section until after the lock has been released, a spinlock can be used instead:

acquire_spinlock_for "spinlock_example" echo "Executing critical section after waiting for lock." release_lock_for "spinlock_example"

Check out Keyway, it’s hosted on GitHub.

It was pointed out to me that the method of checking for and acquiring locks used by Keyway was susceptible to race conditions.

Reddit user /u/sbicknel clued me in with this article from bash-hackers.org. This commit should fix the problem.

29 Kudos