Skip to content

Docs on safety of BufWriter are misleading #136025

Open
@rgr21

Description

@rgr21

Location

/// It can be excessively inefficient to work directly with something that

Summary

This one is long winded. Sorry. A reader may decide this represents an actual code bug. I believe it is at least a documentation bug. I may just be rediscovering something every other programmer already knows.

let mut file = std::fs::File::create("test")?;
file.write_all(b"Hello, world!")?;
file.flush()?; // This does nothing. It is implemented as return Ok()
file.sync_all()?; // This issues an fsync
drop(file); // Close happens here. Docs correctly say that errors are ignored, sync_all *must* have happened to force the fsync.

In my scenario I am writing a file to an NFS mount from Linux. The syscalls are of the pattern open+write+write+...+close.
Close can fail, and that can prevent data from previous writes (which reported success) from being actually saved. I have no way of seeing the output of close. So I need to call sync_all, giving me a safe open+write+write+...+fsync+close.

/// It can be excessively inefficient to work directly with something that

/// It can be excessively inefficient to work directly with something that
/// implements [Write]. [...]
///
/// BufWriter<W> can improve the speed of programs that make small and
/// repeated write calls to the same file or network socket. [...]
///
/// It is critical to call [flush] before BufWriter<W> is dropped. Though
/// dropping will attempt to flush the contents of the buffer, any errors
/// that happen in the process of dropping will be ignored. Calling [flush]
/// ensures that the buffer is empty and thus dropping will not even attempt
/// file operations.

This really advertises itself for the use case

let mut buf = BufWriter::new(std::fs::File::create("test")?)

and then gives guidance on how to use it safely. This talks about errors during drop being lost (correct), says that calling flush is critical (true, but in a misleading way as the call to the inner file.flush is pointless). It does talk about files, not any old Write, steering me further towards madness.

Because I need to call

buf.into_inner()?.sync_all()?;

to avoid risk of silent data loss that is otherwise unobservable to the application.

I propose changing the wording at

/// It is critical to call [`flush`] before `BufWriter<W>` is dropped. Though
to indicate that flush is necessary but not sufficient, and perhaps also adding as an example use of into_inner().

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-docsArea: Documentation for any part of the project, including the compiler, standard library, and toolsT-libsRelevant to the library team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions