10 Replies Latest reply: Feb 4, 2011 5:32 AM by 829050 RSS

    is the RMI registry "process-atomic"?

    829050
      Hi,

      Sorry if this is a really stupid question, and I have really tried to find this out on my own.

      When I say "process" I mean Process, as opposed to Thread.

      What I mean is, if one Process calls Registry.bind( String, Remote ), can we be sure that another Process which does the same thing one nanosecond later will get an AlreadyBoundException if it calls with the same String?

      The context is that up to now I have been starting the RMI Server (only for logging at the mo, these are my first steps) explicitly in a Process. But now I want to move to "lazy" startup of the RMI registry and of the Server... so I would go LoggerInterface.log( bindingName, message ), and if the name "bindingName" is not presently in the registry it will create a new Server, and log the message using it.

      More specifically, this is about me trying to automate OpenOffice apps using Java... and it occurs to me that 2 events could indeed happen almost simultaneously, so in fact even explicitly starting up the Server in each handler module might encounter "Process concurrency" problems ... so I need to have an answer to this.

      I hope the answer is yes... otherwise I'm going to be a bit flummoxed about how to ensure one doesn't start up one Server Process from one calling Process, and another Server Process from another calling Process.

      Thanks
        • 1. Re: is the RMI registry "process-atomic"?
          EJP
          if one Process calls Registry.bind( String, Remote ), can we be sure that another Process which does the same thing one nanosecond later will get an AlreadyBoundException if it calls with the same String?
          Yes. And it is immaterial whether the callers are distinct processes or threads or hosts.
          • 2. Re: is the RMI registry "process-atomic"?
            829050
            Great stuff, thanks very much
            • 3. Re: is the RMI registry "process-atomic"?
              829050
              Ah, sorry to change my decision about "answered"... you did answer my initial question, but as you can see this has led me to another question...
              • 4. Re: is the RMI registry "process-atomic"?
                829050
                Hi,

                Thanks very much... sorry to mark it unanswered... of course you have answered my question... but this leads on to a further question to do with inter-Process synchronization.

                (NB I'm going to leave Registry.rebind() out of this because it doesn't throw any Bound or NotBound exceptions).

                Atomicity relating to AtomicInteger etc. usually involves an atomic (Thread-atomic) check-then-act, i.e. AtomicInteger.getAndSet()... but it seems to me that this is absent from the available methods of Registry. And it therefore seems to me that you could encounter race conditions between Processes.

                Supposing you have a whole bunch of Processes all wanting to do some logging at the same time using the name of LoggerServer, which is not yet running...

                Process A finds that Registry.lookup() throws a NotBoundExcep... and therefore naturally launches a process A' to start a LoggerServer running.

                Meanwhile Process B does exactly the same thing for the same reasons, spawns Process B'.

                One of the spawned Processes, let's say A', after doing UnicastRemoteObject.exportObject() is the first of the two to do bind()... a fraction of a second later Process B' tries to do this, gets an AlreadyBoundExcep and presumably back in the calling Process B (and A) you have to have a loop with a Thread.sleep() going on, testing to find out when the suitable stub becomes available from the Registry.

                But supposing you want to set things up so that you test a stub retrieved from the Registry to find out whether it's valid or not (wouldn't be valid if the Server Process had been destroyed, for example, either manually or programmatically, but the binding remains).

                So my solution at this point is to go "unbind", and then to launch a new Process for the binding.

                So back to the 2 threads A and B... They both more or less simultaneously get what appears to be a valid Remote from the registry, but it turns out that a method of the interface throws a RemoteException... both then assume that the registry must do an unbind followed by launching a Process to bind a proper LoggerServer.

                And this is the problem: with a bit of unlucky timing couldn't you find that in the interval between one Process deciding an "unbind" is in order and it ordering the Registry to "unbind", that another Process has started a perfectly valid Process... the stub of which might well be used by other Processes, including the one which had spawned the new Server Process... but then this would be (incorrectly) unbound. And another start-the-Server Process would be spawned... In short it would be a mess.

                The problem I describe is due to not having a "check-then-act" available between Processes.

                I hope you can tell me what the answer to this is! From your website I see you are a pretty eminent authority...!
                • 5. Re: is the RMI registry "process-atomic"?
                  EJP
                  The simple answer to all that is to use rebind(). You can't get cross-process/cross-host atomicity when calling lookup() and bind() without a lot of extra stuff you would have to build yourself.

                  The Registry methods are all simply synchronized operations on a Map.
                  • 6. Re: is the RMI registry "process-atomic"?
                    829050
                    Thanks... but I don't really see how rebind() solves the problem. Won't there always be an interval between finding a Process wants to rebind, and then rebinding?

                    In that space of time all sorts of things could happen, such as other Processes doing the same thing... but the whole point of RMI is that you want a single, bound Process which many caller Processes can use...

                    To me it seems a bit strange that Java has developed several sophisticated mechanisms to ensure Thread synchronization can be properly implemented for those who are prepared to reason it through... but appears to neglect the need to provide synchronization mechanisms between Processes...

                    If you could point me to this "extra stuff" that would be nice.
                    • 7. Re: is the RMI registry "process-atomic"?
                      EJP
                      Won't there always be an interval between finding a Process wants to rebind, and then rebinding?
                      I mean to use rebind() instead of the lookup()/bind() pair. It is atomic.
                      ... appears to neglect the need to provide synchronization mechanisms between Processes...
                      Between processes can be accomplished with FileLock, but that isn't sufficient for RMI, it would have to be between processes on different hosts in full generality, and that's a non-trivial problem. Google 'Byzantine Clock Agreement' for an example. Not something that belongs inside the RMI API IMHO.

                      OTOH, I did implement an RMI Registry with an enhanced API for two-phase commit at some point. It's a commercial product so I can't say anything more about it here but if you're interested contact me off-forum.

                      But if you want lazy instantiation you should be using RMI Activation.
                      • 8. Re: is the RMI registry "process-atomic"?
                        829050
                        I mean to use rebind() instead of the lookup()/bind() pair. It is atomic.
                        ... I understand it is atomic, but my point is that between checking whether you need to rebind (because the bound stub is invalid) and actually doing the rebind there will be an interval. If you systematically use rebind, without a prior check to make sure your Remote is actually attached to an existing Process, every call will cause a new Server Process to be created and then rebound, one after another. Which would be a mess.

                        I'm going to spend a bit of time looking at your two references... thanks for them.

                        I have thought of a possible solution involving a sort of lock, but I'm not sure if it works.

                        1. create a "DummyInterface" extending Remote:
                        public interface DummyInterface extends Remote {
                        }
                        2. in the Process + Thread which actually sets up the Registry, bind a DummyInterface
                        Registry reg = null;
                        try {
                          reg = LocateRegistry.createRegistry( 1099 );
                        } catch (RemoteException e) {
                          return; // is this right? see below...
                        }
                        DummyInterface dummyStub = new DummyInterface(){};
                        try {
                          dummyStub = (DummyInterface) UnicastRemoteObject.exportObject( dummyStub, 0);
                        } catch (RemoteException e) {
                          // TODO sthg 
                          e.printStackTrace();
                        }
                        try {
                          reg.bind( "DummyLockForLoggerServer", dummyStub );
                        } catch (AlreadyBoundException e) {
                          // every Thread in every Process (except the first such) to call "bind" will get here
                          return;
                        } catch (Exception e) {
                          // TODO sthg 
                          e.printStackTrace();
                        }
                        3.     the first Process + Thread which wants to set up the LoggerServer will have first to unbind the DummyLock.
                        try {
                           reg.unbind( "DummyLockForLoggerServer" );
                        } catch (AccessException e) {
                           // TODO sthg 
                           e.printStackTrace();
                        } catch (RemoteException e) {
                           // TODO sthg
                           e.printStackTrace();
                        } catch (NotBoundException e) {
                          // every Thread in every Process (except the first such) to call "unbind" will get here
                          return;
                        }
                        
                        // only one Thread in one Process will ever succeed in getting here
                        // start the LoggerServer
                        String qualifiedClassName = ".... rmi.LoggerServer";
                        String[] a_commandArgs = { "java", qualifiedClassName, "logName" };
                        Process process = null;
                        try {
                          process = Utils.runSubprocess(a_commandArgs, null, ProcessSettings.getJavaRootDir());
                        } catch (IOException e) {
                           // TODO sthg
                           e.printStackTrace();
                        }
                        ... however there seem to be one or two questions about this:

                        - does reg = LocateRegistry.createRegistry( 1099 ); throw a RemoteException if the Registry is already bound? I don't know and intend to do a few experiments to find this out for myself. But in any event only one Process+Thread can ever bind the dummy lock
                        - there might be a race condition nonetheless to do with the interval between creating the Registry and binding the dummy lock... during this interval the Registry is established, and the dummylock is not yet set up... but I think this does no harm, as a Process trying to start the LoggerServer during this time will get the "NotBoundException" and simply return (and the calling thread will then sleep for a bit before trying again).
                        • 9. Re: is the RMI registry "process-atomic"?
                          EJP
                          ... I understand it is atomic, but my point is that between checking whether you need to rebind (because the bound stub is invalid) and actually doing the rebind there will be an interval.
                          Of course. And my point is that if you don't check, just call rebind(), there is no interval. If that doesn't suit your application then I suspect you should indeed be looking into Activation. It sounds ideal for your problem, although IMHO it is by no means ideal in all respects. ;-(

                          Also IMHO you are wasting time trying to get the Registry operations which are not atomic to be atomic. Same reasoning here as the shift from synchronized Vector to unsynchronized ArrayList. It is always up to the application to ensure it is using a resource in an atomic way, apart from single operations which can be made atomic behind the scenes. You are trying to do lazy instantiation; Activation does lazy instantiation; QED.
                          - does reg = LocateRegistry.createRegistry( 1099 ); throw a RemoteException if the Registry is already bound?
                          I don't know what exactly you mean by 'bound' here, but the second of two successive createRegistry() calls will always fail.
                          • 10. Re: is the RMI registry "process-atomic"?
                            829050
                            thanks once again... I'll investigate Activation ASAP!