• Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Unreferenced Problem

 
Akshay Sharma
Ranch Hand
Posts: 42
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Guys,
When my remote object implements unreferneced interface and the client goes down normally the unreeferenced method is invoked automatically.
But if I press Cntrl C on the client then it is not invoked.
Rgds
Akshay
 
Andrew Monkhouse
author and jackaroo
Marshal Commander
Pie
Posts: 12014
220
C++ Firefox Browser IntelliJ IDE Java Mac Oracle
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Akshay
Did you wait more than 20 minutes for the lease to expire? (leases are supposed to default to 20 minutes, and unreferenced is supposed to get called sometime after that - I have noticed delays of up to half an hour before getting unreferenced called).
You should still get unreferenced called, even on a Control-C.
Regards, Andrew
 
Akshay Sharma
Ranch Hand
Posts: 42
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks Andrew
But if set the leaseValue system property to say 1 minute then it should be called.
My idea wa basically this.
If we set the remote referenece to null and then call System.gc then unreferenced gets called instantly.This works fine
I tried to put this stuff in a finally block and them pressed cntrl c. The control in this case does not fo to the finally block.
But I didnt wait for 20 minutes.
 
Andrew Monkhouse
author and jackaroo
Marshal Commander
Pie
Posts: 12014
220
C++ Firefox Browser IntelliJ IDE Java Mac Oracle
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Akshay
Hmmm, difficult to say what the issue is. Are you sure you are setting the lease value in the right place in your code (or setting it correctly from the command line)? Likewise, are you sure you have gotten the remote reference before you kill your client?
I modified the code I posted the other day in this thread. Now it runs as either client or server (if there are any parameters it is a client, otherwise it is a server). In this I have set the lease value to 10 seconds, and put a delay of 5 seconds on the client after calling the remote code. If I press Control-C within the 5 seconds then I have to wait for the lease to expire and then unreferenced gets called.

Regards, Andrew
 
Akshay Sharma
Ranch Hand
Posts: 42
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks for the help.
It works fine for me......
 
Patrick Cobbett
Ranch Hand
Posts: 44
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi all,
Unreferenced is called when there are no longer any client references to a given remote object right?
A source on the web says this:

If a client does not refresh the connection to the remote object before the lease term expires, the reference is considered to be dead and the remote object may be garbage collected.

In order to 'refresh the connection', does the client have to invoke methods on the remote object? How is the connection refreshed? Let me explain my concern. I considered using a small leaseValue so that a crashed client would not hold locked records for long. But am i right in thinking that if the client didn't invoke any methods on the remote object during that time that unreferenced would also be called? What is the result of unreferenced being called? Can a client no longer invoke methods on it?
What is a reasonable leaseValue? Is the default value appropriate or have most overriden it?
thanks in advance
 
Patrick Cobbett
Ranch Hand
Posts: 44
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
One last thing. Some posts discuss problems people have been having with unreferenced, but i haven't experienced them.
All i gotta do is implement unreferenced() in my remote implementation and that's it right? Maybe i haven't tested under all possible outcomes, so let me know if i've missed something. Are there any special circumstances that i need to look out for?
I read that unreferenced() could be called more than once for a given object. Is that right and what is that dependant on?
 
Andrew Monkhouse
author and jackaroo
Marshal Commander
Pie
Posts: 12014
220
C++ Firefox Browser IntelliJ IDE Java Mac Oracle
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Patrick,
When half of the lease has expired, the server will send a message to the connected client to verify that it is still alive. Sun recommend that you do not set your lease value too low, since doing so could generate a lot of traffic.
Personally I left the lease value alone for my submission - I did modify it while testing, but did not set it or mention it in my deliverables. I felt that it wasn't asked for, and could only cost me marks if the examiner didnt like it. Even in a real life application I would be hesitant to change this value by default, since it is something that can be modified at the command line.
If you are not already aware: the default value is 20 minutes. This is the minimum before you will see unreferenced getting called - it could be sometime after that (or (in theory) never).
I read that unreferenced() could be called more than once for a given object. Is that right and what is that dependant on?

