Do round-robin writes of at most 16 kB per write. This might

be more fair on loaded Tor servers, and it might resolve our
Windows crash bug. It might also slow things down.


svn:r5332
This commit is contained in:
Roger Dingledine 2005-10-29 18:19:37 +00:00
parent 862e8a1bd1
commit bf2be9abd7
4 changed files with 53 additions and 20 deletions

View File

@ -576,21 +576,19 @@ flush_buf_impl(int s, buf_t *buf, size_t sz, size_t *buf_flushlen)
return 0;
} else {
*buf_flushlen -= write_result;
buf_remove_from_front(buf, write_result);
return write_result;
}
}
/** Write data from <b>buf</b> to the socket <b>s</b>. Write at most
* *<b>buf_flushlen</b> bytes, decrement *<b>buf_flushlen</b> by
* <b>sz</b> bytes, decrement *<b>buf_flushlen</b> by
* the number of bytes actually written, and remove the written bytes
* from the buffer. Return the number of bytes written on success,
* -1 on failure. Return 0 if write() would block.
*/
int
flush_buf(int s, buf_t *buf, size_t *buf_flushlen)
flush_buf(int s, buf_t *buf, size_t sz, size_t *buf_flushlen)
{
int r;
size_t flushed = 0;
@ -600,11 +598,12 @@ flush_buf(int s, buf_t *buf, size_t *buf_flushlen)
tor_assert(buf_flushlen);
tor_assert(s>=0);
tor_assert(*buf_flushlen <= buf->datalen);
tor_assert(sz <= *buf_flushlen);
if (*buf_flushlen == 0) /* nothing to flush */
if (sz == 0) /* nothing to flush */
return 0;
flushlen0 = *buf_flushlen;
flushlen0 = sz;
_split_range(buf, buf->cur, &flushlen0, &flushlen1);
r = flush_buf_impl(s, buf, flushlen0, buf_flushlen);
@ -653,7 +652,7 @@ flush_buf_tls_impl(tor_tls_t *tls, buf_t *buf, size_t sz, size_t *buf_flushlen)
/** As flush_buf(), but writes data to a TLS connection.
*/
int
flush_buf_tls(tor_tls_t *tls, buf_t *buf, size_t *buf_flushlen)
flush_buf_tls(tor_tls_t *tls, buf_t *buf, size_t sz, size_t *buf_flushlen)
{
int r;
size_t flushed=0;
@ -661,12 +660,14 @@ flush_buf_tls(tor_tls_t *tls, buf_t *buf, size_t *buf_flushlen)
assert_buf_ok(buf);
tor_assert(tls);
tor_assert(buf_flushlen);
tor_assert(*buf_flushlen <= buf->datalen);
tor_assert(sz <= *buf_flushlen);
/* we want to let tls write even if flushlen is zero, because it might
* have a partial record pending */
check_no_tls_errors();
flushlen0 = *buf_flushlen;
flushlen0 = sz;
_split_range(buf, buf->cur, &flushlen0, &flushlen1);
r = flush_buf_tls_impl(tls, buf, flushlen0, buf_flushlen);

View File

@ -23,7 +23,6 @@ static int connection_finished_connecting(connection_t *conn);
static int connection_reached_eof(connection_t *conn);
static int connection_read_to_buf(connection_t *conn, int *max_to_read);
static int connection_process_inbuf(connection_t *conn, int package_partial);
static int connection_bucket_read_limit(connection_t *conn);
static void client_check_address_changed(int sock);
static uint32_t last_interface_ip = 0;
@ -983,6 +982,29 @@ connection_bucket_read_limit(connection_t *conn)
return at_most;
}
/** How many bytes at most can we write onto this connection? */
int
connection_bucket_write_limit(connection_t *conn)
{
int at_most;
/* do a rudimentary round-robin so one circuit can't hog a connection */
if (connection_speaks_cells(conn)) {
at_most = 32*(CELL_NETWORK_SIZE);
} else {
at_most = 32*(RELAY_PAYLOAD_SIZE);
}
if (at_most > conn->outbuf_flushlen)
at_most = conn->outbuf_flushlen;
#if 0 /* don't enable til we actually do write limiting */
if (at_most > global_write_bucket)
at_most = global_write_bucket;
#endif
return at_most;
}
/** We just read num_read onto conn. Decrement buckets appropriately. */
static void
connection_read_bucket_decrement(connection_t *conn, int num_read)
@ -1317,6 +1339,7 @@ connection_handle_write(connection_t *conn)
int e;
socklen_t len=sizeof(e);
int result;
int max_to_write;
time_t now = time(NULL);
tor_assert(!connection_is_listener(conn));
@ -1359,6 +1382,8 @@ connection_handle_write(connection_t *conn)
return -1;
}
max_to_write = connection_bucket_write_limit(conn);
if (connection_speaks_cells(conn) && conn->state > OR_CONN_STATE_PROXY_READING) {
if (conn->state == OR_CONN_STATE_HANDSHAKING) {
connection_stop_writing(conn);
@ -1371,7 +1396,8 @@ connection_handle_write(connection_t *conn)
}
/* else open, or closing */
result = flush_buf_tls(conn->tls, conn->outbuf, &conn->outbuf_flushlen);
result = flush_buf_tls(conn->tls, conn->outbuf,
max_to_write, &conn->outbuf_flushlen);
switch (result) {
case TOR_TLS_ERROR:
case TOR_TLS_CLOSE:
@ -1403,7 +1429,8 @@ connection_handle_write(connection_t *conn)
}
} else {
CONN_LOG_PROTECT(conn,
result = flush_buf(conn->s, conn->outbuf, &conn->outbuf_flushlen));
result = flush_buf(conn->s, conn->outbuf,
max_to_write, &conn->outbuf_flushlen));
if (result < 0) {
if (CONN_IS_EDGE(conn))
connection_edge_end_errno(conn, conn->cpath_layer);
@ -1429,7 +1456,8 @@ connection_handle_write(connection_t *conn)
return 0;
}
/* DOCDOC */
/* A controller event has just happened with such urgency that we
* need to write it onto controller <b>conn</b> immediately. */
void
_connection_controller_force_write(connection_t *conn)
{
@ -1445,7 +1473,8 @@ _connection_controller_force_write(connection_t *conn)
return;
CONN_LOG_PROTECT(conn,
result = flush_buf(conn->s, conn->outbuf, &conn->outbuf_flushlen));
result = flush_buf(conn->s, conn->outbuf,
conn->outbuf_flushlen, &conn->outbuf_flushlen));
if (result < 0) {
connection_close_immediate(conn); /* Don't flush; connection is dead. */
connection_mark_for_close(conn);

View File

@ -439,8 +439,9 @@ conn_close_if_marked(int i)
debug(LD_NET,"Cleaning up connection (fd %d).",conn->s);
if (conn->s >= 0 && connection_wants_to_flush(conn)) {
/* -1 means it's an incomplete edge connection, or that the socket
/* s == -1 means it's an incomplete edge connection, or that the socket
* has already been closed as unflushable. */
int sz = connection_bucket_write_limit(conn);
if (!conn->hold_open_until_flushed)
info(LD_NET,
"Conn (addr %s, fd %d, type %s, state %d) marked, but wants to flush %d bytes. "
@ -449,14 +450,15 @@ conn_close_if_marked(int i)
(int)conn->outbuf_flushlen, conn->marked_for_close_file, conn->marked_for_close);
if (connection_speaks_cells(conn)) {
if (conn->state == OR_CONN_STATE_OPEN) {
retval = flush_buf_tls(conn->tls, conn->outbuf, &conn->outbuf_flushlen);
retval = flush_buf_tls(conn->tls, conn->outbuf, sz, &conn->outbuf_flushlen);
} else
retval = -1; /* never flush non-open broken tls connections */
} else {
retval = flush_buf(conn->s, conn->outbuf, &conn->outbuf_flushlen);
retval = flush_buf(conn->s, conn->outbuf, sz, &conn->outbuf_flushlen);
}
if (retval >= 0 &&
conn->hold_open_until_flushed && connection_wants_to_flush(conn)) {
if (retval >= 0 && /* Technically, we could survive things like
TLS_WANT_WRITE here. But don't bother for now. */
conn->hold_open_until_flushed && connection_wants_to_flush(conn)) {
LOG_FN_CONN(conn,
(LOG_INFO,LD_NET,"Holding conn (fd %d) open for more flushing.",conn->s));
/* XXX should we reset timestamp_lastwritten here? */

View File

@ -1363,8 +1363,8 @@ const char *_buf_peek_raw_buffer(const buf_t *buf);
int read_to_buf(int s, size_t at_most, buf_t *buf, int *reached_eof);
int read_to_buf_tls(tor_tls_t *tls, size_t at_most, buf_t *buf);
int flush_buf(int s, buf_t *buf, size_t *buf_flushlen);
int flush_buf_tls(tor_tls_t *tls, buf_t *buf, size_t *buf_flushlen);
int flush_buf(int s, buf_t *buf, size_t sz, size_t *buf_flushlen);
int flush_buf_tls(tor_tls_t *tls, buf_t *buf, size_t sz, size_t *buf_flushlen);
int write_to_buf(const char *string, size_t string_len, buf_t *buf);
int fetch_from_buf(char *string, size_t string_len, buf_t *buf);
@ -1541,6 +1541,7 @@ int connection_connect(connection_t *conn, char *address, uint32_t addr, uint16_
int retry_all_listeners(int force, smartlist_t *replaced_conns,
smartlist_t *new_conns);
int connection_bucket_write_limit(connection_t *conn);
void connection_bucket_init(void);
void connection_bucket_refill(struct timeval *now);