1 // Copyright 2012 The Chromium Authors 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 <memory> 9 #include <string> 10 11 #include "base/base_export.h" 12 #include "base/files/file_path.h" 13 #include "base/functional/callback.h" 14 #include "base/memory/raw_ptr.h" 15 #include "base/sequence_checker.h" 16 #include "base/strings/string_piece.h" 17 #include "base/time/time.h" 18 #include "base/timer/timer.h" 19 #include "third_party/abseil-cpp/absl/types/optional.h" 20 #include "third_party/abseil-cpp/absl/types/variant.h" 21 22 namespace base { 23 24 class SequencedTaskRunner; 25 26 // Helper for atomically writing a file to ensure that it won't be corrupted by 27 // *application* crash during write (implemented as create, flush, rename). 28 // 29 // As an added benefit, ImportantFileWriter makes it less likely that the file 30 // is corrupted by *system* crash, though even if the ImportantFileWriter call 31 // has already returned at the time of the crash it is not specified which 32 // version of the file (old or new) is preserved. And depending on system 33 // configuration (hardware and software) a significant likelihood of file 34 // corruption may remain, thus using ImportantFileWriter is not a valid 35 // substitute for file integrity checks and recovery codepaths for malformed 36 // files. 37 // 38 // Also note that ImportantFileWriter can be *really* slow (cf. File::Flush() 39 // for details) and thus please don't block shutdown on ImportantFileWriter. 40 class BASE_EXPORT ImportantFileWriter { 41 public: 42 // Promise-like callback that returns (via output parameter) the serialized 43 // data to be written. This callback is invoked on the sequence where I/O 44 // operations are executed. Returning false indicates an error. 45 using BackgroundDataProducerCallback = 46 base::OnceCallback<absl::optional<std::string>()>; 47 48 // Used by ScheduleSave to lazily provide the data to be saved. Allows us 49 // to also batch data serializations. 50 class BASE_EXPORT DataSerializer { 51 public: 52 // Returns a string for serialisation when successful, or a nullopt in case 53 // it failed to generate the data. Will be called on the same thread on 54 // which ImportantFileWriter has been created. 55 virtual absl::optional<std::string> SerializeData() = 0; 56 57 protected: 58 virtual ~DataSerializer() = default; 59 }; 60 61 // Same as DataSerializer but allows the caller to move some of the 62 // serialization logic to the sequence where I/O operations are executed. 63 class BASE_EXPORT BackgroundDataSerializer { 64 public: 65 // Returns a promise-like callback that, when invoked, will produce the 66 // serialized string. This getter itself will be called on the same thread 67 // on which ImportantFileWriter has been created, but the callback will be 68 // invoked from the sequence where I/O operations are executed. 69 virtual BackgroundDataProducerCallback 70 GetSerializedDataProducerForBackgroundSequence() = 0; 71 72 protected: 73 virtual ~BackgroundDataSerializer() = default; 74 }; 75 76 // Save |data| to |path| in an atomic manner. Blocks and writes data on the 77 // current thread. Does not guarantee file integrity across system crash (see 78 // the class comment above). 79 static bool WriteFileAtomically(const FilePath& path, 80 StringPiece data, 81 StringPiece histogram_suffix = StringPiece()); 82 83 // Initialize the writer. 84 // |path| is the name of file to write. 85 // |task_runner| is the SequencedTaskRunner instance where on which we will 86 // execute file I/O operations. 87 // All non-const methods, ctor and dtor must be called on the same thread. 88 ImportantFileWriter(const FilePath& path, 89 scoped_refptr<SequencedTaskRunner> task_runner, 90 StringPiece histogram_suffix = StringPiece()); 91 92 // Same as above, but with a custom commit interval. 93 ImportantFileWriter(const FilePath& path, 94 scoped_refptr<SequencedTaskRunner> task_runner, 95 TimeDelta interval, 96 StringPiece histogram_suffix = StringPiece()); 97 98 ImportantFileWriter(const ImportantFileWriter&) = delete; 99 ImportantFileWriter& operator=(const ImportantFileWriter&) = delete; 100 101 // You have to ensure that there are no pending writes at the moment 102 // of destruction. 103 ~ImportantFileWriter(); 104 path()105 const FilePath& path() const { return path_; } 106 107 // Returns true if there is a scheduled write pending which has not yet 108 // been started. 109 bool HasPendingWrite() const; 110 111 // Save |data| to target filename. Does not block. If there is a pending write 112 // scheduled by ScheduleWrite(), it is cancelled. 113 void WriteNow(std::string data); 114 115 // Schedule a save to target filename. Data will be serialized and saved 116 // to disk after the commit interval. If another ScheduleWrite is issued 117 // before that, only one serialization and write to disk will happen, and 118 // the most recent |serializer| will be used. This operation does not block. 119 // |serializer| should remain valid through the lifetime of 120 // ImportantFileWriter. 121 void ScheduleWrite(DataSerializer* serializer); 122 123 // Same as above but uses the BackgroundDataSerializer API. 124 void ScheduleWriteWithBackgroundDataSerializer( 125 BackgroundDataSerializer* serializer); 126 127 // Serialize data pending to be saved and execute write on background thread. 128 void DoScheduledWrite(); 129 130 // Registers |before_next_write_callback| and |after_next_write_callback| to 131 // be synchronously invoked from WriteFileAtomically() before its next write 132 // and after its next write, respectively. The boolean passed to 133 // |after_next_write_callback| indicates whether the write was successful. 134 // Both callbacks must be thread safe as they will be called on |task_runner_| 135 // and may be called during Chrome shutdown. 136 // If called more than once before a write is scheduled on |task_runner|, the 137 // latest callbacks clobber the others. 138 void RegisterOnNextWriteCallbacks( 139 OnceClosure before_next_write_callback, 140 OnceCallback<void(bool success)> after_next_write_callback); 141 commit_interval()142 TimeDelta commit_interval() const { 143 return commit_interval_; 144 } 145 146 // Overrides the timer to use for scheduling writes with |timer_override|. 147 void SetTimerForTesting(OneShotTimer* timer_override); 148 149 #if defined(UNIT_TEST) previous_data_size()150 size_t previous_data_size() const { return previous_data_size_; } 151 #endif set_previous_data_size(size_t previous_data_size)152 void set_previous_data_size(size_t previous_data_size) { 153 previous_data_size_ = previous_data_size; 154 } 155 156 private: timer()157 const OneShotTimer& timer() const { 158 return timer_override_ ? *timer_override_ : timer_; 159 } timer()160 OneShotTimer& timer() { return timer_override_ ? *timer_override_ : timer_; } 161 162 // Same as WriteNow() but it uses a promise-like signature that allows running 163 // custom logic in the background sequence. 164 void WriteNowWithBackgroundDataProducer( 165 BackgroundDataProducerCallback background_producer); 166 167 // Helper function to call WriteFileAtomically() with a promise-like callback 168 // producing a std::string. 169 static void ProduceAndWriteStringToFileAtomically( 170 const FilePath& path, 171 BackgroundDataProducerCallback data_producer_for_background_sequence, 172 OnceClosure before_write_callback, 173 OnceCallback<void(bool success)> after_write_callback, 174 const std::string& histogram_suffix); 175 176 // Writes |data| to |path|, recording histograms with an optional 177 // |histogram_suffix|. |from_instance| indicates whether the call originates 178 // from an instance of ImportantFileWriter or a direct call to 179 // WriteFileAtomically. When false, the directory containing |path| is added 180 // to the set cleaned by the ImportantFileWriterCleaner (Windows only). 181 static bool WriteFileAtomicallyImpl(const FilePath& path, 182 StringPiece data, 183 StringPiece histogram_suffix, 184 bool from_instance); 185 186 void ClearPendingWrite(); 187 188 // Invoked synchronously on the next write event. 189 OnceClosure before_next_write_callback_; 190 OnceCallback<void(bool success)> after_next_write_callback_; 191 192 // Path being written to. 193 const FilePath path_; 194 195 // TaskRunner for the thread on which file I/O can be done. 196 const scoped_refptr<SequencedTaskRunner> task_runner_; 197 198 // Timer used to schedule commit after ScheduleWrite. 199 OneShotTimer timer_; 200 201 // An override for |timer_| used for testing. 202 raw_ptr<OneShotTimer> timer_override_ = nullptr; 203 204 // Serializer which will provide the data to be saved. 205 absl::variant<absl::monostate, DataSerializer*, BackgroundDataSerializer*> 206 serializer_; 207 208 // Time delta after which scheduled data will be written to disk. 209 const TimeDelta commit_interval_; 210 211 // Custom histogram suffix. 212 const std::string histogram_suffix_; 213 214 // Memorizes the amount of data written on the previous write. This helps 215 // preallocating memory for the data serialization. It is only used for 216 // scheduled writes. 217 size_t previous_data_size_ = 0; 218 219 SEQUENCE_CHECKER(sequence_checker_); 220 221 WeakPtrFactory<ImportantFileWriter> weak_factory_{this}; 222 }; 223 224 } // namespace base 225 226 #endif // BASE_FILES_IMPORTANT_FILE_WRITER_H_ 227