blob: db09d324d69220b368edff690419dfec741698c4 [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
4#include "absl/types/span.h"
Tyler Chatow2015bc62021-08-04 21:15:09 -07005#include "flatbuffers/flatbuffers.h"
Austin Schuh48d10d62022-10-16 22:19:23 -07006#include "glog/logging.h"
Brian Silvermanf51499a2020-09-21 12:49:08 -07007
Philipp Schrader790cb542023-07-05 21:06:52 -07008#include "aos/containers/resizeable_buffer.h"
9#include "aos/events/logging/logger_generated.h"
Maxwell Gumleyd26e6292024-04-24 10:45:07 -060010#include "aos/time/time.h"
Philipp Schrader790cb542023-07-05 21:06:52 -070011
Brian Silvermanf51499a2020-09-21 12:49:08 -070012namespace aos::logger {
13
Austin Schuh48d10d62022-10-16 22:19:23 -070014// Interface to encode data as it is written to a file.
15class DataEncoder {
Brian Silvermanf51499a2020-09-21 12:49:08 -070016 public:
Austin Schuh48d10d62022-10-16 22:19:23 -070017 virtual ~DataEncoder() = default;
Brian Silvermanf51499a2020-09-21 12:49:08 -070018
Austin Schuhd9336bc2024-04-29 18:41:23 -070019 // Size of an aligned sector used to detect when the data is aligned enough to
20 // use O_DIRECT instead.
21 static constexpr size_t kSector = 512u;
22
Austin Schuh48d10d62022-10-16 22:19:23 -070023 // Interface to copy data into a buffer.
24 class Copier {
25 public:
26 Copier(size_t size) : size_(size) {}
27
28 // Returns the data this will write.
29 size_t size() const { return size_; }
30
31 // Writes size() bytes to data, and returns the data written.
Austin Schuh71a40d42023-02-04 21:22:22 -080032 [[nodiscard]] virtual size_t Copy(uint8_t *data, size_t start_byte,
33 size_t end_byte) = 0;
Austin Schuh48d10d62022-10-16 22:19:23 -070034
35 private:
36 size_t size_;
37 };
38
Austin Schuh8bdfc492023-02-11 12:53:13 -080039 // Copies a span. The span must have a longer lifetime than the coppier is
Austin Schuh48d10d62022-10-16 22:19:23 -070040 // being used.
41 class SpanCopier : public Copier {
42 public:
43 SpanCopier(absl::Span<const uint8_t> data)
44 : Copier(data.size()), data_(data) {
Austin Schuh71a40d42023-02-04 21:22:22 -080045 CHECK(data_.data() != nullptr);
Austin Schuh48d10d62022-10-16 22:19:23 -070046 }
47
Austin Schuh71a40d42023-02-04 21:22:22 -080048 size_t Copy(uint8_t *data, size_t start_byte, size_t end_byte) final {
49 DCHECK_LE(start_byte, end_byte);
50 DCHECK_LE(end_byte, data_.size());
51
52 std::memcpy(data, data_.data() + start_byte, end_byte - start_byte);
53 return end_byte - start_byte;
Austin Schuh48d10d62022-10-16 22:19:23 -070054 }
55
56 private:
57 const absl::Span<const uint8_t> data_;
58 };
59
60 // Returns true if there is space in the buffer for the next request, or if
61 // the output needs to be flushed.
62 virtual bool HasSpace(size_t request) const = 0;
63
Austin Schuh8bdfc492023-02-11 12:53:13 -080064 // Returns the space available.
65 virtual size_t space() const = 0;
Brian Silvermanf51499a2020-09-21 12:49:08 -070066
Austin Schuh8bdfc492023-02-11 12:53:13 -080067 // Encodes and enqueues the given data encoder. Starts at the start byte
68 // (which must be a multiple of 8 bytes), and goes as far as it can. Returns
Maxwell Gumleyd26e6292024-04-24 10:45:07 -060069 // the amount encoded. The `encode_duration` is optional, when provided it
70 // will be set to the amount of time spent by the encoder during this call.
71 virtual size_t Encode(
72 Copier *copy, size_t start_byte,
73 std::chrono::nanoseconds *encode_duration = nullptr) = 0;
Brian Silvermanf51499a2020-09-21 12:49:08 -070074
75 // Finalizes the encoding process. After this, queue_size() represents the
76 // full extent of data which will be written to this file.
Maxwell Gumleyd26e6292024-04-24 10:45:07 -060077 // This function may invoke the encoder to encode any remaining data remaining
78 // in the queue. The `encode_duration` is optional, when provided it will be
79 // set to the amount of time spent by the encoder during this call. Do not
80 // call Encode after calling this method.
81 virtual void Finish(std::chrono::nanoseconds *encode_duration = nullptr) = 0;
Brian Silvermanf51499a2020-09-21 12:49:08 -070082
83 // Clears the first n encoded buffers from the queue.
84 virtual void Clear(int n) = 0;
85
Austin Schuh48d10d62022-10-16 22:19:23 -070086 // Returns a view of the queue of encoded buffers. Valid until any other
87 // method on this class is called.
88 virtual absl::Span<const absl::Span<const uint8_t>> queue() = 0;
Brian Silvermanf51499a2020-09-21 12:49:08 -070089
90 // Returns the total number of of bytes currently queued up.
91 virtual size_t queued_bytes() const = 0;
92
93 // Returns the cumulative number of bytes which have been queued. This
94 // includes data which has been removed via Clear.
95 virtual size_t total_bytes() const = 0;
96
97 // Returns the number of elements in the queue.
98 virtual size_t queue_size() const = 0;
99};
100
101// This class does not encode the data. It just claims ownership of the raw data
102// and queues it up as is.
Austin Schuh48d10d62022-10-16 22:19:23 -0700103class DummyEncoder final : public DataEncoder {
Brian Silvermanf51499a2020-09-21 12:49:08 -0700104 public:
Austin Schuh8bdfc492023-02-11 12:53:13 -0800105 DummyEncoder(size_t max_message_size, size_t buffer_size = 128 * 1024);
Austin Schuhc41603c2020-10-11 16:17:37 -0700106 DummyEncoder(const DummyEncoder &) = delete;
107 DummyEncoder(DummyEncoder &&other) = delete;
108 DummyEncoder &operator=(const DummyEncoder &) = delete;
109 DummyEncoder &operator=(DummyEncoder &&other) = delete;
Brian Silvermanf51499a2020-09-21 12:49:08 -0700110 ~DummyEncoder() override = default;
111
Austin Schuh48d10d62022-10-16 22:19:23 -0700112 bool HasSpace(size_t request) const final;
Austin Schuh8bdfc492023-02-11 12:53:13 -0800113 size_t space() const final;
Maxwell Gumleyd26e6292024-04-24 10:45:07 -0600114
115 // See base class for commments.
116 size_t Encode(Copier *copy, size_t start_byte,
117 std::chrono::nanoseconds *encode_duration = nullptr) final;
118 void Finish(std::chrono::nanoseconds * /*encode_duration*/ = nullptr) final {}
Brian Silvermanf51499a2020-09-21 12:49:08 -0700119 void Clear(int n) final;
Austin Schuh48d10d62022-10-16 22:19:23 -0700120 absl::Span<const absl::Span<const uint8_t>> queue() final;
Brian Silvermanf51499a2020-09-21 12:49:08 -0700121 size_t queued_bytes() const final;
122 size_t total_bytes() const final { return total_bytes_; }
Austin Schuh48d10d62022-10-16 22:19:23 -0700123 size_t queue_size() const final {
124 return input_buffer_.size() != 0 ? 1u : 0u;
125 }
Brian Silvermanf51499a2020-09-21 12:49:08 -0700126
127 private:
Brian Silvermanf51499a2020-09-21 12:49:08 -0700128 size_t total_bytes_ = 0;
Austin Schuh48d10d62022-10-16 22:19:23 -0700129
Austin Schuhd9336bc2024-04-29 18:41:23 -0700130 AllocatorResizeableBuffer<aos::AlignedReallocator<kSector>> input_buffer_;
Austin Schuh48d10d62022-10-16 22:19:23 -0700131 std::vector<absl::Span<const uint8_t>> return_queue_;
Brian Silvermanf51499a2020-09-21 12:49:08 -0700132};
133
134// Interface to decode chunks of data. Implementations of this interface will
135// manage opening, reading, and closing the file stream.
136class DataDecoder {
137 public:
138 virtual ~DataDecoder() = default;
139
140 // Reads data into the given range. Returns the number of bytes read.
141 //
142 // Returns less than end-begin if all bytes have been read. Otherwise, this
143 // will always fill the whole range.
144 virtual size_t Read(uint8_t *begin, uint8_t *end) = 0;
Tyler Chatow2015bc62021-08-04 21:15:09 -0700145
146 // Returns the underlying filename, for debugging purposes.
147 virtual std::string_view filename() const = 0;
Brian Silvermanf51499a2020-09-21 12:49:08 -0700148};
149
150// Simply reads the contents of the file into the target buffer.
151class DummyDecoder final : public DataDecoder {
152 public:
153 explicit DummyDecoder(std::string_view filename);
Austin Schuhc41603c2020-10-11 16:17:37 -0700154 DummyDecoder(const DummyDecoder &) = delete;
155 DummyDecoder(DummyDecoder &&other) = delete;
156 DummyDecoder &operator=(const DummyDecoder &) = delete;
157 DummyDecoder &operator=(DummyDecoder &&other) = delete;
Brian Silvermanf51499a2020-09-21 12:49:08 -0700158 ~DummyDecoder() override;
159
160 size_t Read(uint8_t *begin, uint8_t *end) final;
Tyler Chatow2015bc62021-08-04 21:15:09 -0700161 std::string_view filename() const final { return filename_; }
Brian Silvermanf51499a2020-09-21 12:49:08 -0700162
163 private:
Tyler Chatow2015bc62021-08-04 21:15:09 -0700164 const std::string filename_;
165
Brian Silvermanf51499a2020-09-21 12:49:08 -0700166 // File descriptor for the log file.
167 int fd_;
168
169 // Cached bit for if we have reached the end of the file. Otherwise we will
170 // hammer on the kernel asking for more data each time we send.
171 bool end_of_file_ = false;
172};
173
174} // namespace aos::logger
175
176#endif // AOS_EVENTS_LOGGING_BUFFER_ENCODER_H_