1 /*
2 * Copyright (C) by Argonne National Laboratory
3 * See COPYRIGHT in top-level directory
4 */
5
6 #include "ad_daos.h"
7 #include "gurt/hash.h"
8 #include <gurt/common.h>
9
10 static struct d_hash_table *coh_hash;
11 static struct d_hash_table *poh_hash;
12
13 enum {
14 DAOS_POOL,
15 DAOS_CONT,
16 };
17
hdl_obj(d_list_t * rlink)18 static inline struct adio_daos_hdl *hdl_obj(d_list_t * rlink)
19 {
20 return container_of(rlink, struct adio_daos_hdl, entry);
21 }
22
23 static bool
key_cmp(struct d_hash_table * htable,d_list_t * rlink,const void * key,unsigned int ksize)24 key_cmp(struct d_hash_table *htable, d_list_t * rlink, const void *key, unsigned int ksize)
25 {
26 struct adio_daos_hdl *hdl = hdl_obj(rlink);
27
28 return (strcmp(hdl->value, key) == 0);
29 }
30
rec_addref(struct d_hash_table * htable,d_list_t * rlink)31 static void rec_addref(struct d_hash_table *htable, d_list_t * rlink)
32 {
33 hdl_obj(rlink)->ref++;
34 }
35
rec_decref(struct d_hash_table * htable,d_list_t * rlink)36 static bool rec_decref(struct d_hash_table *htable, d_list_t * rlink)
37 {
38 struct adio_daos_hdl *hdl = hdl_obj(rlink);
39
40 assert(hdl->ref > 0);
41 hdl->ref--;
42 return (hdl->ref == 0);
43 }
44
rec_free(struct d_hash_table * htable,d_list_t * rlink)45 static void rec_free(struct d_hash_table *htable, d_list_t * rlink)
46 {
47 struct adio_daos_hdl *hdl = hdl_obj(rlink);
48
49 assert(d_hash_rec_unlinked(&hdl->entry));
50 assert(hdl->ref == 0);
51
52 if (hdl->type == DAOS_POOL)
53 daos_pool_disconnect(hdl->open_hdl, NULL);
54 else if (hdl->type == DAOS_CONT) {
55 dfs_umount(hdl->dfs);
56 daos_cont_close(hdl->open_hdl, NULL);
57 } else
58 assert(0);
59 ADIOI_Free(hdl);
60 }
61
rec_hash(struct d_hash_table * htable,d_list_t * rlink)62 static uint32_t rec_hash(struct d_hash_table *htable, d_list_t * rlink)
63 {
64 struct adio_daos_hdl *hdl = hdl_obj(rlink);
65
66 return d_hash_string_u32(hdl->value, strlen(hdl->value));
67 }
68
69 static d_hash_table_ops_t hdl_hash_ops = {
70 .hop_key_cmp = key_cmp,
71 .hop_rec_addref = rec_addref,
72 .hop_rec_decref = rec_decref,
73 .hop_rec_free = rec_free,
74 .hop_rec_hash = rec_hash
75 };
76
adio_daos_hash_init(void)77 int adio_daos_hash_init(void)
78 {
79 int rc;
80
81 rc = d_hash_table_create(D_HASH_FT_EPHEMERAL | D_HASH_FT_LRU,
82 4, NULL, &hdl_hash_ops, &poh_hash);
83 if (rc)
84 return rc;
85
86 return d_hash_table_create(D_HASH_FT_EPHEMERAL | D_HASH_FT_LRU,
87 4, NULL, &hdl_hash_ops, &coh_hash);
88 }
89
adio_daos_hash_finalize(void)90 void adio_daos_hash_finalize(void)
91 {
92 d_list_t *rlink;
93
94 while (1) {
95 rlink = d_hash_rec_first(coh_hash);
96 if (rlink == NULL)
97 break;
98
99 d_hash_rec_decref(coh_hash, rlink);
100 }
101 d_hash_table_destroy(coh_hash, false);
102
103 while (1) {
104 rlink = d_hash_rec_first(poh_hash);
105 if (rlink == NULL)
106 break;
107
108 d_hash_rec_decref(poh_hash, rlink);
109 }
110 d_hash_table_destroy(poh_hash, false);
111 }
112
adio_daos_poh_lookup(struct duns_attr_t * attr)113 struct adio_daos_hdl *adio_daos_poh_lookup(struct duns_attr_t *attr)
114 {
115 d_list_t *rlink;
116
117 #if CHECK_DAOS_API_VERSION(1, 4)
118 rlink = d_hash_rec_find(poh_hash, attr->da_pool, strlen(attr->da_pool));
119 #else
120 char str[37];
121
122 uuid_unparse(attr->da_puuid, str);
123 rlink = d_hash_rec_find(poh_hash, str, strlen(str));
124 #endif
125 if (rlink == NULL)
126 return NULL;
127
128 return hdl_obj(rlink);
129 }
130
adio_daos_poh_release(struct adio_daos_hdl * hdl)131 void adio_daos_poh_release(struct adio_daos_hdl *hdl)
132 {
133 d_hash_rec_decref(poh_hash, &hdl->entry);
134 }
135
adio_daos_poh_insert(struct duns_attr_t * attr,daos_handle_t poh,struct adio_daos_hdl ** hdl)136 int adio_daos_poh_insert(struct duns_attr_t *attr, daos_handle_t poh, struct adio_daos_hdl **hdl)
137 {
138 struct adio_daos_hdl *phdl;
139 int rc;
140
141 phdl = (struct adio_daos_hdl *) ADIOI_Calloc(1, sizeof(struct adio_daos_hdl));
142 if (phdl == NULL)
143 return -1;
144
145 phdl->type = DAOS_POOL;
146 phdl->open_hdl.cookie = poh.cookie;
147 phdl->ref = 2;
148 #if CHECK_DAOS_API_VERSION(1, 4)
149 strncpy(phdl->value, attr->da_pool, DAOS_PROP_LABEL_MAX_LEN + 1);
150 phdl->value[DAOS_PROP_LABEL_MAX_LEN] = 0;
151 #else
152 uuid_unparse(attr->da_puuid, phdl->value);
153 #endif
154 rc = d_hash_rec_insert(poh_hash, phdl->value, strlen(phdl->value) + 1, &phdl->entry, true);
155 if (rc) {
156 PRINT_MSG(stderr, "Failed to add pool hdl to hashtable (%d)\n", rc);
157 goto free_hdl;
158 }
159
160 *hdl = phdl;
161
162 return 0;
163
164 free_hdl:
165 ADIOI_Free(phdl);
166 return rc;
167 }
168
adio_daos_poh_lookup_connect(struct duns_attr_t * attr,struct adio_daos_hdl ** hdl)169 int adio_daos_poh_lookup_connect(struct duns_attr_t *attr, struct adio_daos_hdl **hdl)
170 {
171 struct adio_daos_hdl *phdl;
172 char *sys = NULL;
173 daos_handle_t poh;
174 int rc;
175
176 phdl = adio_daos_poh_lookup(attr);
177 if (phdl != NULL) {
178 *hdl = phdl;
179 return 0;
180 }
181
182 /** Get the DAOS system name from env variable */
183 #if CHECK_DAOS_API_VERSION(1, 4)
184 if (attr->da_sys)
185 sys = attr->da_sys;
186 #endif
187
188 if (sys == NULL)
189 sys = getenv("DAOS_SYSTEM");
190
191 #if CHECK_DAOS_API_VERSION(1, 4)
192 rc = daos_pool_connect(attr->da_pool, sys, DAOS_PC_RW, &poh, NULL, NULL);
193 #else
194 rc = daos_pool_connect(attr->da_puuid, sys, DAOS_PC_RW, &poh, NULL, NULL);
195 #endif
196 if (rc < 0) {
197 PRINT_MSG(stderr, "Failed to connect to pool (%d)\n", rc);
198 goto free_hdl;
199 }
200
201 rc = adio_daos_poh_insert(attr, poh, &phdl);
202 if (rc) {
203 PRINT_MSG(stderr, "Failed to add phdl to hashtable (%d)\n", rc);
204 goto err_pool;
205 }
206
207 *hdl = phdl;
208
209 return 0;
210
211 err_pool:
212 daos_pool_disconnect(phdl->open_hdl, NULL);
213 free_hdl:
214 ADIOI_Free(phdl);
215 return rc;
216 }
217
adio_daos_coh_lookup(struct duns_attr_t * attr)218 struct adio_daos_hdl *adio_daos_coh_lookup(struct duns_attr_t *attr)
219 {
220 d_list_t *rlink;
221
222 #if CHECK_DAOS_API_VERSION(1, 4)
223 rlink = d_hash_rec_find(coh_hash, attr->da_cont, strlen(attr->da_cont));
224 #else
225 char str[37];
226
227 uuid_unparse(attr->da_cuuid, str);
228 rlink = d_hash_rec_find(coh_hash, str, strlen(str));
229 #endif
230 if (rlink == NULL)
231 return NULL;
232
233 return hdl_obj(rlink);
234 }
235
adio_daos_coh_release(struct adio_daos_hdl * hdl)236 void adio_daos_coh_release(struct adio_daos_hdl *hdl)
237 {
238 d_hash_rec_decref(coh_hash, &hdl->entry);
239 }
240
adio_daos_coh_insert(struct duns_attr_t * attr,daos_handle_t coh,dfs_t * dfs,struct adio_daos_hdl ** hdl)241 int adio_daos_coh_insert(struct duns_attr_t *attr, daos_handle_t coh, dfs_t * dfs,
242 struct adio_daos_hdl **hdl)
243 {
244 struct adio_daos_hdl *co_hdl;
245 int rc;
246
247 co_hdl = (struct adio_daos_hdl *) ADIOI_Calloc(1, sizeof(struct adio_daos_hdl));
248 if (co_hdl == NULL)
249 return -1;
250
251 co_hdl->type = DAOS_CONT;
252 co_hdl->dfs = dfs;
253 co_hdl->open_hdl.cookie = coh.cookie;
254 co_hdl->ref = 2;
255 #if CHECK_DAOS_API_VERSION(1, 4)
256 strncpy(co_hdl->value, attr->da_cont, DAOS_PROP_LABEL_MAX_LEN + 1);
257 co_hdl->value[DAOS_PROP_LABEL_MAX_LEN] = 0;
258 #else
259 uuid_unparse(attr->da_cuuid, co_hdl->value);
260 #endif
261 rc = d_hash_rec_insert(coh_hash, co_hdl->value, strlen(co_hdl->value), &co_hdl->entry, true);
262 if (rc) {
263 PRINT_MSG(stderr, "Failed to add container hdl to hashtable (%d)\n", rc);
264 goto err_coh;
265 }
266
267 *hdl = co_hdl;
268
269 return 0;
270
271 err_coh:
272 ADIOI_Free(co_hdl);
273 return rc;
274 }
275
276 int
adio_daos_coh_lookup_create(daos_handle_t poh,struct duns_attr_t * attr,int amode,bool create,struct adio_daos_hdl ** hdl)277 adio_daos_coh_lookup_create(daos_handle_t poh, struct duns_attr_t *attr, int amode,
278 bool create, struct adio_daos_hdl **hdl)
279 {
280 struct adio_daos_hdl *co_hdl;
281 daos_handle_t coh;
282 dfs_t *dfs;
283 int rc;
284
285 co_hdl = adio_daos_coh_lookup(attr);
286 if (co_hdl != NULL) {
287 *hdl = co_hdl;
288 return 0;
289 }
290
291 /* Try to open the DAOS container first */
292 #if CHECK_DAOS_API_VERSION(1, 4)
293 rc = daos_cont_open(poh, attr->da_cont, DAOS_COO_RW, &coh, NULL, NULL);
294 #else
295 rc = daos_cont_open(poh, attr->da_cuuid, DAOS_COO_RW, &coh, NULL, NULL);
296 #endif
297 /* If fails with NOEXIST we can create it then reopen if create mode */
298 if (rc == -DER_NONEXIST && create) {
299 #if CHECK_DAOS_API_VERSION(1, 4)
300 uuid_t cuuid;
301
302 if (uuid_parse(attr->da_cont, cuuid) != 0) {
303 rc = dfs_cont_create_with_label(poh, attr->da_cont, NULL, &cuuid, &coh, &dfs);
304 } else {
305 rc = dfs_cont_create(poh, cuuid, NULL, &coh, &dfs);
306 }
307 #else
308 rc = dfs_cont_create(poh, attr->da_cuuid, NULL, &coh, &dfs);
309 #endif
310 /** if someone got there first, re-open*/
311 if (rc == EEXIST) {
312 #if CHECK_DAOS_API_VERSION(1, 4)
313 rc = daos_cont_open(poh, attr->da_cont, DAOS_COO_RW, &coh, NULL, NULL);
314 #else
315 rc = daos_cont_open(poh, attr->da_cuuid, DAOS_COO_RW, &coh, NULL, NULL);
316 #endif
317 if (rc) {
318 PRINT_MSG(stderr, "Failed to create DFS container (%d)\n", rc);
319 goto free_coh;
320 }
321 rc = dfs_mount(poh, coh, amode, &dfs);
322 if (rc) {
323 PRINT_MSG(stderr, "Failed to mount DFS namesapce (%d)\n", rc);
324 goto err_cont;
325 }
326 } else if (rc) {
327 PRINT_MSG(stderr, "Failed to create DFS container (%d)\n", rc);
328 goto free_coh;
329 }
330 } else if (rc == 0) {
331 /* Mount a DFS namespace on the container */
332 rc = dfs_mount(poh, coh, amode, &dfs);
333 if (rc) {
334 PRINT_MSG(stderr, "Failed to mount DFS namespace (%d)\n", rc);
335 goto err_cont;
336 }
337 } else {
338 goto free_coh;
339 }
340
341 rc = adio_daos_coh_insert(attr, coh, dfs, &co_hdl);
342 if (rc) {
343 PRINT_MSG(stderr, "Failed to add container hdl to hashtable (%d)\n", rc);
344 goto err_dfs;
345 }
346
347 *hdl = co_hdl;
348 return 0;
349
350 err_dfs:
351 dfs_umount(dfs);
352 err_cont:
353 daos_cont_close(coh, NULL);
354 free_coh:
355 ADIOI_Free(co_hdl);
356 return rc;
357 }
358