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
|
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_METRICS_STRUCTURED_PERSISTENT_PROTO_H_
#define COMPONENTS_METRICS_STRUCTURED_PERSISTENT_PROTO_H_
#include "base/files/file_path.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
namespace metrics::structured {
// The result of reading a backing file from disk.
enum class ReadStatus {
kOk = 0,
kMissing = 1,
kReadError = 2,
kParseError = 3,
};
// The result of writing a backing file to disk.
enum class WriteStatus {
kOk = 0,
kWriteError = 1,
kSerializationError = 2,
};
// PersistentProto wraps a proto class and persists it to disk. Usage summary.
// - Init is asynchronous, usage before |on_read| is called will crash.
// - pproto->Method() will call Method on the underlying proto.
// - Call QueueWrite() to write to disk.
//
// Reading. The backing file is read asynchronously from disk once at
// initialization, and the |on_read| callback is run once this is done. Until
// |on_read| is called, has_value is false and get() will always return nullptr.
// If no proto file exists on disk, or it is invalid, a blank proto is
// constructed and immediately written to disk.
//
// Writing. Writes must be triggered manually. Two methods are available:
// - QueueWrite() delays writing to disk for |write_delay| time, in order to
// batch successive writes.
// - StartWrite() writes to disk as soon as the task scheduler allows.
// The |on_write| callback is run each time a write has completed.
//
// WARNING. Every proto this class can be used with needs to be listed at the
// bottom of the cc file.
template <class T>
class PersistentProto {
public:
using ReadCallback = base::OnceCallback<void(ReadStatus)>;
using WriteCallback = base::RepeatingCallback<void(WriteStatus)>;
PersistentProto(const base::FilePath& path,
base::TimeDelta write_delay,
typename PersistentProto<T>::ReadCallback on_read,
typename PersistentProto<T>::WriteCallback on_write);
~PersistentProto();
PersistentProto(const PersistentProto&) = delete;
PersistentProto& operator=(const PersistentProto&) = delete;
T* get() { return proto_.get(); }
T* operator->() {
CHECK(proto_);
return proto_.get();
}
const T* operator->() const {
CHECK(proto_);
return proto_.get();
}
T& operator*() {
CHECK(proto_);
return *proto_;
}
const T& operator*() const {
CHECK(proto_);
return *proto_;
}
constexpr bool has_value() const { return proto_.get() != nullptr; }
constexpr explicit operator bool() const { return has_value(); }
// Write the backing proto to disk after |save_delay_ms_| has elapsed.
void QueueWrite();
// Write the backing proto to disk 'now'.
void StartWrite();
// Safely clear this proto from memory and disk. This is preferred to clearing
// the proto, because it ensures the proto is purged even if called before the
// backing file is read from disk. In this case, the file is overwritten after
// it has been read. In either case, the file is written as soon as possible,
// skipping the |save_delay_ms_| wait time.
void Purge();
private:
void OnReadComplete(std::pair<ReadStatus, std::unique_ptr<T>> result);
void OnWriteComplete(WriteStatus status);
void OnQueueWrite();
// Path on disk to read from and write to.
const base::FilePath path_;
// How long to delay writing to disk for on a call to QueueWrite.
const base::TimeDelta write_delay_;
// Whether or not a write is currently scheduled.
bool write_is_queued_ = false;
// Whether we should immediately clear the proto after reading it.
bool purge_after_reading_ = false;
// Run when the cache finishes reading from disk, if provided.
ReadCallback on_read_;
// Run when the cache finishes writing to disk, if provided.
WriteCallback on_write_;
// The proto itself.
std::unique_ptr<T> proto_;
scoped_refptr<base::SequencedTaskRunner> task_runner_;
base::WeakPtrFactory<PersistentProto> weak_factory_{this};
};
} // namespace metrics::structured
#endif // COMPONENTS_METRICS_STRUCTURED_PERSISTENT_PROTO_H_
|