[systemd-devel] [PATCH 2/2] journald: when buffering stdout, allow buffer to grow if needed
Zbigniew Jędrzejewski-Szmek
zbyszek at in.waw.pl
Tue Dec 10 04:22:57 PST 2013
On Sun, Dec 08, 2013 at 11:32:34AM -0600, Dan McGee wrote:
> When logging really long lines (e.g. those without an '\n') to journald
> via capture of stdout, the hardcoded buffer length of LINE_MAX limited
> us to processing the data in 2KB chunks. This is rather inefficient if
> we are getting a 1+ MB message handed to us.
>
> Actual case is via a unit file where PostgreSQL logs via stdout and
> emits slow query logs. When the slow query is a long multi-row insert
> statement, it can often be a megabyte or more of text. Rather than
> process this as one message and going down the stack to the compression
> code just once, we were doing it for each and every 2K read() call.
> ---
>
> As stated in the prior patch, if there is some preexisting dynamic buffer stuff
> I should be using, please let me know.
See below.
> Here is a brief test script that stresses the stdout capture. Run it through
> systemd-run and watch the CPU usage of the systemd-journal process before and
> after.
>
> #!/usr/bin/env python2
>
> data = []
> for i in range(1000):
> data.append('abcdefghijklmnopqrstuvwxyz')
> data.append('%d' % i)
>
> print ' '.join(data * 5)
> print ' '.join(data * 15)
> print ' '.join(data * 25)
>
>
> src/journal/journald-stream.c | 19 ++++++++++++++++++-
> 1 file changed, 18 insertions(+), 1 deletion(-)
>
> diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c
> index 193d438..890c0bf 100644
> --- a/src/journal/journald-stream.c
> +++ b/src/journal/journald-stream.c
> @@ -236,6 +236,8 @@ static int stdout_stream_line(StdoutStream *s, char *p) {
> assert_not_reached("Unknown stream state");
> }
>
> +#define STDOUT_BUFFER_MAX 256*1024u
> +
> static int stdout_stream_scan(StdoutStream *s, bool force_flush) {
> char *p;
> size_t remaining;
> @@ -253,7 +255,22 @@ static int stdout_stream_scan(StdoutStream *s, bool force_flush) {
> if (end)
> skip = end - p + 1;
> else if (remaining >= s->size - 1) {
We have GREEDY_REALLOC which wraps the realloc() with exponential increase of size.
It doesn't test for maximum size, so you'll still have to do that.
> - /* ran out of buffer space, log what we have */
> + /* grow buffer up to max permitted size if possible; if
> + * we fail to alloc just use the old buffer. */
> + if (s->size < STDOUT_BUFFER_MAX) {
> + char *new_buffer;
> + size_t new_size;
> +
> + new_size = MIN(s->size * 2, STDOUT_BUFFER_MAX);
> + new_buffer = realloc(s->buffer, new_size);
> + if (new_buffer) {
> + p = new_buffer + (p - s->buffer);
> + memset(&new_buffer[s->size], 0, new_size-s->size);
I hope zeroing the buffer is not necessary. We should always know what
parts of it are filled.
> + s->size = new_size;
> + s->buffer = new_buffer;
> + }
> + break;
> + }
> end = s->buffer + s->size - 1;
> skip = remaining;
> } else
Zbyszek
More information about the systemd-devel
mailing list