We haved conducted more tests this afternoon, using another JVM on Mac OS X 10.5 (java 6), and didn't had the same problem. Here is the failing test in this case :

-------------------------------------------------------------------------------
Test set: org.apache.ftpserver.clienttests.RmDirTest
-------------------------------------------------------------------------------
Tests run: 7, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.076 sec <<< 
FAILURE!
testRmdirCurrentWorkingDirectory(org.apache.ftpserver.clienttests.RmDirTest)  Time 
elapsed: 0.014 sec  <<< FAILURE!
junit.framework.AssertionFailedError: expected:<false> but was:<true>
        at junit.framework.Assert.fail(Assert.java:47)
        at junit.framework.Assert.failNotEquals(Assert.java:280)
        at junit.framework.Assert.assertEquals(Assert.java:64)
        at junit.framework.Assert.assertEquals(Assert.java:146)
        at junit.framework.Assert.assertEquals(Assert.java:152)
        at 
org.apache.ftpserver.clienttests.RmDirTest.testRmdirCurrentWorkingDirectory(RmDirTest.java:119)




Guillaume Nodet wrote:
On OS X, the test does not behave the same way: the session is created
and the byte written, but the server does not have any managed session
so the last assertion fails.
To make this test fail as expected, I need to add the following calls
to AbstractPollingIoAcceptor#unbind0

        startupAcceptor();
        wakeup();

I may have an explanation.   In the unregisterHandles() method, the
handle is closed and then there is a call to wakeup().  However, when
the last bound socket is unregistered, the Acceptor#run() method will
simply exit just after the call to unregisterHandles() because
nHandles == 0.   So I think the call to wakeup() has no effect at all,
because the acceptor is not running anymore, thus no select() call is
performed.

I've also tried the following patch:

Index: 
core/src/main/java/org/apache/mina/core/polling/AbstractPollingIoAcceptor.java
===================================================================
--- 
core/src/main/java/org/apache/mina/core/polling/AbstractPollingIoAcceptor.java
     (revision 747700)
+++ 
core/src/main/java/org/apache/mina/core/polling/AbstractPollingIoAcceptor.java
     (working copy)
@@ -406,6 +406,7 @@
                     }

                     // check to see if any cancellation request has been made.
+                    int nbPreviousHandles = nHandles;
                     nHandles -= unregisterHandles();

                     // Now, if the number of registred handles is 0, we can
@@ -415,6 +416,9 @@
                         synchronized (lock) {
                             if (registerQueue.isEmpty()
                                     && cancelQueue.isEmpty()) {
+                                if (nbPreviousHandles > 0) {
+                                    select();
+                                }
                                 acceptor = null;
                                 break;
                             }

But I don't think it's very clean either.

Note that the problem also happen with datagram sockets and none of
the above solution seems to work in that case.

2009/2/25 Emmanuel Lecharny <elecha...@apache.org>:
Guillaume Nodet wrote:
I've just spotted that the acceptor is not correctly disposed.
I've managed to get the test running succesfully by adding the
following code just after server.suspend()

       for (Listener listener :
server.getServerContext().getListeners().values()) {
           if (listener instanceof NioListener) {
               Field field = listener.getClass().getDeclaredField("acceptor");
               field.setAccessible(true);
               NioSocketAcceptor acceptor = (NioSocketAcceptor)
field.get(listener);
               Method method =
AbstractPollingIoAcceptor.class.getDeclaredMethod("dispose0");
               method.setAccessible(true);
               method.invoke(acceptor);
           }
       }

Which is about callling the dispose0() method of the NioSocketAcceptor.
This method looks like:

   protected IoFuture dispose0() throws Exception {
       unbind();
       if (!disposalFuture.isDone()) {
           startupAcceptor();
           wakeup();
       }
       return disposalFuture;
   }

So I guess what we're missing is a call to:
           startupAcceptor();
           wakeup();
somewhere.
I'm not too familiar with mina internals, so I'm not sure where this
methods should be called or if it makes any sense to call those after
an unbind.

The problem is that when you do an acceptor.unbind(), here is what MINA does :

acceptor.unbind() -->
 unbind(getLocalAddresses()) -->
  unbind0(localAddressesCopy) with

  protected final void unbind0(List<? extends SocketAddress> localAddresses)
          throws Exception {
      AcceptorOperationFuture future = new AcceptorOperationFuture(
              localAddresses);

      cancelQueue.add(future);
      startupAcceptor();
      wakeup();
      ...

There is obviously something wrong somewhere, if you consider the following 
test :
org.apache.mina.transport.AbstractBindTest

  public void testUnbindDisconnectsClients() throws Exception {
      bind(true);
      IoConnector connector = newConnector();
      IoSession[] sessions = new IoSession[5];
      connector.setHandler(new IoHandlerAdapter());

      // Create 5 sessions, and write when established
      for (int i = 0; i < sessions.length; i++) {
          ConnectFuture future = connector.connect(createSocketAddress(port));
          future.awaitUninterruptibly();
          sessions[i] = future.getSession();
          Assert.assertTrue(sessions[i].isConnected());
          
Assert.assertTrue(sessions[i].write(IoBuffer.allocate(1)).awaitUninterruptibly().isWritten());
      }

      // Wait for the server side sessions to be created.
      Thread.sleep(500);

      Collection<IoSession> managedSessions = 
acceptor.getManagedSessions().values();
      Assert.assertEquals(5, managedSessions.size());

      // Now unbind
      acceptor.unbind();

      // Wait for the accessor to unbind
      Thread.sleep(500);

      // The session must have been closed
      Assert.assertEquals(0, managedSessions.size());
      for (IoSession element : managedSessions) {
          Assert.assertFalse(element.isConnected());
      }

      // And now, try to create a session on a unbound acceptor !!!
      ConnectFuture future = connector.connect(createSocketAddress(port));
      future.awaitUninterruptibly();
      IoSession session = future.getSession();
      Assert.assertTrue(session.isConnected());
      
Assert.assertTrue(session.write(IoBuffer.allocate(1)).awaitUninterruptibly().isWritten());

      // Wait for the server side sessions to be created.
      Thread.sleep(500);

      managedSessions = acceptor.getManagedSessions().values();
      Assert.assertEquals(1, managedSessions.size());
  }


On Linux, this tests passes, all lights green !

--
--
cordialement, regards,
Emmanuel Lécharny
www.iktek.com
directory.apache.org








--
--
cordialement, regards,
Emmanuel Lécharny
www.iktek.com
directory.apache.org


Reply via email to