aspose file tools*
The moose likes Developer Certification (SCJD/OCMJD) and the fly likes FBNX: Locking, clientID and deadlock... Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Certification » Developer Certification (SCJD/OCMJD)
Bookmark "FBNX: Locking, clientID and deadlock..." Watch "FBNX: Locking, clientID and deadlock..." New topic
Author

FBNX: Locking, clientID and deadlock...

Klaas van Gelder
Ranch Hand

Joined: Jul 08, 2004
Posts: 100
One more locking issue...

After all very helpful reactions so far, I have implemented the locking mechanism in the Data class as follows:




The specs tell us:
"If an attempt is made to unlock a record that has not been locked by this connection, then no action is taken."

I saw some implementations using a clientId variable. In my implementation, i use the reference to the Data object itself as a "unique key", by saving the "this" identifier together with the record number. In the unlock method, I carry out the approriate check.
I haven't seen this implemnetation on the forum, but IMO it should work because every client has his own instance of the Data class.

My questions are:
1. Is this a good way of doing or do I overlook something... ?
2. If a particular client locks a record but never unlocks it (f.e. when the client crashes or loses connection), the record remains locked forever... This can even lead to deadlock. Is there an elegant solution for this ? Maybe using the wait method with a timeout of, lets day, one minute ?

I hope for some feedback :-)
Greetz Klaas

[ July 19, 2004: Message edited by: Klaas van Gelder ]

[Andrew: Removed unlock() method]
[ July 19, 2004: Message edited by: Andrew Monkhouse ]

"What you don't know, can't help you"
SCJP (81%), SCWCD (81%), SCJD (354/400), SCBCD (85%)
Andrew Monkhouse
author and jackaroo
Marshal Commander

Joined: Mar 28, 2003
Posts: 11503
    
  95

Hi Klass,

I have removed some of your posted code, as we do not allow major sections of the assignment to be posted in this forum. The locking code is worth 20% of the assignment, and this is far too much to post in total.

