This week's book giveaway is in the OO, Patterns, UML and Refactoring forum. We're giving away four copies of Refactoring for Software Design Smells: Managing Technical Debt and have Girish Suryanarayana, Ganesh Samarthyam & Tushar Sharma on-line! See this thread for details.
somehow I do not really check why the implemented CleanExit class ensures file consistency.
After some redirections it uses to ensure no other thread can modify recordNumbers which would be the case in write operations.
However, the writing operations unlock recordNumbersLock after updating the recordNumbers but before actually writing to the file.
So it looks to me as if in case a write operation releases recordNumbersLock and starts writing to the file and at the same time the shutdown hook uses CleanExit to lock recordNumbers the database file may still end up corrupt?
Can you please help me with what I am missing?
PS: I searched the forum but did not find the answer, so if it is already there please have mercy (newbie bonus)
Welcome to the JavaRanch! Best wishes for 2010 and good luck with the scjd assignment!
I think you have to take a look at this thread (certainly from the moment Paul Balm joins the discussion): it contains valuable information about how a shutdown hook and other threads behave.
the JVM makes no guarantees on the order in which shutdown hooks are started. If any application threads (daemon or nondaemon) are still running at shutdown time, they continue to run concurrently with the shutdown process.
So if we take that into account: new calls to create/update/delete are blocked (because they can't acquire the needed lock on recordNumbers), other calls already having acquired (and released) that lock just run to completion before the JVM really exits (and the database file never gets corrupted).
So the point regarding currently updating operations is that
other calls already having acquired (and released) that lock just run to completion before the JVM really exits
and are not cancelled in the middle of a file access operation.
It seems as if I am using a similar approach as you did (regarding the post you pointed me to), with a singleton Data instance and synchronized methods. So I guess I should be on the safe side having a shutdownHook in the Data instance which calls another synchronized method closing the RandomAccessFile (and set the reference to null). Probably I need to check whether the reference to RAF is null before actually performing a write operation (or even let the client run into a NullPointerException...).
I 'll describe my own approach: I have a singleton Data class with every method marked synchronized. My Data class uses also a record cache, so the shutdown hook is really important in my approach, because when server is shutdown the record cache (with all changes) has to be written back to file or else all changes are lost (and that would be inacceptable). So in my shutdown hook I call my stop-method (which is of course synchronized).
When the server is stopped, the shutdown hook is started and it has to acquire the lock on the single Data object. So if another thread is still busy (with deleting a record for example), the shutdown hook thread has to wait.
When the other thread has finished the delete-method the shutdown hook thread (or any other thread that was waiting to get the lock) runs and writes everything back to the file and indicates it was stopped (just reset the path to the database file to null). Assume another thread (which wants to update a record) was also waiting to acquire lock on the single Data object. So when shutdown hook thread exits the stop-method the lock is available and the update-method gets the lock, notices the data object is stopped (by checking path to database file) and an IllegalStateException is thrown.
The database file will never be corrupted with such an approach and that's the most important (I realize now that I didn't handle such a situation at the client )
Joined: Jan 08, 2010
seems as if I understood it right, looks pretty similar to the approach I added now
(although I do not use a cache and only have to close RAF)