The standard http://www.strozzi.it/cgi-bin/CSA/tw7/I/en_US/CSA CSA library provides functions that are needed to handle concurrent access to the data by multiple programs, with the objective of preserving file integrity during update operations. Concurrency is handled through the use of lock-files, or semaphores. These can be created/destroyed with the relevant CSA library functions csaLock
and csaUnlock
. Handling locks is a tricky subject, due to the possibility of race-conditions that may lead to either data corruption or dead-locks. The former can occur whenever we have a test operation, followed by an action based on the result of the test. This test-action sequence is non-atomical, hence the potential for races.
Preventing dead-locks is another issue that the library functions try to cope with, although for this to be effective a CSA application program must be designed sensibly in the first place.
As a rule-of-thumb, semaphores MUST be set whenever any of the following conditions are met:
Whatever the locking policy, it is left entirely up to the CSA application program. The CSA library merely provides the locking primitives, but whether to lock individual files, whole directories, or other application-dependent collections of resources is an application-level affair from the CSA point of view.
Explicitly releasing lock-files is usually not necessary, as they are removed automatically when a program calls csaExit
or one of its variants ( csaExit.ok
, csaExit.fault
, etc.). Removing one or more locks with an explicit call to csaUnlock
may be necessary only if a program needs to iterate multiple times before exiting, and in general when it is expected to go on for a while before calling csaExit
. In such cases we SHOULD release the locks when we no longer need them, or others may time-out while waiting to try and set their own locks on the same resources.
A program that wants to read from, or write to a certain file, and that wants to make sure that nobody else changes that file in the meantime, can set a lock on that file as follows:
csaLock /path/to/file || csaExit.fault 0007 /path/to/file
csaExit.ok 0028
The csaLock
function will create a file named /path/to/file.lock
under the directory pointed to by CSA_LOCK_ROOT
, returning non-zero if the operation fails. If the lock already exists, csaLock will keep trying for a configurable number of seconds, after which it will give-up and fail with a error.
In the example, if the lock fails, an error exit is taken, with a suitable error message. If locking succeedes, csaLock
returns zero and the program continues (in this case it will simply exit with a positive completion message). It is normally not necessary to release a lock when it is no longer needed, as that will occur anyway when the program terminates with any of the CSA functions of the csaExit.*
family.
There is a lot more to be said to use lock-files properly. I'll eventually expand this section a bit, to try and make it more useful.