Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
more pluginification of our pseudo file system
[simgrid.git] / src / msg / msg_io.cpp
1 /* Copyright (c) 2004-2017. 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/File.hpp"
7 #include "simgrid/s4u/Host.hpp"
8 #include "simgrid/s4u/Storage.hpp"
9 #include "src/msg/msg_private.hpp"
10 #include <numeric>
11
12 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(msg_io, msg, "Logging specific to MSG (io)");
13
14 extern "C" {
15
16 /** @addtogroup msg_file
17  * (#msg_file_t) and the functions for managing it.
18  *
19  *  \see #msg_file_t
20  */
21
22 static int MSG_host_get_file_descriptor_id(msg_host_t host)
23 {
24   simgrid::MsgHostExt* priv = host->extension<simgrid::MsgHostExt>();
25   if (priv->file_descriptor_table == nullptr) {
26     priv->file_descriptor_table = new std::vector<int>(sg_storage_max_file_descriptors);
27     std::iota(priv->file_descriptor_table->rbegin(), priv->file_descriptor_table->rend(), 0); // Fill with ..., 1, 0.
28   }
29   xbt_assert(not priv->file_descriptor_table->empty(), "Too much files are opened! Some have to be closed.");
30   int desc = priv->file_descriptor_table->back();
31   priv->file_descriptor_table->pop_back();
32   return desc;
33 }
34
35 static void MSG_host_release_file_descriptor_id(msg_host_t host, int id)
36 {
37   host->extension<simgrid::MsgHostExt>()->file_descriptor_table->push_back(id);
38 }
39
40 /** \ingroup msg_file
41  *
42  * \brief Set the user data of a #msg_file_t.
43  *
44  * This functions attach \a data to \a file.
45  */
46 msg_error_t MSG_file_set_data(msg_file_t fd, void *data)
47 {
48   fd->setUserdata(data);
49   return MSG_OK;
50 }
51
52 /** \ingroup msg_file
53  *
54  * \brief Return the user data of a #msg_file_t.
55  *
56  * This functions checks whether \a file is a valid pointer and return the user data associated to \a file if possible.
57  */
58 void* MSG_file_get_data(msg_file_t fd)
59 {
60   return fd->getUserdata();
61 }
62
63 /** \ingroup msg_file
64  * \brief Display information related to a file descriptor
65  *
66  * \param fd is a the file descriptor
67  */
68 void MSG_file_dump (msg_file_t fd){
69   XBT_INFO("File Descriptor information:\n"
70            "\t\tFull path: '%s'\n"
71            "\t\tSize: %llu\n"
72            "\t\tMount point: '%s'\n"
73            "\t\tStorage Id: '%s'\n"
74            "\t\tStorage Type: '%s'\n"
75            "\t\tFile Descriptor Id: %d",
76            fd->getPath(), fd->size(), fd->mount_point_.c_str(), fd->localStorage->getCname(),
77            fd->localStorage->getType(), fd->desc_id);
78 }
79
80 /** \ingroup msg_file
81  * \brief Read a file (local or remote)
82  *
83  * \param size of the file to read
84  * \param fd is a the file descriptor
85  * \return the number of bytes successfully read or -1 if an error occurred
86  */
87 sg_size_t MSG_file_read(msg_file_t fd, sg_size_t size)
88 {
89   sg_size_t read_size;
90
91   if (fd->size() == 0) /* Nothing to read, return */
92     return 0;
93
94   /* Find the host where the file is physically located and read it */
95   msg_storage_t storage_src           = fd->localStorage;
96   msg_host_t attached_host            = storage_src->getHost();
97   read_size                           = fd->read(size);
98
99   if (strcmp(attached_host->getCname(), MSG_host_self()->getCname())) {
100     /* the file is hosted on a remote host, initiate a communication between src and dest hosts for data transfer */
101     XBT_DEBUG("File is on %s remote host, initiate data transfer of %llu bytes.", attached_host->getCname(), read_size);
102     msg_host_t m_host_list[] = {MSG_host_self(), attached_host};
103     double flops_amount[]    = {0, 0};
104     double bytes_amount[]    = {0, 0, static_cast<double>(read_size), 0};
105
106     msg_task_t task = MSG_parallel_task_create("file transfer for read", 2, m_host_list, flops_amount, bytes_amount,
107                       nullptr);
108     msg_error_t transfer = MSG_parallel_task_execute(task);
109     MSG_task_destroy(task);
110
111     if(transfer != MSG_OK){
112       if (transfer == MSG_HOST_FAILURE)
113         XBT_WARN("Transfer error, %s remote host just turned off!", attached_host->getCname());
114       if (transfer == MSG_TASK_CANCELED)
115         XBT_WARN("Transfer error, task has been canceled!");
116
117       return -1;
118     }
119   }
120   return read_size;
121 }
122
123 /** \ingroup msg_file
124  * \brief Write into a file (local or remote)
125  *
126  * \param size of the file to write
127  * \param fd is a the file descriptor
128  * \return the number of bytes successfully write or -1 if an error occurred
129  */
130 sg_size_t MSG_file_write(msg_file_t fd, sg_size_t size)
131 {
132   if (size == 0) /* Nothing to write, return */
133     return 0;
134
135   /* Find the host where the file is physically located (remote or local)*/
136   msg_storage_t storage_src = fd->localStorage;
137   msg_host_t attached_host  = storage_src->getHost();
138
139   if (strcmp(attached_host->getCname(), MSG_host_self()->getCname())) {
140     /* the file is hosted on a remote host, initiate a communication between src and dest hosts for data transfer */
141     XBT_DEBUG("File is on %s remote host, initiate data transfer of %llu bytes.", attached_host->getCname(), size);
142     msg_host_t m_host_list[] = {MSG_host_self(), attached_host};
143     double flops_amount[]    = {0, 0};
144     double bytes_amount[]    = {0, static_cast<double>(size), 0, 0};
145
146     msg_task_t task = MSG_parallel_task_create("file transfer for write", 2, m_host_list, flops_amount, bytes_amount,
147                                                nullptr);
148     msg_error_t transfer = MSG_parallel_task_execute(task);
149     MSG_task_destroy(task);
150
151     if(transfer != MSG_OK){
152       if (transfer == MSG_HOST_FAILURE)
153         XBT_WARN("Transfer error, %s remote host just turned off!", attached_host->getCname());
154       if (transfer == MSG_TASK_CANCELED)
155         XBT_WARN("Transfer error, task has been canceled!");
156
157       return -1;
158     }
159   }
160   /* Write file on local or remote host */
161   sg_size_t write_size = fd->write(size);
162
163   return write_size;
164 }
165
166 /** \ingroup msg_file
167  * \brief Opens the file whose name is the string pointed to by path
168  *
169  * \param fullpath is the file location on the storage
170  * \param data user data to attach to the file
171  *
172  * \return An #msg_file_t associated to the file
173  */
174 msg_file_t MSG_file_open(const char* fullpath, void* data)
175 {
176   msg_file_t fd         = new simgrid::s4u::File(fullpath, MSG_host_self());
177   fd->desc_id           = MSG_host_get_file_descriptor_id(MSG_host_self());
178   fd->setUserdata(data);
179   return fd;
180 }
181
182 /** \ingroup msg_file
183  * \brief Close the file
184  *
185  * \param fd is the file to close
186  * \return 0 on success or 1 on error
187  */
188 int MSG_file_close(msg_file_t fd)
189 {
190   MSG_host_release_file_descriptor_id(MSG_host_self(), fd->desc_id);
191   delete fd;
192
193   return MSG_OK;
194 }
195
196 /** \ingroup msg_file
197  * \brief Unlink the file pointed by fd
198  *
199  * \param fd is the file descriptor (#msg_file_t)
200  * \return 0 on success or 1 on error
201  */
202 msg_error_t MSG_file_unlink(msg_file_t fd)
203 {
204   fd->unlink();
205   delete fd;
206   return MSG_OK;
207 }
208
209 /** \ingroup msg_file
210  * \brief Return the size of a file
211  *
212  * \param fd is the file descriptor (#msg_file_t)
213  * \return the size of the file (as a #sg_size_t)
214  */
215 sg_size_t MSG_file_get_size(msg_file_t fd)
216 {
217   return fd->size();
218 }
219
220 /**
221  * \ingroup msg_file
222  * \brief Set the file position indicator in the msg_file_t by adding offset bytes
223  * to the position specified by origin (either SEEK_SET, SEEK_CUR, or SEEK_END).
224  *
225  * \param fd : file object that identifies the stream
226  * \param offset : number of bytes to offset from origin
227  * \param origin : Position used as reference for the offset. It is specified by one of the following constants defined
228  *                 in \<stdio.h\> exclusively to be used as arguments for this function (SEEK_SET = beginning of file,
229  *                 SEEK_CUR = current position of the file pointer, SEEK_END = end of file)
230  * \return If successful, the function returns MSG_OK (=0). Otherwise, it returns MSG_TASK_CANCELED (=8).
231  */
232 msg_error_t MSG_file_seek(msg_file_t fd, sg_offset_t offset, int origin)
233 {
234   fd->seek(offset, origin);
235   return MSG_OK;
236 }
237
238 /**
239  * \ingroup msg_file
240  * \brief Returns the current value of the position indicator of the file
241  *
242  * \param fd : file object that identifies the stream
243  * \return On success, the current value of the position indicator is returned.
244  *
245  */
246 sg_size_t MSG_file_tell(msg_file_t fd)
247 {
248   return fd->tell();
249 }
250
251 const char *MSG_file_get_name(msg_file_t fd) {
252   xbt_assert((fd != nullptr), "Invalid parameters");
253   return fd->getPath();
254 }
255
256 /**
257  * \ingroup msg_file
258  * \brief Move a file to another location on the *same mount point*.
259  *
260  */
261 msg_error_t MSG_file_move (msg_file_t fd, const char* fullpath)
262 {
263   fd->move(fullpath);
264   return MSG_OK;
265 }
266
267 /**
268  * \ingroup msg_file
269  * \brief Copy a file to another location on a remote host.
270  * \param file : the file to move
271  * \param host : the remote host where the file has to be copied
272  * \param fullpath : the complete path destination on the remote host
273  * \return If successful, the function returns MSG_OK. Otherwise, it returns MSG_TASK_CANCELED.
274  */
275 msg_error_t MSG_file_rcopy (msg_file_t file, msg_host_t host, const char* fullpath)
276 {
277   /* Find the host where the file is physically located and read it */
278   msg_storage_t storage_src = file->localStorage;
279   msg_host_t src_host       = storage_src->getHost();
280   MSG_file_seek(file, 0, SEEK_SET);
281   sg_size_t read_size = file->read(file->size());
282
283   /* Find the host that owns the storage where the file has to be copied */
284   msg_storage_t storage_dest = nullptr;
285   msg_host_t dst_host;
286   size_t longest_prefix_length = 0;
287
288   for (auto const& elm : host->getMountedStorages()) {
289     std::string mount_point = std::string(fullpath).substr(0, elm.first.size());
290     if (mount_point == elm.first && elm.first.length() > longest_prefix_length) {
291       /* The current mount name is found in the full path and is bigger than the previous*/
292       longest_prefix_length = elm.first.length();
293       storage_dest          = elm.second;
294     }
295   }
296
297   if (storage_dest != nullptr) {
298     /* Mount point found, retrieve the host the storage is attached to */
299     dst_host = storage_dest->getHost();
300   }else{
301     XBT_WARN("Can't find mount point for '%s' on destination host '%s'", fullpath, host->getCname());
302     return MSG_TASK_CANCELED;
303   }
304
305   XBT_DEBUG("Initiate data transfer of %llu bytes between %s and %s.", read_size, src_host->getCname(),
306             storage_dest->getHost()->getCname());
307   msg_host_t m_host_list[] = {src_host, dst_host};
308   double flops_amount[]    = {0, 0};
309   double bytes_amount[]    = {0, static_cast<double>(read_size), 0, 0};
310
311   msg_task_t task =
312       MSG_parallel_task_create("file transfer for write", 2, m_host_list, flops_amount, bytes_amount, nullptr);
313   msg_error_t err = MSG_parallel_task_execute(task);
314   MSG_task_destroy(task);
315
316   if (err != MSG_OK) {
317     if (err == MSG_HOST_FAILURE)
318       XBT_WARN("Transfer error, %s remote host just turned off!", storage_dest->getHost()->getCname());
319     if (err == MSG_TASK_CANCELED)
320       XBT_WARN("Transfer error, task has been canceled!");
321
322     return err;
323   }
324
325   /* Create file on remote host, write it and close it */
326   msg_file_t fd = new simgrid::s4u::File(fullpath, dst_host, nullptr);
327   fd->write(read_size);
328   delete fd;
329   return MSG_OK;
330 }
331
332 /**
333  * \ingroup msg_file
334  * \brief Move a file to another location on a remote host.
335  * \param file : the file to move
336  * \param host : the remote host where the file has to be moved
337  * \param fullpath : the complete path destination on the remote host
338  * \return If successful, the function returns MSG_OK. Otherwise, it returns MSG_TASK_CANCELED.
339  */
340 msg_error_t MSG_file_rmove (msg_file_t file, msg_host_t host, const char* fullpath)
341 {
342   msg_error_t res = MSG_file_rcopy(file, host, fullpath);
343   MSG_file_unlink(file);
344   return res;
345 }
346
347 /********************************* Storage **************************************/
348 /** @addtogroup msg_storage_management
349  * (#msg_storage_t) and the functions for managing it.
350  */
351
352 /** \ingroup msg_storage_management
353  *
354  * \brief Returns the name of the #msg_storage_t.
355  *
356  * This functions checks whether a storage is a valid pointer or not and return its name.
357  */
358 const char* MSG_storage_get_name(msg_storage_t storage)
359 {
360   xbt_assert((storage != nullptr), "Invalid parameters");
361   return storage->getCname();
362 }
363
364 /** \ingroup msg_storage_management
365  * \brief Returns a xbt_dict_t consisting of the list of properties assigned to this storage
366  * \param storage a storage
367  * \return a dict containing the properties
368  */
369 xbt_dict_t MSG_storage_get_properties(msg_storage_t storage)
370 {
371   xbt_assert((storage != nullptr), "Invalid parameters (storage is nullptr)");
372   xbt_dict_t as_dict = xbt_dict_new_homogeneous(xbt_free_f);
373   std::map<std::string, std::string>* props = storage->getProperties();
374   if (props == nullptr)
375     return nullptr;
376   for (auto const& elm : *props) {
377     xbt_dict_set(as_dict, elm.first.c_str(), xbt_strdup(elm.second.c_str()), nullptr);
378   }
379   return as_dict;
380 }
381
382 /** \ingroup msg_storage_management
383  * \brief Change the value of a given storage property
384  *
385  * \param storage a storage
386  * \param name a property name
387  * \param value what to change the property to
388  */
389 void MSG_storage_set_property_value(msg_storage_t storage, const char* name, char* value)
390 {
391   storage->setProperty(name, value);
392 }
393
394 /** \ingroup m_storage_management
395  * \brief Returns the value of a given storage property
396  *
397  * \param storage a storage
398  * \param name a property name
399  * \return value of a property (or nullptr if property not set)
400  */
401 const char *MSG_storage_get_property_value(msg_storage_t storage, const char *name)
402 {
403   return storage->getProperty(name);
404 }
405
406 /** \ingroup msg_storage_management
407  * \brief Finds a msg_storage_t using its name.
408  * \param name the name of a storage
409  * \return the corresponding storage
410  */
411 msg_storage_t MSG_storage_get_by_name(const char *name)
412 {
413   return simgrid::s4u::Storage::byName(name);
414 }
415
416 /** \ingroup msg_storage_management
417  * \brief Returns a dynar containing all the storage elements declared at a given point of time
418  */
419 xbt_dynar_t MSG_storages_as_dynar()
420 {
421   std::map<std::string, simgrid::s4u::Storage*>* storage_map = simgrid::s4u::allStorages();
422   xbt_dynar_t res = xbt_dynar_new(sizeof(msg_storage_t),nullptr);
423   for (auto const& s : *storage_map)
424     xbt_dynar_push(res, &(s.second));
425   delete storage_map;
426   return res;
427 }
428
429 /** \ingroup msg_storage_management
430  *
431  * \brief Set the user data of a #msg_storage_t.
432  * This functions attach \a data to \a storage if possible.
433  */
434 msg_error_t MSG_storage_set_data(msg_storage_t storage, void *data)
435 {
436   storage->setUserdata(data);
437   return MSG_OK;
438 }
439
440 /** \ingroup m_host_management
441  *
442  * \brief Returns the user data of a #msg_storage_t.
443  *
444  * This functions checks whether \a storage is a valid pointer and returns its associate user data if possible.
445  */
446 void *MSG_storage_get_data(msg_storage_t storage)
447 {
448   xbt_assert((storage != nullptr), "Invalid parameters");
449   return storage->getUserdata();
450 }
451
452 /** \ingroup msg_storage_management
453  *
454  * \brief Returns the content (file list) of a #msg_storage_t.
455  * \param storage a storage
456  * \return The content of this storage element as a dict (full path file => size)
457  */
458 xbt_dict_t MSG_storage_get_content(msg_storage_t storage)
459 {
460   std::map<std::string, sg_size_t>* content = storage->getContent();
461   // Note: ::operator delete is ok here (no destructor called) since the dict elements are of POD type sg_size_t.
462   xbt_dict_t content_as_dict = xbt_dict_new_homogeneous(::operator delete);
463
464   for (auto const& entry : *content) {
465     sg_size_t* psize = new sg_size_t;
466     *psize           = entry.second;
467     xbt_dict_set(content_as_dict, entry.first.c_str(), psize, nullptr);
468   }
469   return content_as_dict;
470 }
471
472 /** \ingroup msg_storage_management
473  *
474  * \brief Returns the host name the storage is attached to
475  *
476  * This functions checks whether a storage is a valid pointer or not and return its name.
477  */
478 const char* MSG_storage_get_host(msg_storage_t storage)
479 {
480   xbt_assert((storage != nullptr), "Invalid parameters");
481   return storage->getHost()->getCname();
482 }
483
484 sg_size_t MSG_storage_read(msg_storage_t storage, sg_size_t size)
485 {
486   return storage->read(size);
487 }
488
489 sg_size_t MSG_storage_write(msg_storage_t storage, sg_size_t size)
490 {
491   return storage->write(size);
492 }
493 }