1 // Copyright 2024 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_LIB_PERSISTENT_PROTO_INTERNAL_H_ 6 #define COMPONENTS_METRICS_STRUCTURED_LIB_PERSISTENT_PROTO_INTERNAL_H_ 7 8 #include <atomic> 9 #include <memory> 10 #include <string> 11 12 #include "base/files/file_path.h" 13 #include "base/files/important_file_writer.h" 14 #include "base/functional/callback_forward.h" 15 #include "base/memory/scoped_refptr.h" 16 #include "base/memory/weak_ptr.h" 17 #include "base/task/sequenced_task_runner.h" 18 #include "base/time/time.h" 19 #include "base/types/expected.h" 20 #include "third_party/protobuf/src/google/protobuf/message_lite.h" 21 22 namespace metrics::structured { 23 24 // The result of reading a backing file from disk. 25 enum class ReadStatus { 26 kOk = 0, 27 kMissing = 1, 28 kReadError = 2, 29 kParseError = 3, 30 }; 31 32 // The result of writing a backing file to disk. 33 enum class WriteStatus { 34 kOk = 0, 35 kWriteError = 1, 36 kSerializationError = 2, 37 }; 38 39 namespace internal { 40 41 // Implementation to be used for PersistentProto. Refer to persistent_proto.h 42 // for more details. 43 class PersistentProtoInternal 44 : public base::ImportantFileWriter::DataSerializer { 45 public: 46 using ReadCallback = base::OnceCallback<void(ReadStatus)>; 47 using WriteCallback = base::RepeatingCallback<void(WriteStatus)>; 48 49 PersistentProtoInternal(const base::FilePath& path, 50 base::TimeDelta write_delay, 51 PersistentProtoInternal::ReadCallback on_read, 52 PersistentProtoInternal::WriteCallback on_write); 53 54 PersistentProtoInternal(const PersistentProtoInternal&) = delete; 55 PersistentProtoInternal& operator=(const PersistentProtoInternal&) = delete; 56 57 ~PersistentProtoInternal() override; 58 59 // Retrieves the underlying proto. Must never be null. 60 virtual google::protobuf::MessageLite* GetProto() = 0; 61 get()62 google::protobuf::MessageLite* get() { return proto_; } get()63 const google::protobuf::MessageLite* get() const { return proto_; } 64 65 // Queues a write task on the current task runner. 66 void QueueWrite(); 67 68 // Purges the proto by resetting |proto_| and triggering a write. If called 69 // before |proto_| is ready, |proto_| will be purged once it becomes ready. 70 void Purge(); 71 has_value()72 constexpr bool has_value() const { return proto_ != nullptr; } 73 74 constexpr explicit operator bool() const { return has_value(); } 75 76 // base::ImportantFileWriter::DataSerializer: 77 std::optional<std::string> SerializeData() override; 78 79 // Schedules a write to be executed immediately. Only to be used for tests. 80 void StartWriteForTesting(); 81 82 // Updates the path of this persistent proto to a new file. The contents at 83 // |path| will be merged with existing content of |proto_|. Optional fields 84 // are overwritten and repeated fields are appended. 85 // |on_read| is called once the read of the new path is complete. 86 // |remove_existing| specifies if the existing file should be removed. 87 void UpdatePath(const base::FilePath& path, 88 ReadCallback on_read, 89 bool remove_existing = false); 90 91 protected: 92 // Cleans up the in-memory proto. 93 void DeallocProto(); 94 95 private: 96 // Completes a write if there is a queued one. 97 // 98 // This is needed because it needs to be called by the class that owns the 99 // proto. If this is called in PersistentProtoInternal dtor the owning proto 100 // has already been destructed. 101 void FlushQueuedWrites(); 102 103 // Callback when the file has been loaded into a file. 104 void OnReadComplete(base::expected<std::string, ReadStatus> read_status); 105 106 // Called after |proto_file_| has attempted to write with the write status 107 // captured in |write_successful|. 108 void OnWriteAttempt(bool write_successful); 109 110 // Called after OnWriteAttempt() or if the write was unsuccessful earlier. 111 void OnWriteComplete(WriteStatus status); 112 113 // Whether we should immediately clear the proto after reading it. 114 bool purge_after_reading_ = false; 115 116 // Run when the cache finishes reading from disk, if provided. 117 ReadCallback on_read_; 118 119 // Run when the cache finishes writing to disk, if provided. 120 WriteCallback on_write_; 121 122 // Boolean to flag whether the path is being updated. 123 // 124 // If the path is being updated queuing a write needs to be blocked. 125 std::atomic_bool updating_path_ = false; 126 127 // The proto itself. 128 raw_ptr<google::protobuf::MessageLite> proto_ = nullptr; 129 130 // Task runner for reads and writes to be queued. 131 scoped_refptr<base::SequencedTaskRunner> task_runner_; 132 133 // Persistence for |proto_|. 134 std::unique_ptr<base::ImportantFileWriter> proto_file_; 135 136 base::WeakPtrFactory<PersistentProtoInternal> weak_factory_{this}; 137 }; 138 139 } // namespace internal 140 } // namespace metrics::structured 141 142 #endif // COMPONENTS_METRICS_STRUCTURED_LIB_PERSISTENT_PROTO_INTERNAL_H_ 143