I've spent longer than I have on my locking, and its still in bad order. Im hoping, once again, for help.
What is wrong with this, as far as I can tell, it is logical.
A client (an instance of Data) calls my singletons lock method.
my singletons lock method calls my LockManager class' synchronized lock method.
the lock method checks to see if the Data instance owns the lock on my index file, if not, this.wait() ----this being the singletons instance of my LockManager class
the lock method places the instance of Data against the record in a reservations map.
The client then calls my singletons update. Update checks to see if the Data instance owns the record in the reservations map.
The client then calls my singletons unlock method. My singletons unlock method calls my LockManager class' synchronized unlock method. This synchronized unlock method checks to see if the Data instance owns the lock on my index file. If not, throws THIS EXCEPTION HERE
To me this is perfect. To me that exception can never get thrown as Im using Robertos test class which, in sequence, calls lock,update and unlock
I just dont see how unlock gets called without owning the lock.
The client runs as:
how can the get to unlock without still owning the lock? I throw an exception when this happens as I cannot guarantee that a client will always run in this order. However, for my testing, I KNOW that the client is running in this order and therefore should never cause the exception
Let's say thread1 (or client1) locks record 5. If this thread/client doesn't make a call to unlock(5), this record will be locked forever.
When a developer uses your api has code like this
then his application will get an exception from unlock-method, because he made a (stupid) mistake when developing. But when the calling code is working perfectly, the unlock-method will never throw an exception. Just like you only get NullPointerException if you forgot to include a null check for a reference variable.
Don't forget you are developing an API (which can be used by other developers who might make mistakes) and an application which uses this API. And you have to inform these other developers if they misuse your API.
So you'll have to debug: is the unlock-method invoked by the same thread/client/instance as the lock/update method. You have to have some kind of identification for your client. And don't forget that if you use RMI you don't have the guarantee that each request of a given client is handled by the same thread. So when you choose RMI you can't use thread id as an identifier.
Sorry Folks, I know how annoying I am being but im beyond desperate now. Any help is appreciated.
The sequence of events is ALWAYS (under these test conditions)
unlock (executed in finally)
With the below locking code, if I remove the while loop, I see clients waking up and locking a record that, as far as I can see, is already locked by a different client. I know the while loop fixes this, but it is a hack and only covering up a deeper problem. This deeper problem is what is troubling me.
I don't have much time, I have to get ready for holiday.
In your lock-method I don't get why you would 1st check to see if it's locked. Why not just start waiting as long as the record is already locked? So no need for the ifs.
Secondly in the unlock-method you are using == operator (which compares adresses) to compare your locking objects. Are you sure that's the operator you want to use? I didn't do it myself that way, so I have no idea about what the problem could be. Just using my common sense and if I see a == operator to compare 2 objects I always have my doubts if that gives the desired results...
Thanks for your help on this chaps. Having figured out the problem here it is briefly (for the sake of those that come across this thread in the future):
threads AAAAA and threads BBBBB want to lock record 4.
Thread AAAAA locks record 4 and places it into the reservations map so the reservations map looks like: (AAAAA.4)
Thread BBBBB attempts to lock record 4 and see that it is in the reservations map and then wait()s on record 4.
Thread AAAAA deletes record 4.
Thread BBBBB is still waiting.
Thread AAAAA unlocks record 4 so the reservations map looks like: ()
Thread BBBBB is still waiting
Thread AAAAA notifyAll() on record 4.
Thread BBBBB attempts to lock record 4.
HERE IS THE PROBLEM...what was record 4 when thread BBBBB first attempted to lock is now gone. Now what is record 4 was record 5.
It's obvious that in this scenario Thread BBBBB should get a RecordNotFoundException. And that doesn't need a lot of thinking: you just try to lock record 4, the record doesn't exist and the exception is thrown.