Removed double lock requirement for pass through sockets.

This commit is contained in:
wcrisman
2014-07-27 22:04:42 -07:00
parent b0ae8b7e72
commit 0b5e458dff

View File

@@ -291,10 +291,10 @@ public class WebServer {
protected AbstractSocketContext relatedSocketContext = null; protected AbstractSocketContext relatedSocketContext = null;
/** /**
* Whether this socket context should be synchronized on before the related socket context (if one exists). This simply allows locking to always occur in the same order, preventing deadlocking in the case of related sockets and bad behavior (or SPEEDY like pipelining). * Gets the lockable (synchronizable) object for this context. For contexts with a related context, only one of the two will be returned, such that a single synchronize block covers both contexts.
* @return Whether this context is to be locked before the related context (if it exists). * @return The object to synchronize on such that two threads don't attempt to interact with the context at the same time (AsynchronousSocketChannel required for that).
*/ */
protected abstract boolean lockFirst(); protected abstract Object getLock();
/** /**
* Processes the next response in the sequence. * Processes the next response in the sequence.
* @throws IOException * @throws IOException
@@ -483,11 +483,11 @@ public class WebServer {
flagReadOnly(); flagReadOnly();
}//PassThroughSocketContext()// }//PassThroughSocketContext()//
/* (non-Javadoc) /* (non-Javadoc)
* @see com.foundation.web.server.WebServer.AbstractSocketContext#lockFirst() * @see com.foundation.web.server.WebServer.AbstractSocketContext#getLock()
*/ */
protected boolean lockFirst() { protected Object getLock() {
return false; return getRelatedSocketContext();
}//lockFirst()// }//getLock()//
/* (non-Javadoc) /* (non-Javadoc)
* @see com.foundation.web.server.WebServer.AbstractSocketContext#processResponses() * @see com.foundation.web.server.WebServer.AbstractSocketContext#processResponses()
*/ */
@@ -561,7 +561,6 @@ public class WebServer {
//Note: We are throddling this for active connections to prevent a single connection from hogging all the resources.// //Note: We are throddling this for active connections to prevent a single connection from hogging all the resources.//
while(loopCount < 10 && result && count > 0) { while(loopCount < 10 && result && count > 0) {
loopCount++; loopCount++;
socketReadBuffer.clear();
count = channel.read(socketReadBuffer); count = channel.read(socketReadBuffer);
socketReadBuffer.flip(); socketReadBuffer.flip();
@@ -698,11 +697,11 @@ public class WebServer {
return (PassThroughSocketContext) getRelatedSocketContext(); return (PassThroughSocketContext) getRelatedSocketContext();
}//getPassThroughSocketContext()// }//getPassThroughSocketContext()//
/* (non-Javadoc) /* (non-Javadoc)
* @see com.foundation.web.server.WebServer.AbstractSocketContext#lockFirst() * @see com.foundation.web.server.WebServer.AbstractSocketContext#getLock()
*/ */
protected boolean lockFirst() { protected Object getLock() {
return true; return this;
}//lockFirst()// }//getLock()//
protected synchronized void close() { protected synchronized void close() {
try { try {
if(applicationDataMap != null) { if(applicationDataMap != null) {
@@ -1916,53 +1915,23 @@ public class WebServer {
// Debug.log("Socket is write available: " + ((SocketChannel) channel).socket().getInetAddress() + ":" + ((SocketChannel) channel).socket().getPort()); // Debug.log("Socket is write available: " + ((SocketChannel) channel).socket().getInetAddress() + ":" + ((SocketChannel) channel).socket().getPort());
// }//if// // }//if//
//Lock on both contexts if there is a related socket - do it deadlock safe.//
if(((AbstractSocketContext) context).getRelatedSocketContext() == null) {
//Prevent another thread from reading/writing on the same socket at the same time (safety). This would have to be removed if SPEEDY (or similar pipelining) were allowed, and AsynchronousSocketChannel/AsynchronousServerSocketChannel would have to be used (requiring jdk7).// //Prevent another thread from reading/writing on the same socket at the same time (safety). This would have to be removed if SPEEDY (or similar pipelining) were allowed, and AsynchronousSocketChannel/AsynchronousServerSocketChannel would have to be used (requiring jdk7).//
synchronized(context) { synchronized(((AbstractSocketContext) context).getLock()) {
//Process the pending write to the socket as much as is possible, then return.// //Process the pending write to the socket as much as is possible, then return.//
((AbstractSocketContext) context).processResponses(); ((AbstractSocketContext) context).processResponses();
}//synchronized// }//synchronized//
}//if// }//if//
else { else {
Object lockFirst = ((AbstractSocketContext) context).lockFirst() ? context : ((AbstractSocketContext) context).getRelatedSocketContext();
Object lockSecond = ((AbstractSocketContext) context).lockFirst() ? ((AbstractSocketContext) context).getRelatedSocketContext() : context;
//Prevent another thread from reading/writing on the same socket at the same time (safety). This would have to be removed if SPEEDY (or similar pipelining) were allowed, and AsynchronousSocketChannel/AsynchronousServerSocketChannel would have to be used (requiring jdk7).//
synchronized(lockFirst) {
synchronized(lockSecond) {
//Process the pending write to the socket as much as is possible, then return.//
((AbstractSocketContext) context).processResponses();
}//synchronized//
}//synchronized//
}//else//
}//if//
else {
// if(debug) { // if(debug) {
// ((SocketContext) context).debugBuffer.append("Socket is now read available.\n"); // ((SocketContext) context).debugBuffer.append("Socket is now read available.\n");
// Debug.log("Socket is read available: " + ((SocketChannel) channel).socket().getInetAddress() + ":" + ((SocketChannel) channel).socket().getPort()); // Debug.log("Socket is read available: " + ((SocketChannel) channel).socket().getInetAddress() + ":" + ((SocketChannel) channel).socket().getPort());
// }//if// // }//if//
//Lock on both contexts if there is a related socket - do it deadlock safe.//
if(((AbstractSocketContext) context).getRelatedSocketContext() == null) {
//Prevent another thread from reading/writing on the same socket at the same time (safety). This would have to be removed if SPEEDY (or similar pipelining) were allowed, and AsynchronousSocketChannel/AsynchronousServerSocketChannel would have to be used (requiring jdk7).// //Prevent another thread from reading/writing on the same socket at the same time (safety). This would have to be removed if SPEEDY (or similar pipelining) were allowed, and AsynchronousSocketChannel/AsynchronousServerSocketChannel would have to be used (requiring jdk7).//
synchronized(context) { synchronized(((AbstractSocketContext) context).getLock()) {
//Process the incoming request and send the response (a partial response may be sent in which case the socket will be set to wait for a write opportunity and not a read opportunity).// //Process the incoming request and send the response (a partial response may be sent in which case the socket will be set to wait for a write opportunity and not a read opportunity).//
((AbstractSocketContext) context).processRequest(); ((AbstractSocketContext) context).processRequest();
}//synchronized// }//synchronized//
}//if//
else {
Object lockFirst = ((AbstractSocketContext) context).lockFirst() ? context : ((AbstractSocketContext) context).getRelatedSocketContext();
Object lockSecond = ((AbstractSocketContext) context).lockFirst() ? ((AbstractSocketContext) context).getRelatedSocketContext() : context;
//Prevent another thread from reading/writing on the same socket at the same time (safety). This would have to be removed if SPEEDY (or similar pipelining) were allowed, and AsynchronousSocketChannel/AsynchronousServerSocketChannel would have to be used (requiring jdk7).//
synchronized(lockFirst) {
synchronized(lockSecond) {
//Process the incoming request and send the response (a partial response may be sent in which case the socket will be set to wait for a write opportunity and not a read opportunity).//
((AbstractSocketContext) context).processRequest();
}//synchronized//
}//synchronized//
}//else//
}//else// }//else//
}//if// }//if//
}//try// }//try//