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