blob: 0832f58c9c10fe23bc0b4f92d06d9d8049452813 [file] [log] [blame]
Matt Spinler89fa0822019-07-17 13:54:30 -05001#pragma once
2#include "bcd_time.hpp"
3#include "pel.hpp"
4
5#include <algorithm>
Matt Spinler0ff00482019-11-06 16:19:46 -06006#include <bitset>
Matt Spinler89fa0822019-07-17 13:54:30 -05007#include <filesystem>
Matt Spinler475e5742019-07-18 16:09:49 -05008#include <map>
Matt Spinler89fa0822019-07-17 13:54:30 -05009
10namespace openpower
11{
12namespace pels
13{
14
15/**
16 * @class Repository
17 *
18 * The class handles saving and retrieving PELs on the BMC.
19 */
20class Repository
21{
22 public:
Matt Spinler475e5742019-07-18 16:09:49 -050023 /**
Matt Spinler0ff00482019-11-06 16:19:46 -060024 * @brief Structure of commonly used PEL attributes.
25 */
26 struct PELAttributes
27 {
28 std::filesystem::path path;
29 std::bitset<16> actionFlags;
30
31 PELAttributes() = delete;
32
33 PELAttributes(const std::filesystem::path& path, uint16_t flags) :
34 path(path), actionFlags(flags)
35 {
36 }
37 };
38
39 /**
Matt Spinler475e5742019-07-18 16:09:49 -050040 * @brief A structure that holds both the PEL and corresponding
41 * OpenBMC IDs.
42 * Used for correlating the IDs with their data files for quick
43 * lookup. To find a PEL based on just one of the IDs, just use
44 * the constructor that takes that ID.
45 */
46 struct LogID
47 {
48 struct Pel
49 {
50 uint32_t id;
51 explicit Pel(uint32_t i) : id(i)
52 {
53 }
54 };
55 struct Obmc
56 {
57 uint32_t id;
58 explicit Obmc(uint32_t i) : id(i)
59 {
60 }
61 };
62
63 Pel pelID;
64
65 Obmc obmcID;
66
67 LogID(Pel pel, Obmc obmc) : pelID(pel), obmcID(obmc)
68 {
69 }
70
71 explicit LogID(Pel id) : pelID(id), obmcID(0)
72 {
73 }
74
75 explicit LogID(Obmc id) : pelID(0), obmcID(id)
76 {
77 }
78
79 LogID() = delete;
80
81 /**
82 * @brief A == operator that will match on either ID
83 * being equal if the other is zero, so that
84 * one can look up a PEL with just one of the IDs.
85 */
86 bool operator==(const LogID& id) const
87 {
88 if (id.pelID.id != 0)
89 {
90 return id.pelID.id == pelID.id;
91 }
92 if (id.obmcID.id != 0)
93 {
94 return id.obmcID.id == obmcID.id;
95 }
96 return false;
97 }
98
99 bool operator<(const LogID& id) const
100 {
101 return pelID.id < id.pelID.id;
102 }
103 };
104
Matt Spinler89fa0822019-07-17 13:54:30 -0500105 Repository() = delete;
106 ~Repository() = default;
107 Repository(const Repository&) = default;
108 Repository& operator=(const Repository&) = default;
109 Repository(Repository&&) = default;
110 Repository& operator=(Repository&&) = default;
111
112 /**
113 * @brief Constructor
114 *
115 * @param[in] basePath - the base filesystem path for the repository
116 */
117 Repository(const std::filesystem::path& basePath);
118
119 /**
120 * @brief Adds a PEL to the repository
121 *
122 * Throws File.Error.Open or File.Error.Write exceptions on failure
123 *
124 * @param[in] pel - the PEL to add
125 */
126 void add(std::unique_ptr<PEL>& pel);
127
128 /**
Matt Spinler475e5742019-07-18 16:09:49 -0500129 * @brief Removes a PEL from the repository
130 *
131 * @param[in] id - the ID (either the pel ID, OBMC ID, or both) to remove
132 */
133 void remove(const LogID& id);
134
135 /**
Matt Spinler89fa0822019-07-17 13:54:30 -0500136 * @brief Generates the filename to use for the PEL ID and BCDTime.
137 *
138 * @param[in] pelID - the PEL ID
139 * @param[in] time - the BCD time
140 *
141 * @return string - A filename string of <BCD_time>_<pelID>
142 */
143 static std::string getPELFilename(uint32_t pelID, const BCDTime& time);
144
Matt Spinler475e5742019-07-18 16:09:49 -0500145 /**
146 * @brief Returns true if the PEL with the specified ID is in the repo.
147 *
148 * @param[in] id - the ID (either the pel ID, OBMC ID, or both)
149 * @return bool - true if that PEL is present
150 */
151 inline bool hasPEL(const LogID& id)
152 {
Matt Spinler0ff00482019-11-06 16:19:46 -0600153 return findPEL(id) != _pelAttributes.end();
Matt Spinler475e5742019-07-18 16:09:49 -0500154 }
155
Matt Spinler2813f362019-07-19 12:45:28 -0500156 /**
157 * @brief Returns the PEL data based on its ID.
158 *
159 * If the data can't be found for that ID, then the optional object
160 * will be empty.
161 *
162 * @param[in] id - the LogID to get the PEL for, which can be either a
163 * PEL ID or OpenBMC log ID.
164 * @return std::optional<std::vector<uint8_t>> - the PEL data
165 */
166 std::optional<std::vector<uint8_t>> getPELData(const LogID& id);
167
Matt Spinler1ea78802019-11-01 13:04:59 -0500168 using ForEachFunc = std::function<bool(const PEL&)>;
169
170 /**
171 * @brief Run a user defined function on every PEL in the repository.
172 *
173 * ForEachFunc takes a const PEL reference, and should return
174 * true to stop iterating and return out of for_each.
175 *
176 * For example, to save up to 100 IDs in the repo into a vector:
177 *
178 * std::vector<uint32_t> ids;
179 * ForEachFunc f = [&ids](const PEL& pel) {
180 * ids.push_back(pel.id());
181 * return ids.size() == 100 ? true : false;
182 * };
183 *
184 * @param[in] func - The function to run.
185 */
186 void for_each(ForEachFunc func) const;
187
Matt Spinler421f6532019-11-06 15:40:45 -0600188 using AddCallback = std::function<void(const PEL&)>;
189
190 /**
191 * @brief Subscribe to PELs being added to the repository.
192 *
193 * Every time a PEL is added to the repository, the provided
194 * function will be called with the new PEL as the argument.
195 *
196 * The function must be of type void(const PEL&).
197 *
198 * @param[in] name - The subscription name
199 * @param[in] func - The callback function
200 */
201 void subscribeToAdds(const std::string& name, AddCallback func)
202 {
203 if (_addSubscriptions.find(name) == _addSubscriptions.end())
204 {
205 _addSubscriptions.emplace(name, func);
206 }
207 }
208
209 /**
210 * @brief Unsubscribe from new PELs.
211 *
212 * @param[in] name - The subscription name
213 */
214 void unsubscribeFromAdds(const std::string& name)
215 {
216 _addSubscriptions.erase(name);
217 }
218
219 using DeleteCallback = std::function<void(uint32_t)>;
220
221 /**
222 * @brief Subscribe to PELs being deleted from the repository.
223 *
224 * Every time a PEL is deleted from the repository, the provided
225 * function will be called with the PEL ID as the argument.
226 *
227 * The function must be of type void(const uint32_t).
228 *
229 * @param[in] name - The subscription name
230 * @param[in] func - The callback function
231 */
232 void subscribeToDeletes(const std::string& name, DeleteCallback func)
233 {
234 if (_deleteSubscriptions.find(name) == _deleteSubscriptions.end())
235 {
236 _deleteSubscriptions.emplace(name, func);
237 }
238 }
239
240 /**
241 * @brief Unsubscribe from deleted PELs.
242 *
243 * @param[in] name - The subscription name
244 */
245 void unsubscribeFromDeletes(const std::string& name)
246 {
247 _deleteSubscriptions.erase(name);
248 }
249
Matt Spinler0ff00482019-11-06 16:19:46 -0600250 /**
251 * @brief Get the PEL attributes for a PEL
252 *
253 * @param[in] id - The ID to find the attributes for
254 *
255 * @return The attributes or an empty optional if not found
256 */
257 std::optional<std::reference_wrapper<const PELAttributes>>
258 getPELAttributes(const LogID& id) const;
259
Matt Spinler89fa0822019-07-17 13:54:30 -0500260 private:
261 /**
Matt Spinler0ff00482019-11-06 16:19:46 -0600262 * @brief Finds an entry in the _pelAttributes map.
Matt Spinler475e5742019-07-18 16:09:49 -0500263 *
264 * @param[in] id - the ID (either the pel ID, OBMC ID, or both)
265 *
266 * @return an iterator to the entry
267 */
Matt Spinler0ff00482019-11-06 16:19:46 -0600268 std::map<LogID, PELAttributes>::const_iterator
269 findPEL(const LogID& id) const
Matt Spinler475e5742019-07-18 16:09:49 -0500270 {
Matt Spinler0ff00482019-11-06 16:19:46 -0600271 return std::find_if(_pelAttributes.begin(), _pelAttributes.end(),
272 [&id](const auto& a) { return a.first == id; });
Matt Spinler475e5742019-07-18 16:09:49 -0500273 }
274
275 /**
Matt Spinler421f6532019-11-06 15:40:45 -0600276 * @brief Call any subscribed functions for new PELs
277 *
278 * @param[in] pel - The new PEL
279 */
280 void processAddCallbacks(const PEL& pel) const;
281
282 /**
283 * @brief Call any subscribed functions for deleted PELs
284 *
285 * @param[in] id - The ID of the deleted PEL
286 */
287 void processDeleteCallbacks(uint32_t id) const;
288
289 /**
Matt Spinler0ff00482019-11-06 16:19:46 -0600290 * @brief Restores the _pelAttributes map on startup based on the existing
Matt Spinler475e5742019-07-18 16:09:49 -0500291 * PEL data files.
292 */
293 void restore();
294
295 /**
Matt Spinlerab1b97f2019-11-07 13:38:07 -0600296 * @brief Stores a PEL object in the filesystem.
297 *
298 * @param[in] pel - The PEL to write
299 * @param[in] path - The file to write to
300 *
301 * Throws exceptions on failures.
302 */
303 void write(const PEL& pel, const std::filesystem::path& path);
304
305 /**
Matt Spinler89fa0822019-07-17 13:54:30 -0500306 * @brief The filesystem path to the PEL logs.
307 */
308 const std::filesystem::path _logPath;
Matt Spinler475e5742019-07-18 16:09:49 -0500309
310 /**
Matt Spinler0ff00482019-11-06 16:19:46 -0600311 * @brief A map of the PEL/OBMC IDs to PEL attributes.
Matt Spinler475e5742019-07-18 16:09:49 -0500312 */
Matt Spinler0ff00482019-11-06 16:19:46 -0600313 std::map<LogID, PELAttributes> _pelAttributes;
Matt Spinler421f6532019-11-06 15:40:45 -0600314
315 /**
316 * @brief Subcriptions for new PELs.
317 */
318 std::map<std::string, AddCallback> _addSubscriptions;
319
320 /**
321 * @brief Subscriptions for deleted PELs.
322 */
323 std::map<std::string, DeleteCallback> _deleteSubscriptions;
Matt Spinler89fa0822019-07-17 13:54:30 -0500324};
325
326} // namespace pels
327} // namespace openpower