I have implemented my lock method by storing locked records in a HashSet. If a record is currently locked I call wait(). If a database lock is requested (record == -1) I set a boolean to true and once again call wait() if the Hash is not empty. If the aforementioned boolean is set, no more locks are granted so that the Hash can eventually empty so the database lock can be granted. Of course I throw an IOException on an invalid record request. No problem (I hope )
Now the problem comes in with unlock. One of the requirements is to ignore the unlock request if the client does not own the lock. This implies that we need to track who owns each lock. The easiest way to do that (as I see it) is to use a static long (for a unique ID), change my HashSet to a HashMap using the record number as the key and the unique ID as the value. Then tracking who owns the lock is accomplished but at the expense of changing the signature of lock() to return a long (so the client knows its ID) and unlock to accept the unique ID along with the record position.
Is there a better way to do this?
Thanks in advance
I did not keep track who own the lock in my project.
I just checked if record # exist or not in the HASH_SET. I mean unlock method unlocks the requested record. But ignores if the caller does not have a current lock on the requested record. Following is sample code.
There are multiple way of doing same thing. Some used tracking mechanisium who owns the each lock and ran extra mile changing signiture with unique ID. Extra work, more thought, more code. That is super. Some lazy guy like me never bothered. Who cares who wons the lock. Easy going, right! Bottem line is to save project from being dead lock. That is the main objective of this project, I think. You know what! even I did not use boolean true or false to check database/record locked or not. If HASH_SET does not contain a record on it, come'on YOU ARE WELCOME lock it. If it does, wait until it is unlocked.
For unlocking process, see weather it is locked or not. If it is locked unlock it, otherwise SMILE AND SAY you cannot unlock mam! you did not have lock before.
Hope it helps. -Bal
I have some questions for you.
In your unlock codes, you simply check whether the record has already been locked by seeing whethre the recordID is in the HashSet. If not, simply print some words and return. If yes, you unlock it.
But Morris' problem is that you don't make sure you are unlocking some record locked by you!!! If thread A locks record 1 and is doing some work, thread B can unlock record 1 prematurely, which violates synchronization requirement.
1. Like what Morris has done, use HashMap to save who has locked one particular record. But how you generate the unique long is more or less a problem
2. Use some ways (such as encapsulate commands in a object) to make sure no thread will call unlock without calling lock first.
... 2. Use some ways (such as encapsulate commands in a object) to make sure no thread will call unlock without calling lock first.....
I did exactly same what you are talking. I had a method name lockRecordOrDatabase(). It was responsible for locking business. Let me show you how did I use it.
See, there is sequence if you wanna modify a record you got to follow lock, read, modify, and unlock process. If naughty client wanna give a try unlock method without locking it. He/she should have some message, right! The message comes from unlock method for this problem.
Hope it mke some sense. -Bal
I see your point Bal and I am all in favor of keeping it simple and not changing signatures of the provided code.
Laudney, to make a unique ID is pretty simple. You just declare a private static long, set it to some starting point (0 is fine) and increment on all successful locks. You could test for Long.MAX_VALUE and reset to 0 if that occurs but that is probably unnecessary.
If you assume that lock and unlock are done in the same thread, then the simplest way to keep track of whether or not you currently have the lock is to use Thread.currentThread() to obtain a Thread object for yourself and then save that away on the lock() and then make sure on the unlock() make sure that LockOwner(id)==Thread.currentThread()
If you are using RMI, you cannot guarantee that the client will always be using the same thread. So this won't really work.
Following is from Mark's comment concerning my question. Hope it will make you clear the design.
"Nico, one of the requirements for the Server was an interface that implements all the public methods of the Data class. What this really does, besides make it nice to switch between local and remote mode. It also de-couples the Data class from everything. the data class know nothing except how to read/write/modify the db.db file.
So by binding the Data class into RMI, you have to rely more on that Data class to handle more things. First you have to change the signatures of all the methods, and also have it extend UnicastRemote. Not really a good design there.
What xiaoma is doing is taking a factory class called ConnectionFactory and it has a reference to the one and only instance of the Data class. It also has a method called getConnection(). This method creates a Remote object that resides on the server machine, and has a one to one relationship with the clients. Each client has it's own Connection object to service it's needs. When the getConnection method creates this class it passes a reference to the Data object via it's constructor.