Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
complete s4u::Storage interface, what a mess...
[simgrid.git] / src / msg / msg_io.cpp
1 /* Copyright (c) 2004-2016. The SimGrid Team. All rights reserved.          */
2
3 /* This program is free software; you can redistribute it and/or modify it
4  * under the terms of the license (GNU LGPL) which comes with this package. */
5
6 #include "simgrid/s4u/host.hpp"
7 #include "src/msg/msg_private.h"
8 #include "src/surf/storage_interface.hpp"
9 #include <numeric>
10
11 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(msg_io, msg, "Logging specific to MSG (io)");
12
13 SG_BEGIN_DECL()
14
15 /** @addtogroup msg_file
16  * (#msg_file_t) and the functions for managing it.
17  *
18  *  \see #msg_file_t
19  */
20
21 /********************************* File **************************************/
22 void __MSG_file_get_info(msg_file_t fd){
23
24   msg_file_priv_t priv = MSG_file_priv(fd);
25   xbt_dynar_t info = simcall_file_get_info(priv->simdata->smx_file);
26   sg_size_t *psize;
27
28   priv->content_type = xbt_dynar_pop_as(info, char *);
29   priv->storage_type = xbt_dynar_pop_as(info, char *);
30   priv->storageId = xbt_dynar_pop_as(info, char *);
31   priv->mount_point = xbt_dynar_pop_as(info, char *);
32   psize = xbt_dynar_pop_as(info, sg_size_t*);
33   priv->size = *psize;
34   xbt_free(psize);
35   xbt_dynar_free_container(&info);
36 }
37
38 static int MSG_host_get_file_descriptor_id(msg_host_t host)
39 {
40   simgrid::MsgHostExt* priv = host->extension<simgrid::MsgHostExt>();
41   if (priv->file_descriptor_table == nullptr) {
42     priv->file_descriptor_table = new std::vector<int>(sg_storage_max_file_descriptors);
43     std::iota(priv->file_descriptor_table->rbegin(), priv->file_descriptor_table->rend(), 0); // Fill with ..., 1, 0.
44   }
45   xbt_assert(!priv->file_descriptor_table->empty(), "Too much files are opened! Some have to be closed.");
46   int desc = priv->file_descriptor_table->back();
47   priv->file_descriptor_table->pop_back();
48   return desc;
49 }
50
51 static void MSG_host_release_file_descriptor_id(msg_host_t host, int id)
52 {
53   host->extension<simgrid::MsgHostExt>()->file_descriptor_table->push_back(id);
54 }
55
56 /** \ingroup msg_file
57  *
58  * \brief Set the user data of a #msg_file_t.
59  *
60  * This functions attach \a data to \a file.
61  */
62 msg_error_t MSG_file_set_data(msg_file_t fd, void *data)
63 {
64   msg_file_priv_t priv = MSG_file_priv(fd);
65   priv->data = data;
66   return MSG_OK;
67 }
68
69 /** \ingroup msg_file
70  *
71  * \brief Return the user data of a #msg_file_t.
72  *
73  * This functions checks whether \a file is a valid pointer and return the user data associated to \a file if possible.
74  */
75 void *MSG_file_get_data(msg_file_t fd)
76 {
77   msg_file_priv_t priv = MSG_file_priv(fd);
78   return priv->data;
79 }
80
81 /** \ingroup msg_file
82  * \brief Display information related to a file descriptor
83  *
84  * \param fd is a the file descriptor
85  */
86 void MSG_file_dump (msg_file_t fd){
87   /* Update the cached information first */
88   __MSG_file_get_info(fd);
89
90   msg_file_priv_t priv = MSG_file_priv(fd);
91   XBT_INFO("File Descriptor information:\n"
92            "\t\tFull path: '%s'\n"
93            "\t\tSize: %llu\n"
94            "\t\tMount point: '%s'\n"
95            "\t\tStorage Id: '%s'\n"
96            "\t\tStorage Type: '%s'\n"
97            "\t\tContent Type: '%s'\n"
98            "\t\tFile Descriptor Id: %d",
99            priv->fullpath, priv->size, priv->mount_point,
100            priv->storageId, priv->storage_type,
101            priv->content_type, priv->desc_id);
102 }
103
104 /** \ingroup msg_file
105  * \brief Read a file (local or remote)
106  *
107  * \param size of the file to read
108  * \param fd is a the file descriptor
109  * \return the number of bytes successfully read or -1 if an error occurred
110  */
111 sg_size_t MSG_file_read(msg_file_t fd, sg_size_t size)
112 {
113   msg_file_priv_t file_priv = MSG_file_priv(fd);
114   sg_size_t read_size;
115
116   if (file_priv->size == 0) /* Nothing to read, return */
117     return 0;
118
119   /* Find the host where the file is physically located and read it */
120   msg_storage_t storage_src = static_cast<msg_storage_t>(xbt_lib_get_elm_or_null(storage_lib, file_priv->storageId));
121   msg_storage_priv_t storage_priv_src = MSG_storage_priv(storage_src);
122   msg_host_t attached_host = MSG_host_by_name(storage_priv_src->hostname);
123   read_size = simcall_file_read(file_priv->simdata->smx_file, size, attached_host);
124
125   if (strcmp(storage_priv_src->hostname, MSG_host_self()->cname())) {
126     /* the file is hosted on a remote host, initiate a communication between src and dest hosts for data transfer */
127     XBT_DEBUG("File is on %s remote host, initiate data transfer of %llu bytes.", storage_priv_src->hostname, read_size);
128     msg_host_t *m_host_list = nullptr;
129     m_host_list = xbt_new0(msg_host_t, 2);
130
131     m_host_list[0] = MSG_host_self();
132     m_host_list[1] = attached_host;
133     double flops_amount[] = { 0, 0};
134     double bytes_amount[] = { 0, 0, static_cast<double>(read_size), 0 };
135
136     msg_task_t task = MSG_parallel_task_create("file transfer for read", 2, m_host_list, flops_amount, bytes_amount,
137                       nullptr);
138     msg_error_t transfer = MSG_parallel_task_execute(task);
139     MSG_task_destroy(task);
140     xbt_free(m_host_list);
141     if(transfer != MSG_OK){
142       if (transfer == MSG_HOST_FAILURE)
143         XBT_WARN("Transfer error, %s remote host just turned off!", attached_host->cname());
144       if (transfer == MSG_TASK_CANCELED)
145         XBT_WARN("Transfer error, task has been canceled!");
146
147       return -1;
148     }
149   }
150   return read_size;
151 }
152
153 /** \ingroup msg_file
154  * \brief Write into a file (local or remote)
155  *
156  * \param size of the file to write
157  * \param fd is a the file descriptor
158  * \return the number of bytes successfully write or -1 if an error occurred
159  */
160 sg_size_t MSG_file_write(msg_file_t fd, sg_size_t size)
161 {
162   msg_file_priv_t file_priv = MSG_file_priv(fd);
163
164   if (size == 0) /* Nothing to write, return */
165     return 0;
166
167   /* Find the host where the file is physically located (remote or local)*/
168   msg_storage_t storage_src = static_cast<msg_storage_t>(xbt_lib_get_elm_or_null(storage_lib, file_priv->storageId));
169   msg_storage_priv_t storage_priv_src = MSG_storage_priv(storage_src);
170   msg_host_t attached_host = MSG_host_by_name(storage_priv_src->hostname);
171
172   if (strcmp(storage_priv_src->hostname, MSG_host_self()->cname())) {
173     /* the file is hosted on a remote host, initiate a communication between src and dest hosts for data transfer */
174     XBT_DEBUG("File is on %s remote host, initiate data transfer of %llu bytes.", storage_priv_src->hostname, size);
175     msg_host_t *m_host_list = nullptr;
176     m_host_list = xbt_new0(msg_host_t, 2);
177
178     m_host_list[0] = MSG_host_self();
179     m_host_list[1] = attached_host;
180     double flops_amount[] = { 0, 0 };
181     double bytes_amount[] = { 0, static_cast<double>(size), 0, 0 };
182
183     msg_task_t task = MSG_parallel_task_create("file transfer for write", 2, m_host_list, flops_amount, bytes_amount,
184                                                nullptr);
185     msg_error_t transfer = MSG_parallel_task_execute(task);
186     MSG_task_destroy(task);
187     free(m_host_list);
188     if(transfer != MSG_OK){
189       if (transfer == MSG_HOST_FAILURE)
190         XBT_WARN("Transfer error, %s remote host just turned off!", attached_host->cname());
191       if (transfer == MSG_TASK_CANCELED)
192         XBT_WARN("Transfer error, task has been canceled!");
193
194       return -1;
195     }
196   }
197   /* Write file on local or remote host */
198   sg_size_t offset = simcall_file_tell(file_priv->simdata->smx_file);
199   sg_size_t write_size = simcall_file_write(file_priv->simdata->smx_file, size, attached_host);
200   file_priv->size = offset+write_size;
201
202   return write_size;
203 }
204
205 /** \ingroup msg_file
206  * \brief Opens the file whose name is the string pointed to by path
207  *
208  * \param fullpath is the file location on the storage
209  * \param data user data to attach to the file
210  *
211  * \return An #msg_file_t associated to the file
212  */
213 msg_file_t MSG_file_open(const char* fullpath, void* data)
214 {
215   char *name;
216   msg_file_priv_t priv = xbt_new(s_msg_file_priv_t, 1);
217   priv->data = data;
218   priv->fullpath = xbt_strdup(fullpath);
219   priv->simdata = xbt_new0(s_simdata_file_t,1);
220   priv->simdata->smx_file = simcall_file_open(fullpath, MSG_host_self());
221   priv->desc_id           = MSG_host_get_file_descriptor_id(MSG_host_self());
222
223   name = bprintf("%s:%s:%d", priv->fullpath, MSG_host_self()->cname(), priv->desc_id);
224
225   xbt_lib_set(file_lib, name, MSG_FILE_LEVEL, priv);
226   msg_file_t fd = static_cast<msg_file_t>(xbt_lib_get_elm_or_null(file_lib, name));
227   __MSG_file_get_info(fd);
228   xbt_free(name);
229
230   return fd;
231 }
232
233 /** \ingroup msg_file
234  * \brief Close the file
235  *
236  * \param fd is the file to close
237  * \return 0 on success or 1 on error
238  */
239 int MSG_file_close(msg_file_t fd)
240 {
241   char *name;
242   msg_file_priv_t priv = MSG_file_priv(fd);
243   if (priv->data)
244     xbt_free(priv->data);
245
246   int res = simcall_file_close(priv->simdata->smx_file, MSG_host_self());
247   name    = bprintf("%s:%s:%d", priv->fullpath, MSG_host_self()->cname(), priv->desc_id);
248   MSG_host_release_file_descriptor_id(MSG_host_self(), priv->desc_id);
249   xbt_lib_unset(file_lib, name, MSG_FILE_LEVEL, 1);
250   xbt_free(name);
251   return res;
252 }
253
254 /** \ingroup msg_file
255  * \brief Unlink the file pointed by fd
256  *
257  * \param fd is the file descriptor (#msg_file_t)
258  * \return 0 on success or 1 on error
259  */
260 msg_error_t MSG_file_unlink(msg_file_t fd)
261 {
262   msg_file_priv_t file_priv = MSG_file_priv(fd);
263   /* Find the host where the file is physically located (remote or local)*/
264   msg_storage_t storage_src = static_cast<msg_storage_t>(xbt_lib_get_elm_or_null(storage_lib, file_priv->storageId));
265   msg_storage_priv_t storage_priv_src = MSG_storage_priv(storage_src);
266   msg_host_t attached_host = MSG_host_by_name(storage_priv_src->hostname);
267   int res = simcall_file_unlink(file_priv->simdata->smx_file, attached_host);
268   return static_cast<msg_error_t>(res);
269 }
270
271 /** \ingroup msg_file
272  * \brief Return the size of a file
273  *
274  * \param fd is the file descriptor (#msg_file_t)
275  * \return the size of the file (as a #sg_size_t)
276  */
277 sg_size_t MSG_file_get_size(msg_file_t fd){
278   msg_file_priv_t priv = MSG_file_priv(fd);
279   return simcall_file_get_size(priv->simdata->smx_file);
280 }
281
282 /**
283  * \ingroup msg_file
284  * \brief Set the file position indicator in the msg_file_t by adding offset bytes
285  * to the position specified by origin (either SEEK_SET, SEEK_CUR, or SEEK_END).
286  *
287  * \param fd : file object that identifies the stream
288  * \param offset : number of bytes to offset from origin
289  * \param origin : Position used as reference for the offset. It is specified by one of the following constants defined
290  *                 in \<stdio.h\> exclusively to be used as arguments for this function (SEEK_SET = beginning of file,
291  *                 SEEK_CUR = current position of the file pointer, SEEK_END = end of file)
292  * \return If successful, the function returns MSG_OK (=0). Otherwise, it returns MSG_TASK_CANCELED (=8).
293  */
294 msg_error_t MSG_file_seek(msg_file_t fd, sg_offset_t offset, int origin)
295 {
296   msg_file_priv_t priv = MSG_file_priv(fd);
297   return static_cast<msg_error_t>(simcall_file_seek(priv->simdata->smx_file, offset, origin));
298 }
299
300 /**
301  * \ingroup msg_file
302  * \brief Returns the current value of the position indicator of the file
303  *
304  * \param fd : file object that identifies the stream
305  * \return On success, the current value of the position indicator is returned.
306  *
307  */
308 sg_size_t MSG_file_tell(msg_file_t fd)
309 {
310   msg_file_priv_t priv = MSG_file_priv(fd);
311   return simcall_file_tell(priv->simdata->smx_file);
312 }
313
314 const char *MSG_file_get_name(msg_file_t fd) {
315   xbt_assert((fd != nullptr), "Invalid parameters");
316   msg_file_priv_t priv = MSG_file_priv(fd);
317   return priv->fullpath;
318 }
319
320 /**
321  * \ingroup msg_file
322  * \brief Move a file to another location on the *same mount point*.
323  *
324  */
325 msg_error_t MSG_file_move (msg_file_t fd, const char* fullpath)
326 {
327   msg_file_priv_t priv = MSG_file_priv(fd);
328   return static_cast<msg_error_t>(simcall_file_move(priv->simdata->smx_file, fullpath));
329 }
330
331 /**
332  * \ingroup msg_file
333  * \brief Copy a file to another location on a remote host.
334  * \param file : the file to move
335  * \param host : the remote host where the file has to be copied
336  * \param fullpath : the complete path destination on the remote host
337  * \return If successful, the function returns MSG_OK. Otherwise, it returns MSG_TASK_CANCELED.
338  */
339 msg_error_t MSG_file_rcopy (msg_file_t file, msg_host_t host, const char* fullpath)
340 {
341   msg_file_priv_t file_priv = MSG_file_priv(file);
342   sg_size_t read_size;
343
344   /* Find the host where the file is physically located and read it */
345   msg_storage_t storage_src = static_cast<msg_storage_t>(xbt_lib_get_elm_or_null(storage_lib, file_priv->storageId));
346   msg_storage_priv_t storage_priv_src = MSG_storage_priv(storage_src);
347   msg_host_t attached_host = MSG_host_by_name(storage_priv_src->hostname);
348   MSG_file_seek(file, 0, SEEK_SET);
349   read_size = simcall_file_read(file_priv->simdata->smx_file, file_priv->size, attached_host);
350
351   /* Find the real host destination where the file will be physically stored */
352   xbt_dict_cursor_t cursor = nullptr;
353   msg_storage_t storage_dest = nullptr;
354   msg_host_t host_dest;
355   size_t longest_prefix_length = 0;
356
357   xbt_dict_t storage_list = host->mountedStoragesAsDict();
358   char *mount_name;
359   char *storage_name;
360   xbt_dict_foreach(storage_list,cursor,mount_name,storage_name){
361     char* file_mount_name = static_cast<char *>(xbt_malloc ((strlen(mount_name)+1)));
362     strncpy(file_mount_name,fullpath,strlen(mount_name)+1);
363     file_mount_name[strlen(mount_name)] = '\0';
364
365     if(!strcmp(file_mount_name,mount_name) && strlen(mount_name)>longest_prefix_length){
366       /* The current mount name is found in the full path and is bigger than the previous*/
367       longest_prefix_length = strlen(mount_name);
368       storage_dest = (msg_storage_t) xbt_lib_get_elm_or_null(storage_lib, storage_name);
369     }
370     xbt_free(file_mount_name);
371   }
372   xbt_dict_free(&storage_list);
373
374   char* host_name_dest = nullptr;
375   if(longest_prefix_length>0){
376     /* Mount point found, retrieve the host the storage is attached to */
377     msg_storage_priv_t storage_dest_priv = MSG_storage_priv(storage_dest);
378     host_name_dest = (char*)storage_dest_priv->hostname;
379     host_dest = MSG_host_by_name(host_name_dest);
380   }else{
381     XBT_WARN("Can't find mount point for '%s' on destination host '%s'", fullpath, host->cname());
382     return MSG_TASK_CANCELED;
383   }
384
385   XBT_DEBUG("Initiate data transfer of %llu bytes between %s and %s.", read_size, storage_priv_src->hostname,
386             host_name_dest);
387   msg_host_t *m_host_list = nullptr;
388   m_host_list = xbt_new0(msg_host_t, 2);
389
390   m_host_list[0] = attached_host;
391   m_host_list[1] = host_dest;
392   double flops_amount[] = { 0, 0 };
393   double bytes_amount[] = { 0, static_cast<double>(read_size), 0, 0 };
394
395   msg_task_t task =
396       MSG_parallel_task_create("file transfer for write", 2, m_host_list, flops_amount, bytes_amount, nullptr);
397   msg_error_t transfer = MSG_parallel_task_execute(task);
398   MSG_task_destroy(task);
399   xbt_free(m_host_list);
400   if(transfer != MSG_OK){
401     if (transfer == MSG_HOST_FAILURE)
402       XBT_WARN("Transfer error, %s remote host just turned off!", host_name_dest);
403     if (transfer == MSG_TASK_CANCELED)
404       XBT_WARN("Transfer error, task has been canceled!");
405
406     return transfer;
407   }
408
409   /* Create file on remote host, write it and close it */
410   smx_file_t smx_file = simcall_file_open(fullpath, host_dest);
411   simcall_file_write(smx_file, read_size, host_dest);
412   simcall_file_close(smx_file, host_dest);
413   return MSG_OK;
414 }
415
416 /**
417  * \ingroup msg_file
418  * \brief Move a file to another location on a remote host.
419  * \param file : the file to move
420  * \param host : the remote host where the file has to be moved
421  * \param fullpath : the complete path destination on the remote host
422  * \return If successful, the function returns MSG_OK. Otherwise, it returns MSG_TASK_CANCELED.
423  */
424 msg_error_t MSG_file_rmove (msg_file_t file, msg_host_t host, const char* fullpath)
425 {
426   msg_error_t res = MSG_file_rcopy(file, host, fullpath);
427   MSG_file_unlink(file);
428   return res;
429 }
430
431 /**
432  * \brief Destroys a file (internal call only)
433  */
434 void __MSG_file_destroy(msg_file_priv_t file) {
435   xbt_free(file->fullpath);
436   xbt_free(file->simdata);
437   xbt_free(file);
438 }
439
440 /********************************* Storage **************************************/
441 /** @addtogroup msg_storage_management
442  * (#msg_storage_t) and the functions for managing it.
443  */
444
445 msg_storage_t __MSG_storage_create(smx_storage_t storage)
446 {
447   msg_storage_priv_t storage_private = xbt_new0(s_msg_storage_priv_t, 1);
448
449   storage_private->name     = SIMIX_storage_get_name(storage);
450   storage_private->hostname = surf_storage_get_host(storage);
451   storage_private->size     = surf_storage_get_size(storage);
452
453   xbt_lib_set(storage_lib, storage_private->name, MSG_STORAGE_LEVEL, storage_private);
454   return xbt_lib_get_elm_or_null(storage_lib, storage_private->name);
455 }
456
457 /**
458  * \brief Destroys a storage (internal call only)
459  */
460 void __MSG_storage_destroy(msg_storage_priv_t storage) {
461   free(storage);
462 }
463
464 /** \ingroup msg_storage_management
465  *
466  * \brief Returns the name of the #msg_storage_t.
467  *
468  * This functions checks whether a storage is a valid pointer or not and return its name.
469  */
470 const char *MSG_storage_get_name(msg_storage_t storage) {
471   xbt_assert((storage != nullptr), "Invalid parameters");
472   msg_storage_priv_t priv = MSG_storage_priv(storage);
473   return priv->name;
474 }
475
476 /** \ingroup msg_storage_management
477  * \brief Returns the free space size of a storage element
478  * \param storage a storage
479  * \return the free space size of the storage element (as a #sg_size_t)
480  */
481 sg_size_t MSG_storage_get_free_size(msg_storage_t storage){
482   return simcall_storage_get_free_size(storage);
483 }
484
485 /** \ingroup msg_storage_management
486  * \brief Returns the used space size of a storage element
487  * \param storage a storage
488  * \return the used space size of the storage element (as a #sg_size_t)
489  */
490 sg_size_t MSG_storage_get_used_size(msg_storage_t storage){
491   return simcall_storage_get_used_size(storage);
492 }
493
494 /** \ingroup msg_storage_management
495  * \brief Returns a xbt_dict_t consisting of the list of properties assigned to this storage
496  * \param storage a storage
497  * \return a dict containing the properties
498  */
499 xbt_dict_t MSG_storage_get_properties(msg_storage_t storage)
500 {
501   xbt_assert((storage != nullptr), "Invalid parameters (storage is nullptr)");
502   return (simcall_storage_get_properties(storage));
503 }
504
505 /** \ingroup msg_storage_management
506  * \brief Change the value of a given storage property
507  *
508  * \param storage a storage
509  * \param name a property name
510  * \param value what to change the property to
511  */
512 void MSG_storage_set_property_value(msg_storage_t storage, const char* name, char* value)
513 {
514   xbt_dict_set(MSG_storage_get_properties(storage), name, value, nullptr);
515 }
516
517 /** \ingroup m_storage_management
518  * \brief Returns the value of a given storage property
519  *
520  * \param storage a storage
521  * \param name a property name
522  * \return value of a property (or nullptr if property not set)
523  */
524 const char *MSG_storage_get_property_value(msg_storage_t storage, const char *name)
525 {
526   return static_cast<char*>(xbt_dict_get_or_null(MSG_storage_get_properties(storage), name));
527 }
528
529 /** \ingroup msg_storage_management
530  * \brief Finds a msg_storage_t using its name.
531  * \param name the name of a storage
532  * \return the corresponding storage
533  */
534 msg_storage_t MSG_storage_get_by_name(const char *name)
535 {
536   return static_cast<msg_storage_t>(xbt_lib_get_elm_or_null(storage_lib,name));
537 }
538
539 /** \ingroup msg_storage_management
540  * \brief Returns a dynar containing all the storage elements declared at a given point of time
541  */
542 xbt_dynar_t MSG_storages_as_dynar() {
543   xbt_lib_cursor_t cursor;
544   char *key;
545   void **data;
546   xbt_dynar_t res = xbt_dynar_new(sizeof(msg_storage_t),nullptr);
547
548   xbt_lib_foreach(storage_lib, cursor, key, data) {
549     if(xbt_lib_get_level(xbt_lib_get_elm_or_null(storage_lib, key), MSG_STORAGE_LEVEL) != nullptr) {
550       xbt_dictelm_t elm = xbt_dict_cursor_get_elm(cursor);
551       xbt_dynar_push(res, &elm);
552     }
553   }
554   return res;
555 }
556
557 /** \ingroup msg_storage_management
558  *
559  * \brief Set the user data of a #msg_storage_t.
560  * This functions attach \a data to \a storage if possible.
561  */
562 msg_error_t MSG_storage_set_data(msg_storage_t storage, void *data)
563 {
564   msg_storage_priv_t priv = MSG_storage_priv(storage);
565   priv->data = data;
566   return MSG_OK;
567 }
568
569 /** \ingroup m_host_management
570  *
571  * \brief Returns the user data of a #msg_storage_t.
572  *
573  * This functions checks whether \a storage is a valid pointer and returns its associate user data if possible.
574  */
575 void *MSG_storage_get_data(msg_storage_t storage)
576 {
577   xbt_assert((storage != nullptr), "Invalid parameters");
578   msg_storage_priv_t priv = MSG_storage_priv(storage);
579   return priv->data;
580 }
581
582 /** \ingroup msg_storage_management
583  *
584  * \brief Returns the content (file list) of a #msg_storage_t.
585  * \param storage a storage
586  * \return The content of this storage element as a dict (full path file => size)
587  */
588 xbt_dict_t MSG_storage_get_content(msg_storage_t storage)
589 {
590   std::map<std::string, sg_size_t*>* content =
591       static_cast<simgrid::surf::Storage*>(surf_storage_resource_priv(storage))->getContent();
592   xbt_dict_t content_dict = xbt_dict_new_homogeneous(nullptr);
593
594   for (auto entry : *content) {
595     xbt_dict_set(content_dict, entry.first.c_str(), entry.second, nullptr);
596   }
597   return content_dict;
598 }
599
600 /** \ingroup msg_storage_management
601  *
602  * \brief Returns the size of a #msg_storage_t.
603  * \param storage a storage
604  * \return The size of the storage
605  */
606 sg_size_t MSG_storage_get_size(msg_storage_t storage)
607 {
608   msg_storage_priv_t priv = MSG_storage_priv(storage);
609   return priv->size;
610 }
611
612 /** \ingroup msg_storage_management
613  *
614  * \brief Returns the host name the storage is attached to
615  *
616  * This functions checks whether a storage is a valid pointer or not and return its name.
617  */
618 const char *MSG_storage_get_host(msg_storage_t storage) {
619   xbt_assert((storage != nullptr), "Invalid parameters");
620   msg_storage_priv_t priv = MSG_storage_priv(storage);
621   return priv->hostname;
622 }
623
624 SG_END_DECL()