Logo AND Algorithmique Numérique Distribuée

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