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/basictypes.h" 12 #include "base/files/file_path.h" 13 #include "base/memory/ref_counted.h" 14 #include "base/threading/non_thread_safe.h" 15 #include "base/time/time.h" 16 #include "base/timer/timer.h" 17 18 namespace base { 19 20 class SequencedTaskRunner; 21 class Thread; 22 23 // Helper to ensure that a file won't be corrupted by the write (for example on 24 // application crash). Consider a naive way to save an important file F: 25 // 26 // 1. Open F for writing, truncating it. 27 // 2. Write new data to F. 28 // 29 // It's good when it works, but it gets very bad if step 2. doesn't complete. 30 // It can be caused by a crash, a computer hang, or a weird I/O error. And you 31 // end up with a broken file. 32 // 33 // To be safe, we don't start with writing directly to F. Instead, we write to 34 // to a temporary file. Only after that write is successful, we rename the 35 // temporary file to target filename. 36 // 37 // If you want to know more about this approach and ext3/ext4 fsync issues, see 38 // http://valhenson.livejournal.com/37921.html 39 class BASE_EXPORT ImportantFileWriter : public NonThreadSafe { 40 public: 41 // Used by ScheduleSave to lazily provide the data to be saved. Allows us 42 // to also batch data serializations. 43 class BASE_EXPORT DataSerializer { 44 public: 45 // Should put serialized string in |data| and return true on successful 46 // serialization. Will be called on the same thread on which 47 // ImportantFileWriter has been created. 48 virtual bool SerializeData(std::string* data) = 0; 49 50 protected: ~DataSerializer()51 virtual ~DataSerializer() {} 52 }; 53 54 // Save |data| to |path| in an atomic manner (see the class comment above). 55 // Blocks and writes data on the current thread. 56 static bool WriteFileAtomically(const FilePath& path, 57 const std::string& data); 58 59 // Initialize the writer. 60 // |path| is the name of file to write. 61 // |task_runner| is the SequencedTaskRunner instance where on which we will 62 // execute file I/O operations. 63 // All non-const methods, ctor and dtor must be called on the same thread. 64 ImportantFileWriter(const FilePath& path, 65 base::SequencedTaskRunner* task_runner); 66 67 // You have to ensure that there are no pending writes at the moment 68 // of destruction. 69 ~ImportantFileWriter(); 70 path()71 const FilePath& path() const { return path_; } 72 73 // Returns true if there is a scheduled write pending which has not yet 74 // been started. 75 bool HasPendingWrite() const; 76 77 // Save |data| to target filename. Does not block. If there is a pending write 78 // scheduled by ScheduleWrite, it is cancelled. 79 void WriteNow(const std::string& data); 80 81 // Schedule a save to target filename. Data will be serialized and saved 82 // to disk after the commit interval. If another ScheduleWrite is issued 83 // before that, only one serialization and write to disk will happen, and 84 // the most recent |serializer| will be used. This operation does not block. 85 // |serializer| should remain valid through the lifetime of 86 // ImportantFileWriter. 87 void ScheduleWrite(DataSerializer* serializer); 88 89 // Serialize data pending to be saved and execute write on backend thread. 90 void DoScheduledWrite(); 91 commit_interval()92 TimeDelta commit_interval() const { 93 return commit_interval_; 94 } 95 set_commit_interval(const TimeDelta & interval)96 void set_commit_interval(const TimeDelta& interval) { 97 commit_interval_ = interval; 98 } 99 100 private: 101 // Path being written to. 102 const FilePath path_; 103 104 // TaskRunner for the thread on which file I/O can be done. 105 const scoped_refptr<base::SequencedTaskRunner> task_runner_; 106 107 // Timer used to schedule commit after ScheduleWrite. 108 OneShotTimer<ImportantFileWriter> timer_; 109 110 // Serializer which will provide the data to be saved. 111 DataSerializer* serializer_; 112 113 // Time delta after which scheduled data will be written to disk. 114 TimeDelta commit_interval_; 115 116 DISALLOW_COPY_AND_ASSIGN(ImportantFileWriter); 117 }; 118 119 } // namespace base 120 121 #endif // BASE_FILES_IMPORTANT_FILE_WRITER_H_ 122