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