After much deliberation, pseudo code writing, diagram drawing and some revision of this post, I have come up with the following plan for locking. Please let me know if you think there is something I am over looking.
NOTE: I keep a static key,value (primary key,locking instance of Data) hashmap of the currently locked records named reservations.
to read a record from the database: the following steps are all inside the synchronized read method of my singleton DatabaseAccess class.
1 - readLock the dbIndexLock
2 - read from the db file
3 - unlock the dbIndexLock
to update a record in the database: the following steps are all inside the synchronized update method of my singleton DatabaseAccess class.
1 - writeLock the dbIndexLock
2 - lock the record in reservations
3 - read from the db file
4 - update the in memory record
5 - write to the updated record to file
6 - unlock the dbIndexLock
7 - unlock the record in reservations
8 - notify all
Your update-method should only do what the method name suggests: updating the record that is. Not locking the record (that's courtesy of the lock-method), not unlocking record (courtesy of unlock method). Just updating the record. That's it! Of course you'll also have to do a check to see if the record was successfully locked by the thread/client that's wanting to update the record. If the check completes successfully, the record is updated and that's really it for this method. Why would you otherwise have methods like lock/unlock?
In standalone mode, we know that only one client will ever try to book a record, should I still go through the locking / unlocking of the index file and the record each time a user books/returns a contractor, even tho' technically, there is no need?
Using the oft quoted KISS methodology, I would say no.
However, for consistency if nothing else, it feels like I should route these functions of my application through the same locking / unlocking methods.
Based on the given interface you have to lock the record before you can update the record (and your update record is checking if it's correctly locked). You definitely don't want a seperate update implementation for standalone mode. Your Data class should be completely unaware of the mode it's running in. So you'll have to call lock/update/unlock to successfully update a record.