Skip to content

GzDecoder eager reading in the constructor blocks IO #368

Open
@cgbur

Description

@cgbur

Currently the GzDecoder new method eagerly attempts to read the header information in the constructor. It has match statements for if the io should be non-blocking, but in general this will never happen. I think it would be more proper to follow the usual pattern of constructors in Rust not doing work by trying to read the underlying stream, and instead lazily determine the state when a read is requested.

The case where this eager reading behavior is a problem is when there are multiple fifo stream being initialized. The first decoder created will block on trying to read from the underlying stream before any work as been done, preventing the rest of the application from working. I don't think it is technically incorrect, but in general Rust prefers being lazy with computation especially when it has side effects.

The current workaround that I have to use to avoid generating read syscalls during construction is pretty hacky:

enum LazyGzipReader {
    Uninitialized(File),
    Initialized(MultiGzDecoder<BufReader<File>>),
}

impl Read for LazyGzipReader {
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        match self {
            LazyGzipReader::Uninitialized(file) => {
                *self = LazyGzipReader::Initialized(MultiGzDecoder::new(BufReader::new(
                    file.try_clone()?,
                )));
                self.read(buf)
            }
            LazyGzipReader::Initialized(reader) => reader.read(buf),
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions