I'm confused whether we have to call lock/unlock INSIDE the read/update etc. methods or before and after. I have implemented the second, but just now I read that in a response to another post, Bob Perillo wrote
And also, your delete method must use the locking mechanism as well as your update method (note the comments of the lock method in the interface that was provided to you; it says that it locks a record so it can be updated or deleted).
From the client I'm calling a custom "book" method, which does lock - update -unlock so this should not be a problem, but what if the Sun just call the API methods update, delete etc. and expect the locking to happen within?
By using the locking mechanism, I meant that, before updating or deleting a record, you have to make sure that the client that is going to perform such operation owns the lock of that particular record. For instance, in my delete method, I verify if the client that is deleting a particular record owns its lock. But yes, you have to call them separately. In practice, you will just be calling the update method somewhere in your business/services layer, so it will be lock/update/unlock, but your delete method must be implemented as well, and there you have to verify if the client deleting a record owns its lock.
One good tip is, in your lock method, after waiting to get the lock of a record, make sure it still exists before indeed locking it (remember that, to delete a record, you also have to own its lock, so after waiting for a record and getting its lock, it may have been deleted).
thanks both of you for your replies! Bob, I'm very grateful for your explanation 'cause I would not have done the "is-record-correctly-locked" check in my delete, update etc. methods - I just did not think of this and would have blindly trusted the caller...
Also it's a very good hint to check whether the record still exists, I'll do that.
Now that I see I have to do these checks in the db access methods, I wonder do I have to make sure the record's locked for a READ? It's a bit awkward to ask such a stupid question but...
Bob, I'm very grateful for your explanation 'cause I would not have done the "is-record-correctly-locked" check in my delete, update etc. methods - I just did not think of this and would have blindly trusted the caller...
I'm very glad to help you, champ! Yeah, I wouldn't have done that either, but after I got some deadlocks, I came to this conclusion!
About the read method, no, you don't have to verify if it is locked or not. This is just for the update and delete methods.
Now, other good tip: before submitting your project, make sure your locking mechanism works correctly in both standalone and networked mode (which means that, in both modes, the wait/notifyAll schema has to exist). So, if I get your implementation of Sun's interface, I have to be able to do this (this is a very very small part of the tests I created to test my locking mechanism before submission):
where Room is a class I created to represent each record in the database, and RoomRetriever is class that transforms a String array to a Room object, and a Room object to a String array.
Joined: Jan 14, 2007
but after I got some deadlocks, I came to this conclusion
thanks again - now I also realize WHY I have to implement the deadlock check... It was the same thing here - I was thinking that as anyway I'm just calling , which has the lock and unlock inside, I can never have any overlapping lockings... but of course when Sun calls the interface methods independently, they can create deadlock, so I'd better prevent this
Dear Roberto, thanks for explanations. One more question: you wrote
By using the locking mechanism, I meant that, before updating or deleting a record, you have to make sure that the client that is going to perform such operation owns the lock of that particular record.
How to identify the client calling the method, i have no way to pass a client id to the delete method. Identify the calling thread?
In order to identify a client, here's what I did: first, my remote server has a method called lock that also takes a long. Here's its signature:
When I'm about to book a room, I generate a long value that will identify the remote client. Here's what I do:
This way, no way 2 different clients can have the same ID when booking a room.
My Data class actually implements an interface that I created (which I called DB) where I added a few extra methods, and extends the DBMain interface (the one you're required to implement). In this DB interface, I added a method called setClientId, that takes a long value as parameter (the same one that is generated in the client side). Then, when working in networked mode, when the server's lock method is called (and the server class has a reference to the Data class), I call the setClientId in the Data class, passing the long value as parameter, then call the Data class' lock method. In the lock method of the Data class, I verify if the clientId variable is null; if so (then it is running in standalone mode), I use the Thread's Id. I had to do this because, when using RMI, it is not guaranteed that the same Thread that handles the first request of a client will also identify their subsequent calls.
One observation is that, on the server class, I used the wait(); method while the record to be locked is still locked. On the Data class, I used the wait(); method as well, while the HashMap where I keep the locked records contains the record to be locked as key.
So use only the Thread's id to identify a client in standalone mode. [ January 02, 2009: Message edited by: Roberto Perillo ]
As I customised it for my application I was almost holding my breath. However, thanks in large part to you, Roel and the rest of the guys on here, she runs like a dream....well almost.
When I set the loop to 10000 it took 58 minutes to complete but complete it did. During that time, it seemd to freeze, at one point, one of these freezes lasted 42 seconds. Im pretty sure that my laptop just was unable to handle the processing but I just thought I'd post on here so people in the future can see that tests can take a long time. Also, if you think I need to be concerned with this, please say so.
EDIT - Yes, I should be worried, very worried. I cannot recreate a deadlock situation even when I remove the unlock(1) lines. I'll update soon with the solution.
Sound advice and much appreciated Dennis. Due to time constraints I dont think that will be an option for me tho
Regarding why it took so long - I had an oversight and was locking and unlocking all the records with the same object instead of different objects A silly mistake I made as I was very eager to try Roberto's great test. I've reworked my code hugely now and when I get back to a point where I can run Roberto's test, I will post my findings here.