aspose file tools*
The moose likes Developer Certification (SCJD/OCMJD) and the fly likes IS the locking mechanism in the EXAM CRAM2 book wrong 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 "IS the locking mechanism in the EXAM CRAM2 book wrong" Watch "IS the locking mechanism in the EXAM CRAM2 book wrong" New topic
Author

IS the locking mechanism in the EXAM CRAM2 book wrong

yang wulong
Greenhorn

Joined: Jun 07, 2004
Posts: 5
hello,
I am reading the EXAM CRAM2 java Develper book, and I have read some messages from this forum that someone said the locking mechanism in the book has some mistake,could anyone tell me what kind of the mistake the locking mechanism in the EXAM CRAM2 has?

thank you
Marcus Beale
Ranch Hand

Joined: Apr 13, 2004
Posts: 33
I didn't see anything obviously wrong with the EXAM CRAM2 Developer book lock manager. What part of the lock manager validity is called into question? Overall I'd have to say it was not a very good book. The locking mechanism is a bit inefficent (Search for "notifying a particular client" for a more efficent approach.), but it looks like it would work. Though I admit I haven't reviewed it very closely.

The lock manager wouldn't work for my project since there really isn't a client object to pass in. I got around the issue by using the current thread object as the client. This won't necessarily be correct for multithreaded clients, but I figured it's good enough. Can anyone think of something better?

I didn't use the lockmanager provided in the book, but I created my own that was fairly similar. I may revamp it to make it more efficent after I'm finished everything else.

,Marcus
Andrew Monkhouse
author and jackaroo
Marshal Commander

Joined: Mar 28, 2003
Posts: 11460
    
  94

Hi Yang,

Some of the items I noticed:

The LockManager relies on a unique instance of a class to provide the unique client identifier (listing 7.1), however DatabaseRMIServer (not in the book - from the code on CD) only ever instantiates one instance of DatabaseRMIImpl. So there is no unique client identifier.

And since there is only one instance of DatabaseRMIImpl, and the RMI Registry has a reference to it, putting it inside a WeakReference for detecting client crashes (listing 7.1) will not work, as there will always be at least one strong reference to it.

The lock() method in the LockManager (listing 7.1) seems to allow individual records to be locked after a lock on the entire database has been granted.

Originally posted by Marcus Beale:
The lock manager wouldn't work for my project since there really isn't a client object to pass in. I got around the issue by using the current thread object as the client.


