blob: a877006e087dc3e7fa71e7210b2379e90b035cd0 [file] [log] [blame]
[email protected]512d03f2012-06-26 01:06:061// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]6faa0e0d2009-04-28 06:50:362// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]43486252012-10-24 16:33:365#ifndef BASE_FILES_IMPORTANT_FILE_WRITER_H_
6#define BASE_FILES_IMPORTANT_FILE_WRITER_H_
[email protected]6faa0e0d2009-04-28 06:50:367
Greg Thompsondfc7d7f42020-05-14 19:30:508#include <memory>
[email protected]6faa0e0d2009-04-28 06:50:369#include <string>
10
[email protected]43486252012-10-24 16:33:3611#include "base/base_export.h"
[email protected]e33c9512014-05-12 02:24:1312#include "base/callback.h"
[email protected]57999812013-02-24 05:40:5213#include "base/files/file_path.h"
[email protected]3b63f8f42011-03-28 01:54:1514#include "base/memory/ref_counted.h"
gab7d2fae42017-06-01 14:02:5515#include "base/sequence_checker.h"
bcwhitebe133b52016-04-11 20:03:3816#include "base/strings/string_piece.h"
[email protected]99084f62013-06-28 00:49:0717#include "base/time/time.h"
18#include "base/timer/timer.h"
Mikel Astizb6108d62021-03-18 17:34:4919#include "third_party/abseil-cpp/absl/types/variant.h"
[email protected]6faa0e0d2009-04-28 06:50:3620
21namespace base {
[email protected]43486252012-10-24 16:33:3622
[email protected]0de615a2012-11-08 04:40:5923class SequencedTaskRunner;
[email protected]6faa0e0d2009-04-28 06:50:3624
tnagelc1d331a2016-08-16 21:39:5425// Helper for atomically writing a file to ensure that it won't be corrupted by
26// *application* crash during write (implemented as create, flush, rename).
[email protected]6faa0e0d2009-04-28 06:50:3627//
tnagelc1d331a2016-08-16 21:39:5428// As an added benefit, ImportantFileWriter makes it less likely that the file
29// is corrupted by *system* crash, though even if the ImportantFileWriter call
30// has already returned at the time of the crash it is not specified which
31// version of the file (old or new) is preserved. And depending on system
32// configuration (hardware and software) a significant likelihood of file
33// corruption may remain, thus using ImportantFileWriter is not a valid
34// substitute for file integrity checks and recovery codepaths for malformed
35// files.
[email protected]6faa0e0d2009-04-28 06:50:3636//
tnagelc1d331a2016-08-16 21:39:5437// Also note that ImportantFileWriter can be *really* slow (cf. File::Flush()
38// for details) and thus please don't block shutdown on ImportantFileWriter.
gab7d2fae42017-06-01 14:02:5539class BASE_EXPORT ImportantFileWriter {
[email protected]6faa0e0d2009-04-28 06:50:3640 public:
Mikel Astizb6108d62021-03-18 17:34:4941 // Promise-like callback that returns (via output parameter) the serialized
42 // data to be written. This callback is invoked on the sequence where I/O
43 // operations are executed. Returning false indicates an error.
44 using BackgroundDataProducerCallback = base::OnceCallback<bool(std::string*)>;
45
[email protected]6c1164042009-05-08 14:41:0846 // Used by ScheduleSave to lazily provide the data to be saved. Allows us
47 // to also batch data serializations.
[email protected]f59f33e2012-11-01 12:05:2748 class BASE_EXPORT DataSerializer {
[email protected]6c1164042009-05-08 14:41:0849 public:
[email protected]6c1164042009-05-08 14:41:0850 // Should put serialized string in |data| and return true on successful
51 // serialization. Will be called on the same thread on which
52 // ImportantFileWriter has been created.
53 virtual bool SerializeData(std::string* data) = 0;
[email protected]512d03f2012-06-26 01:06:0654
55 protected:
Chris Watkins091d6292017-12-13 04:25:5856 virtual ~DataSerializer() = default;
[email protected]6c1164042009-05-08 14:41:0857 };
58
Mikel Astizb6108d62021-03-18 17:34:4959 // Same as DataSerializer but allows the caller to move some of the
60 // serialization logic to the sequence where I/O operations are executed.
61 class BASE_EXPORT BackgroundDataSerializer {
62 public:
63 // Returns a promise-like callback that, when invoked, will produce the
64 // serialized string. This getter itself will be called on the same thread
65 // on which ImportantFileWriter has been created, but the callback will be
66 // invoked from the sequence where I/O operations are executed.
67 virtual BackgroundDataProducerCallback
68 GetSerializedDataProducerForBackgroundSequence() = 0;
69
70 protected:
71 virtual ~BackgroundDataSerializer() = default;
72 };
73
tnagelc1d331a2016-08-16 21:39:5474 // Save |data| to |path| in an atomic manner. Blocks and writes data on the
75 // current thread. Does not guarantee file integrity across system crash (see
76 // the class comment above).
xaerox4ae8d172017-06-20 10:20:1277 static bool WriteFileAtomically(const FilePath& path,
78 StringPiece data,
79 StringPiece histogram_suffix = StringPiece());
[email protected]95b42e22012-11-29 14:00:1280
[email protected]6faa0e0d2009-04-28 06:50:3681 // Initialize the writer.
[email protected]6fad2632009-11-02 05:59:3782 // |path| is the name of file to write.
[email protected]0de615a2012-11-08 04:40:5983 // |task_runner| is the SequencedTaskRunner instance where on which we will
84 // execute file I/O operations.
[email protected]6faa0e0d2009-04-28 06:50:3685 // All non-const methods, ctor and dtor must be called on the same thread.
thestig1433edb2015-08-06 21:45:2786 ImportantFileWriter(const FilePath& path,
xaerox4ae8d172017-06-20 10:20:1287 scoped_refptr<SequencedTaskRunner> task_runner,
Dominic Battre81f1908c2020-12-02 22:27:3788 StringPiece histogram_suffix = StringPiece());
thestig1433edb2015-08-06 21:45:2789
90 // Same as above, but with a custom commit interval.
91 ImportantFileWriter(const FilePath& path,
vmpstr82b0c16d2016-03-18 19:17:2892 scoped_refptr<SequencedTaskRunner> task_runner,
xaerox4ae8d172017-06-20 10:20:1293 TimeDelta interval,
Dominic Battre81f1908c2020-12-02 22:27:3794 StringPiece histogram_suffix = StringPiece());
[email protected]6faa0e0d2009-04-28 06:50:3695
David Bienvenue56b996a2020-12-18 04:44:1996 ImportantFileWriter(const ImportantFileWriter&) = delete;
97 ImportantFileWriter& operator=(const ImportantFileWriter&) = delete;
98
[email protected]6c1164042009-05-08 14:41:0899 // You have to ensure that there are no pending writes at the moment
100 // of destruction.
[email protected]6faa0e0d2009-04-28 06:50:36101 ~ImportantFileWriter();
102
[email protected]a83d42292010-08-17 22:51:10103 const FilePath& path() const { return path_; }
[email protected]6faa0e0d2009-04-28 06:50:36104
[email protected]6c1164042009-05-08 14:41:08105 // Returns true if there is a scheduled write pending which has not yet
106 // been started.
107 bool HasPendingWrite() const;
108
[email protected]6faa0e0d2009-04-28 06:50:36109 // Save |data| to target filename. Does not block. If there is a pending write
thestig1433edb2015-08-06 21:45:27110 // scheduled by ScheduleWrite(), it is cancelled.
dcheng093de9b2016-04-04 21:25:51111 void WriteNow(std::unique_ptr<std::string> data);
[email protected]6faa0e0d2009-04-28 06:50:36112
[email protected]6c1164042009-05-08 14:41:08113 // Schedule a save to target filename. Data will be serialized and saved
114 // to disk after the commit interval. If another ScheduleWrite is issued
115 // before that, only one serialization and write to disk will happen, and
116 // the most recent |serializer| will be used. This operation does not block.
117 // |serializer| should remain valid through the lifetime of
118 // ImportantFileWriter.
119 void ScheduleWrite(DataSerializer* serializer);
120
Mikel Astizb6108d62021-03-18 17:34:49121 // Same as above but uses the BackgroundDataSerializer API.
122 void ScheduleWriteWithBackgroundDataSerializer(
123 BackgroundDataSerializer* serializer);
124
125 // Serialize data pending to be saved and execute write on background thread.
[email protected]6c1164042009-05-08 14:41:08126 void DoScheduledWrite();
[email protected]6faa0e0d2009-04-28 06:50:36127
probergec503d692016-09-28 19:51:05128 // Registers |before_next_write_callback| and |after_next_write_callback| to
129 // be synchronously invoked from WriteFileAtomically() before its next write
130 // and after its next write, respectively. The boolean passed to
131 // |after_next_write_callback| indicates whether the write was successful.
132 // Both callbacks must be thread safe as they will be called on |task_runner_|
133 // and may be called during Chrome shutdown.
probergefc46ac12016-09-21 18:03:00134 // If called more than once before a write is scheduled on |task_runner|, the
probergec503d692016-09-28 19:51:05135 // latest callbacks clobber the others.
136 void RegisterOnNextWriteCallbacks(
Christian Dullweberee89d672018-11-29 15:12:28137 OnceClosure before_next_write_callback,
138 OnceCallback<void(bool success)> after_next_write_callback);
[email protected]e33c9512014-05-12 02:24:13139
[email protected]43486252012-10-24 16:33:36140 TimeDelta commit_interval() const {
[email protected]6faa0e0d2009-04-28 06:50:36141 return commit_interval_;
142 }
143
Sam McNally365428e2017-05-22 05:25:22144 // Overrides the timer to use for scheduling writes with |timer_override|.
tzikd93bb0862018-07-19 11:54:14145 void SetTimerForTesting(OneShotTimer* timer_override);
Sam McNally365428e2017-05-22 05:25:22146
Dominic Battre0a41c4a2020-11-26 15:08:10147#if defined(UNIT_TEST)
148 size_t previous_data_size() const { return previous_data_size_; }
149#endif
Dominic Battrec7911fe2020-11-26 21:13:18150 void set_previous_data_size(size_t previous_data_size) {
151 previous_data_size_ = previous_data_size;
152 }
Dominic Battre0a41c4a2020-11-26 15:08:10153
[email protected]6faa0e0d2009-04-28 06:50:36154 private:
tzikd93bb0862018-07-19 11:54:14155 const OneShotTimer& timer() const {
156 return timer_override_ ? *timer_override_ : timer_;
Sam McNally365428e2017-05-22 05:25:22157 }
tzikd93bb0862018-07-19 11:54:14158 OneShotTimer& timer() { return timer_override_ ? *timer_override_ : timer_; }
Sam McNally365428e2017-05-22 05:25:22159
Mikel Astizb6108d62021-03-18 17:34:49160 // Same as WriteNow() but it uses a promise-like signature that allows running
161 // custom logic in the background sequence.
162 void WriteNowWithBackgroundDataProducer(
163 BackgroundDataProducerCallback background_producer);
164
165 // Helper function to call WriteFileAtomically() with a promise-like callback
166 // producing a std::string.
167 static void ProduceAndWriteStringToFileAtomically(
Greg Thompsondfc7d7f42020-05-14 19:30:50168 const FilePath& path,
Mikel Astizb6108d62021-03-18 17:34:49169 BackgroundDataProducerCallback data_producer_for_background_sequence,
Greg Thompsondfc7d7f42020-05-14 19:30:50170 OnceClosure before_write_callback,
171 OnceCallback<void(bool success)> after_write_callback,
172 const std::string& histogram_suffix);
173
174 // Writes |data| to |path|, recording histograms with an optional
175 // |histogram_suffix|. |from_instance| indicates whether the call originates
176 // from an instance of ImportantFileWriter or a direct call to
177 // WriteFileAtomically. When false, the directory containing |path| is added
178 // to the set cleaned by the ImportantFileWriterCleaner (Windows only).
179 static bool WriteFileAtomicallyImpl(const FilePath& path,
180 StringPiece data,
181 StringPiece histogram_suffix,
182 bool from_instance);
183
Sam McNally8f50faa2017-05-19 05:08:00184 void ClearPendingWrite();
185
probergefc46ac12016-09-21 18:03:00186 // Invoked synchronously on the next write event.
Christian Dullweberee89d672018-11-29 15:12:28187 OnceClosure before_next_write_callback_;
188 OnceCallback<void(bool success)> after_next_write_callback_;
[email protected]e33c9512014-05-12 02:24:13189
[email protected]6faa0e0d2009-04-28 06:50:36190 // Path being written to.
191 const FilePath path_;
192
[email protected]0de615a2012-11-08 04:40:59193 // TaskRunner for the thread on which file I/O can be done.
thestig1433edb2015-08-06 21:45:27194 const scoped_refptr<SequencedTaskRunner> task_runner_;
[email protected]6658ca82010-05-20 18:20:29195
[email protected]6faa0e0d2009-04-28 06:50:36196 // Timer used to schedule commit after ScheduleWrite.
danakj8c3eb802015-09-24 07:53:00197 OneShotTimer timer_;
[email protected]6faa0e0d2009-04-28 06:50:36198
Sam McNally365428e2017-05-22 05:25:22199 // An override for |timer_| used for testing.
tzikd93bb0862018-07-19 11:54:14200 OneShotTimer* timer_override_ = nullptr;
Sam McNally365428e2017-05-22 05:25:22201
[email protected]6c1164042009-05-08 14:41:08202 // Serializer which will provide the data to be saved.
Mikel Astizb6108d62021-03-18 17:34:49203 absl::variant<absl::monostate, DataSerializer*, BackgroundDataSerializer*>
204 serializer_;
[email protected]6faa0e0d2009-04-28 06:50:36205
206 // Time delta after which scheduled data will be written to disk.
thestig1433edb2015-08-06 21:45:27207 const TimeDelta commit_interval_;
[email protected]6faa0e0d2009-04-28 06:50:36208
xaerox4ae8d172017-06-20 10:20:12209 // Custom histogram suffix.
210 const std::string histogram_suffix_;
211
Dominic Battre0a41c4a2020-11-26 15:08:10212 // Memorizes the amount of data written on the previous write. This helps
213 // preallocating memory for the data serialization. It is only used for
214 // scheduled writes.
215 size_t previous_data_size_ = 0;
216
gab7d2fae42017-06-01 14:02:55217 SEQUENCE_CHECKER(sequence_checker_);
218
Jeremy Roman577d88492019-07-05 14:30:23219 WeakPtrFactory<ImportantFileWriter> weak_factory_{this};
[email protected]6faa0e0d2009-04-28 06:50:36220};
221
[email protected]43486252012-10-24 16:33:36222} // namespace base
223
224#endif // BASE_FILES_IMPORTANT_FILE_WRITER_H_