• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Chromium Authors
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 COMPONENTS_METRICS_STRUCTURED_PERSISTENT_PROTO_H_
6 #define COMPONENTS_METRICS_STRUCTURED_PERSISTENT_PROTO_H_
7 
8 #include "base/files/file_path.h"
9 #include "base/memory/scoped_refptr.h"
10 #include "base/memory/weak_ptr.h"
11 #include "base/task/sequenced_task_runner.h"
12 #include "base/time/time.h"
13 
14 namespace metrics {
15 namespace structured {
16 // The result of reading a backing file from disk.
17 enum class ReadStatus {
18   kOk = 0,
19   kMissing = 1,
20   kReadError = 2,
21   kParseError = 3,
22 };
23 
24 // The result of writing a backing file to disk.
25 enum class WriteStatus {
26   kOk = 0,
27   kWriteError = 1,
28   kSerializationError = 2,
29 };
30 
31 // PersistentProto wraps a proto class and persists it to disk. Usage summary.
32 //  - Init is asynchronous, usage before |on_read| is called will crash.
33 //  - pproto->Method() will call Method on the underlying proto.
34 //  - Call QueueWrite() to write to disk.
35 //
36 // Reading. The backing file is read asynchronously from disk once at
37 // initialization, and the |on_read| callback is run once this is done. Until
38 // |on_read| is called, has_value is false and get() will always return nullptr.
39 // If no proto file exists on disk, or it is invalid, a blank proto is
40 // constructed and immediately written to disk.
41 //
42 // Writing. Writes must be triggered manually. Two methods are available:
43 //  - QueueWrite() delays writing to disk for |write_delay| time, in order to
44 //    batch successive writes.
45 //  - StartWrite() writes to disk as soon as the task scheduler allows.
46 // The |on_write| callback is run each time a write has completed.
47 //
48 // WARNING. Every proto this class can be used with needs to be listed at the
49 // bottom of the cc file.
50 template <class T>
51 class PersistentProto {
52  public:
53   using ReadCallback = base::OnceCallback<void(ReadStatus)>;
54   using WriteCallback = base::RepeatingCallback<void(WriteStatus)>;
55 
56   PersistentProto(const base::FilePath& path,
57                   base::TimeDelta write_delay,
58                   typename PersistentProto<T>::ReadCallback on_read,
59                   typename PersistentProto<T>::WriteCallback on_write);
60   ~PersistentProto();
61 
62   PersistentProto(const PersistentProto&) = delete;
63   PersistentProto& operator=(const PersistentProto&) = delete;
64 
get()65   T* get() { return proto_.get(); }
66 
67   T* operator->() {
68     CHECK(proto_);
69     return proto_.get();
70   }
71 
72   T operator*() {
73     CHECK(proto_);
74     return *proto_;
75   }
76 
has_value()77   constexpr bool has_value() const { return proto_.get() != nullptr; }
78 
79   constexpr explicit operator bool() const { return has_value(); }
80 
81   // Write the backing proto to disk after |save_delay_ms_| has elapsed.
82   void QueueWrite();
83 
84   // Write the backing proto to disk 'now'.
85   void StartWrite();
86 
87   // Safely clear this proto from memory and disk. This is preferred to clearing
88   // the proto, because it ensures the proto is purged even if called before the
89   // backing file is read from disk. In this case, the file is overwritten after
90   // it has been read. In either case, the file is written as soon as possible,
91   // skipping the |save_delay_ms_| wait time.
92   void Purge();
93 
94  private:
95   void OnReadComplete(std::pair<ReadStatus, std::unique_ptr<T>> result);
96   void OnWriteComplete(WriteStatus status);
97   void OnQueueWrite();
98 
99   // Path on disk to read from and write to.
100   const base::FilePath path_;
101 
102   // How long to delay writing to disk for on a call to QueueWrite.
103   const base::TimeDelta write_delay_;
104 
105   // Whether or not a write is currently scheduled.
106   bool write_is_queued_ = false;
107 
108   // Whether we should immediately clear the proto after reading it.
109   bool purge_after_reading_ = false;
110 
111   // Run when the cache finishes reading from disk, if provided.
112   ReadCallback on_read_;
113 
114   // Run when the cache finishes writing to disk, if provided.
115   WriteCallback on_write_;
116 
117   // The proto itself.
118   std::unique_ptr<T> proto_;
119 
120   scoped_refptr<base::SequencedTaskRunner> task_runner_;
121   base::WeakPtrFactory<PersistentProto> weak_factory_{this};
122 };
123 
124 }  // namespace structured
125 }  // namespace metrics
126 
127 #endif  // COMPONENTS_METRICS_STRUCTURED_PERSISTENT_PROTO_H_
128