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