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