Yes this is correct. The specifications tell us that unreferenced will be called each time the count of objects referencing your remote object reaches zero. One way that this could happen is if your server created a pool of remote objects to give to clients. Something like:
  • remoteObject1 given to Client1
  • remoteObject2 given to Client2
  • Client1 disconnects -> remoteObject1.unreferenced() called
  • remoteObject1 given to Client3
  • Client3 disconnects -> remoteObject1.unreferenced() called

  • If you are just creating "one off" instances of your remote clients (create one per client and destroy it (or let it die a natural death) when they disconnect), then this should not affect you.
    There are also some weird ways you could cause this. Such as having a remote lock manager - if you passed it the instance of the object that just had unreferenced called, then you have just increased the reference count. If you do fall into this category then I think you have other issues
    Regards, Andrew
    [ July 27, 2003: Message edited by: Andrew Monkhouse ]
     
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander
    Pie
    Posts: 12014
    220
    C++ Firefox Browser IntelliJ IDE Java Mac Oracle
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Sorry, need to make a correction. It is the client that renews the lease.
    From Sun's RMI FAQ:

    The client will renew each lease when it is halfway expired. If the lease interval is too short, the client will waste a lot of network bandwidth needlessly renewing its lease. If the lease interval is much too short, the client will be unable to renew the lease in time, and the exported object may be deleted as a result.

    Regards, Andrew
    [ July 27, 2003: Message edited by: Andrew Monkhouse ]
     
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander
    Pie
    Posts: 12014
    220
    C++ Firefox Browser IntelliJ IDE Java Mac Oracle
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    And to continue my trend of hiting send before I have finished what I wanted to say - you don't have to do anything in your client code to renew this lease. There is a special method (dirty()) that the client will call on your behalf.
    Regards, Andrew
     
    Akshay Sharma
    Ranch Hand
    Posts: 42
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Hi Guys,
    I just wanted to share a thought on how to instantly notify that the client has died.
    In jdk1.3 we can add a Runtime hook which will invoke a method on the
    remote object which in turn invokes unreferenced.
    The remote interface will have a fn called free
    and the client will call it when it dies from the hook.
    Free in turn calls unreferenced.
    I dont know whether this will work or not.
    Rgds
    Akshay
     
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander
    Pie
    Posts: 12014
    220
    C++ Firefox Browser IntelliJ IDE Java Mac Oracle
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Hi Akshay
    This will only help for a limited number of "unplanned" exits - such as someone hitting Control-C to kill your client. Obviously it cannot handle somone hitting the power button, or pulling the network cable or 101 other really drastic crashes.
    Another possibility is listed in the RMI FAQ.
    Regards, Andrew
     
    Patrick Cobbett
    Ranch Hand
    Posts: 44
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Hi Andrew,
    thanks for your as always quick and thorough response to my problems! This unreferenced issue is the last little snag on my mind before i finally submit my project.
    I don't think my implementation has any of the issues described, but i'm just asking for some final reassurance. My RemoteConnection implementation implements Unreferenced. A RemoteConnection instance is created for each client, and they are not pooled for other clients. Also, the server, or more specifically the Connection factory maintains no references to Connections it's issues to clients.
    Can you see any reason for concern? Unreferenced should only be called once per client, am i right? And am i right in thinking there's no reason why unreferenced wouldn't be called?
    I hope i can get away with subtley deviating a little to get some more of your insightful wisdom with this next related question.
    So, i take it unreferenced simply calls close(). What does close() do? For starters it should unlock all records owned by that connection, perhaps by calling unlock(-1). But what else should it do? In another post (which i now can't find!) it was discussed that the specification for close() on Connection should agree with that of Data. Meaning that once close() is called the Connection can no longer be used. Certainly close() could set it's reference to data to null, but that will cause NullPointerExceptions to be thrown rather than an IOException. It would be a bit much to trap the NullPointerException for each method to throw an IOException. Similiarly it seems a bit much to have a boolean flag indicating whether the connection is closed as each method would have to check for it before it executes.
    Both my ideas seem like over-kill, i know there's a simpler solution. Care to enlighten me?
     
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander
    Pie
    Posts: 12014
    220
    C++ Firefox Browser IntelliJ IDE Java Mac Oracle
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Hi Patrick,
    It sounds like the way you are using unreferenced should be OK.
    it was discussed that the specification for close() on Connection should agree with that of Data

    Well you could try to make it agree with the stated specification for Data.close(). But you may have noticed that even the Data class does not get it right - some of the methods in Data will still work after you have called close, and some of them cannot throw an IOException, which is what is supposedly going to happen if you call them after calling Data.close().
    If you are going to try and stop the connection being used after it's close() method has been called, then you will have to handle each method separately, and work out what is logical for that method.
    Regards, Andrew
     
    Patrick Cobbett
    Ranch Hand
    Posts: 44
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Hi Andrew,
    I get the feeling your trying to get me to think about his one! Sorry if i'm i'm asking u to spell it out for me . I have thought about it but let me explain where i'm stuck in my mental thread. You quite rightly say that it's only the methods which use the file pointer which will not operate. The close() method in Data calls close() on the file pointer. So any attempt to use the file pointer will result in an IOException being thrown.. or if it's caught a DatabaseException. That is what i thought was the case. But looking again i'm a little confused. Unless I inadvertantly changed the code, Data also sets the file pointer to null after closing it. So it seems that it would throw NullPointer exceptions after all? Are we expected to change the code in Data so that it does agree with the contract specified? I thought the code should already be complete and functional.. with the exceptions explictly stated in the requirements.
    If all this is necessary then the best way of doing it would be to check for null at the beginning of each method which accesses the database, and throw IOExceptions. However, the criteriaFind() method is only able to throw a DatabaseException.. (or did i delete the IOException:eek so this would already be an inconsitency. Or is it fair to add an IOException since it is accessing the database?
    Am i supposed to satisfy the contract imposed by Data in Connection even though Data doesn't satisfy it!? There's a sense of inconsistency. Or are we supposed to satisfy the contract for close() in Data ourselves? Once again, i thought that exisiting method were supposed to be complete.
    For me, the cleanest way of doing this in terms of code would be to remove the code which sets db to null. Then accesses to the database would throw an IOException, although i appreciate that Data should unreference it's resources when closed.
     
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander
    Pie
    Posts: 12014
    220
    C++ Firefox Browser IntelliJ IDE Java Mac Oracle
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Hi Patrick
    Talking about fixing the Data class is opening a can of worms.
  • the Javadoc says that the methods should throw IOException
  • very few methods throw IOException
  • changing the methods to throw IOException could break existing clients
  • we could change the JavaDoc to say that methods will throw RuntimeException
  • we would have to change all the methods to throw this
  • this could also affect existing clients


  • Speaking from experience, if code does one thing, and documentation says another, changing either will result in users complaining. And, as you pointed out, we have been told that these classes are complete, so should we be meddling? Time for you to make a design decision and document it
    If all this is necessary then the best way of doing it would be to check for null at the beginning of each method which accesses the database, and throw ....

    Yes, that is what I did. What I threw (if anything) depeneded on the method. I had tried to get the methods to do logical things if they were called after close() was called.
    However, the criteriaFind() method is only able to throw a DatabaseException.. (or did i delete the IOException

    No - you didn't delete it. Most methods in Data class do not throw IOException. Some of them do not throw any exception at all.
    Or is it fair to add an IOException since it is accessing the database?

    But then you are changing the signature - and I dont think we can get away with that.
    You are going to have to decide what is right for you, and then do it. Sorry, no easy answers here.
    Regards, Andrew
     
    Patrick Cobbett
    Ranch Hand
    Posts: 44
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Hi Andrew,
    fair play. I think you're right, there's no clear cut answer here, hence the lack of a straight reply in your previous posts. Having looked again, there may be less inconsistency then i thought. The contract for close() in Data says:

    This method closes the database, flushing any outstanding
    writes at the same time. Any attempt to access the
    database after this results in a IOException.

    Perhaps it's not fair to say that methods such as add(DataInfo) actually access the database. Rather it call methods which access the database. The fact that add() catches any thrown IOExceptions and throws a DatabaseException is it's own business. If i check for null every time before the file pointer is used and throw an IOException, then i can let that method deal with it as it would had the IOException been thrown by another method in the try-catch block. In i think all cases they catch it and throw a DatabaseException.
    I feel that methods which do not operate on the file pointer should not throw exceptions. The contract for close() above doesn't even say it should.. only methods which access the database should throw them. The method getFieldInfo[] doesn't throw IOException or DatabaseExceptions because it caches the field data. Should this be considered something encapsulated, and so as far as the client is concerned it is accessing the database and so SHOULD throw an exception of some sort.. perhaps Runtime?
    Although, do you accept that we are changing existing code which is supposed to be complete? This is certainly something which should be documented.
    Do you disagree with anything i have said? No doubt there's many ways of argueing this and you will tell me to just argue my view as fully as possible. However do you think i have a strong enough case to defend my ground?
     
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander
    Pie
    Posts: 12014
    220
    C++ Firefox Browser IntelliJ IDE Java Mac Oracle
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Hi Patrick,
    hence the lack of a straight reply in your previous posts

    Part of my lack of a straight reply is also that I do not want to force my views on anyone - you have to deliver your implementation of the assignment, not my implementation. So I will happily play devil's advocate and agree that every proposal is wrong, or that 2 or 3 mutually exclusive proposals are great. I prefer to just provide things to think about and let you come to your own conclusions.
    Although, do you accept that we are changing existing code which is supposed to be complete? This is certainly something which should be documented.

    Having said that, I will now violate these principals: My personal opinion is that we have been given very limited scope for changing the provided classes, and I dont believe we should change the Data class in any way that might break an existing client.
    However do you think i have a strong enough case to defend my ground?

    Yes, I think you are presenting a well thought out case, and as long as you detail what you did (and why) in your design decisions document, you should do well.
    Regards, Andrew
     
    • Post Reply
    • Bookmark Topic Watch Topic
    • New Topic