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