Home | History | Annotate | Download | only in files
      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/sequence_checker.h"
     16 #include "base/strings/string_piece.h"
     17 #include "base/time/time.h"
     18 #include "base/timer/timer.h"
     19 
     20 namespace base {
     21 
     22 class 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.
     38 class BASE_EXPORT ImportantFileWriter {
     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() = default;
     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,
     57                                   StringPiece data,
     58                                   StringPiece histogram_suffix = StringPiece());
     59 
     60   // Initialize the writer.
     61   // |path| is the name of file to write.
     62   // |task_runner| is the SequencedTaskRunner instance where on which we will
     63   // execute file I/O operations.
     64   // All non-const methods, ctor and dtor must be called on the same thread.
     65   ImportantFileWriter(const FilePath& path,
     66                       scoped_refptr<SequencedTaskRunner> task_runner,
     67                       const char* histogram_suffix = nullptr);
     68 
     69   // Same as above, but with a custom commit interval.
     70   ImportantFileWriter(const FilePath& path,
     71                       scoped_refptr<SequencedTaskRunner> task_runner,
     72                       TimeDelta interval,
     73                       const char* histogram_suffix = nullptr);
     74 
     75   // You have to ensure that there are no pending writes at the moment
     76   // of destruction.
     77   ~ImportantFileWriter();
     78 
     79   const FilePath& path() const { return path_; }
     80 
     81   // Returns true if there is a scheduled write pending which has not yet
     82   // been started.
     83   bool HasPendingWrite() const;
     84 
     85   // Save |data| to target filename. Does not block. If there is a pending write
     86   // scheduled by ScheduleWrite(), it is cancelled.
     87   void WriteNow(std::unique_ptr<std::string> data);
     88 
     89   // Schedule a save to target filename. Data will be serialized and saved
     90   // to disk after the commit interval. If another ScheduleWrite is issued
     91   // before that, only one serialization and write to disk will happen, and
     92   // the most recent |serializer| will be used. This operation does not block.
     93   // |serializer| should remain valid through the lifetime of
     94   // ImportantFileWriter.
     95   void ScheduleWrite(DataSerializer* serializer);
     96 
     97   // Serialize data pending to be saved and execute write on backend thread.
     98   void DoScheduledWrite();
     99 
    100   // Registers |before_next_write_callback| and |after_next_write_callback| to
    101   // be synchronously invoked from WriteFileAtomically() before its next write
    102   // and after its next write, respectively. The boolean passed to
    103   // |after_next_write_callback| indicates whether the write was successful.
    104   // Both callbacks must be thread safe as they will be called on |task_runner_|
    105   // and may be called during Chrome shutdown.
    106   // If called more than once before a write is scheduled on |task_runner|, the
    107   // latest callbacks clobber the others.
    108   void RegisterOnNextWriteCallbacks(
    109       const Closure& before_next_write_callback,
    110       const Callback<void(bool success)>& after_next_write_callback);
    111 
    112   TimeDelta commit_interval() const {
    113     return commit_interval_;
    114   }
    115 
    116   // Overrides the timer to use for scheduling writes with |timer_override|.
    117   void SetTimerForTesting(Timer* timer_override);
    118 
    119  private:
    120   const Timer& timer() const {
    121     return timer_override_ ? const_cast<const Timer&>(*timer_override_)
    122                            : timer_;
    123   }
    124   Timer& timer() { return timer_override_ ? *timer_override_ : timer_; }
    125 
    126   void ClearPendingWrite();
    127 
    128   // Invoked synchronously on the next write event.
    129   Closure before_next_write_callback_;
    130   Callback<void(bool success)> after_next_write_callback_;
    131 
    132   // Path being written to.
    133   const FilePath path_;
    134 
    135   // TaskRunner for the thread on which file I/O can be done.
    136   const scoped_refptr<SequencedTaskRunner> task_runner_;
    137 
    138   // Timer used to schedule commit after ScheduleWrite.
    139   OneShotTimer timer_;
    140 
    141   // An override for |timer_| used for testing.
    142   Timer* timer_override_ = nullptr;
    143 
    144   // Serializer which will provide the data to be saved.
    145   DataSerializer* serializer_;
    146 
    147   // Time delta after which scheduled data will be written to disk.
    148   const TimeDelta commit_interval_;
    149 
    150   // Custom histogram suffix.
    151   const std::string histogram_suffix_;
    152 
    153   SEQUENCE_CHECKER(sequence_checker_);
    154 
    155   WeakPtrFactory<ImportantFileWriter> weak_factory_;
    156 
    157   DISALLOW_COPY_AND_ASSIGN(ImportantFileWriter);
    158 };
    159 
    160 }  // namespace base
    161 
    162 #endif  // BASE_FILES_IMPORTANT_FILE_WRITER_H_
    163