window_size: explicit adjustments only

Removed the automatic window_size adjustments from
_libssh2_channel_read() and instead all channel readers must now make
sure to enlarge the window sizes properly themselves.

libssh2_channel_read_ex() - the public function, now grows the window
size according to the requested buffer size. Applications can still opt
to grow the window more on demand. Larger windows tend to give higher
performance.

sftp_read() now uses the read-ahead logic to figure out a window_size.
This commit is contained in:
Daniel Stenberg 2011-09-09 13:54:12 +02:00
parent 7d58994571
commit 03ca902075
2 changed files with 40 additions and 31 deletions

View File

@ -1734,6 +1734,9 @@ libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel,
* It is important to not return 0 until the currently read channel is
* complete. If we read stuff from the wire but it was no payload data to fill
* in the buffer with, we MUST make sure to return LIBSSH2_ERROR_EAGAIN.
*
* The receive window must be maintained (enlarged) by the user of this
* function.
*/
ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id,
char *buf, size_t buflen)
@ -1755,15 +1758,6 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id,
channel->read_state = libssh2_NB_state_created;
}
/*
* =============================== NOTE ===============================
* I know this is very ugly and not a really good use of "goto", but
* this case statement would be even uglier to do it any other way
*/
if (channel->read_state == libssh2_NB_state_jump1) {
goto channel_read_window_adjust;
}
rc = 1; /* set to >0 to let the while loop start */
/* Process all pending incoming packets in all states in order to "even
@ -1872,26 +1866,6 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id,
more off the network again */
channel->read_state = libssh2_NB_state_created;
if(channel->remote.window_size < (LIBSSH2_CHANNEL_WINDOW_DEFAULT*30)) {
/* the window is getting too narrow, expand it! */
channel_read_window_adjust:
channel->read_state = libssh2_NB_state_jump1;
/* the actual window adjusting may not finish so we need to deal with
this special state here */
rc = _libssh2_channel_receive_window_adjust(channel,
(LIBSSH2_CHANNEL_WINDOW_DEFAULT*60), 0, NULL);
if (rc)
return rc;
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
"channel_read() filled %d adjusted %d",
bytes_read, buflen);
/* continue in 'created' state to drain the already read packages
first before starting to empty the socket further */
channel->read_state = libssh2_NB_state_created;
}
return bytes_read;
}
@ -1904,16 +1878,29 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id,
* currently read channel is complete. If we read stuff from the wire but it
* was no payload data to fill in the buffer with, we MUST make sure to return
* LIBSSH2_ERROR_EAGAIN.
*
* This function will first make sure there's a receive window enough to
* receive a full buffer's wort of contents. An application may choose to
* adjust the receive window more to increase transfer performance.
*/
LIBSSH2_API ssize_t
libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id, char *buf,
size_t buflen)
{
int rc;
unsigned long recv_window;
if(!channel)
return LIBSSH2_ERROR_BAD_USE;
recv_window = libssh2_channel_window_read_ex(channel, NULL, NULL);
if(buflen > recv_window) {
BLOCK_ADJUST(rc, channel->session,
_libssh2_channel_receive_window_adjust(channel, buflen,
0, NULL));
}
BLOCK_ADJUST(rc, channel->session,
_libssh2_channel_read(channel, stream_id, buf, buflen));
return rc;

View File

@ -1111,8 +1111,10 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer,
having been acked - until we reach EOF. */
if(!filep->eof) {
size_t max_read_ahead = buffer_size*4;
if(max_read_ahead > LIBSSH2_CHANNEL_WINDOW_DEFAULT*30)
max_read_ahead = LIBSSH2_CHANNEL_WINDOW_DEFAULT*30;
unsigned long recv_window;
if(max_read_ahead > LIBSSH2_CHANNEL_WINDOW_DEFAULT*4)
max_read_ahead = LIBSSH2_CHANNEL_WINDOW_DEFAULT*4;
/* if the buffer_size passed in now is smaller than what has already
been sent, we risk getting count become a very large number */
@ -1137,6 +1139,26 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer,
buffer_size*4 amount of data so that we can return them very fast
in subsequent calls.
*/
recv_window = libssh2_channel_window_read_ex(sftp->channel,
NULL, NULL);
if(max_read_ahead > recv_window) {
/* more data will be asked for than what the window currently
allows, expand it! */
if(total_read)
/* since we risk getting EAGAIN below, we return here if
there is data available */
return total_read;
rc = _libssh2_channel_receive_window_adjust(sftp->channel,
max_read_ahead*8,
0, NULL);
/* if this returns EAGAIN, we will get back to this function
at next call */
if (rc)
return rc;
}
}
while(count > 0) {