Skip to content

Commit

Permalink
Improve sendfile handling when requests are pipelined.
Browse files Browse the repository at this point in the history
git-svn-id: https://svn.apache.org/repos/asf/tomcat/tc7.0.x/trunk@1789008 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
markt-asf committed Mar 27, 2017
1 parent 3443b1d commit a4efd3c
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 25 deletions.
7 changes: 3 additions & 4 deletions java/org/apache/coyote/AbstractProtocol.java
Original file line number Diff line number Diff line change
Expand Up @@ -693,10 +693,9 @@ public SocketState process(SocketWrapper<S> wrapper,
release(wrapper, processor, false, true);
} else if (state == SocketState.SENDFILE) {
// Sendfile in progress. If it fails, the socket will be
// closed. If it works, the socket will be re-added to the
// poller
connections.remove(socket);
release(wrapper, processor, false, false);
// closed. If it works, the socket either be added to the
// poller (or equivalent) to await more data or processed
// if there are any pipe-lined requests remaining.
} else if (state == SocketState.UPGRADED) {
// Need to keep the connection associated with the processor
connections.put(socket, processor);
Expand Down
11 changes: 10 additions & 1 deletion java/org/apache/coyote/http11/Http11AprProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
import org.apache.tomcat.util.net.AprEndpoint;
import org.apache.tomcat.util.net.SSLSupport;
import org.apache.tomcat.util.net.SendfileKeepAliveState;
import org.apache.tomcat.util.net.SocketStatus;
import org.apache.tomcat.util.net.SocketWrapper;

Expand Down Expand Up @@ -211,7 +212,15 @@ protected boolean breakKeepAliveLoop(SocketWrapper<Long> socketWrapper) {
// Do sendfile as needed: add socket to sendfile and end
if (sendfileData != null && !getErrorState().isError()) {
sendfileData.socket = socketWrapper.getSocket().longValue();
sendfileData.keepAlive = keepAlive;
if (keepAlive) {
if (getInputBuffer().available() == 0) {
sendfileData.keepAliveState = SendfileKeepAliveState.OPEN;
} else {
sendfileData.keepAliveState = SendfileKeepAliveState.PIPELINED;
}
} else {
sendfileData.keepAliveState = SendfileKeepAliveState.NONE;
}
switch (((AprEndpoint)endpoint).getSendfile().add(sendfileData)) {
case DONE:
return false;
Expand Down
11 changes: 10 additions & 1 deletion java/org/apache/coyote/http11/Http11NioProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import org.apache.tomcat.util.net.NioEndpoint.KeyAttachment;
import org.apache.tomcat.util.net.SSLSupport;
import org.apache.tomcat.util.net.SecureNioChannel;
import org.apache.tomcat.util.net.SendfileKeepAliveState;
import org.apache.tomcat.util.net.SocketStatus;
import org.apache.tomcat.util.net.SocketWrapper;

Expand Down Expand Up @@ -275,7 +276,15 @@ protected boolean breakKeepAliveLoop(SocketWrapper<NioChannel> socketWrapper) {
// Do sendfile as needed: add socket to sendfile and end
if (sendfileData != null && !getErrorState().isError()) {
((KeyAttachment) socketWrapper).setSendfileData(sendfileData);
sendfileData.keepAlive = keepAlive;
if (keepAlive) {
if (getInputBuffer().available() == 0) {
sendfileData.keepAliveState = SendfileKeepAliveState.OPEN;
} else {
sendfileData.keepAliveState = SendfileKeepAliveState.PIPELINED;
}
} else {
sendfileData.keepAliveState = SendfileKeepAliveState.NONE;
}
SelectionKey key = socketWrapper.getSocket().getIOChannel().keyFor(
socketWrapper.getSocket().getPoller().getSelector());
//do the first write on this thread, might as well
Expand Down
37 changes: 25 additions & 12 deletions java/org/apache/tomcat/util/net/AprEndpoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -2106,7 +2106,7 @@ public static class SendfileData {
// Position
public long pos;
// KeepAlive flag
public boolean keepAlive;
public SendfileKeepAliveState keepAliveState = SendfileKeepAliveState.NONE;
}


Expand Down Expand Up @@ -2349,20 +2349,33 @@ public void run() {
state.pos = state.pos + nw;
if (state.pos >= state.end) {
remove(state);
if (state.keepAlive) {
switch (state.keepAliveState) {
case NONE: {
// Close the socket since this is
// the end of the not keep-alive request.
closeSocket(state.socket);
break;
}
case PIPELINED: {
// Destroy file descriptor pool, which should close the file
Pool.destroy(state.fdpool);
Socket.timeoutSet(state.socket,
getSoTimeout() * 1000);
// If all done put the socket back in the
// poller for processing of further requests
getPoller().add(
state.socket, getKeepAliveTimeout(),
Socket.timeoutSet(state.socket, getSoTimeout() * 1000);
// Process the pipelined request data
if (!processSocket(state.socket, SocketStatus.OPEN_READ)) {
closeSocket(state.socket);
}
break;
}
case OPEN: {
// Destroy file descriptor pool, which should close the file
Pool.destroy(state.fdpool);
Socket.timeoutSet(state.socket, getSoTimeout() * 1000);
// Put the socket back in the poller for
// processing of further requests
getPoller().add(state.socket, getKeepAliveTimeout(),
true, false);
} else {
// Close the socket since this is
// the end of not keep-alive request.
closeSocket(state.socket);
break;
}
}
}
}
Expand Down
28 changes: 21 additions & 7 deletions java/org/apache/tomcat/util/net/NioEndpoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -1383,16 +1383,30 @@ public SendfileState processSendfile(SelectionKey sk, KeyAttachment attachment,
// responsible for registering the socket for the
// appropriate event(s) if sendfile completes.
if (!calledByProcessor) {
if ( sd.keepAlive ) {
if (log.isDebugEnabled()) {
log.debug("Connection is keep alive, registering back for OP_READ");
}
reg(sk,attachment,SelectionKey.OP_READ);
} else {
switch (sd.keepAliveState) {
case NONE: {
if (log.isDebugEnabled()) {
log.debug("Send file connection is being closed");
}
cancelledKey(sk,SocketStatus.STOP,false);
break;
}
case PIPELINED: {
if (log.isDebugEnabled()) {
log.debug("Connection is keep alive, processing pipe-lined data");
}
if (!processSocket(sc, SocketStatus.OPEN_READ, true)) {
cancelledKey(sk, SocketStatus.DISCONNECT, false);
}
break;
}
case OPEN: {
if (log.isDebugEnabled()) {
log.debug("Connection is keep alive, registering back for OP_READ");
}
reg(sk, attachment, SelectionKey.OP_READ);
break;
}
}
}
return SendfileState.DONE;
Expand Down Expand Up @@ -1836,6 +1850,6 @@ public static class SendfileData {
public volatile long pos;
public volatile long length;
// KeepAlive flag
public volatile boolean keepAlive;
public SendfileKeepAliveState keepAliveState = SendfileKeepAliveState.NONE;
}
}
39 changes: 39 additions & 0 deletions java/org/apache/tomcat/util/net/SendfileKeepAliveState.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tomcat.util.net;

public enum SendfileKeepAliveState {

/**
* Keep-alive is not in use. The socket can be closed when the response has
* been written.
*/
NONE,

/**
* Keep-alive is in use and there is pipelined data in the input buffer to
* be read as soon as the current response has been written.
*/
PIPELINED,

/**
* Keep-alive is in use. The socket should be added to the poller (or
* equivalent) to await more data as soon as the current response has been
* written.
*/
OPEN
}
3 changes: 3 additions & 0 deletions webapps/docs/changelog.xml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@
configuration attributes and internal code. Based on a patch by Michael
Osipov. (markt)
</fix>
<fix>
Improve sendfile handling when requests are pipelined. (markt)
</fix>
</changelog>
</subsection>
<subsection name="Jasper">
Expand Down

0 comments on commit a4efd3c

Please sign in to comment.