Originally posted by Philippe Maquet:
[
If the line is now <client-code> --> <network> --> <Data> --> <LockManager>, Data simply delegates its locking job to some smarter class to achieve it, but IMO, by doing so, it's still implementing lock/unlock. Right ?
BTW, my Data class also uses MetaData, Field, Index, Cache and a few other helper classes which have no other purpose than to help me to present a Data code wich is easier-to-read and easier-to-maintain.
Max
//data.lock
//synch on staticMap
//insert this and recono unto static method (if it's not already there: otherwise wait)
//exit synch block
Nice !
But I suppose that your unlock method would be written :
If it's right, just two (little) remarks :
Each time a record is unlocked, all (if any) threads waiting for the lock compete to get it. It goes against performance and order (I like order )
I like order too, as all good engineers should. However, the nature of Java threading is that is likes disorder. If I may quote from my own book, p. 81.
the metaphor of children greedily trying to get ice cream is not an arbitrary one. Competing threads do not behave like polite adducts in a grocery store line. There is no sense of order. All compete voraciously, and based on the underlying operating system, priorities, and the other variables, on or another wins.
I love metaphors too : it's like if in a MacDonald, each time a Big Mac is served, all people in the line had to fight with others to get a chance to be the next happy customer. A lot of energy lost, and ... what a mess !![]()
In comparison, for each recNo in a HashMap, the value is a LinkedList of pending lock objects. As each waiting thread is waiting on its own Lock object, in unlock() I just need to notify the next Lock in the list.The instructions say that "Any attempt to lock a resource that is already locked should cause the current thread to give up the CPU, consuming no CPU cycles until the desired resource becomes available.". Well with notifyAll(), you'll consume a few CPU cycles just to compete for the lock, which is a (slight ) deviation from the requirements.
In comparison, for each recNo in a HashMap, the value is a LinkedList of pending lock objects. As each waiting thread is waiting on its own Lock object, in unlock() I just need to notify the next Lock in the list.
The instructions say that "Any attempt to lock a resource that is already locked should cause the current thread to give up the CPU, consuming no CPU cycles until the desired resource becomes available.". Well with notifyAll(), you'll consume a few CPU cycles just to compete for the lock, which is a (slight ) deviation from the requirements.
Very slight, I would say . Also, remember that notify is a bit like volatile. It should work, but sometimes, it just doesn't seem to. I wouldn't risk failing the assignment over it: not a few non-measureable cpu cycles
Assignment: URLyBird 1.3.3, using Java 1.4.0_01<br />Status: Designing, Experimenting, Reading.
BEA 8.1 Certified Administrator, IBM Certified Solution Developer For XML 1.1 and Related Technologies, SCJP, SCWCD, SCBCD, SCDJWS, SCJD, SCEA,
Oracle Certified Master Java EE 5 Enterprise Architect
THere is no need for a lock manager , I didnt implement one
Andrew: We are talking about FBNS here. This is the one where Sun provided the Data class. So we have some limitations. The lock method should be implemented in the Data class or in a class that extends Data.
I don't believe we should be making one instance of Data class per connection.
Max: Ok, that's fine. However, there's no reason, based on the requirements, to constrain ourselves design-wise at this point. That is, this is a design constraint you're placing on yourself, not one that being placed on you by the SCJD.
Sun's requirement that the Data.unlock method know who owns the lock: that's not open to interpretation, since the javadoc comment on the data.unlock explicitly requires this.
Further, your implementing makes the actual locking/ unlocking vestigial
The Sun Certified Java Developer Exam with J2SE 5: paper version from Amazon, PDF from Apress, Online reference: Books 24x7 Personal blog
The easiest thing to do would be to overload lock, allowing the second argument to indicate the owner.
lock(int){ lock(int, null);
lock(int, Object src){ // do locking; }
Is this allowed?
Additionally, i've found that a LockManager is only good for detecting dead-lock. RemoteConnections themselves can ensure that they only unlock what they have locked. I delegated all requests to lock to the LockManager, however with refactoring LockManager may be eliminated. The only advantage for LockManager (except for seperating responsibilities) is to have a localised mapping of connections and locks. This is really only useful for dead-lock recovery. Who is actually implementing this?
Anyone have any example code for detecting a dead-lock recovery?
When do we introduce the constraint that only connections which called the lock() can successfuly unlock it? Should it be declared in Connection? This would mean that the contract wasn't quite the same as that of the Data class?
The Sun Certified Java Developer Exam with J2SE 5: paper version from Amazon, PDF from Apress, Online reference: Books 24x7 Personal blog
Andrew: If you have a LockManager as a front end to the Data class (so <client-code> --> <network> --> <LockManager> --> <Data> ) then it becomes easy.
Philippe: <client-code> --> <network> --> <Data> --> <LockManager> is even easier
The Sun Certified Java Developer Exam with J2SE 5: paper version from Amazon, PDF from Apress, Online reference: Books 24x7 Personal blog
Billy THere is no need for a lock manager , I didnt implement one
Philippe It would be so great if I could be so clear and concise in my choice.txt file !![]()
The Sun Certified Java Developer Exam with J2SE 5: paper version from Amazon, PDF from Apress, Online reference: Books 24x7 Personal blog
[SCJP, SCJD]
Now the lock methods to accomplish this resided in RemoteConnectionImpl. Afterall, there are likely to be multiple Connections from clients. However, shouldn't this code also reside in LocalConnection?
Would it not be logical for RemoteConnectionImpl to extend LocalConnection?
The Sun Certified Java Developer Exam with J2SE 5: paper version from Amazon, PDF from Apress, Online reference: Books 24x7 Personal blog
Didn't I use this metaphor in my book? Like McBurger example?
As I said before, I like your solution a lot.
The second part of your implementation, which seems to force order, is a little concerning. It seems that You're adding complexity to address a non existent requirement that clients be treated in a FIFO order.
Also, remember that notify is a bit like volatile. It should work, but sometimes, it just doesn't seem to. I wouldn't risk failing the assignment over it: not a few non-measureable cpu cycles.
As, by design, I am sure that the caller is the only thread waiting on it (its Lock object), I may use notify() in place of notifyAll().
Wakes up a single thread that is waiting on this object's monitor. If any threads are waiting on this object, one of them is chosen to be awakened. The choice is arbitrary and occurs at the discretion of the implementation. A thread waits on an object's monitor by calling one of the wait methods.
Originally posted by Philippe Maquet:
Hi Max,
Didn't I use this metaphor in my book? Like McBurger example?
Oops, sorry ! Where our inspiration for metaphors is coming from ? We have so many sources ... But my MacDonald one comes for sure and in direct line from your book ! Sorry again.![]()
As I said before, I like your solution a lot.
Yes, and thank you to recall it. The only thing which worries me a bit, as that you are - in all threads which concern locking - a hard defender of all no-LockManager-solutions. Is that for simplicity ?
[/qb]
The second part of your implementation, which seems to force order, is a little concerning. It seems that You're adding complexity to address a non existent requirement that clients be treated in a FIFO order.
[/qb]
As I wrote it elsewhere, I need a Lock object mainly to store the caller's thread, the cookie and the time at which the lock was granted.
Are you still doing this? This is a serious issue that could cause you to fail, and I would hate for you to do so.
You are not guaranteed that the calling threads will be consistant for a given object. As a matter o fact, I know that they are not. I know you're thinking of documenting this, because there's a small opportunity for it to occur. However, you might as well not implement locking and document that fact. If your grader is paying attention, they'll be obligated to fail you here, because this just isn't the way RMI works, and you're not deomonstrating mastery.
Also, I am unsure about your looking at thread death as a way of determining if the client has died. I guess it depends on what thread you are using. Just using the thread running your remote class is not really valid though, as there is no guarantee that two calls to remote methods from the one client will run in the same thread.
I use sockets and make sure that a client connection keeps the same thread. But of course, I will document that locks cannot spread over multiple threads, and explain why.
The Sun Certified Java Developer Exam with J2SE 5: paper version from Amazon, PDF from Apress, Online reference: Books 24x7 Personal blog
[SCJP, SCJD]
The Sun Certified Java Developer Exam with J2SE 5: paper version from Amazon, PDF from Apress, Online reference: Books 24x7 Personal blog
[SCJP, SCJD]
The Sun Certified Java Developer Exam with J2SE 5: paper version from Amazon, PDF from Apress, Online reference: Books 24x7 Personal blog
I think Max was thinking that you allowed the clients to call the lock method,
and that you were using RMI.
Since neither is true, I dont believe his comments apply to your situation.
Looking at what you have described I think you will be safe in your
implementation.
If we do use a LockManager, is it better to use it as a private inner class to the data class, so that only Data class has access to it. This way the locks will be secure.
Any comments?
[SCJP, SCJD]
In URLBird LockManager has to access Data methods (to throw RecordNotFoundException if a record was not found). That is why I decided not to have separate class for LockManager...
A LockManager class doesn't need to access Data. As a matter of fact, the check to see is RecordNotFoundException must be thrown must be done after the lock is granted, to make sure the record was not deleted while you are waiting for the lock.
]Max .... ultimate thoughts seem sometimes impenetrable to the common human being I am
So I just found out a new way to break that dilemma, and I think that new solution is the good one (so, and if it is, thank you Max for having driven me into a corner). Besides, it does not need too much refactoring :
Let's say that I :
Rename my current "Data" class in "Database" and keep it for the most part as it is now (a multiton, allowing only one instance per database file) Change the lock and unlock signatures in that new Database class to accept one more parameter (Object connection) which will be transmitted to LockManager Create a new Data class which respects all DBAccess requirements, but whose constructor has this form : public Data(String fileName, Object connection). I may do that because there is nothing written in the instructions about the Data constructor. Data just need to store connection as a private strong reference and get a private Database reference. In its lock/unlock methods, Data may pass connection to the Database lock/unlock methods from inside its own lock/unlock methods. For all other methods, it will simply delegate the job to Database (same signatures). Finally, LockManager must be refactored to :
[/list=1]accept Object connection in its own lock/unlock methods store them as WeakReferences and implement a ReferenceQueue use connection in place of thread to identify a lock owner in my MaintenanceThread, replace my isAlive() test by a poll() on the ReferenceQueue [/list]
That's all and with no tradeoff.
What do you think about it ? Am I right ? (I'll wait a little before refactoring)
The Sun Certified Java Developer Exam with J2SE 5: paper version from Amazon, PDF from Apress, Online reference: Books 24x7 Personal blog
You did not state it explicitly, but this means that you have one instance of Data class per connection, with the IO being handled by the single instance of the Database class. Correct?
If so, then I like this solution.
I made mention a couple of times that this was one way that I could see of having the Data class aware of who the owner of the lock was. I did not spell it out since we were originally talking about the Fly By Night Services assignment, and I cannot see how to make this solution work with the code that gets provided in that assignment. But for the Hotel or Contractors assignments, this should work very well.
My only question is whether you need to pass a "Connection" object to the Data class.
If there is one instance of the Data class for each connection, then can the instance of the Data class itself act as your identifier to the lock methods?
By the way, I use the same locking functionally for local Data and remote Data. Specification says locking for local mode is not required. Do you think it Ok if we have anyway all the locking logic in local Data?
Originally posted by Philippe Maquet:
Hi S,
By designing a LockManager class, you decided to delegate lock/unlock to it. So I think it's better in Data just calling the lock/unlock methods of LockManager, putting there the wait() and any call to one of your isRecordAvailable methods.
For the one who reads your Data class, it's simpler to have just one line in your lock/unlock methods, telling him "OK, LockManager performs the whole job".
Now I think about questions you may ask yourself : Is my database system multi-table ? Or may it become multi-table in the future ? If you reply YES to one of them, then your LockManager design could need to take it into account.
Best,
Phil.
Space seems cool in the movies, but once you get out there, it is super boring. Now for a fascinating tiny ad:
We need your help - Coderanch server fundraiser
https://coderanch.com/wiki/782867/Coderanch-server-fundraiser
|