my problem is what to do if a client crashes while he still holds lock for a record (assume client calls unlock, lock, update etc.)
I' ve already read this great discussion, and i wanted to follow Andrew's proposal making my remote instance implement Unreferenced Interface. I first tested it with small pieces of code (copied from here), unfortunately it doesn't work...
RMI specification tells that unreferenced() is called about 10minutes later, but even when i started that sample with
to shorten the time nothing "happens" (there will be no output)...
Does anyone has experience using that Interface?
i got it working! The solution is to set my remote instance to null and to call System.gc() from client side. It is described here. This doesn't seem to be possible in every case the client crashes...
Another way to handle it is to implement a timer task which kicks "old" locks out...
But, is that what SUN wants me really to do? Or is that "beyond the scope"?
But, is that what SUN wants me really to do? Or is that "beyond the scope"?
Well, I'd say it is out of scope. In my case, I implemented a thick client, which means that the client calls lock() and unlock() methods in the remote interface; in other words, the client is responsible for handling the transaction. Honestly, it sounds a little complicated. If you are exposing these methods to the client side, then you also have a thick client. Well, I myself didn't worry about these situations, and justified that I didn't do anything about it because it's pretty likely that the client crashing in the middle of a transaction will never happen.
A few remarks:
- System.gc(); does not guarantee that gc will run, so your code should not rely on it.
- I hope your code works also without the -Djava.rmi.server.dcg.leaseValue=30000 option, because you are not allowed to use extra startup parameters (except for "server" and "alone")
- I would consider handling the crash of a thick/fat client out of scope. I just would mention this problem in your choices.txt and suggest possible solutions, like this solution using Unreferenced or some kind of timer
I just went for a thin client, so I didn't have to handle this issue. But I believe Pete Palmer also used a fat client and he didn't handle this issue.
Thank you for the solution with Unreferenced interface. Couple of days ago I also tried to get it work, but encountered the same problem.
In my opinion, to avoid such lost locks it will be reasonable to implement timeout (for example, 5 sec.) for the time of lock holding. This means that if client didn't release the lock within specified timeout the operation should throw an exception and lock should be released by timeout.
Andriy Pererva wrote:In my opinion, to avoid such lost locks it will be reasonable to implement timeout (for example, 5 sec.) for the time of lock holding. This means that if client didn't release the lock within specified timeout the operation should throw an exception and lock should be released by timeout.
Guys, please take a look at this interesting discussion that went on some time ago, where our good buddy Andrew Monkhouse gives his opinion about this exact same situation.
First of all, yes i'm having a fat client and don't want to change it now at this stage of development ( i agree with you "thin-client-guys" that it is much more simple having a thin client...)
And thanks for your answers. I will prefer the way to declare it in my choices.txt and let this case be an option for future....
If i have a little more time, i will consider about a timer like Tom does here
Thank you all!!!
@Roel: Don't worry, using System.gc() was just a try to get it work, so using additional vm args too....
@Andriy: Nice to have you here with that problem..
I decided to implement a thick client as well, although this is probably more complex to implement than the suggested thin client version.
In order to handle locks, if corresponding client crashes or network fails and in order to prevent clients to lock records arbitrarily long, my
lock-method on server side spawns a TimerTask-thread that takes effect after a specified period of time has elapsed and releases a lock automatically.
The timout value (set to a default value of 30 secs) can be specified in the initial configuration dialog.
It works absolutely fine, is easy to implement and this way I never had any hung locks, regardless of the possible failures I simulated.
could anyone tell me why you call a client that has the lock() / unlock() methods 'thick', and the other one that doesn't have them 'thin'? It all happens on the server side (the locks and so on), so I would say that both of them are thin. The one that exposes the lock methods uses just a finer-grained facade, whereas the one that doesn't have them uses a more coarse-grained facade. I don't understand why adding these two methods makes it 'thick'.
I am probably wrong as everyone uses this naming, except for me - did you read about this in some book? I am very willing to learn.
I am nearly finished with the assignment (B&S contractors) and I also exposed the lock / unlock methods to the client. Otherwise I don't think it makes any sense because:
- the lockCookie - what would that be for? why would the SecurityException be for? if you do lock - update / delete - unlock atomically on the server, this cannot possibly be thrown, unless you made an error coding?
- when 2 users (that work for B&S, they are called CSRs in my specs, that serve clients booking ontractors for them) use this app and both have a certain record displayed and want to book it - what you get is more or less what is called a 'lost update' in databases - CSR A locks the record - atomically; CSR B sees at this point an outdated record information and thinks the record is free, so books it (again, atomically), and all goes well, except that CSR A thinks he owns the lock, tells the client of B&S that the booked contractor will come on Monday at noon, but actually the contractor will go to whomever CSR B was serving - this is a great bug in the application IMHO; the client of CSR A would also be very disappointed with the service and I would say it means death for B&S in the real world
- on the other hand, when you expose locking, and make the policy among CSRs that they should never ever touch booked records - you can enforce correctness; OK, the policy might seem flimsy but this is the most I can take out of my requirements, normally I would impose much stricter rules, like remembering who booked a record and only allow that CSR to unbook it, with ability to take down old lingering locks on the server side by some superuser
Right now I am trying to think of a solution for client crashes. I already implemented that when a client has any locked record, he cannot close the app nor can he make a new search (not to forget about the locked records). I think it is OK with the specs and still provides security and does not produce abandoned locks. When the client crashes, though, it will be different, so no I am trying to think of a solution. I might as well just mention it in choices.txt and not implement, but, hey, I do the assignment not for the cert but rather to learn, and it has been a great experience for me (especially the GUI, which I hated).
Sorry for hijacking the topic a little. Do you, moderators, think this should be a new topic?
Roel De Nijs wrote:Sounds you have done (high)way more than needed
actually, yes. Even if this doesn't give extra points (in the opposite I run danger of having additional mistakes) my approach was having also fun and learning a bit beyond the basic must requirements (this is why all the stuff with icons et cetera et cetera ...).
If I fail, I will take another chance and reduce the application to the absolute necessary must-requirements .
I didn't ran the line-counter tool yet but I think this app must have grown beyond the 10.000 lines already ... .