Logo ROOT  
Reference Guide
Loading...
Searching...
No Matches
libdaos_mock.cxx
Go to the documentation of this file.
1/// \file libdaos_mock.cxx
2/// \author Javier Lopez-Gomez <j.lopez@cern.ch>
3/// \date 2021-01-20
4/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
5/// is welcome!
6
7/*************************************************************************
8 * Copyright (C) 1995-2021, Rene Brun and Fons Rademakers. *
9 * All rights reserved. *
10 * *
11 * For the licensing terms see $ROOTSYS/LICENSE. *
12 * For the list of contributors see $ROOTSYS/README/CREDITS. *
13 *************************************************************************/
14
15#include <ROOT/RLogger.hxx>
16#include <ROOT/RNTupleUtils.hxx>
17#include <string_view>
18
19#include <daos.h>
20
21#include <array>
22#include <algorithm>
23#include <cstring>
24#include <memory>
25#include <mutex>
26#include <string>
27#include <type_traits>
28#include <unordered_map>
29
30using label_t = std::string;
31namespace std {
32// Required by `std::unordered_map<daos_obj_id, ...>`. Based on boost::hash_combine().
33template <>
34struct hash<daos_obj_id_t> {
35 std::size_t operator()(const daos_obj_id_t &oid) const
36 {
37 auto seed = std::hash<uint64_t>{}(oid.lo);
38 seed ^= std::hash<uint64_t>{}(oid.hi) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
39 return seed;
40 }
41};
42} // namespace std
43
44inline bool operator==(const daos_obj_id_t &lhs, const daos_obj_id_t &rhs)
45{
46 return (lhs.lo == rhs.lo) && (lhs.hi == rhs.hi);
47}
48
49namespace {
50// clang-format off
51/**
52\class RDaosFakeObject
53\brief Manages in-memory storage for a fake DAOS object.
54
55Currently, only 1 I/O descriptor/scather-gather list is supported.
56*/
57// clang-format on
58class RDaosFakeObject {
59private:
60 std::mutex fMutexStorage;
61 std::unordered_map<std::string, std::string> fStorage;
62
63 /// \brief Return the internal storage key by concatenating both dkey and akey.
64 static std::string GetKey(daos_key_t *dkey, daos_key_t *akey)
65 {
66 return std::string{reinterpret_cast<char *>(dkey->iov_buf), dkey->iov_buf_len}.append(
67 reinterpret_cast<char *>(akey->iov_buf), akey->iov_buf_len);
68 }
69
70public:
71 RDaosFakeObject() = default;
72 ~RDaosFakeObject() = default;
73
74 int Fetch(daos_key_t *dkey, unsigned int nr, daos_iod_t *iods, d_sg_list_t *sgls);
75 int Update(daos_key_t *dkey, unsigned int nr, daos_iod_t *iods, d_sg_list_t *sgls);
76};
77
78int RDaosFakeObject::Fetch(daos_key_t *dkey, unsigned int nr, daos_iod_t *iods, d_sg_list_t *sgls)
79{
80 /* For documentation see DAOS' daos_obj_fetch */
81
82 std::lock_guard<std::mutex> lock(fMutexStorage);
83 /* Iterate over pairs of (I/O descriptor, scatter-gather list) */
84 for (unsigned i = 0; i < nr; i++) {
85 /* Retrieve entry data for (dkey, akey). Fails if not found */
86 auto data = fStorage.find(GetKey(dkey, /*akey=*/&iods[i].iod_name));
87 if (data == fStorage.end())
88 return -DER_INVAL;
89
90 /* In principle, we can safely assume that each attribute key is associated to a single value,
91 * i.e. one extent per I/O descriptor; and that the corresponding data is copied to exactly one
92 * I/O vector. */
93 if (iods[i].iod_nr != 1 || iods[i].iod_type != DAOS_IOD_SINGLE)
94 return -DER_INVAL;
95 if (sgls[i].sg_nr != 1)
96 return -DER_INVAL;
97
98 d_iov_t &iov = sgls[i].sg_iovs[0];
99 std::copy_n(std::begin(data->second), std::min(iov.iov_buf_len, data->second.size()),
100 reinterpret_cast<char *>(iov.iov_buf));
101 }
102 return 0;
103}
104
105int RDaosFakeObject::Update(daos_key_t *dkey, unsigned int nr, daos_iod_t *iods, d_sg_list_t *sgls)
106{
107 /* For documentation see DAOS' daos_obj_update */
108
109 std::lock_guard<std::mutex> lock(fMutexStorage);
110 /* Process each I/O descriptor and associated SG list */
111 for (unsigned i = 0; i < nr; i++) {
112 auto &data = fStorage[GetKey(dkey, /*akey=*/&iods[i].iod_name)];
113 /* We assume each attribute key is associated to a single value whose corresponding data is
114 * sequentially updated from one or more I/O vectors. */
115 if (iods[i].iod_nr != 1 || iods[i].iod_type != DAOS_IOD_SINGLE)
116 return -DER_INVAL;
117
118 data.clear();
119 for (unsigned j = 0; j < sgls[i].sg_nr; j++) {
120 const d_iov_t &iov = sgls[i].sg_iovs[j];
121 data.append(reinterpret_cast<const char *>(iov.iov_buf), iov.iov_buf_len);
122 }
123 }
124 return 0;
125}
126
127// clang-format off
128/**
129\class RDaosFakeContainer
130\brief Manages objects in a fake DAOS container.
131*/
132// clang-format on
133class RDaosFakeContainer {
134private:
135 std::mutex fMutexObjects;
136 std::unordered_map<daos_obj_id_t, std::unique_ptr<RDaosFakeObject>> fObjects;
137
138public:
139 RDaosFakeContainer() = default;
140 ~RDaosFakeContainer() = default;
141
142 RDaosFakeObject *GetObject(daos_obj_id_t oid, unsigned int /*mode*/)
143 {
144 std::lock_guard<std::mutex> lock(fMutexObjects);
145 auto &obj = fObjects[oid];
146 if (!obj)
147 obj = std::make_unique<RDaosFakeObject>();
148 return obj.get();
149 }
150};
151
152// clang-format off
153/**
154\class RDaosFakePool
155\brief Manages user-defined containers in a fake DAOS pool.
156*/
157// clang-format on
158class RDaosFakePool {
159private:
160 static std::mutex fMutexPools;
161 static std::unordered_map<label_t, std::unique_ptr<RDaosFakePool>> fPools;
162
163 std::mutex fMutexContainers;
164 std::unordered_map<label_t, std::unique_ptr<RDaosFakeContainer>> fContainers;
165
166public:
167 /// \brief Get a pointer to a RDaosFakePool object associated to the given UUID.
168 /// Non-existent pools shall be created on-demand.
169 static RDaosFakePool *GetPool(const label_t &label)
170 {
171 std::lock_guard<std::mutex> lock(fMutexPools);
172 auto &pool = fPools[label];
173 if (!pool)
174 pool = std::make_unique<RDaosFakePool>();
175 return pool.get();
176 }
177
178 RDaosFakePool() = default;
179 ~RDaosFakePool() = default;
180
181 void CreateContainer(const label_t &label)
182 {
183 std::lock_guard<std::mutex> lock(fMutexContainers);
184 fContainers.emplace(label, std::make_unique<RDaosFakeContainer>());
185 }
186
187 RDaosFakeContainer *GetContainer(const label_t &label)
188 {
189 std::lock_guard<std::mutex> lock(fMutexContainers);
190 auto it = fContainers.find(label);
191 return (it != fContainers.end()) ? it->second.get() : nullptr;
192 }
193};
194
195std::mutex RDaosFakePool::fMutexPools;
196std::unordered_map<label_t, std::unique_ptr<RDaosFakePool>> RDaosFakePool::fPools;
197
198// clang-format off
199/**
200\class RDaosHandle
201\brief Translates a `daos_handle_t` to a pointer to object and viceversa.
202
203A `daos_handle_t` is used by some API functions (in particular, those that work
204with pools, containers, or objects) to reference an entity. This type (aka
205`uint64_t`) is large enough for a pointer in all architectures. However, an
206indirection layer is added in order to detect the use of invalidated handles.
207*/
208// clang-format on
209class RDaosHandle {
210private:
211 /// \brief Wrapper over a `void *` that may help to detect the use of invalid handles.
212 struct Cookie {
213 Cookie(void *p) : fPointer(p) {}
214 ~Cookie() { fPointer = nullptr; }
215 void *GetPointer() { return fPointer; }
216
217 void *fPointer;
218 };
219
220public:
221 template <typename T>
222 static inline daos_handle_t ToHandle(const T &p)
223 {
224 return {reinterpret_cast<decltype(daos_handle_t::cookie)>(new Cookie(p))};
225 }
226
227 template <typename T>
228 static inline typename std::add_pointer<T>::type ToPointer(const daos_handle_t h)
229 {
230 return reinterpret_cast<typename std::add_pointer<T>::type>(reinterpret_cast<Cookie *>(h.cookie)->GetPointer());
231 }
232
233 static inline void Invalidate(daos_handle_t h) { delete reinterpret_cast<Cookie *>(h.cookie); }
234};
235
236} // anonymous namespace
237
238extern "C" {
239int daos_init(void)
240{
241 R__LOG_WARNING(ROOT::Internal::NTupleLog()) << "This RNTuple build uses libdaos_mock. Use only for testing!";
242 return 0;
243}
244
245int daos_fini(void)
246{
247 return 0;
248}
249
250const char *d_errstr(int rc)
251{
252 return rc ? "DER_INVAL" : "Success";
253}
254
255int daos_oclass_name2id(const char *name)
256{
257 if (strcmp(name, "SX") == 0)
258 return OC_SX;
259 if (strcmp(name, "RP_XSF") == 0)
260 return OC_RP_XSF;
261 return OC_UNKNOWN;
262}
263
265{
266 switch (oc_id) {
267 case OC_SX:
268 strcpy(name, "SX"); // NOLINT
269 return 0;
270 case OC_RP_XSF:
271 strcpy(name, "RP_XSF"); // NOLINT
272 return 0;
273 }
274 return -1;
275}
276
277////////////////////////////////////////////////////////////////////////////////
278
279int daos_cont_create_with_label(daos_handle_t poh, const char *label, daos_prop_t * /*cont_prop*/, uuid_t * /*uuid*/,
280 daos_event_t * /*ev*/)
281{
282 auto pool = RDaosHandle::ToPointer<RDaosFakePool>(poh);
283 if (!pool)
284 return -DER_INVAL;
285
286 if (!daos_label_is_valid(label))
287 return -DER_INVAL;
288
289 pool->CreateContainer(label_t(label));
290 return 0;
291}
292
293int daos_cont_open(daos_handle_t poh, const char *label, unsigned int /*flags*/, daos_handle_t *coh,
294 daos_cont_info_t * /*info*/, daos_event_t * /*ev*/)
295{
296 auto pool = RDaosHandle::ToPointer<RDaosFakePool>(poh);
297 if (!pool)
298 return -DER_INVAL;
299
300 if (!daos_label_is_valid(label))
301 return -DER_INVAL;
302
303 auto cont = pool->GetContainer(label_t(label));
304 if (!cont)
305 return -DER_INVAL;
306 *coh = RDaosHandle::ToHandle(cont);
307 return 0;
308}
309
311{
312 RDaosHandle::Invalidate(coh);
313 return 0;
314}
315
316////////////////////////////////////////////////////////////////////////////////
317
319{
320 return 0;
321}
322
323int daos_eq_destroy(daos_handle_t /*eqh*/, int /*flags*/)
324{
325 return 0;
326}
327
328int daos_eq_poll(daos_handle_t /*eqh*/, int /*wait_running*/, int64_t /*timeout*/, unsigned int nevents,
329 daos_event_t ** /*events*/)
330{
331 return nevents;
332}
333
334int daos_event_test(daos_event * /*ev*/, int64_t /*timeout*/, bool *flag)
335{
336 if (flag != nullptr)
337 *flag = true;
338 return 0;
339}
340
342{
343 return 0;
344}
345
346int daos_event_init(daos_event_t * /*ev*/, daos_handle_t /*eqh*/, daos_event_t * /*parent*/)
347{
348 return 0;
349}
350
352{
353 return 0;
354}
355
356////////////////////////////////////////////////////////////////////////////////
357
358int daos_obj_open(daos_handle_t coh, daos_obj_id_t oid, unsigned int mode, daos_handle_t *oh, daos_event_t * /*ev*/)
359{
360 auto cont = RDaosHandle::ToPointer<RDaosFakeContainer>(coh);
361 if (!cont)
362 return -DER_INVAL;
363 auto obj = cont->GetObject(oid, mode);
364 *oh = RDaosHandle::ToHandle(obj);
365 return 0;
366}
367
369{
370 RDaosHandle::Invalidate(oh);
371 return 0;
372}
373
375 daos_oclass_hints_t /*hints*/, uint32_t /*args*/)
376{
377 uint64_t hdr;
378
379 /* Validate user-specified bits are not reserved by DAOS */
380 if (!daos_otype_t_is_valid(type))
381 return -DER_INVAL;
382
383 oid->hi &= (1ULL << OID_FMT_INTR_BITS) - 1;
384 // | Upper bits contain
385 // | OID_FMT_TYPE_BITS (object type)
386 // | OID_FMT_META_BITS (object class metadata)
387 // | OID_FMT_CLASS_BITS (object class)
388 // | 96-bit for upper layer
389 hdr = ((uint64_t)type << OID_FMT_TYPE_SHIFT);
390 hdr |= ((uint64_t)0 << OID_FMT_META_SHIFT);
391 hdr |= ((uint64_t)cid << OID_FMT_CLASS_SHIFT);
392 oid->hi |= hdr;
393
394 return 0;
395}
396
397int daos_obj_fetch(daos_handle_t oh, daos_handle_t /*th*/, uint64_t /*flags*/, daos_key_t *dkey, unsigned int nr,
398 daos_iod_t *iods, d_sg_list_t *sgls, daos_iom_t * /*ioms*/, daos_event_t * /*ev*/)
399{
400 auto obj = RDaosHandle::ToPointer<RDaosFakeObject>(oh);
401 if (!obj)
402 return -DER_INVAL;
403 return obj->Fetch(dkey, nr, iods, sgls);
404}
405
406int daos_obj_update(daos_handle_t oh, daos_handle_t /*th*/, uint64_t /*flags*/, daos_key_t *dkey, unsigned int nr,
407 daos_iod_t *iods, d_sg_list_t *sgls, daos_event_t * /*ev*/)
408{
409 auto obj = RDaosHandle::ToPointer<RDaosFakeObject>(oh);
410 if (!obj)
411 return -DER_INVAL;
412 return obj->Update(dkey, nr, iods, sgls);
413}
414
415////////////////////////////////////////////////////////////////////////////////
416
417int daos_pool_connect(const char *label, const char * /*grp*/, unsigned int /*flags*/, daos_handle_t *poh,
418 daos_pool_info_t * /*info*/, daos_event_t * /*ev*/)
419{
420
421 *poh = RDaosHandle::ToHandle(RDaosFakePool::GetPool(label_t(label)));
422 return 0;
423}
424
426{
427 RDaosHandle::Invalidate(poh);
428 return 0;
429}
430
431} // extern "C"
#define R__LOG_WARNING(...)
Definition RLogger.hxx:357
#define h(i)
Definition RSha256.hxx:106
char name[80]
Definition TGX11.cxx:148
TRObject operator()(const T1 &t1) const
This file is a reduced version of daos_xxx.h headers that provides (simplified) declarations for use ...
int daos_oclass_id2name(daos_oclass_id_t oc_id, char *name)
const char * d_errstr(int rc)
int daos_pool_disconnect(daos_handle_t poh, daos_event_t *ev)
d_iov_t daos_key_t
Definition daos.h:76
daos_otype_t
DAOS object type.
Definition daos.h:162
int daos_oclass_name2id(const char *name)
int daos_obj_fetch(daos_handle_t oh, daos_handle_t th, uint64_t flags, daos_key_t *dkey, unsigned int nr, daos_iod_t *iods, d_sg_list_t *sgls, daos_iom_t *ioms, daos_event_t *ev)
@ OC_SX
Definition daos.h:129
@ OC_UNKNOWN
Definition daos.h:109
@ OC_RP_XSF
Replicated object class which is extremely scalable for fetch.
Definition daos.h:112
int daos_obj_open(daos_handle_t coh, daos_obj_id_t oid, unsigned int mode, daos_handle_t *oh, daos_event_t *ev)
uint16_t daos_oclass_hints_t
Definition daos.h:136
int daos_pool_connect(const char *pool, const char *grp, unsigned int flags, daos_handle_t *poh, daos_pool_info_t *info, daos_event_t *ev)
int daos_event_fini(daos_event_t *ev)
int daos_init(void)
int daos_obj_generate_oid(daos_handle_t coh, daos_obj_id_t *oid, enum daos_otype_t type, daos_oclass_id_t cid, daos_oclass_hints_t hints, uint32_t args)
int daos_obj_update(daos_handle_t oh, daos_handle_t th, uint64_t flags, daos_key_t *dkey, unsigned int nr, daos_iod_t *iods, d_sg_list_t *sgls, daos_event_t *ev)
#define OID_FMT_META_SHIFT
Definition daos.h:159
int daos_cont_close(daos_handle_t coh, daos_event_t *ev)
static bool daos_label_is_valid(const char *)
Definition daos.h:247
uint16_t daos_oclass_id_t
Definition daos.h:135
#define OID_FMT_INTR_BITS
Definition daos.h:152
int daos_event_init(daos_event_t *ev, daos_handle_t eqh, daos_event_t *parent)
int daos_event_test(daos_event_t *ev, int64_t timeout, bool *flag)
struct daos_event daos_event_t
Event and event queue.
static bool daos_otype_t_is_valid(enum daos_otype_t type)
Definition daos.h:172
int daos_eq_create(daos_handle_t *eqh)
int daos_obj_close(daos_handle_t oh, daos_event_t *ev)
@ DAOS_IOD_SINGLE
Definition daos.h:195
int daos_cont_create_with_label(daos_handle_t poh, const char *label, daos_prop_t *cont_prop, uuid_t *uuid, daos_event_t *ev)
int daos_eq_destroy(daos_handle_t eqh, int flags)
int daos_eq_poll(daos_handle_t eqh, int wait_running, int64_t timeout, unsigned int nevents, daos_event_t **events)
int daos_cont_open(daos_handle_t poh, const char *uuid, unsigned int flags, daos_handle_t *coh, daos_cont_info_t *info, daos_event_t *ev)
#define DER_INVAL
Definition daos.h:284
#define OID_FMT_CLASS_SHIFT
Definition daos.h:158
int daos_fini(void)
int daos_event_parent_barrier(daos_event_t *ev)
#define OID_FMT_TYPE_SHIFT
Definition daos.h:157
bool operator==(const daos_obj_id_t &lhs, const daos_obj_id_t &rhs)
std::string label_t
ROOT::RLogChannel & NTupleLog()
Log channel for RNTuple diagnostics.
size_t iov_buf_len
Definition daos.h:39
void * iov_buf
Definition daos.h:38
Scatter/gather list for memory buffers.
Definition daos.h:44
d_iov_t * sg_iovs
Definition daos.h:47
uint32_t sg_nr
Definition daos.h:45
Container information.
Definition daos.h:259
Event and event queue.
Definition daos.h:79
Generic handle for various DAOS components like container, object, etc.
Definition daos.h:59
uint64_t cookie
Definition daos.h:60
uint64_t hi
Definition daos.h:147
uint64_t lo
Definition daos.h:146
Storage pool.
Definition daos.h:273
daos properties, for pool or container
Definition daos.h:239