xref: /aosp_15_r20/external/cronet/components/metrics/structured/lib/persistent_proto_internal.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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