1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef BASE_FILES_IMPORTANT_FILE_WRITER_H_
6#define BASE_FILES_IMPORTANT_FILE_WRITER_H_
7
8#include <string>
9
10#include "base/base_export.h"
11#include "base/callback.h"
12#include "base/files/file_path.h"
13#include "base/macros.h"
14#include "base/memory/ref_counted.h"
15#include "base/strings/string_piece.h"
16#include "base/threading/non_thread_safe.h"
17#include "base/time/time.h"
18#include "base/timer/timer.h"
19
20namespace base {
21
22class SequencedTaskRunner;
23
24// Helper for atomically writing a file to ensure that it won't be corrupted by
25// *application* crash during write (implemented as create, flush, rename).
26//
27// As an added benefit, ImportantFileWriter makes it less likely that the file
28// is corrupted by *system* crash, though even if the ImportantFileWriter call
29// has already returned at the time of the crash it is not specified which
30// version of the file (old or new) is preserved. And depending on system
31// configuration (hardware and software) a significant likelihood of file
32// corruption may remain, thus using ImportantFileWriter is not a valid
33// substitute for file integrity checks and recovery codepaths for malformed
34// files.
35//
36// Also note that ImportantFileWriter can be *really* slow (cf. File::Flush()
37// for details) and thus please don't block shutdown on ImportantFileWriter.
38class BASE_EXPORT ImportantFileWriter : public NonThreadSafe {
39 public:
40  // Used by ScheduleSave to lazily provide the data to be saved. Allows us
41  // to also batch data serializations.
42  class BASE_EXPORT DataSerializer {
43   public:
44    // Should put serialized string in |data| and return true on successful
45    // serialization. Will be called on the same thread on which
46    // ImportantFileWriter has been created.
47    virtual bool SerializeData(std::string* data) = 0;
48
49   protected:
50    virtual ~DataSerializer() {}
51  };
52
53  // Save |data| to |path| in an atomic manner. Blocks and writes data on the
54  // current thread. Does not guarantee file integrity across system crash (see
55  // the class comment above).
56  static bool WriteFileAtomically(const FilePath& path, StringPiece data);
57
58  // Initialize the writer.
59  // |path| is the name of file to write.
60  // |task_runner| is the SequencedTaskRunner instance where on which we will
61  // execute file I/O operations.
62  // All non-const methods, ctor and dtor must be called on the same thread.
63  ImportantFileWriter(const FilePath& path,
64                      scoped_refptr<SequencedTaskRunner> task_runner);
65
66  // Same as above, but with a custom commit interval.
67  ImportantFileWriter(const FilePath& path,
68                      scoped_refptr<SequencedTaskRunner> task_runner,
69                      TimeDelta interval);
70
71  // You have to ensure that there are no pending writes at the moment
72  // of destruction.
73  ~ImportantFileWriter();
74
75  const FilePath& path() const { return path_; }
76
77  // Returns true if there is a scheduled write pending which has not yet
78  // been started.
79  bool HasPendingWrite() const;
80
81  // Save |data| to target filename. Does not block. If there is a pending write
82  // scheduled by ScheduleWrite(), it is cancelled.
83  void WriteNow(std::unique_ptr<std::string> data);
84
85  // Schedule a save to target filename. Data will be serialized and saved
86  // to disk after the commit interval. If another ScheduleWrite is issued
87  // before that, only one serialization and write to disk will happen, and
88  // the most recent |serializer| will be used. This operation does not block.
89  // |serializer| should remain valid through the lifetime of
90  // ImportantFileWriter.
91  void ScheduleWrite(DataSerializer* serializer);
92
93  // Serialize data pending to be saved and execute write on backend thread.
94  void DoScheduledWrite();
95
96  // Registers |before_next_write_callback| and |after_next_write_callback| to
97  // be synchronously invoked from WriteFileAtomically() before its next write
98  // and after its next write, respectively. The boolean passed to
99  // |after_next_write_callback| indicates whether the write was successful.
100  // Both callbacks must be thread safe as they will be called on |task_runner_|
101  // and may be called during Chrome shutdown.
102  // If called more than once before a write is scheduled on |task_runner|, the
103  // latest callbacks clobber the others.
104  void RegisterOnNextWriteCallbacks(
105      const Closure& before_next_write_callback,
106      const Callback<void(bool success)>& after_next_write_callback);
107
108  TimeDelta commit_interval() const {
109    return commit_interval_;
110  }
111
112 private:
113  // Invoked synchronously on the next write event.
114  Closure before_next_write_callback_;
115  Callback<void(bool success)> after_next_write_callback_;
116
117  // Path being written to.
118  const FilePath path_;
119
120  // TaskRunner for the thread on which file I/O can be done.
121  const scoped_refptr<SequencedTaskRunner> task_runner_;
122
123  // Timer used to schedule commit after ScheduleWrite.
124  OneShotTimer timer_;
125
126  // Serializer which will provide the data to be saved.
127  DataSerializer* serializer_;
128
129  // Time delta after which scheduled data will be written to disk.
130  const TimeDelta commit_interval_;
131
132  WeakPtrFactory<ImportantFileWriter> weak_factory_;
133
134  DISALLOW_COPY_AND_ASSIGN(ImportantFileWriter);
135};
136
137}  // namespace base
138
139#endif  // BASE_FILES_IMPORTANT_FILE_WRITER_H_
140