blob: d1eb0c6757f2b858db24bc4bfd363318ecbaef74 [file] [log] [blame]
Eric Schmiedeberge279b532023-04-19 16:36:02 -06001#ifndef AOS_EVENTS_LOGGING_CONFIG_REMAPPER_H_
2#define AOS_EVENTS_LOGGING_CONFIG_REMAPPER_H_
3
4#include <map>
5#include <string_view>
6#include <tuple>
7#include <vector>
8
9#include "flatbuffers/flatbuffers.h"
10
11#include "aos/events/event_loop.h"
12#include "aos/events/logging/logger_generated.h"
13#include "aos/events/logging/replay_channels.h"
14
15namespace aos {
16
17// This class is used for remapping and renaming channels with the passed in
18// configuration to the constructor. Typically, the templated versions of
19// RemapOriginalChannel and RenameOriginalChannel are the main functions to use
20// for type safety. After remapping and renaming, the remapped configuration can
21// be accessed through remapped_configuration(), and the original configuration
22// that is not mutated can be accessed through original_configuration.
23//
24// This class assumes no ownership over any pointers provided to it.
25//
26// Timestamp channels are automatically remapped on construction
27//
28// Note: This class does not need logfiles to function unlike LogReader. This
29// logic originally lived in LogReader and was refactored out into this class.
30// The same API for remapping and renaming still exists in LogReader which now
31// just passes along the args to this class.
32class ConfigRemapper {
33 public:
34 ConfigRemapper(const Configuration *config,
35 const Configuration *replay_config = nullptr,
36 const logger::ReplayChannels *replay_channels = nullptr);
37 ~ConfigRemapper();
38
39 // Map of channel indices to new name. The channel index will be an index into
40 // original_configuration(), and the string key will be the name of the
41 // channel to send on instead of the orignal channel name.
42 struct RemappedChannel {
43 std::string remapped_name;
44 std::string new_type;
45 };
46
47 // Enum to use for indicating how RemapOriginalChannel behaves when there is
48 // already a channel with the remapped name (e.g., as may happen when
49 // replaying a logfile that was itself generated from replay).
50 enum class RemapConflict {
51 // LOG(FATAL) on conflicts in remappings.
52 kDisallow,
53 // If we run into a conflict, attempt to remap the channel we would be
54 // overriding (and continue to do so if remapping *that* channel also
55 // generates a conflict).
56 // This will mean that if we repeatedly replay a log, we will end up
57 // stacking more and more /original's on the start of the oldest version
58 // of the channels.
59 kCascade
60 };
61
62 // Remaps a channel from the original configuration passed to the constructor
63 // to the given one. This operates on raw channel names, without any node or
64 // application specific mappings.
65 void RemapOriginalChannel(
66 std::string_view name, std::string_view type,
67 std::string_view add_prefix = "/original", std::string_view new_type = "",
68 RemapConflict conflict_handling = RemapConflict::kCascade);
69 template <typename T>
70 void RemapOriginalChannel(
71 std::string_view name, std::string_view add_prefix = "/original",
72 std::string_view new_type = "",
73 RemapConflict conflict_handling = RemapConflict::kCascade) {
74 RemapOriginalChannel(name, T::GetFullyQualifiedName(), add_prefix, new_type,
75 conflict_handling);
76 }
77
78 // Remaps the provided channel, though this respects node mappings, and
79 // preserves them too. This makes it so if /aos -> /pi1/aos on one node,
80 // /original/aos -> /original/pi1/aos on the same node after renaming, just
81 // like you would hope. If new_type is not empty, the new channel will use
82 // the provided type instead. This allows for renaming messages.
83 //
84 // TODO(austin): If you have 2 nodes remapping something to the same channel,
85 // this doesn't handle that. No use cases exist yet for that, so it isn't
86 // being done yet.
87 void RemapOriginalChannel(
88 std::string_view name, std::string_view type, const Node *node,
89 std::string_view add_prefix = "/original", std::string_view new_type = "",
90 RemapConflict conflict_handling = RemapConflict::kCascade);
91
92 template <typename T>
93 void RemapOriginalChannel(
94 std::string_view name, const Node *node,
95 std::string_view add_prefix = "/original", std::string_view new_type = "",
96 RemapConflict conflict_handling = RemapConflict::kCascade) {
97 RemapOriginalChannel(name, T::GetFullyQualifiedName(), node, add_prefix,
98 new_type, conflict_handling);
99 }
100
101 // Similar to RemapOriginalChannel(), but lets you specify a name for the new
102 // channel without constraints. By default, this will not add any maps for the
103 // new channel. Use add_maps to specify any maps you'd like added.
104 void RenameOriginalChannel(std::string_view name, std::string_view type,
105 std::string_view new_name,
106 const std::vector<MapT> &add_maps = {});
107 template <typename T>
108 void RenameOriginalChannel(std::string_view name, std::string_view new_name,
109 const std::vector<MapT> &add_maps = {}) {
110 RenameOriginalChannel(name, T::GetFullyQualifiedName(), new_name, add_maps);
111 }
112 // The following overloads are more suitable for multi-node configurations,
113 // and let you rename a channel on a specific node.
114 void RenameOriginalChannel(std::string_view name, std::string_view type,
115 const Node *node, std::string_view new_name,
116 const std::vector<MapT> &add_maps = {});
117 template <typename T>
118 void RenameOriginalChannel(std::string_view name, const Node *node,
119 std::string_view new_name,
120 const std::vector<MapT> &add_maps = {}) {
121 RenameOriginalChannel(name, T::GetFullyQualifiedName(), node, new_name,
122 add_maps);
123 }
124
125 template <typename T>
126 bool HasChannel(std::string_view name, const Node *node = nullptr) {
127 return HasChannel(name, T::GetFullyQualifiedName(), node);
128 }
129 bool HasChannel(std::string_view name, std::string_view type,
130 const Node *node) {
131 return configuration::GetChannel(original_configuration(), name, type, "",
132 node, true) != nullptr;
133 }
134
135 // Returns true if the channel exists on the node and was in the original
136 // config
137 template <typename T>
138 bool HasOriginalChannel(std::string_view name, const Node *node = nullptr) {
139 const Channel *channel =
140 configuration::GetChannel(original_configuration(), name,
141 T::GetFullyQualifiedName(), "", node, true);
142 if (channel == nullptr) return false;
143 return channel->logger() != LoggerConfig::NOT_LOGGED;
144 }
145
146 template <typename T>
147 void MaybeRemapOriginalChannel(std::string_view name,
148 const Node *node = nullptr) {
149 if (HasChannel<T>(name, node)) {
150 RemapOriginalChannel<T>(name, node);
151 }
152 }
153 template <typename T>
154 void MaybeRenameOriginalChannel(std::string_view name, const Node *node,
155 std::string_view new_name,
156 const std::vector<MapT> &add_maps = {}) {
157 if (HasChannel<T>(name, node)) {
158 RenameOriginalChannel<T>(name, node, new_name, add_maps);
159 }
160 }
161
162 const Channel *RemapChannel(const EventLoop *event_loop, const Node *node,
163 const Channel *channel);
164 // Returns a list of all the original channels from remapping.
165 std::vector<const Channel *> RemappedChannels() const;
166
167 void set_configuration(const Configuration *configuration);
168
169 // Returns the configuration that was originally passed to the constructor.
170 // This class does not own this pointer.
171 const Configuration *original_configuration() const;
172
173 // Returns the configuration that contains the remapping and renamings done on
174 // the original configuration. The pointer is invalidated whenever
175 // RemapOriginalChannel is called.
176 const Configuration *remapped_configuration() const;
177
178 private:
179 // Handle constructing a configuration with all the additional remapped
180 // channels from calls to RemapOriginalChannel.
181 void MakeRemappedConfig();
182
183 std::map<size_t, RemappedChannel> remapped_channels_;
184 std::vector<MapT> maps_;
185 std::unique_ptr<FlatbufferDetachedBuffer<Configuration>>
186 remapped_configuration_buffer_;
187
188 const Configuration *remapped_configuration_ = nullptr;
189 const Configuration *original_configuration_ = nullptr;
190 const Configuration *replay_configuration_ = nullptr;
191
192 const logger::ReplayChannels *replay_channels_ = nullptr;
193}; // class ConfigRemapper
194
195} // namespace aos
196#endif // AOS_EVENTS_LOGGING_CONFIG_REMAPPER_H_