-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Bob,

On 6/11/13 1:05 AM, ruxing bao wrote:
> Sorry,I can't get any more of the stack trace.
> 
> We wrapped zookeepr client as a spring bean and invoked method 
> "close" of zookeeper in "destory-method" of bean,in that method 
> "close",zookeeper Send Thread was closed. When tomcat was shut
> down, Spring closed it's container and bean was destroyed, then 
> "destroy-method" of bean was invoked. I'am confusing why is Send 
> Thread of Zookeeper seemed to exit slower than the
> WebappClassLoader shedding its loaded classes.


Threads don't always shut down immediately... let's see how you are
telling the thread to shut down:

> ps: details of zookeeper closing

(Thanks!)

> org.apache.zookeeper.Zookeeper public synchronized void close()
> throws InterruptedException { if (!cnxn.getState().isAlive()) { if
> (LOG.isDebugEnabled()) { LOG.debug("Close called on already closed
> client"); } return; } if (LOG.isDebugEnabled()) { 
> LOG.debug("Closing session: 0x" +
> Long.toHexString(getSessionId())); } try { cnxn.close(); } catch
> (IOException e) { if (LOG.isDebugEnabled()) { LOG.debug("Ignoring
> unexpected exception during close", e); } } LOG.info("Session: 0x"
> + Long.toHexString(getSessionId()) + " closed"); }

So, during webapp shutdown you should be getting the message "Closing
session 0x[...]", right? No errors?

Is "cnxn" of type org.apache.zookeeped.ClientCnxn? That seems to be
the case, but it's worth checking.

> ----------------------------------------------------------------------------------------------------------------------
>
> 
org.apache.zookeeper.ClientCnxn
> public void close() throws IOException { if (LOG.isDebugEnabled())
> { LOG.debug("Closing client for session: 0x" +
> Long.toHexString(getSessionId())); } try { RequestHeader h = new
> RequestHeader(); h.setType(ZooDefs.OpCode.closeSession); 
> submitRequest(h, null, null, null); } catch (InterruptedException
> e) { // ignore, close the send/event threads } finally { 
> disconnect(); } }
> 
> public void disconnect() { if (LOG.isDebugEnabled()) { 
> LOG.debug("Disconnecting client for session: 0x" +
> Long.toHexString(getSessionId())); } sendThread.close(); 
> eventThread.queueEventOfDeath(); }

Okay, so calling "close" asks the thread to stop (somewhat indirectly).

> org.apache.zookeeper.ClientCnxn.SendThread void close() { state =
> States.CLOSED; clientCnxnSocket.wakeupCnxn(); }
> 
> 
> @Override public void run() { 
> clientCnxnSocket.introduce(this,sessionId); 
> clientCnxnSocket.updateNow(); 
> clientCnxnSocket.updateLastSendAndHeard(); int to; long
> lastPingRwServer = System.currentTimeMillis(); while
> (state.isAlive()) { try { if (!clientCnxnSocket.isConnected()) { 
> if(!isFirstConnect){ try { Thread.sleep(r.nextInt(1000)); } catch
> (InterruptedException e) { LOG.warn("Unexpected exception", e); } 
> } // don't re-establish connection if we are closing if (closing ||
> !state.isAlive()) { break; } startConnect(); 
> clientCnxnSocket.updateLastSendAndHeard(); } if
> (state.isConnected()) { // determine whether we need to send an
> AuthFailed event. if (zooKeeperSaslClient != null) { boolean
> sendAuthEvent = false; if (zooKeeperSaslClient.getSaslState() ==
> ZooKeeperSaslClient.SaslState.INITIAL) { try { 
> zooKeeperSaslClient.initialize(ClientCnxn.this); } catch
> (SaslException e) { LOG.error("SASL authentication with Zookeeper
> Quorum member failed: " + e); state = States.AUTH_FAILED; 
> sendAuthEvent = true; } } KeeperState authState =
> zooKeeperSaslClient.getKeeperState(); if (authState != null) { if
> (authState == KeeperState.AuthFailed) { // An authentication error
> occurred during authentication with the Zookeeper Server. state =
> States.AUTH_FAILED; sendAuthEvent = true; } else { if (authState ==
> KeeperState.SaslAuthenticated) { sendAuthEvent = true; } } } if
> (sendAuthEvent == true) { eventThread.queueEvent(new WatchedEvent( 
> Watcher.Event.EventType.None, authState,null)); } } to =
> readTimeout - clientCnxnSocket.getIdleRecv(); } else { to =
> connectTimeout - clientCnxnSocket.getIdleRecv(); }
> 
> if (to <= 0) { throw new SessionTimeoutException( "Client session
> timed out, have not heard from server in " +
> clientCnxnSocket.getIdleRecv() + "ms" + " for sessionid 0x" +
> Long.toHexString(sessionId)); } if (state.isConnected()) { int
> timeToNextPing = readTimeout / 2 - clientCnxnSocket.getIdleSend(); 
> if (timeToNextPing <= 0) { sendPing(); 
> clientCnxnSocket.updateLastSend(); } else { if (timeToNextPing <
> to) { to = timeToNextPing; } } } // If we are in read-only mode,
> seek for read/write server if (state == States.CONNECTEDREADONLY)
> { long now = System.currentTimeMillis(); int idlePingRwServer =
> (int) (now - lastPingRwServer); if (idlePingRwServer >=
> pingRwTimeout) { lastPingRwServer = now; idlePingRwServer = 0; 
> pingRwTimeout = Math.min(2*pingRwTimeout, maxPingRwTimeout); 
> pingRwServer(); } to = Math.min(to, pingRwTimeout -
> idlePingRwServer); } clientCnxnSocket.doTransport(to, pendingQueue,
> outgoingQueue, ClientCnxn.this); } catch (Throwable e) { if
> (closing) { if (LOG.isDebugEnabled()) { // closing so this is
> expected LOG.debug("An exception was thrown while closing send
> thread for session 0x" + Long.toHexString(getSessionId()) + " : " +
> e.getMessage()); } break; } else { // this is ugly, you have a
> better way speak up if (e instanceof SessionExpiredException) { 
> LOG.info(e.getMessage() + ", closing socket connection"); } else if
> (e instanceof SessionTimeoutException) { LOG.info(e.getMessage() +
> RETRY_CONN_MSG); } else if (e instanceof EndOfStreamException) { 
> LOG.info(e.getMessage() + RETRY_CONN_MSG); } else if (e instanceof
> RWServerFoundException) { LOG.info(e.getMessage()); } else { 
> LOG.warn( "Session 0x" + Long.toHexString(getSessionId()) + " for
> server " + clientCnxnSocket.getRemoteSocketAddress() + ",
> unexpected error" + RETRY_CONN_MSG, e); } cleanup(); if
> (state.isAlive()) { eventThread.queueEvent(new WatchedEvent( 
> Event.EventType.None, Event.KeeperState.Disconnected, null)); } 
> clientCnxnSocket.updateNow(); 
> clientCnxnSocket.updateLastSendAndHeard(); } } } cleanup(); 
> clientCnxnSocket.close(); if (state.isAlive()) { 
> eventThread.queueEvent(new WatchedEvent(Event.EventType.None, 
> Event.KeeperState.Disconnected, null)); } 
> ZooTrace.logTraceMessage(LOG, ZooTrace.getTextTraceLevel(), 
> "SendThread exitedloop.");//at this line, error occurs. }

It seems you have a race condition, here: you are asking the thread to
stop (indirectly, by setting state=CLOSED). But, the thread requesting
the close continues running without checking to see what happens with
the SendThread. The SendThread has a Thread.sleep() call which means
that it might be waiting for a while before exiting its run() method.

Can you modify the code somewhere to:

a) Call SendThread.interrupt()

and

b) Do a short loop waiting for SendThread.getState() == TERMINATED

I think if you do these two things, you'll have a clean shutdown.

Hope that helps,
- -chris
-----BEGIN PGP SIGNATURE-----
Version: GnuPG/MacGPG2 v2.0.17 (Darwin)
Comment: GPGTools - http://gpgtools.org
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/

iQIcBAEBCAAGBQJRtyyEAAoJEBzwKT+lPKRY32MQAL8TYt1jFL7smrWLU3/UwHW5
gRp5AD45E8VFd93944IWTsfBda7pGWbStBvUO/N/seJb2hDXdtLI2vf2Ol1ZbEas
00I/Vauqourllv6cGvJzKYeFht9iMF3thZHy1HC5aKTrJqtbBZ6y39qjb0P2Z+7W
BhVQlxEmCC2kJzAP2Df8+1eITm0PsaJ/4XTSoAPD4uS8MM+F2wKTjXR3kErmp4TF
+8PHUbEy0m+I0fXZl9fw7+atU0vEDXs5NnL7dVyy5lK3qrEBfsxMerfD62Z2zlOZ
FQwcf5yXSz8tLDNzjuS5m5fe6P10HPHPnGwijEN6LCQ/bEdCcGZSflvfGXTggtTw
gdWRrsPzpizCxYtXMVAjqMaSeEiiO7YcOCjnZNvQxmkjzwDwx9WdD28kFmlkNS4k
vS5mhXvL6tRMZ62VGMoUP+QkRB0oTbRDVBZu6zwxV3Jl82Oq3iueX/ojtrgxBfS4
v6anlPSehA0Ooep8XD9iu4Q2Nq1NBoe34uM1ZLZLqXCSjpTImaqFUdgxcsxzGqS8
6wpuWSw5gB2z1FP858n2pKs66KiWzIknkMRG9peyZmgPqg4ytUREKhQb1x4NY9Ni
7uAPgWbEq+WJ8x0elOzbAgpIIsFbHd13N4eYFRv/FkVEYnirMySKzpF9zBk0cPW9
Nr5Vy5k194wFBDeAtL38
=QUc/
-----END PGP SIGNATURE-----

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org

Reply via email to