From 8c5200b5689e9612a59c12d28e71a716efac2830 Mon Sep 17 00:00:00 2001 From: Richard Nyberg Date: Mon, 6 Nov 2006 08:48:22 +0000 Subject: [PATCH] Instead of immediately reading all data a peer requests into outgoing net buffers, we put placeholder buffers on the list and fill them as they are needed. At most 4 blocks will be filled per peer we upload to. This number should probably be made tunable or be based on SO_SNDBUF or something. Anyway, this should lower btpd's memory usage if one has many uploads. --- btpd/net.c | 18 ++++++++++++++++++ btpd/net_buf.c | 19 +++++++++++++++++-- btpd/net_buf.h | 5 ++++- btpd/peer.c | 17 +++++++---------- 4 files changed, 46 insertions(+), 13 deletions(-) diff --git a/btpd/net.c b/btpd/net.c index 17271f0..5551221 100644 --- a/btpd/net.c +++ b/btpd/net.c @@ -134,6 +134,8 @@ net_read32(const void *buf) | (uint16_t)*(p + 2) << 8 | *(p + 3); } +#define BLOCK_MEM_COUNT 4 + static unsigned long net_write(struct peer *p, unsigned long wmax) { @@ -143,13 +145,29 @@ net_write(struct peer *p, unsigned long wmax) int limited; ssize_t nwritten; unsigned long bcount; + int block_count = 0; limited = wmax > 0; niov = 0; assert((nl = BTPDQ_FIRST(&p->outq)) != NULL); + if (nl->nb->type == NB_TORRENTDATA) + block_count = 1; while ((niov < IOV_MAX && nl != NULL && (!limited || (limited && wmax > 0)))) { + if (nl->nb->type == NB_PIECE) { + if (block_count >= BLOCK_MEM_COUNT) + break; + struct net_buf *tdata = BTPDQ_NEXT(nl, entry)->nb; + if (tdata->buf == NULL) { + if (nb_torrentdata_fill(tdata, p->n->tp, nb_get_index(nl->nb), + nb_get_begin(nl->nb), nb_get_length(nl->nb)) != 0) { + peer_kill(p); + return 0; + } + } + block_count++; + } if (niov > 0) { iov[niov].iov_base = nl->nb->buf; iov[niov].iov_len = nl->nb->len; diff --git a/btpd/net_buf.c b/btpd/net_buf.c index 6827c9c..1206ef8 100644 --- a/btpd/net_buf.c +++ b/btpd/net_buf.c @@ -90,13 +90,28 @@ nb_create_piece(uint32_t index, uint32_t begin, size_t blen) } struct net_buf * -nb_create_torrentdata(char *block, size_t blen) +nb_create_torrentdata(void) { struct net_buf *out; - out = nb_create_set(NB_TORRENTDATA, block, blen, kill_buf_free); + out = nb_create_set(NB_TORRENTDATA, NULL, 0, kill_buf_no); return out; } +int +nb_torrentdata_fill(struct net_buf *nb, struct torrent *tp, uint32_t index, + uint32_t begin, uint32_t length) +{ + int err; + uint8_t *content; + assert(nb->type == NB_TORRENTDATA && nb->buf == NULL); + if ((err = cm_get_bytes(tp, index, begin, length, &content)) != 0) + return err; + nb->buf = content; + nb->len = length; + nb->kill_buf = kill_buf_free; + return 0; +} + struct net_buf * nb_create_request(uint32_t index, uint32_t begin, uint32_t length) { diff --git a/btpd/net_buf.h b/btpd/net_buf.h index a04bcd7..aa9755c 100644 --- a/btpd/net_buf.h +++ b/btpd/net_buf.h @@ -36,7 +36,7 @@ struct peer; struct net_buf *nb_create_keepalive(void); struct net_buf *nb_create_piece(uint32_t index, uint32_t begin, size_t blen); -struct net_buf *nb_create_torrentdata(char *block, size_t blen); +struct net_buf *nb_create_torrentdata(void); struct net_buf *nb_create_request(uint32_t index, uint32_t begin, uint32_t length); struct net_buf *nb_create_cancel(uint32_t index, @@ -51,6 +51,9 @@ struct net_buf *nb_create_bitfield(struct torrent *tp); struct net_buf *nb_create_bitdata(struct torrent *tp); struct net_buf *nb_create_shake(struct torrent *tp); +int nb_torrentdata_fill(struct net_buf *nb, struct torrent *tp, uint32_t index, + uint32_t begin, uint32_t length); + int nb_drop(struct net_buf *nb); void nb_hold(struct net_buf *nb); diff --git a/btpd/peer.c b/btpd/peer.c index cb34585..864acb0 100644 --- a/btpd/peer.c +++ b/btpd/peer.c @@ -489,16 +489,13 @@ peer_on_request(struct peer *p, uint32_t index, uint32_t begin, btpd_log(BTPD_L_MSG, "received request(%u,%u,%u) from %p\n", index, begin, length, p); if ((p->flags & PF_NO_REQUESTS) == 0) { - uint8_t *content; - if (cm_get_bytes(p->n->tp, index, begin, length, &content) == 0) { - peer_send(p, nb_create_piece(index, begin, length)); - peer_send(p, nb_create_torrentdata(content, length)); - p->npiece_msgs++; - if (p->npiece_msgs >= MAXPIECEMSGS) { - peer_send(p, nb_create_choke()); - peer_send(p, nb_create_unchoke()); - p->flags |= PF_NO_REQUESTS; - } + peer_send(p, nb_create_piece(index, begin, length)); + peer_send(p, nb_create_torrentdata()); + p->npiece_msgs++; + if (p->npiece_msgs >= MAXPIECEMSGS) { + peer_send(p, nb_create_choke()); + peer_send(p, nb_create_unchoke()); + p->flags |= PF_NO_REQUESTS; } } }