blob: 5235d7b0a69bf99d8b2a6b27aafff654f7f0bed8 [file] [log] [blame]
Brian Silvermanf51499a2020-09-21 12:49:08 -07001#ifndef AOS_EVENTS_LOGGING_BUFFER_ENCODER_H_
2#define AOS_EVENTS_LOGGING_BUFFER_ENCODER_H_
3
Austin Schuh99f7c6a2024-06-25 22:07:44 -07004#include "absl/log/check.h"
5#include "absl/log/log.h"
Brian Silvermanf51499a2020-09-21 12:49:08 -07006#include "absl/types/span.h"
Tyler Chatow2015bc62021-08-04 21:15:09 -07007#include "flatbuffers/flatbuffers.h"
Brian Silvermanf51499a2020-09-21 12:49:08 -07008
Philipp Schrader790cb542023-07-05 21:06:52 -07009#include "aos/containers/resizeable_buffer.h"
10#include "aos/events/logging/logger_generated.h"
Maxwell Gumleyd26e6292024-04-24 10:45:07 -060011#include "aos/time/time.h"
Philipp Schrader790cb542023-07-05 21:06:52 -070012
Brian Silvermanf51499a2020-09-21 12:49:08 -070013namespace aos::logger {
14
Austin Schuh48d10d62022-10-16 22:19:23 -070015// Interface to encode data as it is written to a file.
16class DataEncoder {
Brian Silvermanf51499a2020-09-21 12:49:08 -070017 public:
Austin Schuh48d10d62022-10-16 22:19:23 -070018 virtual ~DataEncoder() = default;
Brian Silvermanf51499a2020-09-21 12:49:08 -070019
Austin Schuhd9336bc2024-04-29 18:41:23 -070020 // Size of an aligned sector used to detect when the data is aligned enough to
21 // use O_DIRECT instead.
22 static constexpr size_t kSector = 512u;
23
Austin Schuh48d10d62022-10-16 22:19:23 -070024 // Interface to copy data into a buffer.
25 class Copier {
26 public:
27 Copier(size_t size) : size_(size) {}
28
29 // Returns the data this will write.
30 size_t size() const { return size_; }
31
32 // Writes size() bytes to data, and returns the data written.
Austin Schuh71a40d42023-02-04 21:22:22 -080033 [[nodiscard]] virtual size_t Copy(uint8_t *data, size_t start_byte,
34 size_t end_byte) = 0;
Austin Schuh48d10d62022-10-16 22:19:23 -070035
36 private:
37 size_t size_;
38 };
39
Austin Schuh8bdfc492023-02-11 12:53:13 -080040 // Copies a span. The span must have a longer lifetime than the coppier is
Austin Schuh48d10d62022-10-16 22:19:23 -070041 // being used.
42 class SpanCopier : public Copier {
43 public:
44 SpanCopier(absl::Span<const uint8_t> data)
45 : Copier(data.size()), data_(data) {
Austin Schuh71a40d42023-02-04 21:22:22 -080046 CHECK(data_.data() != nullptr);
Austin Schuh48d10d62022-10-16 22:19:23 -070047 }
48
Austin Schuh71a40d42023-02-04 21:22:22 -080049 size_t Copy(uint8_t *data, size_t start_byte, size_t end_byte) final {
50 DCHECK_LE(start_byte, end_byte);
51 DCHECK_LE(end_byte, data_.size());
52
53 std::memcpy(data, data_.data() + start_byte, end_byte - start_byte);
54 return end_byte - start_byte;
Austin Schuh48d10d62022-10-16 22:19:23 -070055 }
56
57 private:
58 const absl::Span<const uint8_t> data_;
59 };
60
61 // Returns true if there is space in the buffer for the next request, or if
62 // the output needs to be flushed.
63 virtual bool HasSpace(size_t request) const = 0;
64
Austin Schuh8bdfc492023-02-11 12:53:13 -080065 // Returns the space available.
66 virtual size_t space() const = 0;
Brian Silvermanf51499a2020-09-21 12:49:08 -070067
Austin Schuh8bdfc492023-02-11 12:53:13 -080068 // Encodes and enqueues the given data encoder. Starts at the start byte
69 // (which must be a multiple of 8 bytes), and goes as far as it can. Returns
Maxwell Gumleyd26e6292024-04-24 10:45:07 -060070 // the amount encoded. The `encode_duration` is optional, when provided it
71 // will be set to the amount of time spent by the encoder during this call.
72 virtual size_t Encode(
73 Copier *copy, size_t start_byte,
74 std::chrono::nanoseconds *encode_duration = nullptr) = 0;
Brian Silvermanf51499a2020-09-21 12:49:08 -070075
76 // Finalizes the encoding process. After this, queue_size() represents the
77 // full extent of data which will be written to this file.
Maxwell Gumleyd26e6292024-04-24 10:45:07 -060078 // This function may invoke the encoder to encode any remaining data remaining
79 // in the queue. The `encode_duration` is optional, when provided it will be
80 // set to the amount of time spent by the encoder during this call. Do not
81 // call Encode after calling this method.
82 virtual void Finish(std::chrono::nanoseconds *encode_duration = nullptr) = 0;
Brian Silvermanf51499a2020-09-21 12:49:08 -070083
84 // Clears the first n encoded buffers from the queue.
85 virtual void Clear(int n) = 0;
86
Austin Schuh48d10d62022-10-16 22:19:23 -070087 // Returns a view of the queue of encoded buffers. Valid until any other
88 // method on this class is called.
89 virtual absl::Span<const absl::Span<const uint8_t>> queue() = 0;
Brian Silvermanf51499a2020-09-21 12:49:08 -070090
91 // Returns the total number of of bytes currently queued up.
92 virtual size_t queued_bytes() const = 0;
93
94 // Returns the cumulative number of bytes which have been queued. This
95 // includes data which has been removed via Clear.
96 virtual size_t total_bytes() const = 0;
97
98 // Returns the number of elements in the queue.
99 virtual size_t queue_size() const = 0;
100};
101
102// This class does not encode the data. It just claims ownership of the raw data
103// and queues it up as is.
Austin Schuh48d10d62022-10-16 22:19:23 -0700104class DummyEncoder final : public DataEncoder {
Brian Silvermanf51499a2020-09-21 12:49:08 -0700105 public:
Austin Schuh8bdfc492023-02-11 12:53:13 -0800106 DummyEncoder(size_t max_message_size, size_t buffer_size = 128 * 1024);
Austin Schuhc41603c2020-10-11 16:17:37 -0700107 DummyEncoder(const DummyEncoder &) = delete;
108 DummyEncoder(DummyEncoder &&other) = delete;
109 DummyEncoder &operator=(const DummyEncoder &) = delete;
110 DummyEncoder &operator=(DummyEncoder &&other) = delete;
Brian Silvermanf51499a2020-09-21 12:49:08 -0700111 ~DummyEncoder() override = default;
112
Austin Schuh48d10d62022-10-16 22:19:23 -0700113 bool HasSpace(size_t request) const final;
Austin Schuh8bdfc492023-02-11 12:53:13 -0800114 size_t space() const final;
Maxwell Gumleyd26e6292024-04-24 10:45:07 -0600115
116 // See base class for commments.
117 size_t Encode(Copier *copy, size_t start_byte,
118 std::chrono::nanoseconds *encode_duration = nullptr) final;
119 void Finish(std::chrono::nanoseconds * /*encode_duration*/ = nullptr) final {}
Brian Silvermanf51499a2020-09-21 12:49:08 -0700120 void Clear(int n) final;
Austin Schuh48d10d62022-10-16 22:19:23 -0700121 absl::Span<const absl::Span<const uint8_t>> queue() final;
Brian Silvermanf51499a2020-09-21 12:49:08 -0700122 size_t queued_bytes() const final;
123 size_t total_bytes() const final { return total_bytes_; }
Austin Schuh48d10d62022-10-16 22:19:23 -0700124 size_t queue_size() const final {
125 return input_buffer_.size() != 0 ? 1u : 0u;
126 }
Brian Silvermanf51499a2020-09-21 12:49:08 -0700127
128 private:
Brian Silvermanf51499a2020-09-21 12:49:08 -0700129 size_t total_bytes_ = 0;
Austin Schuh48d10d62022-10-16 22:19:23 -0700130
Austin Schuhd9336bc2024-04-29 18:41:23 -0700131 AllocatorResizeableBuffer<aos::AlignedReallocator<kSector>> input_buffer_;
Austin Schuh48d10d62022-10-16 22:19:23 -0700132 std::vector<absl::Span<const uint8_t>> return_queue_;
Brian Silvermanf51499a2020-09-21 12:49:08 -0700133};
134
135// Interface to decode chunks of data. Implementations of this interface will
136// manage opening, reading, and closing the file stream.
137class DataDecoder {
138 public:
139 virtual ~DataDecoder() = default;
140
141 // Reads data into the given range. Returns the number of bytes read.
142 //
143 // Returns less than end-begin if all bytes have been read. Otherwise, this
144 // will always fill the whole range.
145 virtual size_t Read(uint8_t *begin, uint8_t *end) = 0;
Tyler Chatow2015bc62021-08-04 21:15:09 -0700146
147 // Returns the underlying filename, for debugging purposes.
148 virtual std::string_view filename() const = 0;
Brian Silvermanf51499a2020-09-21 12:49:08 -0700149};
150
151// Simply reads the contents of the file into the target buffer.
152class DummyDecoder final : public DataDecoder {
153 public:
154 explicit DummyDecoder(std::string_view filename);
Austin Schuhc41603c2020-10-11 16:17:37 -0700155 DummyDecoder(const DummyDecoder &) = delete;
156 DummyDecoder(DummyDecoder &&other) = delete;
157 DummyDecoder &operator=(const DummyDecoder &) = delete;
158 DummyDecoder &operator=(DummyDecoder &&other) = delete;
Brian Silvermanf51499a2020-09-21 12:49:08 -0700159 ~DummyDecoder() override;
160
161 size_t Read(uint8_t *begin, uint8_t *end) final;
Tyler Chatow2015bc62021-08-04 21:15:09 -0700162 std::string_view filename() const final { return filename_; }
Brian Silvermanf51499a2020-09-21 12:49:08 -0700163
164 private:
Tyler Chatow2015bc62021-08-04 21:15:09 -0700165 const std::string filename_;
166
Brian Silvermanf51499a2020-09-21 12:49:08 -0700167 // File descriptor for the log file.
168 int fd_;
169
170 // Cached bit for if we have reached the end of the file. Otherwise we will
171 // hammer on the kernel asking for more data each time we send.
172 bool end_of_file_ = false;
173};
174
175} // namespace aos::logger
176
177#endif // AOS_EVENTS_LOGGING_BUFFER_ENCODER_H_