There are multiple reasons for this policy:
  • Sun do not allow you to share your assignment or a solution to the assignment with others.
  • You have spent time and effort getting your solution right. It would not be right for someone else to just copy your solution without working it out for themselves.
  • If someone did get awarded the SCJD certification after copying your code, and were then given employment because they had that certification, the employer would probably find that the employee cannot actually do the work. Which makes the perceived value of this certificate decrease.
  • If people post too much code, then Sun may, in the future, request that we do not allow any SCJD code to be posted.

  • This policy is described in the question "What is the policy on posting questions I saw on the exam / details of how to do the assignment?" in the JavaRanch SCJD FAQ.

    Originally posted by Klaas van Gelder
    1. Is this a good way of doing or do I overlook something... ?


    You are creating a new Integer object for the LOCK_ENTIRE_DB value on each itteration through the while loop. I think it would be better to create that once only (perhaps even as a constant).

    You have not done any validation of the record number being locked - I could attempt to lock record number -500 or record 99999 and both would work. Is this what you really want?

    Originally posted by Klaas van Gelder
    2. If a particular client locks a record but never unlocks it (f.e. when the client crashes or loses connection), the record remains locked forever... This can even lead to deadlock. Is there an elegant solution for this ? Maybe using the wait method with a timeout of, lets day, one minute ?


    Take a look at WeakHashMap and Unreferenced - either one of them may give you an easy way of clearing up locks from dead clients. The WeakHashMap solution could be as simple as just replacing your existing HashMap, however this will leave the potential for a single client to wait forever - a more elegant solution would have some way of waking up that single client - I will let you think about that before giving away any solution .

    Regards, Andrew


    The Sun Certified Java Developer Exam with J2SE 5: paper version from Amazon, PDF from Apress, Online reference: Books 24x7 Personal blog
    Klaas van Gelder
    Ranch Hand

    Joined: Jul 08, 2004
    Posts: 100
    Thanx Andrew for your response !
    I am sorry I posted my complete code, i will try to be more carefull from now on ;-)

    You are totally right about the new Integer(LOCK_ENTIRE_DB) issue.
    More interesting is the validation issue. I think that the allowed values for the record number are restricted to the record numbers which exists in the database, and the value of -1 for locking the entire DB.
    We can perform out the following check as the first statement of the lock method:


    Then the exception must be handled in the DataAdapter class, which calls the lock method.
    Here it can be rethrown as an IOException. IS this a possible solution ???


    The next issue: the removal of forever-locked records due to connection errors.
    The WeakHashMap sould behave as follows:
    "Each key object in a WeakHashMap is stored indirectly as the referent of a weak reference. Therefore a key will automatically be removed only after the weak references to it, both inside and outside of the map, have been cleared by the garbage collector."

    In my solution so far, I save a reference to the Data object itself together with the recNo to memorize the particular client.
    I think, when the connection quits, the Remoteobject will be cleared, and so will the DataAdapber and Data objects, because they all reference only to each other in the sequence of this writing.
    Therefore, as far as I see, replacing the HashMap by a WeakHashMap would address this issue.

    The Unreferenced interface, when implemented by the remote object, calls the unreferenced() method when the list of clients referencing the remote object, becomes empty. This will be the case when the connection is lost.
    In this case, all records FORTHIS PARTICULAR CLIENT should be unlocked. Because the remote object has a reference to the FlightDataAdapter object, the FlightDataAdapter class could maybe be extended with a unlockAll() method, removing all instances of the Map which contain the data object FOR THIS CLIENT as the value of the entry.
    The unlockAll method unlocks all record locked by the client who owns THIS PARTICULAR DB instantion. The implementation could be something like:




    So there appear to be 2 different solutions. Which one should wel choose ???

    The problem with the Unreferenced method is that it is called only ALL client objects stop referencing the remote object. It is not particularly helpful when tracking individual clients. Also, I waited for nearly an hour after killing all my clients just to see how long it took to invoke it, without much success.

    So the first option appears to be the better.... ?

    Pleez gimme any feedback... The locking issue is getting more and more complex.... :-(


    Greetz Klaas

    [ July 20, 2004: Message edited by: Klaas van Gelder ]

    [ July 20, 2004: Message edited by: Klaas van Gelder ]
    [ July 21, 2004: Message edited by: Klaas van Gelder ]
    Philippe Maquet
    Bartender

    Joined: Jun 02, 2003
    Posts: 1872
    Hi Klaas,

    Andrew:
    The WeakHashMap solution could be as simple as just replacing your existing HashMap, however this will leave the potential for a single client to wait forever - a more elegant solution would have some way of waking up that single client - I will let you think about that before giving away any solution .


    Klaas:
    In my solution so far, I save a reference to the Data object itself together with the recNo to memorize the particular client.
    I think, when the connection quits, the Remoteobject will be cleared, and so will the DataAdapber and Data objects, because they all reference only to each other in the sequence of this writing.
    Therefore, as far as I see, replacing the HashMap by a WeakHashMap would address this issue.


    I'm not sure you got the notification issue pointed here by Andrew. As Andrew suggested to think, I'll suggest to search. (Hints: my ID is 50793, a useful keyword can be "WeakHashMap" and we're talking about locking.)

    So the first option appears to be the better.... ?


    The reply to this question will be obvious when you'll reply to these ones: "What if I changed my network layer? Moving from RMI to sockets for instance? With either method, should I need to refactor my dead-clients-detection mechanism?".

    Regards,

    Phil.
    [ July 21, 2004: Message edited by: Philippe Maquet ]
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander

    Joined: Mar 28, 2003
    Posts: 11503
        
      95

    Hi Klass,

    In other posts you have mentioned that you use a factory for creating remote objects. Did you have this implemented at the time you tried using the Unreferenced interface? That is - the instance of the remote object that is created by the factory should implement Unreferenced.

    If you do this, then there will be only one object that has a reference to the remote class - the client. After the client disconnects (deliberately or otherwise) and after the distributed garbage collector runs, there will be no more remote references, so unreferenced() will be called.

    However if the factory object itself (which also implements Remote so that the clients can call it) implemented Unreferenced you would find that it never gets called - there is always at least one reference to it (the RMI Registry).

    You are right about having to wait quite a long time to see some results. Both Unreferenced and WeakHashMap relies on the Distributed Garbage Collector and the RMI Lease Value. By default the RMI Lease is set to 20 minutes. Sometime between when the lease has half expired (10 minutes) and the lease actually expiring (20 minutes) RMI will try to renew the lease. If the renewal fails, then the object will be eligible for garbage collection the next time the garbage collector runs. And it is after this point that unreferenced() will be called or the items will be removed from the WeakHashMap.

    For testing purposes I normally set the RMI lease value to a much lower value (30 seconds or so) - a really bad idea for a production system (if you can't think why, please ask), but it saves you sitting around for hours. The item to set is the java.rmi.dgc.leaseValue property. You can set it programatically (dangerous if you forget to take it out), or you can set it on the command line. The value to set is timed in milliseconds. You must set it on the server before you start your rmi registry.

    Regards, Andrew
     
    I agree. Here's the link: http://aspose.com/file-tools
     
    subject: FBNX: Locking, clientID and deadlock...