This wont work in an RMI solution. The RMI specification explictly states that threading is entirely up to the vendor. So the following is all possible:
  • Client A uses thread 1 to lock record 10
  • Client B uses thread 1 to lock record 11
  • Client A uses thread 1 to modify record 10
  • Client A uses thread 2 to unlock record 10
  • Client B uses thread 3 to modify record 11
  • Client B uses thread 4 to unlock record 11


  • In my example above, two different clients used the same thread to lock records. And neither of them used the same thread to unlock the records they had locked. And you cannot even rely on two "back to back" calls using the same thread.

    So using the thread number is a really bad idea.

    Regards, Andrew


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

    Joined: Apr 13, 2004
    Posts: 33
    Andrew,

    After reviewing the lockmanager in Exam Cram2 I agree that locking the database does not prevent locking records. As for the other comments, I didn't even know there was a cd in the back of the book until you mentioned it.

    Thanks for the warning on using the current Thread as the client object. What you sad makes sense, and now that I've read a little more about RMI threads I see the error of my ways. I did all my lockmanager testing without RMI (doh!).
    The way I can think of to get a reference is to have clients request a client ID from the server and then use that ID when making lock calls. I'll have to make the clients RMI servers themselves, so the DB server can get a reference to the client (based off the ID) to see if the client still alive. Sound complicated? Well I think it is definitely more complicated than what I'm doing now, but the only alternative I can think of is only allowing locks for a certain time period and in my opinion, that's no alternative at all.

    ,Marcus
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander

    Joined: Mar 28, 2003
    Posts: 11460
        
      94

    Hi Marcus,

    I am not sure if your solution will meet the criteria that the Data class' lock method must ensure that a record can only be modified or unlocked by the client who owns the lock. Your solution sounds like the end result will be the same - a client must lock a record before modifying it - but it will not be controlled by the Data class.

    To give you some hints: consider what would happen if each connected client had it's own instance of the Data class. Could you then use the "this" object to identify the ownership of the lock in some way?

    You may find this easier to implement than your proposed solution, and it should also allow you to meet your requirements .

    Regards, Andrew
    Chirag Doshi
    Greenhorn

    Joined: Jul 09, 2003
    Posts: 21
    Hi

    I have the following signatures to follow for locking.



    This signature seems to tell me that recognizing the client who is locking is not a requirement.

    Thus I have implemented it in such a way that it is the responsibility of the clients to make sure they use the following sequence of calls.




    If all clients use this sequence correctly then the DBMain server will work. but if some client does this



    or directly



    Then there will be problems.

    Do you think it is ok, if I go ahead with this approach, given that I document all these limitations correctly in the choices.txt.


    Chirag
    Marcus Beale
    Ranch Hand

    Joined: Apr 13, 2004
    Posts: 33
    Andrew,

    Different people have different method signatures for the lock and unlock methods. My method signatures return cookies and my update, delete methods take in cookies. This makes sure the client who locks a record is the same client who updates or deletes the record. The issue I as discussing previously is detecting when the client dies while having a record locked. How does the server know to release the lock? I need a reference to the client on the server side so I can see if the client has been garbage collected. The complication to my design I discussed in my previous post is directly related to RMI method passing parameters by value. I can't send a this reference to the server through RMI, because it will just be a copy, telling me no information about weather the client is still alive.

    Of course with my design (3 tier) the client will never crash with a lock because I only expose middle ware (business logic) methods to the client (not lock and unlock). I've read the extended "Should lock methods be callable by the client" thread, so don’t' try to tell me how a 3 tier architecture is bad. (Chirag - check out that thread because it discusses different locking method signatures and the consequences of them.) I guess I shouldn't be worrying about detecting when clients die, because it will never happen for me.

    Andrew, your hint confuses me. I have heard several people talking about having multiple instances of the Data class and this sounds like the stupidest idea I've ever heard. Of course if so may people are talking about it on these threads then I must be missing something. I have only one instance of the Data class on the server side. My data object uses synchronized methods to prevent multiple threads from writing to the database at the same time. This will not work if there are multiple instances of the data class, because you are synchronizing on this. I don't think the record lock mechanism is alone sufficient to handle multithreaded requests. You could lock every record before you did anything, such as read the record, but this approach has problems. The DBAccess interface provided in the spec does not mention anything about blocking in the read method, which it would have to if you locked and unlocked inside that method. If you did lock unlock inside read, then what is the point of the lock method anyway? I think the intent of the lock method is just to say, hey I'm interested in this record and I don't want anyone to change it until further notice. The lock shouldn't prevent others from reading the record. With that said, how in the world can you hope to correctly handle multiple threads request to the database with multiple instances of Data (you can't synchronize the methods)?

    ,Marcus
    Javini Javono
    Ranch Hand

    Joined: Dec 03, 2003
    Posts: 286
    Hi,


    how in the world can you hope to correctly handle multiple threads request to the database with multiple instances of Data (you can't synchronize the methods)?


    Assume for every client i there exists one Data i on the server. All Data objects exists and
    are single threaded, and each are invoking FileManager class to read and write to the
    database "simultaneously". If FileManager is thread safe, then there is no problem.

    The above example does not bring into discussion record locking methods lock(), unlock(),
    and the like, but attempts to answer the question quoted above. See also Bruce Eckel's free book available for a free download from www.bruceeckel.com (I think it is) called Thinking in Java;
    and, like me, perhaps you may find the threading chapter enjoyable and informative.

    Thanks,
    Javini Javono
    Marcus Beale
    Ranch Hand

    Joined: Apr 13, 2004
    Posts: 33
    Javini,

    Thanks for the link. I downloaded Thinking in Java 3rd Edition. I'll read more - hey free book. I've read entire books devoted to concurrent programming in java. I see what you are saying, and it could work, but my question is why? What advantage does it give you? You still have to create some kind of handshaking to ensure a one to one relationship between the client and server instances of data. Most of the functionality in my data class is simply making access to my search and dbreadwrite objects thread safe. If you take away that, the data class isn't doing much at all. I guess if you had a spec where there were no cookies in the lock methods and you wanted to make sure that only the client who locks the record can modify it then it might make sense. (My spec does have cookies.) But there are probably better ways to do that than making n data instances. If you are going to have a client initiate a procedure that creates a new instance of Data on the server, you might as well just have them pass in a reference to the client.

    If I understand the purposed solution and the problem that it solves (making sure only the client who locks a record can unlock it), wouldn't it make more sense to just have each client own an instance of Data and have the lower level db access object (DBReadWrite etc) available over RMI?

    I think having any instance of Data on the client side violates the spec, since the data interface is presented in the Server section.

    BTW, The previous discussion isn’t actually answering my real question of what's the best way to determine when a client dies using an RMI solution. Is there a simpler way than making the clients RMI servers that register themselves?

    , Marcus
    Marcus Beale
    Ranch Hand

    Joined: Apr 13, 2004
    Posts: 33
    I got a pretty good answer to my RMI question in the Sun Java Forums:
    RMI Callback messages can not be sent to all clients

    Enjoy,
    Marcus
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander

    Joined: Mar 28, 2003
    Posts: 11460
        
      94

    Hi Chirag,

    Sorry for the delay in responding - for some reason I cannot access JavaRanch from China at the moment (I am posting this over a remote session on a computer in Melbourne :roll: )

    Originally posted by Chirag Doshi:
    I have the following signatures to follow for locking.



    This signature seems to tell me that recognizing the client who is locking is not a requirement.


    Usually the provided interface has some C++ style comments (// comments) with the method signatures which describe what the method should do- you might want to double check whether these comments tell you that client recognition is a requirement or not.

    Regards, Andrew
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander

    Joined: Mar 28, 2003
    Posts: 11460
        
      94

    Hi Marcus,

    Sorry for the delay in responding - for some reason I cannot access JavaRanch from China at the moment (I am posting this over a remote session on a computer in Melbourne :roll: )

    Different people have different method signatures for the lock and unlock methods. ...


    Yes, I am well aware of that. I had assumed that you had one of the interfaces which do not have cookies.

    Of course with my design (3 tier) the client will never crash with a lock because I only expose middle ware (business logic) methods to the client (not lock and unlock).


    So your questions then are just academic? Not a problem.

    I've read the extended "Should lock methods be callable by the client" thread, so don’t' try to tell me how a 3 tier architecture is bad.


    OK

    Andrew, your hint confuses me


    OK, I will be more explicit...

    Most sample RMI code has one remote object on the server:



    Which you will then call from the client:



    In this case, you will only ever have one instance of the remote class, and potentially multiple threads running on it and all the classes used by your Remote class (so you will have to make sure they are all thread safe).

    What I was suggesting earlier was that you could have a Factory on the server which creates instances of your remote class - both of these would be Remote objects (so two classes on the server which extend UnicastRemoteObject) - on the server:



    Which you will then call from the client:



    (Yes, there is no cast required on the second line)

    Doing this means that the client does not have to do anything special to identify itself to the server - the instance of RemoteStuff uniquely identifies the client (or, if RemoteStuff has it's own instance of Data class, then the instance of Data class uniquely identifies the client).

    Also you now have two ways of identifying client death - neither of which requires the client code to be an RMI server:
  • The class which implements RemoteStuff can also implement java.rmi.Unreferenced.


  • If it does this, then at some point after the client dies, the distributed garbage collector will run, notice that the remote client is no longer connected, and call your unreferenced() method (where you can do any clean up you want). This would still require you to track which locks are owned by a particular RemoteStuff instance, but that is not hard.
  • Alternatively (for those without cookies) you could use your unique client referenced (the instance of Data) as the key in a WeakHashMap.


  • If you do this, then at some point after the client dies, the distributed garbage collector will run, notice that the remote client is no longer connected, and remove any entries from the WeakHashMap that were owned by the now dead client. You might want to consider how you would wake up any waiting clients after this (but I have to leave something as an exercise for those reading this )


    Hopefully this is a bit clearer now.


    I have heard several people talking about having multiple instances of the Data class and this sounds like the stupidest idea I've ever heard. ...


    As you saw in Javini's post, you don't have to do all the work in the Data class itself - the Data class can be a Fa´┐Żade to all the real worker classes.

    I see what you are saying, and it could work, but my question is why? What advantage does it give you?


    You can then expose all the Data classes methods to the client?

    You can get notification of client death on the server without any special code on the client side.

    You can write most of your server code without worrying about thread safety - you get to choose which classes will be Singletons or Multitons and therefore need to be thread safe (whereas in your current code, every class in your server must be thread safe).

    You still have to create some kind of handshaking to ensure a one to one relationship between the client and server instances of data.


    Hopefully I have explained taht this is not the case.

    Most of the functionality in my data class is simply making access to my search and dbreadwrite objects thread safe. If you take away that, the data class isn't doing much at all.


    You have to make every class on your server thread safe - not just the ones in your data class.

    Regards, Andrew
    Chirag Doshi
    Greenhorn

    Joined: Jul 09, 2003
    Posts: 21
    Hi Andrew,

    Usually the provided interface has some C++ style comments (// comments) with the method signatures which describe what the method should do- you might want to double check whether these comments tell you that client recognition is a requirement or not.


    Here is the comments in the DBMain interface that I have in my specifications.



    I had not metioned about the isLocked() function earlier.

    After looking at this, in your view, would I be correct in interpreting that
    client identification is not a requirement ?

    Thanks
    Chirag
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander

    Joined: Mar 28, 2003
    Posts: 11460
        
      94

    Hi Chirag,

    Originally posted by Chirag Doshi:
    After looking at this, in your view, would I be correct in interpreting that client identification is not a requirement ?


    I am basing my interpretation on the very first line of the comments:

    Originally posted by Chirag Doshi:



    And my interpretation based on that line is that client identification is required.

    Regards, Andrew
    Marcus Beale
    Ranch Hand

    Joined: Apr 13, 2004
    Posts: 33
    Andrew,

    Thanks for the post about multiple Data objects. (And your consistently good posts in general.) This has given me some food for thought. However there's one point you make that I don't agree with when you are referring to the single data object approach.

    You have to make every class on your server thread safe - not just the ones in your data class.


    I believe the opposite is true! When you have multiple data objects they are writing to the same data file and using the same locks. I can only see this approach working if you make the data class a facade as you mentioned. However, I believe you will have to make each worker class thread safe because are you sharing the objects with multiple threads/data objects. You cannot share the objects without making them thread safe or using some very complicated scheme in the data object to prevent access to those classes except one at a time. For instance how will you prevent users from adding, updating, or deleting records while someone is searching the database? You can't simple lock the entire database. Searches might take 5 minutes or more if someone is slow unlocking something. The complication arises from not being able to synchronize methods since that would use this. I can think of a way this could be done, but it's complicated.

    On the other hand, if you have only one Data class, you can make it thread safe. I have several worker objects DBReadWrite, DBSearch, and LockManager. It is easy in Data to prevent multiple threads from accessing DBReadWrite at the same time and take care of the search requirement mentioned above). My DBReadWrite and DBSearch workers are not thread safe and don't need to be. My middleware is not thread safe. Only my Data class and my Lockmanager are thread safe. In fact with this approach I can even use buffering on my RandomAccessFile object in my DBReadWrite.

    In the multiple data approach if you use static references to worker classes or you make worker classes singletons, then you have restricted your database to only ever having one database and maybe even one table! You will have to make your worker classes multitons or add some more logic to your remote factory (Pass in a key for the database). Of course you would have to do something similar in the other approach. But I have a feeling that the logic would ripple through all your factory methods or multitons in the multiple Data approach, since you would have more.

    With this being said, I think the idea of creating an object on the server for each client is pretty slick. It definitely is better for detecting dead clients what I was planning on doing. There's no good reason the client code should extend Remote. The secret is making sure that the object returned by the Remote factory method extends Remote.

    I have an idea that may give you the best of both worlds. Instead of making Data a facade, you make it a proxy. Have all the proxies simply call a single DataWorker object (One for each database on the server). You could do all your thread safety in that one DataWorker class, but still have the advantage of the identifier objects (the proxies) for each client on the server side.

    , Marcus
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander

    Joined: Mar 28, 2003
    Posts: 11460
        
      94

    Hi Marcus,

    You are correct - with the multiple remote classes, at some point you will need to reduce down to a single instance of some class or classes, and those classes will need to be thread safe. What I was suggesting though, was that it is only these "common single instance" classes that need to be thread safe - the classes calling them (which are muliple instances - one for each connected client) only ever have one thread running on them, and therefore do not need to be thread safe.

    You mentioned that your DBWriter and DBReader classes are not thread safe. This means that you must be calling them in a thread safe manner from within your Data class. There is no problem with this, but it is something that you as a designer have to be aware of. (And you will have to put explicit javadoc comments in these two classes to indicated that they are not thread safe). [All these comments would also apply to the "common single instance" classes that would be used in my alternate code.

    You also mentioned that your middleware code is not thread safe - this does surprise me. You will only have one instance of your middleware classes for all your connected clients, with multiple threads running on them, so they really should be thread safe.

    I have an idea that may give you the best of both worlds. Instead of making Data a facade, you make it a proxy.


    Yes, that would be an excellent way of handling the issues.

    Regards, Andrew
    Marcus Beale
    Ranch Hand

    Joined: Apr 13, 2004
    Posts: 33
    Andrew,

    You are correct, the middleware should be thread safe. It's a good point that I hadn't really considered. I spent a while reviewing the middleware and have come to the conclusion that it is thread safe without really trying. Although I can see a few spots where problems would exist if I allowed more functionity (such as adding and deleting records). All the state information in the middleware is stored in local variables, immutable objects, or thread safe objects. Some objects don't need to be thread safe since they are never shared between threads. This is probably more by chance than anything else.

    , Marcus
     
    I agree. Here's the link: http://aspose.com/file-tools
     
    subject: IS the locking mechanism in the EXAM CRAM2 book wrong