[jcifs] Another fix for Transport deadlock issue ?
Dalton, Tim
Daltontf at AGEDWARDS.com
Fri Apr 28 21:38:09 GMT 2006
We tried using the 1.2.9 release of jcifs, but noticed throughput is significantly lower due to the new Transport.setupDiscoLock monitor. We were only experience the deadlock when a Transport experiences an IOException:
Found one Java-level deadlock:
=============================
"DniDeviceReaderJms-TDMS1_SAMBA49":
waiting to lock monitor 0x080b89ec (object 0x47320060, a java.util.HashMap),
which is held by "DniDeviceReaderJms-TDMS1_SAMBA27"
"DniDeviceReaderJms-TDMS1_SAMBA27":
waiting to lock monitor 0x5190724c (object 0x47320088, a jcifs.smb.SmbTransport),
which is held by "DniDeviceReaderJms-TDMS1_SAMBA49"
Java stack information for the threads listed above:
===================================================
"DniDeviceReaderJms-TDMS1_SAMBA49":
at jcifs.util.transport.Transport.sendrecv(Transport.java:63)
- waiting to lock <0x47320060> (a java.util.HashMap)
at jcifs.smb.SmbTransport.send(SmbTransport.java:595)
at jcifs.smb.SmbSession.sessionSetup(SmbSession.java:264)
- locked <0x47320088> (a jcifs.smb.SmbTransport)
at jcifs.smb.SmbSession.send(SmbSession.java:223)
at jcifs.smb.SmbTree.treeConnect(SmbTree.java:144)
- locked <0x47320088> (a jcifs.smb.SmbTransport)
at jcifs.smb.SmbFile.connect(SmbFile.java:792)
at jcifs.smb.SmbFile.connect0(SmbFile.java:762)
at jcifs.smb.SmbFile.open0(SmbFile.java:817)
at jcifs.smb.SmbFile.open(SmbFile.java:846)
at jcifs.smb.SmbFileOutputStream.write(SmbFileOutputStream.java:209)
at com.agedwards.dniprint.CRLFOutputStream.write(CRLFOutputStream.java:53)
at com.agedwards.dniprint.CRLFOutputStream.write(CRLFOutputStream.java:39)
at com.agedwards.dniprint.DniDeviceWriterCifs.write(DniDeviceWriterCifs.java:237)
at com.agedwards.dniprint.DniDeviceHandler.onMessage(DniDeviceHandler.java:518)
- locked <0x47545610> (a com.agedwards.dniprint.DniDevice)
at com.agedwards.dniprint.DniDeviceReaderJms$JmsListener.run(DniDeviceReaderJms.java:707)
at java.lang.Thread.run(Thread.java:534)
"DniDeviceReaderJms-TDMS1_SAMBA27":
at jcifs.util.transport.Transport.disconnect(Transport.java:192)
- waiting to lock <0x47320088> (a jcifs.smb.SmbTransport)
at jcifs.util.transport.Transport.sendrecv(Transport.java:83)
- locked <0x47320060> (a java.util.HashMap)
at jcifs.smb.SmbTransport.send(SmbTransport.java:595)
at jcifs.smb.SmbSession.send(SmbSession.java:229)
at jcifs.smb.SmbTree.send(SmbTree.java:102)
at jcifs.smb.SmbFile.send(SmbFile.java:688)
at jcifs.smb.SmbFile.open0(SmbFile.java:828)
at jcifs.smb.SmbFile.open(SmbFile.java:846)
at jcifs.smb.SmbFileOutputStream.<init>(SmbFileOutputStream.java:139)
at jcifs.smb.SmbFileOutputStream.<init>(SmbFileOutputStream.java:97)
at jcifs.smb.SmbFileOutputStream.<init>(SmbFileOutputStream.java:82)
at jcifs.smb.SmbFileOutputStream.<init>(SmbFileOutputStream.java:54)
at com.agedwards.dniprint.DniDeviceWriterCifs.write(DniDeviceWriterCifs.java:231)
at com.agedwards.dniprint.DniDeviceHandler.onMessage(DniDeviceHandler.java:518)
- locked <0x47545b28> (a com.agedwards.dniprint.DniDevice)
at com.agedwards.dniprint.DniDeviceReaderJms$JmsListener.run(DniDeviceReaderJms.java:707)
at java.lang.Thread.run(Thread.java:534)
Found 1 deadlock.
Here is the 1.2.7 Transport.sendrecv method with comments:
public void sendrecv( Request request,
Response response,
long timeout ) throws IOException {
synchronized (response_map) {
makeKey( request );
response.isReceived = false;
try {
response_map.put( request, response );
doSend( request );
response.expiration = System.currentTimeMillis() + timeout;
while (!response.isReceived) {
response_map.wait( timeout ); // <- thread can't resume monitor on response_map
timeout = response.expiration - System.currentTimeMillis();
if (timeout <= 0) {
throw new TransportException( name +
" timedout waiting for response to " +
request );
}
}
} catch( IOException ioe ) {
if (log.level > 2)
ioe.printStackTrace( log );
try {
disconnect( true ); //<- other thread can't get monitor on 'this' Transport
} catch( IOException ioe2 ) {
ioe2.printStackTrace( log );
}
throw ioe;
} catch( InterruptedException ie ) {
throw new TransportException( ie );
} finally {
response_map.remove( request );
}
}
}
Here is my modified Transport.sendrecv method:
public void sendrecv( Request request,
Response response,
long timeout ) throws IOException {
try {
synchronized (response_map) {
makeKey( request );
response.isReceived = false;
response_map.put( request, response );
doSend( request );
response.expiration = System.currentTimeMillis() + timeout;
while (!response.isReceived) {
response_map.wait( timeout );
timeout = response.expiration - System.currentTimeMillis();
if (timeout <= 0) {
throw new TransportException( name +
" timedout waiting for response to " +
request );
}
}
}
} catch( IOException ioe ) {
if (log.level > 2)
ioe.printStackTrace( log );
try {
disconnect( true );
} catch( IOException ioe2 ) {
ioe2.printStackTrace( log );
}
throw ioe;
} catch( InterruptedException ie ) {
throw new TransportException( ie );
} finally {
synchronized (response_map) {
response_map.remove( request );
}
}
}
I allow the thread to release the monitor on the response_map while performing the disconnect and re-acquire it when the request needs to be removed from it. In my testing, I have not been able to recreate the above deadlock nor have I experienced any significant performance degradation.
Any feedback about this approach ?
Thanks
Tim Dalton
-------------------------------------------------------------------------------------
A.G. Edwards & Sons' outgoing and incoming e-mails are electronically
archived and subject to review and/or disclosure to someone other
than the recipient.
-------------------------------------------------------------------------------------
-------------- next part --------------
HTML attachment scrubbed and removed
More information about the jcifs
mailing list