mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-10 00:57:02 +02:00
MEDIUM: channel: implement a zero-copy buffer transfer
bi_swpbuf() swaps the buffer passed in argument with the one attached to the channel, but only if this last one is empty. The idea is to avoid a copy when buffers can simply be swapped.
This commit is contained in:
parent
33cb065348
commit
b034b2598d
@ -43,6 +43,7 @@ unsigned long long __channel_forward(struct channel *chn, unsigned long long byt
|
||||
|
||||
/* SI-to-channel functions working with buffers */
|
||||
int bi_putblk(struct channel *chn, const char *str, int len);
|
||||
struct buffer *bi_swpbuf(struct channel *chn, struct buffer *buf);
|
||||
int bi_putchr(struct channel *chn, char c);
|
||||
int bo_inject(struct channel *chn, const char *msg, int len);
|
||||
int bo_getline(struct channel *chn, char *str, int len);
|
||||
|
@ -196,6 +196,51 @@ int bi_putblk(struct channel *chn, const char *blk, int len)
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Tries to copy the whole buffer <buf> into the channel's buffer after length
|
||||
* controls. It will only succeed if the target buffer is empty, in which case
|
||||
* it will simply swap the buffers. The buffer not attached to the channel is
|
||||
* returned so that the caller can store it locally. The chn->buf->o and
|
||||
* to_forward pointers are updated. If the output buffer is a dummy buffer or
|
||||
* if it still contains data <buf> is returned, indicating that nothing could
|
||||
* be done. Channel flag READ_PARTIAL is updated if some data can be transferred.
|
||||
* The chunk's length is updated with the number of bytes sent. On errors, NULL
|
||||
* is returned. Note that only buf->i is considered.
|
||||
*/
|
||||
struct buffer *bi_swpbuf(struct channel *chn, struct buffer *buf)
|
||||
{
|
||||
struct buffer *old;
|
||||
|
||||
if (unlikely(channel_input_closed(chn)))
|
||||
return NULL;
|
||||
|
||||
if (!chn->buf->size || !buffer_empty(chn->buf)) {
|
||||
chn->flags |= CF_WAKE_WRITE;
|
||||
return buf;
|
||||
}
|
||||
|
||||
old = chn->buf;
|
||||
chn->buf = buf;
|
||||
|
||||
if (!buf->i)
|
||||
return old;
|
||||
|
||||
chn->total += buf->i;
|
||||
|
||||
if (chn->to_forward) {
|
||||
unsigned long fwd = buf->i;
|
||||
if (chn->to_forward != CHN_INFINITE_FORWARD) {
|
||||
if (fwd > chn->to_forward)
|
||||
fwd = chn->to_forward;
|
||||
chn->to_forward -= fwd;
|
||||
}
|
||||
b_adv(chn->buf, fwd);
|
||||
}
|
||||
|
||||
/* notify that some data was read from the SI into the buffer */
|
||||
chn->flags |= CF_READ_PARTIAL;
|
||||
return old;
|
||||
}
|
||||
|
||||
/* Gets one text line out of a channel's buffer from a stream interface.
|
||||
* Return values :
|
||||
* >0 : number of bytes read. Includes the \n if present before len or end.
|
||||
|
Loading…
Reference in New Issue
Block a user