blob: adabe8458fb144d06468560268ffefd3e0a3faad [file] [log] [blame]
Patrick Ventureef3aead2018-09-12 08:53:29 -07001/*
2 * Copyright 2018 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Patrick Venturee50d4e42018-10-23 09:50:27 -070017#include <algorithm>
Patrick Ventureaceb4ba2018-09-27 14:50:37 -070018#include <blobs-ipmid/manager.hpp>
Patrick Ventureb3e07e22018-09-27 15:11:57 -070019#include <memory>
Patrick Ventureef3aead2018-09-12 08:53:29 -070020#include <string>
21#include <vector>
22
23namespace blobs
24{
25
26void BlobManager::incrementOpen(const std::string& path)
27{
28 if (path.empty())
29 {
30 return;
31 }
32
33 openFiles[path] += 1;
34}
35
36void BlobManager::decrementOpen(const std::string& path)
37{
38 if (path.empty())
39 {
40 return;
41 }
42
43 /* TODO(venture): Check into the iterator from find, does it makes sense
44 * to just update it directly? */
45 auto entry = openFiles.find(path);
46 if (entry != openFiles.end())
47 {
48 /* found it, decrement it and remove it if 0. */
49 openFiles[path] -= 1;
50 if (openFiles[path] == 0)
51 {
52 openFiles.erase(path);
53 }
54 }
55}
56
57int BlobManager::getOpen(const std::string& path) const
58{
59 /* No need to input check on the read-only call. */
60 auto entry = openFiles.find(path);
61 if (entry != openFiles.end())
62 {
63 return entry->second;
64 }
65
66 return 0;
67}
68
69bool BlobManager::registerHandler(std::unique_ptr<GenericBlobInterface> handler)
70{
71 if (!handler)
72 {
73 return false;
74 }
75
76 handlers.push_back(std::move(handler));
77 return true;
78}
79
80uint32_t BlobManager::buildBlobList()
81{
82 /* Clear out the current list (IPMI handler is presently single-threaded).
83 */
84 ids.clear();
85
86 /* Grab the list of blobs and extend the local list */
Patrick Venturea6e21a02018-10-23 09:45:04 -070087 for (const auto& h : handlers)
Patrick Ventureef3aead2018-09-12 08:53:29 -070088 {
89 std::vector<std::string> blobs = h->getBlobIds();
90 ids.insert(ids.end(), blobs.begin(), blobs.end());
91 }
92
93 return ids.size();
94}
95
96std::string BlobManager::getBlobId(uint32_t index)
97{
98 /* Range check. */
99 if (index >= ids.size())
100 {
101 return "";
102 }
103
104 return ids[index];
105}
106
107bool BlobManager::open(uint16_t flags, const std::string& path,
108 uint16_t* session)
109{
110 GenericBlobInterface* handler = getHandler(path);
111
112 /* No handler found. */
113 if (!handler)
114 {
115 return false;
116 }
117
118 /* No sessions availabe... */
119 if (!getSession(session))
120 {
121 return false;
122 }
123
124 /* Verify flags - must be at least read or write */
125 if (!(flags & (OpenFlags::read | OpenFlags::write)))
126 {
127 /* Neither read not write set, which means calls to Read/Write will
128 * reject. */
129 return false;
130 }
131
132 if (!handler->open(*session, flags, path))
133 {
134 return false;
135 }
136
137 /* Associate session with handler */
138 sessions[*session] = SessionInfo(path, handler, flags);
139 incrementOpen(path);
140 return true;
141}
142
143GenericBlobInterface* BlobManager::getHandler(const std::string& path)
144{
145 /* Find a handler. */
Patrick Venturee50d4e42018-10-23 09:50:27 -0700146 auto h = std::find_if(
147 handlers.begin(), handlers.end(),
148 [&path](const auto& iter) { return (iter->canHandleBlob(path)); });
149 if (h != handlers.end())
Patrick Ventureef3aead2018-09-12 08:53:29 -0700150 {
Patrick Venturee50d4e42018-10-23 09:50:27 -0700151 return h->get();
Patrick Ventureef3aead2018-09-12 08:53:29 -0700152 }
153
Patrick Venturee50d4e42018-10-23 09:50:27 -0700154 return nullptr;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700155}
156
157GenericBlobInterface* BlobManager::getHandler(uint16_t session)
158{
159 auto item = sessions.find(session);
160 if (item == sessions.end())
161 {
162 return nullptr;
163 }
164
165 return item->second.handler;
166}
167
168SessionInfo* BlobManager::getSessionInfo(uint16_t session)
169{
170 auto item = sessions.find(session);
171 if (item == sessions.end())
172 {
173 return nullptr;
174 }
175
176 /* If we go to multi-threaded, this pointer can be invalidated and this
177 * method will need to change.
178 */
179 return &item->second;
180}
181
182std::string BlobManager::getPath(uint16_t session) const
183{
184 auto item = sessions.find(session);
185 if (item == sessions.end())
186 {
187 return "";
188 }
189
190 return item->second.blobId;
191}
192
193bool BlobManager::stat(const std::string& path, struct BlobMeta* meta)
194{
195 /* meta should never be NULL. */
196 GenericBlobInterface* handler = getHandler(path);
197
198 /* No handler found. */
199 if (!handler)
200 {
201 return false;
202 }
203
204 return handler->stat(path, meta);
205}
206
207bool BlobManager::stat(uint16_t session, struct BlobMeta* meta)
208{
209 /* meta should never be NULL. */
210 GenericBlobInterface* handler = getHandler(session);
211
212 /* No handler found. */
213 if (!handler)
214 {
215 return false;
216 }
217
218 return handler->stat(session, meta);
219}
220
221bool BlobManager::commit(uint16_t session, const std::vector<uint8_t>& data)
222{
223 GenericBlobInterface* handler = getHandler(session);
224
225 /* No handler found. */
226 if (!handler)
227 {
228 return false;
229 }
230
231 return handler->commit(session, data);
232}
233
234bool BlobManager::close(uint16_t session)
235{
236 GenericBlobInterface* handler = getHandler(session);
237
238 /* No handler found. */
239 if (!handler)
240 {
241 return false;
242 }
243
244 /* Handler returns failure */
245 if (!handler->close(session))
246 {
247 return false;
248 }
249
250 sessions.erase(session);
251 decrementOpen(getPath(session));
252 return true;
253}
254
255std::vector<uint8_t> BlobManager::read(uint16_t session, uint32_t offset,
256 uint32_t requestedSize)
257{
258 SessionInfo* info = getSessionInfo(session);
259
260 /* No session found. */
261 if (!info)
262 {
263 return std::vector<uint8_t>();
264 }
265
266 /* Check flags. */
267 if (!(info->flags & OpenFlags::read))
268 {
269 return std::vector<uint8_t>();
270 }
271
272 /* Try reading from it. */
273 return info->handler->read(session, offset, requestedSize);
274}
275
276bool BlobManager::write(uint16_t session, uint32_t offset,
277 const std::vector<uint8_t>& data)
278{
279 SessionInfo* info = getSessionInfo(session);
280
281 /* No session found. */
282 if (!info)
283 {
284 return false;
285 }
286
287 /* Check flags. */
288 if (!(info->flags & OpenFlags::write))
289 {
290 return false;
291 }
292
293 /* Try writing to it. */
294 return info->handler->write(session, offset, data);
295}
296
297bool BlobManager::deleteBlob(const std::string& path)
298{
299 GenericBlobInterface* handler = getHandler(path);
300
301 /* No handler found. */
302 if (!handler)
303 {
304 return false;
305 }
306
307 /* Check if the file has any open handles. */
308 if (getOpen(path) > 0)
309 {
310 return false;
311 }
312
313 /* Try deleting it. */
314 return handler->deleteBlob(path);
315}
316
Patrick Venture5c4b17b2018-10-04 10:32:22 -0700317bool BlobManager::writeMeta(uint16_t session, uint32_t offset,
318 const std::vector<uint8_t>& data)
319{
320 SessionInfo* info = getSessionInfo(session);
321
322 /* No session found. */
323 if (!info)
324 {
325 return false;
326 }
327
328 /* Try writing metadata to it. */
329 return info->handler->writeMeta(session, offset, data);
330}
331
Patrick Ventureef3aead2018-09-12 08:53:29 -0700332bool BlobManager::getSession(uint16_t* sess)
333{
334 uint16_t tries = 0;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700335
336 if (!sess)
337 {
338 return false;
339 }
340
341 /* This is not meant to fail as you have 64KiB values available. */
342
343 /* TODO(venture): We could just count the keys in the session map to know
344 * if it's full.
345 */
346 do
347 {
Patrick Venturec9ad5ff2018-10-12 17:05:49 -0700348 uint16_t lsess = next++;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700349 if (!sessions.count(lsess))
350 {
351 /* value not in use, return it. */
352 (*sess) = lsess;
353 return true;
354 }
355 } while (++tries < 0xffff);
356
357 return false;
358}
Patrick Ventureb3e07e22018-09-27 15:11:57 -0700359
360static std::unique_ptr<BlobManager> manager;
361
Patrick Venture73eb6872018-10-01 18:37:34 -0700362ManagerInterface* getBlobManager()
Patrick Ventureb3e07e22018-09-27 15:11:57 -0700363{
364 if (manager == nullptr)
365 {
366 manager = std::make_unique<BlobManager>();
367 }
368
369 return manager.get();
370}
371
Patrick Ventureef3aead2018-09-12 08:53:29 -0700372} // namespace blobs