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