blob: 78ab1743ac5bc5b4514c12f0535f1318db9881d5 [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>
6#include <filesystem>
Matt Spinler475e5742019-07-18 16:09:49 -05007#include <map>
Matt Spinler89fa0822019-07-17 13:54:30 -05008
9namespace openpower
10{
11namespace pels
12{
13
14/**
15 * @class Repository
16 *
17 * The class handles saving and retrieving PELs on the BMC.
18 */
19class Repository
20{
21 public:
Matt Spinler475e5742019-07-18 16:09:49 -050022 /**
23 * @brief A structure that holds both the PEL and corresponding
24 * OpenBMC IDs.
25 * Used for correlating the IDs with their data files for quick
26 * lookup. To find a PEL based on just one of the IDs, just use
27 * the constructor that takes that ID.
28 */
29 struct LogID
30 {
31 struct Pel
32 {
33 uint32_t id;
34 explicit Pel(uint32_t i) : id(i)
35 {
36 }
37 };
38 struct Obmc
39 {
40 uint32_t id;
41 explicit Obmc(uint32_t i) : id(i)
42 {
43 }
44 };
45
46 Pel pelID;
47
48 Obmc obmcID;
49
50 LogID(Pel pel, Obmc obmc) : pelID(pel), obmcID(obmc)
51 {
52 }
53
54 explicit LogID(Pel id) : pelID(id), obmcID(0)
55 {
56 }
57
58 explicit LogID(Obmc id) : pelID(0), obmcID(id)
59 {
60 }
61
62 LogID() = delete;
63
64 /**
65 * @brief A == operator that will match on either ID
66 * being equal if the other is zero, so that
67 * one can look up a PEL with just one of the IDs.
68 */
69 bool operator==(const LogID& id) const
70 {
71 if (id.pelID.id != 0)
72 {
73 return id.pelID.id == pelID.id;
74 }
75 if (id.obmcID.id != 0)
76 {
77 return id.obmcID.id == obmcID.id;
78 }
79 return false;
80 }
81
82 bool operator<(const LogID& id) const
83 {
84 return pelID.id < id.pelID.id;
85 }
86 };
87
Matt Spinler89fa0822019-07-17 13:54:30 -050088 Repository() = delete;
89 ~Repository() = default;
90 Repository(const Repository&) = default;
91 Repository& operator=(const Repository&) = default;
92 Repository(Repository&&) = default;
93 Repository& operator=(Repository&&) = default;
94
95 /**
96 * @brief Constructor
97 *
98 * @param[in] basePath - the base filesystem path for the repository
99 */
100 Repository(const std::filesystem::path& basePath);
101
102 /**
103 * @brief Adds a PEL to the repository
104 *
105 * Throws File.Error.Open or File.Error.Write exceptions on failure
106 *
107 * @param[in] pel - the PEL to add
108 */
109 void add(std::unique_ptr<PEL>& pel);
110
111 /**
Matt Spinler475e5742019-07-18 16:09:49 -0500112 * @brief Removes a PEL from the repository
113 *
114 * @param[in] id - the ID (either the pel ID, OBMC ID, or both) to remove
115 */
116 void remove(const LogID& id);
117
118 /**
Matt Spinler89fa0822019-07-17 13:54:30 -0500119 * @brief Generates the filename to use for the PEL ID and BCDTime.
120 *
121 * @param[in] pelID - the PEL ID
122 * @param[in] time - the BCD time
123 *
124 * @return string - A filename string of <BCD_time>_<pelID>
125 */
126 static std::string getPELFilename(uint32_t pelID, const BCDTime& time);
127
Matt Spinler475e5742019-07-18 16:09:49 -0500128 /**
129 * @brief Returns true if the PEL with the specified ID is in the repo.
130 *
131 * @param[in] id - the ID (either the pel ID, OBMC ID, or both)
132 * @return bool - true if that PEL is present
133 */
134 inline bool hasPEL(const LogID& id)
135 {
136 return findPEL(id) != _idsToPELs.end();
137 }
138
Matt Spinler2813f362019-07-19 12:45:28 -0500139 /**
140 * @brief Returns the PEL data based on its ID.
141 *
142 * If the data can't be found for that ID, then the optional object
143 * will be empty.
144 *
145 * @param[in] id - the LogID to get the PEL for, which can be either a
146 * PEL ID or OpenBMC log ID.
147 * @return std::optional<std::vector<uint8_t>> - the PEL data
148 */
149 std::optional<std::vector<uint8_t>> getPELData(const LogID& id);
150
Matt Spinler1ea78802019-11-01 13:04:59 -0500151 using ForEachFunc = std::function<bool(const PEL&)>;
152
153 /**
154 * @brief Run a user defined function on every PEL in the repository.
155 *
156 * ForEachFunc takes a const PEL reference, and should return
157 * true to stop iterating and return out of for_each.
158 *
159 * For example, to save up to 100 IDs in the repo into a vector:
160 *
161 * std::vector<uint32_t> ids;
162 * ForEachFunc f = [&ids](const PEL& pel) {
163 * ids.push_back(pel.id());
164 * return ids.size() == 100 ? true : false;
165 * };
166 *
167 * @param[in] func - The function to run.
168 */
169 void for_each(ForEachFunc func) const;
170
Matt Spinler421f6532019-11-06 15:40:45 -0600171 using AddCallback = std::function<void(const PEL&)>;
172
173 /**
174 * @brief Subscribe to PELs being added to the repository.
175 *
176 * Every time a PEL is added to the repository, the provided
177 * function will be called with the new PEL as the argument.
178 *
179 * The function must be of type void(const PEL&).
180 *
181 * @param[in] name - The subscription name
182 * @param[in] func - The callback function
183 */
184 void subscribeToAdds(const std::string& name, AddCallback func)
185 {
186 if (_addSubscriptions.find(name) == _addSubscriptions.end())
187 {
188 _addSubscriptions.emplace(name, func);
189 }
190 }
191
192 /**
193 * @brief Unsubscribe from new PELs.
194 *
195 * @param[in] name - The subscription name
196 */
197 void unsubscribeFromAdds(const std::string& name)
198 {
199 _addSubscriptions.erase(name);
200 }
201
202 using DeleteCallback = std::function<void(uint32_t)>;
203
204 /**
205 * @brief Subscribe to PELs being deleted from the repository.
206 *
207 * Every time a PEL is deleted from the repository, the provided
208 * function will be called with the PEL ID as the argument.
209 *
210 * The function must be of type void(const uint32_t).
211 *
212 * @param[in] name - The subscription name
213 * @param[in] func - The callback function
214 */
215 void subscribeToDeletes(const std::string& name, DeleteCallback func)
216 {
217 if (_deleteSubscriptions.find(name) == _deleteSubscriptions.end())
218 {
219 _deleteSubscriptions.emplace(name, func);
220 }
221 }
222
223 /**
224 * @brief Unsubscribe from deleted PELs.
225 *
226 * @param[in] name - The subscription name
227 */
228 void unsubscribeFromDeletes(const std::string& name)
229 {
230 _deleteSubscriptions.erase(name);
231 }
232
Matt Spinler89fa0822019-07-17 13:54:30 -0500233 private:
234 /**
Matt Spinler475e5742019-07-18 16:09:49 -0500235 * @brief Finds an entry in the _idsToPELs map.
236 *
237 * @param[in] id - the ID (either the pel ID, OBMC ID, or both)
238 *
239 * @return an iterator to the entry
240 */
241 std::map<LogID, std::filesystem::path>::iterator findPEL(const LogID& id)
242 {
243 return std::find_if(_idsToPELs.begin(), _idsToPELs.end(),
244 [&id](const auto& i) { return i.first == id; });
245 }
246
247 /**
Matt Spinler421f6532019-11-06 15:40:45 -0600248 * @brief Call any subscribed functions for new PELs
249 *
250 * @param[in] pel - The new PEL
251 */
252 void processAddCallbacks(const PEL& pel) const;
253
254 /**
255 * @brief Call any subscribed functions for deleted PELs
256 *
257 * @param[in] id - The ID of the deleted PEL
258 */
259 void processDeleteCallbacks(uint32_t id) const;
260
261 /**
Matt Spinler475e5742019-07-18 16:09:49 -0500262 * @brief Restores the _idsToPELs map on startup based on the existing
263 * PEL data files.
264 */
265 void restore();
266
267 /**
Matt Spinler89fa0822019-07-17 13:54:30 -0500268 * @brief The filesystem path to the PEL logs.
269 */
270 const std::filesystem::path _logPath;
Matt Spinler475e5742019-07-18 16:09:49 -0500271
272 /**
273 * @brief A map of the PEL/OBMC IDs to the PEL data files.
274 */
275 std::map<LogID, std::filesystem::path> _idsToPELs;
Matt Spinler421f6532019-11-06 15:40:45 -0600276
277 /**
278 * @brief Subcriptions for new PELs.
279 */
280 std::map<std::string, AddCallback> _addSubscriptions;
281
282 /**
283 * @brief Subscriptions for deleted PELs.
284 */
285 std::map<std::string, DeleteCallback> _deleteSubscriptions;
Matt Spinler89fa0822019-07-17 13:54:30 -0500286};
287
288} // namespace pels
289} // namespace openpower