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