blob: 6408aea84a95775a6c49ad8d188bb6426807e931 [file] [log] [blame]
Austin Schuhcb5601b2020-09-10 15:29:59 -07001#ifndef AOS_EVENTS_LOGGING_LOG_NAMER_H_
2#define AOS_EVENTS_LOGGING_LOG_NAMER_H_
3
4#include <functional>
5#include <map>
6#include <memory>
7#include <string_view>
8#include <vector>
9
Austin Schuh58646e22021-08-23 23:51:46 -070010#include "absl/container/btree_map.h"
Philipp Schrader790cb542023-07-05 21:06:52 -070011#include "flatbuffers/flatbuffers.h"
Maxwell Gumley8ad77782023-07-11 13:27:03 -060012#include "glog/logging.h"
Philipp Schrader790cb542023-07-05 21:06:52 -070013
Austin Schuhcb5601b2020-09-10 15:29:59 -070014#include "aos/events/logging/logfile_utils.h"
15#include "aos/events/logging/logger_generated.h"
Austin Schuh4385b142021-03-14 21:31:13 -070016#include "aos/uuid.h"
Austin Schuhcb5601b2020-09-10 15:29:59 -070017
18namespace aos {
19namespace logger {
20
Austin Schuh572924a2021-07-30 22:32:12 -070021class LogNamer;
22
Austin Schuhb8bca732021-07-30 22:32:00 -070023// TODO(austin): Rename this back to DataWriter once all other callers are of
24// the old DataWriter.
Austin Schuh572924a2021-07-30 22:32:12 -070025//
26// Class to manage writing data to log files. This lets us track which boot the
27// written header has in it, and if the header has been written or not.
Austin Schuh58646e22021-08-23 23:51:46 -070028//
29// The design of this class is that instead of being notified when any of the
30// header data changes, it polls and owns that decision. This makes it much
31// harder to write corrupted data. If that becomes a performance problem, we
32// can DCHECK and take it out of production binaries.
Austin Schuhb8bca732021-07-30 22:32:00 -070033class NewDataWriter {
34 public:
35 // Constructs a NewDataWriter.
Austin Schuh572924a2021-07-30 22:32:12 -070036 // log_namer is the log namer which holds the config and any other data we
37 // need for our header.
38 // node is the node whom's prespective we are logging from.
Austin Schuhb8bca732021-07-30 22:32:00 -070039 // reopen is called whenever a file needs to be reopened.
40 // close is called to close that file and extract any statistics.
Austin Schuhf5f99f32022-02-07 20:05:37 -080041 NewDataWriter(LogNamer *log_namer, const Node *node, const Node *logger_node,
Austin Schuh572924a2021-07-30 22:32:12 -070042 std::function<void(NewDataWriter *)> reopen,
Austin Schuh48d10d62022-10-16 22:19:23 -070043 std::function<void(NewDataWriter *)> close,
44 size_t max_message_size);
45
46 void UpdateMaxMessageSize(size_t new_size) {
47 if (new_size > max_message_size_) {
Alexei Strotsbc082d82023-05-03 08:43:42 -070048 CHECK(!header_written_) << ": Tried to update to " << new_size << ", was "
49 << max_message_size_ << " for " << name();
Austin Schuh48d10d62022-10-16 22:19:23 -070050 max_message_size_ = new_size;
51 }
52 }
53 size_t max_message_size() const { return max_message_size_; }
Austin Schuhb8bca732021-07-30 22:32:00 -070054
Mithun Bharadwaja5cb8e02023-08-02 16:10:40 -070055 std::chrono::nanoseconds max_out_of_order_duration() const {
56 return max_out_of_order_duration_;
57 }
58
Austin Schuhb8bca732021-07-30 22:32:00 -070059 NewDataWriter(NewDataWriter &&other) = default;
60 aos::logger::NewDataWriter &operator=(NewDataWriter &&other) = default;
61 NewDataWriter(const NewDataWriter &) = delete;
62 void operator=(const NewDataWriter &) = delete;
63
Austin Schuh572924a2021-07-30 22:32:12 -070064 ~NewDataWriter();
Austin Schuhb8bca732021-07-30 22:32:00 -070065
Austin Schuh572924a2021-07-30 22:32:12 -070066 // Rotates the log file, delaying writing the new header until data arrives.
67 void Rotate();
Austin Schuhb8bca732021-07-30 22:32:00 -070068
Austin Schuhf5f99f32022-02-07 20:05:37 -080069 // Updates all the metadata in the log file about the remote node which this
70 // message is from.
Austin Schuh72211ae2021-08-05 14:02:30 -070071 void UpdateRemote(size_t remote_node_index, const UUID &remote_node_boot_uuid,
72 monotonic_clock::time_point monotonic_remote_time,
73 monotonic_clock::time_point monotonic_event_time,
Austin Schuhf5f99f32022-02-07 20:05:37 -080074 bool reliable,
75 monotonic_clock::time_point monotonic_timestamp_time =
76 monotonic_clock::min_time);
Austin Schuh48d10d62022-10-16 22:19:23 -070077 // Coppies a message with the provided boot UUID.
78 void CopyMessage(DataEncoder::Copier *coppier,
79 const UUID &source_node_boot_uuid,
Mithun Bharadwaja5cb8e02023-08-02 16:10:40 -070080 aos::monotonic_clock::time_point now,
81 aos::monotonic_clock::time_point message_time);
Austin Schuhb8bca732021-07-30 22:32:00 -070082
Austin Schuh5e14d842022-01-21 12:02:15 -080083 // Updates the current boot for the source node. This is useful when you want
84 // to queue a message that may trigger a reboot rotation, but then need to
85 // update the remote timestamps.
86 void UpdateBoot(const UUID &source_node_boot_uuid);
87
Alexei Strotsbc082d82023-05-03 08:43:42 -070088 // Returns the name of the writer. It may be a filename, but assume it is not.
89 std::string_view name() const { return writer ? writer->name() : "(closed)"; }
Austin Schuhb8bca732021-07-30 22:32:00 -070090
Austin Schuh572924a2021-07-30 22:32:12 -070091 void Close();
Austin Schuhb8bca732021-07-30 22:32:00 -070092
93 std::unique_ptr<DetachedBufferWriter> writer = nullptr;
Austin Schuh572924a2021-07-30 22:32:12 -070094
95 size_t node_index() const { return node_index_; }
96 const UUID &parts_uuid() const { return parts_uuid_; }
97 size_t parts_index() const { return parts_index_; }
98 const Node *node() const { return node_; }
Austin Schuhb8bca732021-07-30 22:32:00 -070099
Austin Schuh72211ae2021-08-05 14:02:30 -0700100 // Datastructure used to capture all the information about a remote node.
101 struct State {
102 // Boot UUID of the node.
103 UUID boot_uuid = UUID::Zero();
104 // Timestamp on the remote monotonic clock of the oldest message sent to
105 // node_index_.
106 monotonic_clock::time_point oldest_remote_monotonic_timestamp =
107 monotonic_clock::max_time;
108 // Timestamp on the local monotonic clock of the message in
109 // oldest_remote_monotonic_timestamp.
110 monotonic_clock::time_point oldest_local_monotonic_timestamp =
111 monotonic_clock::max_time;
112 // Timestamp on the remote monotonic clock of the oldest message sent to
113 // node_index_, excluding messages forwarded with time_to_live() == 0.
114 monotonic_clock::time_point oldest_remote_unreliable_monotonic_timestamp =
115 monotonic_clock::max_time;
116 // Timestamp on the local monotonic clock of the message in
117 // oldest_local_unreliable_monotonic_timestamp.
118 monotonic_clock::time_point oldest_local_unreliable_monotonic_timestamp =
119 monotonic_clock::max_time;
Austin Schuhbfe6c572022-01-27 20:48:20 -0800120
121 // Timestamp on the remote monotonic clock of the oldest message sent to
122 // node_index_, only including messages forwarded with time_to_live() == 0.
123 monotonic_clock::time_point oldest_remote_reliable_monotonic_timestamp =
124 monotonic_clock::max_time;
125 // Timestamp on the local monotonic clock of the message in
126 // oldest_local_reliable_monotonic_timestamp.
127 monotonic_clock::time_point oldest_local_reliable_monotonic_timestamp =
128 monotonic_clock::max_time;
Austin Schuhf5f99f32022-02-07 20:05:37 -0800129
130 // Timestamp on the remote monotonic clock of the oldest message timestamp
131 // sent back to logger_node_index_. The remote here will be the node this
132 // part is from the perspective of, ie node_index_.
133 monotonic_clock::time_point
134 oldest_logger_remote_unreliable_monotonic_timestamp =
135 monotonic_clock::max_time;
136 // The time on the monotonic clock of the logger when this timestamp made it
137 // back to the logger (logger_node_index_).
138 monotonic_clock::time_point
139 oldest_logger_local_unreliable_monotonic_timestamp =
140 monotonic_clock::max_time;
Austin Schuh72211ae2021-08-05 14:02:30 -0700141 };
142
Austin Schuhb8bca732021-07-30 22:32:00 -0700143 private:
Austin Schuhe46492f2021-07-31 19:49:41 -0700144 // Signals that a node has rebooted.
Austin Schuh5e14d842022-01-21 12:02:15 -0800145 void Reboot(const UUID &source_node_boot_uuid);
Austin Schuhe46492f2021-07-31 19:49:41 -0700146
Austin Schuh572924a2021-07-30 22:32:12 -0700147 void QueueHeader(
148 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> &&header);
149
Austin Schuhe46492f2021-07-31 19:49:41 -0700150 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> MakeHeader();
151
Austin Schuh58646e22021-08-23 23:51:46 -0700152 monotonic_clock::time_point monotonic_start_time_ = monotonic_clock::min_time;
153
Austin Schuh577610e2021-12-08 12:07:19 -0800154 const Node *node_ = nullptr;
155 size_t node_index_ = 0;
Austin Schuhf5f99f32022-02-07 20:05:37 -0800156 size_t logger_node_index_ = 0;
Austin Schuh572924a2021-07-30 22:32:12 -0700157 LogNamer *log_namer_;
158 UUID parts_uuid_ = UUID::Random();
159 size_t parts_index_ = 0;
160
Austin Schuhb8bca732021-07-30 22:32:00 -0700161 std::function<void(NewDataWriter *)> reopen_;
162 std::function<void(NewDataWriter *)> close_;
Austin Schuh572924a2021-07-30 22:32:12 -0700163 bool header_written_ = false;
Austin Schuhe46492f2021-07-31 19:49:41 -0700164
Austin Schuh72211ae2021-08-05 14:02:30 -0700165 std::vector<State> state_;
Austin Schuh48d10d62022-10-16 22:19:23 -0700166
167 size_t max_message_size_;
Mithun Bharadwaja5cb8e02023-08-02 16:10:40 -0700168
169 // Each data writer logs the channels for that node, i.e.
170 // each data writer writes one file. We may encounter messages which
171 // violate the max out of order duration specified in the header of that file.
172 // Rotate the data writer and start a new part for that particular file.
173 // This shouldn't affect the headers of other data writers, so make this
174 // a property of individual data writer instead of the overall log.
175 std::chrono::nanoseconds max_out_of_order_duration_;
176
177 // Monotonic time point of the latest message we've logged so far, i.e
178 // Message X - time Z
179 // Message Y - time Z + 1
180 // newest_message_time_ = Z + 1 (even if X was logged after Y)
181 //
182 // Since the messages can be logged out of order, this helps determine if
183 // max out of order duration was violated.
184 monotonic_clock::time_point newest_message_time_ = monotonic_clock::min_time;
Austin Schuhb8bca732021-07-30 22:32:00 -0700185};
186
Austin Schuhcb5601b2020-09-10 15:29:59 -0700187// Interface describing how to name, track, and add headers to log file parts.
188class LogNamer {
189 public:
190 // Constructs a LogNamer with the primary node (ie the one the logger runs on)
191 // being node.
Austin Schuh5b728b72021-06-16 14:57:15 -0700192 LogNamer(const aos::Configuration *configuration, EventLoop *event_loop,
193 const aos::Node *node)
Austin Schuha499cea2021-07-31 19:49:53 -0700194 : event_loop_(event_loop),
Austin Schuh5b728b72021-06-16 14:57:15 -0700195 configuration_(configuration),
196 node_(node),
Austin Schuha499cea2021-07-31 19:49:53 -0700197 logger_node_index_(configuration::GetNodeIndex(configuration_, node_)) {
Austin Schuh73340842021-07-30 22:32:06 -0700198 nodes_.emplace_back(node_);
Austin Schuh73340842021-07-30 22:32:06 -0700199 }
Alexei Strots01395492023-03-20 13:59:56 -0700200 virtual ~LogNamer() = default;
Austin Schuhcb5601b2020-09-10 15:29:59 -0700201
Brian Silverman87ac0402020-09-17 14:47:01 -0700202 // Returns a writer for writing data from messages on this channel (on the
203 // primary node).
204 //
205 // The returned pointer will stay valid across rotations, but the object it
206 // points to will be assigned to.
Austin Schuhb8bca732021-07-30 22:32:00 -0700207 virtual NewDataWriter *MakeWriter(const Channel *channel) = 0;
Austin Schuhcb5601b2020-09-10 15:29:59 -0700208
Brian Silverman87ac0402020-09-17 14:47:01 -0700209 // Returns a writer for writing timestamps from messages on this channel (on
210 // the primary node).
211 //
212 // The returned pointer will stay valid across rotations, but the object it
213 // points to will be assigned to.
Austin Schuhb8bca732021-07-30 22:32:00 -0700214 virtual NewDataWriter *MakeTimestampWriter(const Channel *channel) = 0;
Austin Schuhcb5601b2020-09-10 15:29:59 -0700215
216 // Returns a writer for writing timestamps delivered over the special
217 // /aos/remote_timestamps/* channels. node is the node that the timestamps
Brian Silverman87ac0402020-09-17 14:47:01 -0700218 // are forwarded back from (to the primary node).
219 //
220 // The returned pointer will stay valid across rotations, but the object it
221 // points to will be assigned to.
Austin Schuh73340842021-07-30 22:32:06 -0700222 virtual NewDataWriter *MakeForwardedTimestampWriter(const Channel *channel,
223 const Node *node) = 0;
Austin Schuhcb5601b2020-09-10 15:29:59 -0700224
Austin Schuh73340842021-07-30 22:32:06 -0700225 // Rotates all log files for the provided node.
226 virtual void Rotate(const Node *node) = 0;
Austin Schuhcb5601b2020-09-10 15:29:59 -0700227
228 // Returns all the nodes that data is being written for.
229 const std::vector<const Node *> &nodes() const { return nodes_; }
230
Austin Schuh08dba8f2023-05-01 08:29:30 -0700231 // Closes all existing log data writers. No more data may be written after
232 // this.
233 virtual WriteCode Close() = 0;
234
Austin Schuhcb5601b2020-09-10 15:29:59 -0700235 // Returns the node the logger is running on.
236 const Node *node() const { return node_; }
Austin Schuhe46492f2021-07-31 19:49:41 -0700237 const UUID &logger_node_boot_uuid() const { return logger_node_boot_uuid_; }
238 size_t logger_node_index() const { return logger_node_index_; }
Austin Schuhcb5601b2020-09-10 15:29:59 -0700239
Austin Schuh8c399962020-12-25 21:51:45 -0800240 // Writes out the nested Configuration object to the config file location.
241 virtual void WriteConfiguration(
242 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header,
243 std::string_view config_sha256) = 0;
244
Austin Schuh73340842021-07-30 22:32:06 -0700245 void SetHeaderTemplate(
246 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> header) {
247 header_ = std::move(header);
Austin Schuhe46492f2021-07-31 19:49:41 -0700248 logger_node_boot_uuid_ =
249 UUID::FromString(header_.message().logger_node_boot_uuid());
Austin Schuh73340842021-07-30 22:32:06 -0700250 }
Austin Schuhcb5601b2020-09-10 15:29:59 -0700251
Austin Schuh60e77942022-05-16 17:48:24 -0700252 void ClearStartTimes() { node_states_.clear(); }
Austin Schuh58646e22021-08-23 23:51:46 -0700253
254 void SetStartTimes(size_t node_index, const UUID &boot_uuid,
Austin Schuh73340842021-07-30 22:32:06 -0700255 monotonic_clock::time_point monotonic_start_time,
256 realtime_clock::time_point realtime_start_time,
257 monotonic_clock::time_point logger_monotonic_start_time,
258 realtime_clock::time_point logger_realtime_start_time) {
Austin Schuh58646e22021-08-23 23:51:46 -0700259 VLOG(1) << "Setting node " << node_index << " to start time "
260 << monotonic_start_time << " rt " << realtime_start_time << " UUID "
261 << boot_uuid;
262 NodeState *node_state = GetNodeState(node_index, boot_uuid);
263 node_state->monotonic_start_time = monotonic_start_time;
264 node_state->realtime_start_time = realtime_start_time;
265 node_state->logger_monotonic_start_time = logger_monotonic_start_time;
266 node_state->logger_realtime_start_time = logger_realtime_start_time;
Austin Schuh73340842021-07-30 22:32:06 -0700267 }
268
Austin Schuh58646e22021-08-23 23:51:46 -0700269 monotonic_clock::time_point monotonic_start_time(size_t node_index,
270 const UUID &boot_uuid) {
271 DCHECK_NE(boot_uuid, UUID::Zero());
272
273 NodeState *node_state = GetNodeState(node_index, boot_uuid);
274 return node_state->monotonic_start_time;
Austin Schuh73340842021-07-30 22:32:06 -0700275 }
276
Mithun Bharadwaja5cb8e02023-08-02 16:10:40 -0700277 // This returns the initial out of order duration set in the header template
278 // by the logger based on polling period. It may be different than the actual
279 // duration used by the data writer.
280 std::chrono::nanoseconds base_max_out_of_order_duration() const {
281 return std::chrono::nanoseconds(
282 header_.message().max_out_of_order_duration());
283 }
284
Austin Schuh73340842021-07-30 22:32:06 -0700285 protected:
Austin Schuh73340842021-07-30 22:32:06 -0700286 // Structure with state per node about times and such.
Austin Schuh73340842021-07-30 22:32:06 -0700287 struct NodeState {
288 // Time when this node started logging.
289 monotonic_clock::time_point monotonic_start_time =
290 monotonic_clock::min_time;
291 realtime_clock::time_point realtime_start_time = realtime_clock::min_time;
292
293 // Corresponding time on the logger node when it started logging.
294 monotonic_clock::time_point logger_monotonic_start_time =
295 monotonic_clock::min_time;
296 realtime_clock::time_point logger_realtime_start_time =
297 realtime_clock::min_time;
Austin Schuh73340842021-07-30 22:32:06 -0700298 };
Austin Schuh58646e22021-08-23 23:51:46 -0700299
300 // Creates a new header by copying fields out of the template and combining
301 // them with the arguments provided.
302 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> MakeHeader(
303 size_t node_index, const std::vector<NewDataWriter::State> &state,
Mithun Bharadwaja5cb8e02023-08-02 16:10:40 -0700304 const UUID &parts_uuid, int parts_index,
305 std::chrono::nanoseconds max_out_of_order_duration);
Austin Schuh58646e22021-08-23 23:51:46 -0700306
307 EventLoop *event_loop_;
308 const Configuration *const configuration_;
309 const Node *const node_;
310 const size_t logger_node_index_;
311 UUID logger_node_boot_uuid_;
312 std::vector<const Node *> nodes_;
313
314 friend NewDataWriter;
315
316 // Returns the start/stop time state structure for a node and boot. We can
317 // have data from multiple boots, and it makes sense to reuse the start/stop
318 // times if we get data from the same boot again.
319 NodeState *GetNodeState(size_t node_index, const UUID &boot_uuid);
320
321 absl::btree_map<std::pair<size_t, UUID>, NodeState> node_states_;
Austin Schuh73340842021-07-30 22:32:06 -0700322
323 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> header_ =
324 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader>::Empty();
Austin Schuhcb5601b2020-09-10 15:29:59 -0700325};
326
Alexei Strots01395492023-03-20 13:59:56 -0700327// Log namer which uses a config to name a bunch of files.
Austin Schuhcb5601b2020-09-10 15:29:59 -0700328class MultiNodeLogNamer : public LogNamer {
329 public:
Alexei Strotscaf17d32023-04-03 22:31:11 -0700330 MultiNodeLogNamer(std::unique_ptr<LogBackend> log_backend,
Alexei Strots01395492023-03-20 13:59:56 -0700331 EventLoop *event_loop);
Alexei Strotscaf17d32023-04-03 22:31:11 -0700332 MultiNodeLogNamer(std::unique_ptr<LogBackend> log_backend,
Austin Schuh5b728b72021-06-16 14:57:15 -0700333 const Configuration *configuration, EventLoop *event_loop,
334 const Node *node);
Brian Silvermancb805822020-10-06 17:43:35 -0700335 ~MultiNodeLogNamer() override;
336
Austin Schuh48d10d62022-10-16 22:19:23 -0700337 // Sets the function for creating encoders. The argument is the max message
338 // size (including headers) that will be written into this encoder.
Brian Silvermancb805822020-10-06 17:43:35 -0700339 //
340 // Defaults to just creating DummyEncoders.
341 void set_encoder_factory(
Austin Schuh48d10d62022-10-16 22:19:23 -0700342 std::function<std::unique_ptr<DataEncoder>(size_t)> encoder_factory) {
Brian Silvermancb805822020-10-06 17:43:35 -0700343 encoder_factory_ = std::move(encoder_factory);
344 }
345
346 // Sets an additional file extension.
347 //
348 // Defaults to nothing.
349 void set_extension(std::string_view extension) { extension_ = extension; }
Brian Silverman1f345222020-09-24 21:14:48 -0700350
Brian Silvermana621f522020-09-30 16:52:43 -0700351 // A list of all the filenames we've written.
352 //
353 // This only includes the part after base_name().
354 const std::vector<std::string> &all_filenames() const {
355 return all_filenames_;
356 }
357
Austin Schuh73340842021-07-30 22:32:06 -0700358 void Rotate(const Node *node) override;
Austin Schuhcb5601b2020-09-10 15:29:59 -0700359
Austin Schuh8c399962020-12-25 21:51:45 -0800360 void WriteConfiguration(
361 aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> *header,
362 std::string_view config_sha256) override;
363
Austin Schuhb8bca732021-07-30 22:32:00 -0700364 NewDataWriter *MakeWriter(const Channel *channel) override;
Austin Schuhcb5601b2020-09-10 15:29:59 -0700365
Austin Schuhb8bca732021-07-30 22:32:00 -0700366 NewDataWriter *MakeForwardedTimestampWriter(const Channel *channel,
Austin Schuh73340842021-07-30 22:32:06 -0700367 const Node *node) override;
Austin Schuhcb5601b2020-09-10 15:29:59 -0700368
Austin Schuhb8bca732021-07-30 22:32:00 -0700369 NewDataWriter *MakeTimestampWriter(const Channel *channel) override;
Austin Schuhcb5601b2020-09-10 15:29:59 -0700370
Brian Silverman0465fcf2020-09-24 00:29:18 -0700371 // Indicates that at least one file ran out of space. Once this happens, we
372 // stop trying to open new files, to avoid writing any files with holes from
373 // previous parts.
374 //
375 // Besides this function, this object will silently stop logging data when
376 // this occurs. If you want to ensure log files are complete, you must call
377 // this method.
Brian Silvermana9f2ec92020-10-06 18:00:53 -0700378 bool ran_out_of_space() const {
379 return accumulate_data_writers<bool>(
Austin Schuhb8bca732021-07-30 22:32:00 -0700380 ran_out_of_space_, [](bool x, const NewDataWriter &data_writer) {
Maxwell Gumley8ad77782023-07-11 13:27:03 -0600381 CHECK_NOTNULL(data_writer.writer);
Brian Silvermana9f2ec92020-10-06 18:00:53 -0700382 return x ||
383 (data_writer.writer && data_writer.writer->ran_out_of_space());
384 });
385 }
Brian Silverman0465fcf2020-09-24 00:29:18 -0700386
Brian Silverman1f345222020-09-24 21:14:48 -0700387 // Returns the maximum total_bytes() value for all existing
388 // DetachedBufferWriters.
389 //
390 // Returns 0 if no files are open.
391 size_t maximum_total_bytes() const {
Brian Silvermancb805822020-10-06 17:43:35 -0700392 return accumulate_data_writers<size_t>(
Austin Schuhb8bca732021-07-30 22:32:00 -0700393 0, [](size_t x, const NewDataWriter &data_writer) {
Maxwell Gumley8ad77782023-07-11 13:27:03 -0600394 CHECK_NOTNULL(data_writer.writer);
Brian Silvermancb805822020-10-06 17:43:35 -0700395 return std::max(x, data_writer.writer->total_bytes());
396 });
Brian Silverman1f345222020-09-24 21:14:48 -0700397 }
398
Brian Silverman0465fcf2020-09-24 00:29:18 -0700399 // Closes all existing log files. No more data may be written after this.
400 //
401 // This may set ran_out_of_space().
Austin Schuh08dba8f2023-05-01 08:29:30 -0700402 WriteCode Close() override;
Brian Silverman0465fcf2020-09-24 00:29:18 -0700403
Brian Silvermancb805822020-10-06 17:43:35 -0700404 // Accessors for various statistics. See the identically-named methods in
405 // DetachedBufferWriter for documentation. These are aggregated across all
406 // past and present DetachedBufferWriters.
407 std::chrono::nanoseconds max_write_time() const {
408 return accumulate_data_writers(
409 max_write_time_,
Austin Schuhb8bca732021-07-30 22:32:00 -0700410 [](std::chrono::nanoseconds x, const NewDataWriter &data_writer) {
Maxwell Gumley8ad77782023-07-11 13:27:03 -0600411 CHECK_NOTNULL(data_writer.writer);
Alexei Strots01395492023-03-20 13:59:56 -0700412 return std::max(
413 x, data_writer.writer->WriteStatistics()->max_write_time());
Brian Silvermancb805822020-10-06 17:43:35 -0700414 });
415 }
416 int max_write_time_bytes() const {
417 return std::get<0>(accumulate_data_writers(
418 std::make_tuple(max_write_time_bytes_, max_write_time_),
419 [](std::tuple<int, std::chrono::nanoseconds> x,
Austin Schuhb8bca732021-07-30 22:32:00 -0700420 const NewDataWriter &data_writer) {
Maxwell Gumley8ad77782023-07-11 13:27:03 -0600421 CHECK_NOTNULL(data_writer.writer);
Alexei Strots01395492023-03-20 13:59:56 -0700422 if (data_writer.writer->WriteStatistics()->max_write_time() >
423 std::get<1>(x)) {
424 return std::make_tuple(
425 data_writer.writer->WriteStatistics()->max_write_time_bytes(),
426 data_writer.writer->WriteStatistics()->max_write_time());
Brian Silvermancb805822020-10-06 17:43:35 -0700427 }
428 return x;
429 }));
430 }
431 int max_write_time_messages() const {
432 return std::get<0>(accumulate_data_writers(
433 std::make_tuple(max_write_time_messages_, max_write_time_),
434 [](std::tuple<int, std::chrono::nanoseconds> x,
Austin Schuhb8bca732021-07-30 22:32:00 -0700435 const NewDataWriter &data_writer) {
Maxwell Gumley8ad77782023-07-11 13:27:03 -0600436 CHECK_NOTNULL(data_writer.writer);
Alexei Strots01395492023-03-20 13:59:56 -0700437 if (data_writer.writer->WriteStatistics()->max_write_time() >
438 std::get<1>(x)) {
Brian Silvermancb805822020-10-06 17:43:35 -0700439 return std::make_tuple(
Alexei Strots01395492023-03-20 13:59:56 -0700440 data_writer.writer->WriteStatistics()
441 ->max_write_time_messages(),
442 data_writer.writer->WriteStatistics()->max_write_time());
Brian Silvermancb805822020-10-06 17:43:35 -0700443 }
444 return x;
445 }));
446 }
447 std::chrono::nanoseconds total_write_time() const {
448 return accumulate_data_writers(
449 total_write_time_,
Austin Schuhb8bca732021-07-30 22:32:00 -0700450 [](std::chrono::nanoseconds x, const NewDataWriter &data_writer) {
Maxwell Gumley8ad77782023-07-11 13:27:03 -0600451 CHECK_NOTNULL(data_writer.writer);
Alexei Strots01395492023-03-20 13:59:56 -0700452 return x + data_writer.writer->WriteStatistics()->total_write_time();
Brian Silvermancb805822020-10-06 17:43:35 -0700453 });
454 }
455 int total_write_count() const {
456 return accumulate_data_writers(
Austin Schuhb8bca732021-07-30 22:32:00 -0700457 total_write_count_, [](int x, const NewDataWriter &data_writer) {
Maxwell Gumley8ad77782023-07-11 13:27:03 -0600458 CHECK_NOTNULL(data_writer.writer);
Alexei Strots01395492023-03-20 13:59:56 -0700459 return x + data_writer.writer->WriteStatistics()->total_write_count();
Brian Silvermancb805822020-10-06 17:43:35 -0700460 });
461 }
462 int total_write_messages() const {
463 return accumulate_data_writers(
Austin Schuhb8bca732021-07-30 22:32:00 -0700464 total_write_messages_, [](int x, const NewDataWriter &data_writer) {
Alexei Strots01395492023-03-20 13:59:56 -0700465 return x +
466 data_writer.writer->WriteStatistics()->total_write_messages();
Brian Silvermancb805822020-10-06 17:43:35 -0700467 });
468 }
469 int total_write_bytes() const {
470 return accumulate_data_writers(
Austin Schuhb8bca732021-07-30 22:32:00 -0700471 total_write_bytes_, [](int x, const NewDataWriter &data_writer) {
Maxwell Gumley8ad77782023-07-11 13:27:03 -0600472 CHECK_NOTNULL(data_writer.writer);
Alexei Strots01395492023-03-20 13:59:56 -0700473 return x + data_writer.writer->WriteStatistics()->total_write_bytes();
Brian Silvermancb805822020-10-06 17:43:35 -0700474 });
475 }
476
477 void ResetStatistics();
478
Alexei Strotscaf17d32023-04-03 22:31:11 -0700479 protected:
480 // TODO (Alexei): consider to move ownership of log_namer to concrete sub
481 // class and make log_backend_ raw pointer.
482 LogBackend *log_backend() { return log_backend_.get(); }
483 const LogBackend *log_backend() const { return log_backend_.get(); }
484
Austin Schuhcb5601b2020-09-10 15:29:59 -0700485 private:
Austin Schuhcb5601b2020-09-10 15:29:59 -0700486 // Opens up a writer for timestamps forwarded back.
487 void OpenForwardedTimestampWriter(const Channel *channel,
Austin Schuhb8bca732021-07-30 22:32:00 -0700488 NewDataWriter *data_writer);
Austin Schuhcb5601b2020-09-10 15:29:59 -0700489
490 // Opens up a writer for remote data.
Austin Schuhb8bca732021-07-30 22:32:00 -0700491 void OpenWriter(const Channel *channel, NewDataWriter *data_writer);
Austin Schuhcb5601b2020-09-10 15:29:59 -0700492
493 // Opens the main data writer file for this node responsible for data_writer_.
Austin Schuh48d10d62022-10-16 22:19:23 -0700494 void MakeDataWriter();
Austin Schuhcb5601b2020-09-10 15:29:59 -0700495
Austin Schuh48d10d62022-10-16 22:19:23 -0700496 void CreateBufferWriter(std::string_view path, size_t max_message_size,
Brian Silverman0465fcf2020-09-24 00:29:18 -0700497 std::unique_ptr<DetachedBufferWriter> *destination);
498
Brian Silvermancb805822020-10-06 17:43:35 -0700499 void CloseWriter(std::unique_ptr<DetachedBufferWriter> *writer_pointer);
Austin Schuhcb5601b2020-09-10 15:29:59 -0700500
Brian Silvermancb805822020-10-06 17:43:35 -0700501 // A version of std::accumulate which operates over all of our DataWriters.
502 template <typename T, typename BinaryOperation>
503 T accumulate_data_writers(T t, BinaryOperation op) const {
Austin Schuhb8bca732021-07-30 22:32:00 -0700504 for (const std::pair<const Channel *const, NewDataWriter> &data_writer :
Brian Silvermancb805822020-10-06 17:43:35 -0700505 data_writers_) {
Maxwell Gumley8ad77782023-07-11 13:27:03 -0600506 if (data_writer.second.writer != nullptr) {
507 t = op(std::move(t), data_writer.second);
508 }
Brian Silvermancb805822020-10-06 17:43:35 -0700509 }
Maxwell Gumley8ad77782023-07-11 13:27:03 -0600510 if (data_writer_ != nullptr && data_writer_->writer != nullptr) {
Austin Schuhb8bca732021-07-30 22:32:00 -0700511 t = op(std::move(t), *data_writer_);
Brian Silvermancb805822020-10-06 17:43:35 -0700512 }
513 return t;
514 }
515
Alexei Strotscaf17d32023-04-03 22:31:11 -0700516 std::unique_ptr<LogBackend> log_backend_;
Austin Schuhcb5601b2020-09-10 15:29:59 -0700517
Brian Silverman0465fcf2020-09-24 00:29:18 -0700518 bool ran_out_of_space_ = false;
Brian Silvermana621f522020-09-30 16:52:43 -0700519 std::vector<std::string> all_filenames_;
Brian Silverman0465fcf2020-09-24 00:29:18 -0700520
Austin Schuh8bdfc492023-02-11 12:53:13 -0800521 std::function<std::unique_ptr<DataEncoder>(size_t)> encoder_factory_;
Brian Silvermancb805822020-10-06 17:43:35 -0700522 std::string extension_;
523
524 // Storage for statistics from previously-rotated DetachedBufferWriters.
525 std::chrono::nanoseconds max_write_time_ = std::chrono::nanoseconds::zero();
526 int max_write_time_bytes_ = -1;
527 int max_write_time_messages_ = -1;
528 std::chrono::nanoseconds total_write_time_ = std::chrono::nanoseconds::zero();
529 int total_write_count_ = 0;
530 int total_write_messages_ = 0;
531 int total_write_bytes_ = 0;
532
Austin Schuhcb5601b2020-09-10 15:29:59 -0700533 // File to write both delivery timestamps and local data to.
Austin Schuhb8bca732021-07-30 22:32:00 -0700534 std::unique_ptr<NewDataWriter> data_writer_;
Austin Schuhcb5601b2020-09-10 15:29:59 -0700535
Austin Schuhb8bca732021-07-30 22:32:00 -0700536 std::map<const Channel *, NewDataWriter> data_writers_;
Austin Schuhcb5601b2020-09-10 15:29:59 -0700537};
538
Alexei Strots01395492023-03-20 13:59:56 -0700539// This is specialized log namer that deals with directory centric log events.
540class MultiNodeFilesLogNamer : public MultiNodeLogNamer {
541 public:
542 MultiNodeFilesLogNamer(std::string_view base_name, EventLoop *event_loop)
colleen61276dc2023-06-01 09:23:29 -0700543 : MultiNodeLogNamer(
544 std::make_unique<RenamableFileBackend>(base_name, false),
545 event_loop) {}
Alexei Strots01395492023-03-20 13:59:56 -0700546
547 MultiNodeFilesLogNamer(std::string_view base_name,
548 const Configuration *configuration,
549 EventLoop *event_loop, const Node *node)
colleen61276dc2023-06-01 09:23:29 -0700550 : MultiNodeLogNamer(
551 std::make_unique<RenamableFileBackend>(base_name, false),
552 configuration, event_loop, node) {}
553
554 MultiNodeFilesLogNamer(EventLoop *event_loop,
555 std::unique_ptr<RenamableFileBackend> backend)
556 : MultiNodeLogNamer(std::move(backend), event_loop) {}
557
Alexei Strots01395492023-03-20 13:59:56 -0700558 ~MultiNodeFilesLogNamer() override = default;
Alexei Strotscaf17d32023-04-03 22:31:11 -0700559
560 std::string_view base_name() const {
561 return renamable_file_backend()->base_name();
562 }
563
564 // Rotate should be called at least once in between calls to set_base_name.
565 // Otherwise, temporary files will not be recoverable.
566 // Rotate is called by Logger::RenameLogBase, which is currently the only user
567 // of this method.
568 // Only renaming the folder is supported, not the file base name.
569 void set_base_name(std::string_view base_name) {
570 renamable_file_backend()->RenameLogBase(base_name);
571 }
572
573 // When enabled, this will write files under names beginning
574 // with the .tmp suffix, and then rename them to the desired name after
575 // they are fully written.
576 //
577 // This is useful to enable incremental copying of the log files.
578 //
579 // Defaults to writing directly to the final filename.
580 void EnableTempFiles() { renamable_file_backend()->EnableTempFiles(); }
581
582 private:
583 RenamableFileBackend *renamable_file_backend() {
584 return reinterpret_cast<RenamableFileBackend *>(log_backend());
585 }
586 const RenamableFileBackend *renamable_file_backend() const {
587 return reinterpret_cast<const RenamableFileBackend *>(log_backend());
588 }
Alexei Strots01395492023-03-20 13:59:56 -0700589};
590
Austin Schuhcb5601b2020-09-10 15:29:59 -0700591} // namespace logger
592} // namespace aos
593
594#endif // AOS_EVENTS_LOGGING_LOG_NAMER_H_