summaryrefslogtreecommitdiff
path: root/base/files/important_file_writer.h
diff options
context:
space:
mode:
Diffstat (limited to 'base/files/important_file_writer.h')
-rw-r--r--base/files/important_file_writer.h59
1 files changed, 29 insertions, 30 deletions
diff --git a/base/files/important_file_writer.h b/base/files/important_file_writer.h
index 0bd8a7fd35..f154b043b2 100644
--- a/base/files/important_file_writer.h
+++ b/base/files/important_file_writer.h
@@ -20,24 +20,21 @@
namespace base {
class SequencedTaskRunner;
-class Thread;
-// Helper to ensure that a file won't be corrupted by the write (for example on
-// application crash). Consider a naive way to save an important file F:
+// Helper for atomically writing a file to ensure that it won't be corrupted by
+// *application* crash during write (implemented as create, flush, rename).
//
-// 1. Open F for writing, truncating it.
-// 2. Write new data to F.
+// As an added benefit, ImportantFileWriter makes it less likely that the file
+// is corrupted by *system* crash, though even if the ImportantFileWriter call
+// has already returned at the time of the crash it is not specified which
+// version of the file (old or new) is preserved. And depending on system
+// configuration (hardware and software) a significant likelihood of file
+// corruption may remain, thus using ImportantFileWriter is not a valid
+// substitute for file integrity checks and recovery codepaths for malformed
+// files.
//
-// It's good when it works, but it gets very bad if step 2. doesn't complete.
-// It can be caused by a crash, a computer hang, or a weird I/O error. And you
-// end up with a broken file.
-//
-// To be safe, we don't start with writing directly to F. Instead, we write to
-// to a temporary file. Only after that write is successful, we rename the
-// temporary file to target filename.
-//
-// If you want to know more about this approach and ext3/ext4 fsync issues, see
-// http://blog.valerieaurora.org/2009/04/16/dont-panic-fsync-ext34-and-your-data/
+// Also note that ImportantFileWriter can be *really* slow (cf. File::Flush()
+// for details) and thus please don't block shutdown on ImportantFileWriter.
class BASE_EXPORT ImportantFileWriter : public NonThreadSafe {
public:
// Used by ScheduleSave to lazily provide the data to be saved. Allows us
@@ -53,8 +50,9 @@ class BASE_EXPORT ImportantFileWriter : public NonThreadSafe {
virtual ~DataSerializer() {}
};
- // Save |data| to |path| in an atomic manner (see the class comment above).
- // Blocks and writes data on the current thread.
+ // Save |data| to |path| in an atomic manner. Blocks and writes data on the
+ // current thread. Does not guarantee file integrity across system crash (see
+ // the class comment above).
static bool WriteFileAtomically(const FilePath& path, StringPiece data);
// Initialize the writer.
@@ -95,25 +93,26 @@ class BASE_EXPORT ImportantFileWriter : public NonThreadSafe {
// Serialize data pending to be saved and execute write on backend thread.
void DoScheduledWrite();
- // Registers |on_next_successful_write| to be called once, on the next
- // successful write event. Only one callback can be set at once.
- void RegisterOnNextSuccessfulWriteCallback(
- const Closure& on_next_successful_write);
+ // Registers |before_next_write_callback| and |after_next_write_callback| to
+ // be synchronously invoked from WriteFileAtomically() before its next write
+ // and after its next write, respectively. The boolean passed to
+ // |after_next_write_callback| indicates whether the write was successful.
+ // Both callbacks must be thread safe as they will be called on |task_runner_|
+ // and may be called during Chrome shutdown.
+ // If called more than once before a write is scheduled on |task_runner|, the
+ // latest callbacks clobber the others.
+ void RegisterOnNextWriteCallbacks(
+ const Closure& before_next_write_callback,
+ const Callback<void(bool success)>& after_next_write_callback);
TimeDelta commit_interval() const {
return commit_interval_;
}
private:
- // Helper method for WriteNow().
- bool PostWriteTask(const Callback<bool()>& task);
-
- // If |result| is true and |on_next_successful_write_| is set, invokes
- // |on_successful_write_| and then resets it; no-ops otherwise.
- void ForwardSuccessfulWrite(bool result);
-
- // Invoked once and then reset on the next successful write event.
- Closure on_next_successful_write_;
+ // Invoked synchronously on the next write event.
+ Closure before_next_write_callback_;
+ Callback<void(bool success)> after_next_write_callback_;
// Path being written to.
const FilePath path_;