Thread

Commits

  1. pg_basebackup: Fix code that thinks about LZ4 buffer size.

  1. basebackup/lz4 crash

    Justin Pryzby <pryzby@telsasoft.com> — 2022-03-30T14:35:36Z

    Forking: <20220316151253.GB28503@telsasoft.com>
    
    On Wed, Mar 16, 2022 at 10:12:54AM -0500, Justin Pryzby wrote:
    > Also, with a partial regression DB, this crashes when writing to stdout.
    > 
    > $ src/bin/pg_basebackup/pg_basebackup --wal-method fetch -Ft -D - -h /tmp --no-sync --compress=lz4 |wc -c
    > pg_basebackup: bbstreamer_lz4.c:172: bbstreamer_lz4_compressor_content: Assertion `mystreamer->base.bbs_buffer.maxlen >= out_bound' failed.
    > 24117248
    > 
    > #4  0x000055555555e8b4 in bbstreamer_lz4_compressor_content (streamer=0x5555555a5260, member=0x7fffffffc760, 
    >     data=0x7ffff3068010 "{ \"PostgreSQL-Backup-Manifest-Version\": 1,\n\"Files\": [\n{ \"Path\": \"backup_label\", \"Size\": 227, \"Last-Modified\": \"2022-03-16 02:29:11 GMT\", \"Checksum-Algorithm\": \"CRC32C\", \"Checksum\": \"46f69d99\" },\n{ \"Pa"..., len=401072, context=BBSTREAMER_MEMBER_CONTENTS) at bbstreamer_lz4.c:172
    >         mystreamer = 0x5555555a5260
    >         next_in = 0x7ffff3068010 "{ \"PostgreSQL-Backup-Manifest-Version\": 1,\n\"Files\": [\n{ \"Path\": \"backup_label\", \"Size\": 227, \"Last-Modified\": \"2022-03-16 02:29:11 GMT\", \"Checksum-Algorithm\": \"CRC32C\", \"Checksum\": \"46f69d99\" },\n{ \"Pa"...
    >         ...
    > 
    > (gdb) p mystreamer->base.bbs_buffer.maxlen
    > $1 = 524288
    > (gdb) p (int) LZ4F_compressBound(len, &mystreamer->prefs)
    > $4 = 524300
    > 
    > This is with: liblz4-1:amd64 1.9.2-2ubuntu0.20.04.1
    
    It looks like maybe this code was copied from
    bbstreamer_lz4_compressor_finalize() which has an Assert rather than expanding
    the buffer like in bbstreamer_lz4_compressor_new()
    
    commit e70c12214b5ba0bc93c083fdb046304a633018ef
    Author: Justin Pryzby <pryzbyj@telsasoft.com>
    Date:   Mon Mar 28 23:24:15 2022 -0500
    
        basebackup: fix crash with lz4 + stdout + manifests
        
        That's just one known way to trigger this issue.
    
    diff --git a/src/bin/pg_basebackup/bbstreamer_lz4.c b/src/bin/pg_basebackup/bbstreamer_lz4.c
    index 67f841d96a9..8e8352a450c 100644
    --- a/src/bin/pg_basebackup/bbstreamer_lz4.c
    +++ b/src/bin/pg_basebackup/bbstreamer_lz4.c
    @@ -170,7 +170,11 @@ bbstreamer_lz4_compressor_content(bbstreamer *streamer,
     	 * forward the content to next streamer and empty the buffer.
     	 */
     	out_bound = LZ4F_compressBound(len, &mystreamer->prefs);
    -	Assert(mystreamer->base.bbs_buffer.maxlen >= out_bound);
    +
    +	/* Enlarge buffer if it falls short of compression bound. */
    +	if (mystreamer->base.bbs_buffer.maxlen < out_bound)
    +		enlargeStringInfo(&mystreamer->base.bbs_buffer, out_bound);
    +
     	if (avail_out < out_bound)
     	{
     			bbstreamer_content(mystreamer->base.bbs_next, member,
    
    
    
    
  2. Re: basebackup/lz4 crash

    Robert Haas <robertmhaas@gmail.com> — 2022-03-30T16:57:35Z

    On Wed, Mar 30, 2022 at 10:35 AM Justin Pryzby <pryzby@telsasoft.com> wrote:
    > It looks like maybe this code was copied from
    > bbstreamer_lz4_compressor_finalize() which has an Assert rather than expanding
    > the buffer like in bbstreamer_lz4_compressor_new()
    
    Hmm, this isn't great. On the server side, we set up a chain of bbsink
    buffers that can't be resized later. Each bbsink tells the next bbsink
    how to make its buffer, but the successor bbsink has control of that
    buffer and resizing it on-the-fly is not allowed. It looks like
    bbstreamer_lz4_compressor_new() is mimicking that logic, but not well.
    It sets the initial buffer size to
    LZ4F_compressBound(streamer->base.bbs_buffer.maxlen, prefs), but
    streamer->base.bbs_buffer.maxlen is not any kind of promise from the
    caller about future chunk sizes. It's just whatever initStringInfo()
    happens to do. My guess is that Dipesh thought that the buffer
    wouldn't need to be resized because "we made it big enough already"
    but that's not the case. The server knows how much data it is going to
    read from disk at a time, but the client has to deal with whatever the
    server sends.
    
    I think your proposed change is OK, modulo some comments. But I think
    maybe we ought to delete all the stuff related to compressed_bound
    from bbstreamer_lz4_compressor_new() as well, because I don't see that
    there's any point. And then I think we should also add logic similar
    to what you've added here to bbstreamer_lz4_compressor_finalize(), so
    that we're not making the assumption that the buffer will get enlarged
    at some earlier point.
    
    Thoughts?
    
    -- 
    Robert Haas
    EDB: http://www.enterprisedb.com
    
    
    
    
  3. Re: basebackup/lz4 crash

    Dipesh Pandit <dipesh.pandit@gmail.com> — 2022-03-31T07:19:32Z

    Hi,
    
    > I think your proposed change is OK, modulo some comments. But I think
    > maybe we ought to delete all the stuff related to compressed_bound
    > from bbstreamer_lz4_compressor_new() as well, because I don't see that
    > there's any point. And then I think we should also add logic similar
    > to what you've added here to bbstreamer_lz4_compressor_finalize(), so
    > that we're not making the assumption that the buffer will get enlarged
    > at some earlier point.
    >
    > Thoughts?
    I agree that we should remove the compression bound stuff from
    bbstreamer_lz4_compressor_new() and add a fix in
    bbstreamer_lz4_compressor_content() and bbstreamer_lz4_compressor_finalize()
    to enlarge the buffer if it falls short of the compress bound.
    
    Patch attached.
    
    Thanks,
    Dipesh
    
  4. Re: basebackup/lz4 crash

    Robert Haas <robertmhaas@gmail.com> — 2022-04-04T14:45:19Z

    On Thu, Mar 31, 2022 at 3:19 AM Dipesh Pandit <dipesh.pandit@gmail.com> wrote:
    > Patch attached.
    
    Committed. Thanks.
    
    -- 
    Robert Haas
    EDB: http://www.enterprisedb.com