1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Copyright by The HDF Group. *
3 * Copyright by the Board of Trustees of the University of Illinois. *
4 * All rights reserved. *
5 * *
6 * This file is part of HDF5. The full HDF5 copyright notice, including *
7 * terms governing use, modification, and redistribution, is contained in *
8 * the files COPYING and Copyright.html. COPYING can be found at the root *
9 * of the source code distribution tree; Copyright.html can be found at the *
10 * root level of an installed copy of the electronic HDF5 document set and *
11 * is linked from the top-level documents page. It can also be found at *
12 * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have *
13 * access to either file, you may request a copy from help@hdfgroup.org. *
14 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15
16 /*
17 * Programmer: Quincey Koziol <koziol@hdfgroup.org>
18 * Monday, April 17, 2000
19 *
20 * Purpose: The POSIX unbuffered file driver using only the HDF5 public
21 * API and with a few optimizations: the lseek() call is made
22 * only when the current file position is unknown or needs to be
23 * changed based on previous I/O through this driver (don't mix
24 * I/O from this driver with I/O from other parts of the
25 * application to the same file).
26 * With custom modifications...
27 */
28
29 /* Interface initialization */
30 #define H5_INTERFACE_INIT_FUNC H5FD_log_init_interface
31
32
33 #include "H5private.h" /* Generic Functions */
34 #include "H5Eprivate.h" /* Error handling */
35 #include "H5Fprivate.h" /* File access */
36 #include "H5FDprivate.h" /* File drivers */
37 #include "H5FDlog.h" /* Logging file driver */
38 #include "H5FLprivate.h" /* Free Lists */
39 #include "H5Iprivate.h" /* IDs */
40 #include "H5MMprivate.h" /* Memory management */
41 #include "H5Pprivate.h" /* Property lists */
42
43 /* The driver identification number, initialized at runtime */
44 static hid_t H5FD_LOG_g = 0;
45
46 /* Driver-specific file access properties */
47 typedef struct H5FD_log_fapl_t {
48 char *logfile; /* Allocated log file name */
49 unsigned long long flags; /* Flags for logging behavior */
50 size_t buf_size; /* Size of buffers for track flavor and number of times each byte is accessed */
51 } H5FD_log_fapl_t;
52
53 /* Define strings for the different file memory types
54 * These are defined in the H5F_mem_t enum from H5Fpublic.h
55 * Note that H5FD_MEM_NOLIST is not listed here since it has
56 * a negative value.
57 */
58 static const char *flavors[]={
59 "H5FD_MEM_DEFAULT",
60 "H5FD_MEM_SUPER",
61 "H5FD_MEM_BTREE",
62 "H5FD_MEM_DRAW",
63 "H5FD_MEM_GHEAP",
64 "H5FD_MEM_LHEAP",
65 "H5FD_MEM_OHDR",
66 };
67
68 /* The description of a file belonging to this driver. The `eoa' and `eof'
69 * determine the amount of hdf5 address space in use and the high-water mark
70 * of the file (the current size of the underlying filesystem file). The
71 * `pos' value is used to eliminate file position updates when they would be a
72 * no-op. Unfortunately we've found systems that use separate file position
73 * indicators for reading and writing so the lseek can only be eliminated if
74 * the current operation is the same as the previous operation. When opening
75 * a file the `eof' will be set to the current file size, `eoa' will be set
76 * to zero, `pos' will be set to H5F_ADDR_UNDEF (as it is when an error
77 * occurs), and `op' will be set to H5F_OP_UNKNOWN.
78 */
79 typedef struct H5FD_log_t {
80 H5FD_t pub; /* public stuff, must be first */
81 int fd; /* the unix file */
82 haddr_t eoa; /* end of allocated region */
83 haddr_t eof; /* end of file; current file size */
84 haddr_t pos; /* current file I/O position */
85 H5FD_file_op_t op; /* last operation */
86 char filename[H5FD_MAX_FILENAME_LEN]; /* Copy of file name from open operation */
87 #ifndef H5_HAVE_WIN32_API
88 /* On most systems the combination of device and i-node number uniquely
89 * identify a file. Note that Cygwin, MinGW and other Windows POSIX
90 * environments have the stat function (which fakes inodes)
91 * and will use the 'device + inodes' scheme as opposed to the
92 * Windows code further below.
93 */
94 dev_t device; /* file device number */
95 #ifdef H5_VMS
96 ino_t inode[3]; /* file i-node number */
97 #else
98 ino_t inode; /* file i-node number */
99 #endif /*H5_VMS*/
100 #else
101 /* Files in windows are uniquely identified by the volume serial
102 * number and the file index (both low and high parts).
103 *
104 * There are caveats where these numbers can change, especially
105 * on FAT file systems. On NTFS, however, a file should keep
106 * those numbers the same until renamed or deleted (though you
107 * can use ReplaceFile() on NTFS to keep the numbers the same
108 * while renaming).
109 *
110 * See the MSDN "BY_HANDLE_FILE_INFORMATION Structure" entry for
111 * more information.
112 *
113 * http://msdn.microsoft.com/en-us/library/aa363788(v=VS.85).aspx
114 */
115 DWORD nFileIndexLow;
116 DWORD nFileIndexHigh;
117 DWORD dwVolumeSerialNumber;
118
119 HANDLE hFile; /* Native windows file handle */
120 #endif /* H5_HAVE_WIN32_API */
121
122 /* Information from properties set by 'h5repart' tool
123 *
124 * Whether to eliminate the family driver info and convert this file to
125 * a single file
126 */
127 hbool_t fam_to_sec2;
128
129 /* Fields for tracking I/O operations */
130 unsigned char *nread; /* Number of reads from a file location */
131 unsigned char *nwrite; /* Number of write to a file location */
132 unsigned char *flavor; /* Flavor of information written to file location */
133 unsigned long long total_read_ops; /* Total number of read operations */
134 unsigned long long total_write_ops; /* Total number of write operations */
135 unsigned long long total_seek_ops; /* Total number of seek operations */
136 unsigned long long total_truncate_ops; /* Total number of truncate operations */
137 double total_read_time; /* Total time spent in read operations */
138 double total_write_time; /* Total time spent in write operations */
139 double total_seek_time; /* Total time spent in seek operations */
140 size_t iosize; /* Size of I/O information buffers */
141 FILE *logfp; /* Log file pointer */
142 H5FD_log_fapl_t fa; /* Driver-specific file access properties */
143 } H5FD_log_t;
144
145 /*
146 * These macros check for overflow of various quantities. These macros
147 * assume that HDoff_t is signed and haddr_t and size_t are unsigned.
148 *
149 * ADDR_OVERFLOW: Checks whether a file address of type `haddr_t'
150 * is too large to be represented by the second argument
151 * of the file seek function.
152 *
153 * SIZE_OVERFLOW: Checks whether a buffer size of type `hsize_t' is too
154 * large to be represented by the `size_t' type.
155 *
156 * REGION_OVERFLOW: Checks whether an address and size pair describe data
157 * which can be addressed entirely by the second
158 * argument of the file seek function.
159 */
160 #define MAXADDR (((haddr_t)1<<(8*sizeof(HDoff_t)-1))-1)
161 #define ADDR_OVERFLOW(A) (HADDR_UNDEF==(A) || ((A) & ~(haddr_t)MAXADDR))
162 #define SIZE_OVERFLOW(Z) ((Z) & ~(hsize_t)MAXADDR)
163 #define REGION_OVERFLOW(A,Z) (ADDR_OVERFLOW(A) || SIZE_OVERFLOW(Z) || \
164 HADDR_UNDEF==(A)+(Z) || \
165 (HDoff_t)((A)+(Z))<(HDoff_t)(A))
166
167 /* Prototypes */
168 static void *H5FD_log_fapl_get(H5FD_t *file);
169 static void *H5FD_log_fapl_copy(const void *_old_fa);
170 static herr_t H5FD_log_fapl_free(void *_fa);
171 static H5FD_t *H5FD_log_open(const char *name, unsigned flags, hid_t fapl_id,
172 haddr_t maxaddr);
173 static herr_t H5FD_log_close(H5FD_t *_file);
174 static int H5FD_log_cmp(const H5FD_t *_f1, const H5FD_t *_f2);
175 static herr_t H5FD_log_query(const H5FD_t *_f1, unsigned long *flags);
176 static haddr_t H5FD_log_alloc(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, hsize_t size);
177 static haddr_t H5FD_log_get_eoa(const H5FD_t *_file, H5FD_mem_t type);
178 static herr_t H5FD_log_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr);
179 static haddr_t H5FD_log_get_eof(const H5FD_t *_file);
180 static herr_t H5FD_log_get_handle(H5FD_t *_file, hid_t fapl, void** file_handle);
181 static herr_t H5FD_log_read(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, haddr_t addr,
182 size_t size, void *buf);
183 static herr_t H5FD_log_write(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, haddr_t addr,
184 size_t size, const void *buf);
185 static herr_t H5FD_log_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing);
186
187 static const H5FD_class_t H5FD_log_g = {
188 "log", /*name */
189 MAXADDR, /*maxaddr */
190 H5F_CLOSE_WEAK, /* fc_degree */
191 NULL, /*sb_size */
192 NULL, /*sb_encode */
193 NULL, /*sb_decode */
194 sizeof(H5FD_log_fapl_t), /*fapl_size */
195 H5FD_log_fapl_get, /*fapl_get */
196 H5FD_log_fapl_copy, /*fapl_copy */
197 H5FD_log_fapl_free, /*fapl_free */
198 0, /*dxpl_size */
199 NULL, /*dxpl_copy */
200 NULL, /*dxpl_free */
201 H5FD_log_open, /*open */
202 H5FD_log_close, /*close */
203 H5FD_log_cmp, /*cmp */
204 H5FD_log_query, /*query */
205 NULL, /*get_type_map */
206 H5FD_log_alloc, /*alloc */
207 NULL, /*free */
208 H5FD_log_get_eoa, /*get_eoa */
209 H5FD_log_set_eoa, /*set_eoa */
210 H5FD_log_get_eof, /*get_eof */
211 H5FD_log_get_handle, /*get_handle */
212 H5FD_log_read, /*read */
213 H5FD_log_write, /*write */
214 NULL, /*flush */
215 H5FD_log_truncate, /*truncate */
216 NULL, /*lock */
217 NULL, /*unlock */
218 H5FD_FLMAP_DICHOTOMY /*fl_map */
219 };
220
221 /* Declare a free list to manage the H5FD_log_t struct */
222 H5FL_DEFINE_STATIC(H5FD_log_t);
223
224
225 /*-------------------------------------------------------------------------
226 * Function: H5FD_log_init_interface
227 *
228 * Purpose: Initializes any interface-specific data or routines.
229 *
230 * Return: Success: The driver ID for the log driver.
231 * Failure: Negative.
232 *
233 *-------------------------------------------------------------------------
234 */
235 static herr_t
H5FD_log_init_interface(void)236 H5FD_log_init_interface(void)
237 {
238 FUNC_ENTER_NOAPI_NOINIT_NOERR
239
240 FUNC_LEAVE_NOAPI(H5FD_log_init())
241 } /* H5FD_log_init_interface() */
242
243
244 /*-------------------------------------------------------------------------
245 * Function: H5FD_log_init
246 *
247 * Purpose: Initialize this driver by registering the driver with the
248 * library.
249 *
250 * Return: Success: The driver ID for the log driver.
251 * Failure: Negative.
252 *
253 * Programmer: Robb Matzke
254 * Thursday, July 29, 1999
255 *
256 *-------------------------------------------------------------------------
257 */
258 hid_t
H5FD_log_init(void)259 H5FD_log_init(void)
260 {
261 hid_t ret_value; /* Return value */
262
263 FUNC_ENTER_NOAPI(FAIL)
264
265 if(H5I_VFL != H5I_get_type(H5FD_LOG_g))
266 H5FD_LOG_g = H5FD_register(&H5FD_log_g, sizeof(H5FD_class_t), FALSE);
267
268 /* Set return value */
269 ret_value = H5FD_LOG_g;
270
271 done:
272 FUNC_LEAVE_NOAPI(ret_value)
273 } /* end H5FD_log_init() */
274
275
276 /*---------------------------------------------------------------------------
277 * Function: H5FD_log_term
278 *
279 * Purpose: Shut down the VFD
280 *
281 * Returns: <none>
282 *
283 * Programmer: Quincey Koziol
284 * Friday, Jan 30, 2004
285 *
286 *---------------------------------------------------------------------------
287 */
288 void
H5FD_log_term(void)289 H5FD_log_term(void)
290 {
291 FUNC_ENTER_NOAPI_NOINIT_NOERR
292
293 /* Reset VFL ID */
294 H5FD_LOG_g = 0;
295
296 FUNC_LEAVE_NOAPI_VOID
297 } /* end H5FD_log_term() */
298
299
300 /*-------------------------------------------------------------------------
301 * Function: H5Pset_fapl_log
302 *
303 * Purpose: Modify the file access property list to use the H5FD_LOG
304 * driver defined in this source file.
305 *
306 * Return: SUCCEED/FAIL
307 *
308 * Programmer: Robb Matzke
309 * Thursday, February 19, 1998
310 *
311 *-------------------------------------------------------------------------
312 */
313 herr_t
H5Pset_fapl_log(hid_t fapl_id,const char * logfile,unsigned long long flags,size_t buf_size)314 H5Pset_fapl_log(hid_t fapl_id, const char *logfile, unsigned long long flags, size_t buf_size)
315 {
316 H5FD_log_fapl_t fa; /* File access property list information */
317 H5P_genplist_t *plist; /* Property list pointer */
318 herr_t ret_value; /* Return value */
319
320 FUNC_ENTER_API(FAIL)
321 H5TRACE4("e", "i*sULz", fapl_id, logfile, flags, buf_size);
322
323 /* Check arguments */
324 if(NULL == (plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS)))
325 HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list")
326
327 /* This shallow copy is correct! The string will be properly
328 * copied deep down in the H5P code.
329 */
330 fa.logfile = (char *)logfile;
331
332 fa.flags = flags;
333 fa.buf_size = buf_size;
334 ret_value = H5P_set_driver(plist, H5FD_LOG, &fa);
335
336 done:
337 FUNC_LEAVE_API(ret_value)
338 } /* end H5Pset_fapl_log() */
339
340
341 /*-------------------------------------------------------------------------
342 * Function: H5FD_log_fapl_get
343 *
344 * Purpose: Returns a file access property list which indicates how the
345 * specified file is being accessed. The return list could be
346 * used to access another file the same way.
347 *
348 * Return: Success: Ptr to new file access property list with all
349 * members copied from the file struct.
350 * Failure: NULL
351 *
352 * Programmer: Quincey Koziol
353 * Thursday, April 20, 2000
354 *
355 *-------------------------------------------------------------------------
356 */
357 static void *
H5FD_log_fapl_get(H5FD_t * _file)358 H5FD_log_fapl_get(H5FD_t *_file)
359 {
360 H5FD_log_t *file = (H5FD_log_t *)_file;
361 void *ret_value; /* Return value */
362
363 FUNC_ENTER_NOAPI_NOINIT_NOERR
364
365 /* Set return value */
366 ret_value = H5FD_log_fapl_copy(&(file->fa));
367
368 FUNC_LEAVE_NOAPI(ret_value)
369 } /* end H5FD_log_fapl_get() */
370
371
372 /*-------------------------------------------------------------------------
373 * Function: H5FD_log_fapl_copy
374 *
375 * Purpose: Copies the log-specific file access properties.
376 *
377 * Return: Success: Ptr to a new property list
378 * Failure: NULL
379 *
380 * Programmer: Quincey Koziol
381 * Thursday, April 20, 2000
382 *
383 *-------------------------------------------------------------------------
384 */
385 static void *
H5FD_log_fapl_copy(const void * _old_fa)386 H5FD_log_fapl_copy(const void *_old_fa)
387 {
388 const H5FD_log_fapl_t *old_fa = (const H5FD_log_fapl_t*)_old_fa;
389 H5FD_log_fapl_t *new_fa = NULL; /* New FAPL info */
390 void *ret_value; /* Return value */
391
392 FUNC_ENTER_NOAPI_NOINIT
393
394 HDassert(old_fa);
395
396 /* Allocate the new FAPL info */
397 if(NULL == (new_fa = (H5FD_log_fapl_t *)H5MM_calloc(sizeof(H5FD_log_fapl_t))))
398 HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, NULL, "unable to allocate log file FAPL")
399
400 /* Copy the general information */
401 HDmemcpy(new_fa, old_fa, sizeof(H5FD_log_fapl_t));
402
403 /* Deep copy the log file name */
404 if(old_fa->logfile != NULL)
405 if(NULL == (new_fa->logfile = H5MM_xstrdup(old_fa->logfile)))
406 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to allocate log file name")
407
408 /* Set return value */
409 ret_value = new_fa;
410
411 done:
412 if(NULL == ret_value)
413 if(new_fa) {
414 if(new_fa->logfile)
415 H5MM_free(new_fa->logfile);
416 H5MM_free(new_fa);
417 } /* end if */
418
419 FUNC_LEAVE_NOAPI(ret_value)
420 } /* end H5FD_log_fapl_copy() */
421
422
423 /*-------------------------------------------------------------------------
424 * Function: H5FD_log_fapl_free
425 *
426 * Purpose: Frees the log-specific file access properties.
427 *
428 * Return: SUCCEED (Can't fail)
429 *
430 * Programmer: Quincey Koziol
431 * Thursday, April 20, 2000
432 *
433 *-------------------------------------------------------------------------
434 */
435 static herr_t
H5FD_log_fapl_free(void * _fa)436 H5FD_log_fapl_free(void *_fa)
437 {
438 H5FD_log_fapl_t *fa = (H5FD_log_fapl_t*)_fa;
439
440 FUNC_ENTER_NOAPI_NOINIT_NOERR
441
442 /* Free the fapl information */
443 if(fa->logfile)
444 H5MM_xfree(fa->logfile);
445 H5MM_xfree(fa);
446
447 FUNC_LEAVE_NOAPI(SUCCEED)
448 } /* end H5FD_log_fapl_free() */
449
450
451 /*-------------------------------------------------------------------------
452 * Function: H5FD_log_open
453 *
454 * Purpose: Create and/or opens a file as an HDF5 file.
455 *
456 * Return: Success: A pointer to a new file data structure. The
457 * public fields will be initialized by the
458 * caller, which is always H5FD_open().
459 * Failure: NULL
460 *
461 * Programmer: Robb Matzke
462 * Thursday, July 29, 1999
463 *
464 *-------------------------------------------------------------------------
465 */
466 static H5FD_t *
H5FD_log_open(const char * name,unsigned flags,hid_t fapl_id,haddr_t maxaddr)467 H5FD_log_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr)
468 {
469 H5FD_log_t *file = NULL;
470 H5P_genplist_t *plist; /* Property list */
471 H5FD_log_fapl_t *fa; /* File access property list information */
472 int fd = -1; /* File descriptor */
473 int o_flags; /* Flags for open() call */
474 #ifdef H5_HAVE_WIN32_API
475 struct _BY_HANDLE_FILE_INFORMATION fileinfo;
476 #endif
477 #ifdef H5_HAVE_GETTIMEOFDAY
478 struct timeval timeval_start;
479 struct timeval open_timeval_diff;
480 struct timeval stat_timeval_diff;
481 #endif /* H5_HAVE_GETTIMEOFDAY */
482 h5_stat_t sb;
483 H5FD_t *ret_value; /* Return value */
484
485 FUNC_ENTER_NOAPI_NOINIT
486
487 /* Sanity check on file offsets */
488 HDcompile_assert(sizeof(HDoff_t) >= sizeof(size_t));
489
490 /* Check arguments */
491 if(!name || !*name)
492 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid file name")
493 if(0 == maxaddr || HADDR_UNDEF == maxaddr)
494 HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "bogus maxaddr")
495 if(ADDR_OVERFLOW(maxaddr))
496 HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, NULL, "bogus maxaddr")
497
498 /* Build the open flags */
499 o_flags = (H5F_ACC_RDWR & flags) ? O_RDWR : O_RDONLY;
500 if(H5F_ACC_TRUNC & flags)
501 o_flags |= O_TRUNC;
502 if(H5F_ACC_CREAT & flags)
503 o_flags |= O_CREAT;
504 if(H5F_ACC_EXCL & flags)
505 o_flags |= O_EXCL;
506
507 /* Get the driver specific information */
508 if(NULL == (plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS)))
509 HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a file access property list")
510 if(NULL == (fa = (H5FD_log_fapl_t *)H5P_get_driver_info(plist)))
511 HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, NULL, "bad VFL driver info")
512
513 #ifdef H5_HAVE_GETTIMEOFDAY
514 if(fa->flags & H5FD_LOG_TIME_OPEN)
515 HDgettimeofday(&timeval_start, NULL);
516 #endif /* H5_HAVE_GETTIMEOFDAY */
517 /* Open the file */
518 if((fd = HDopen(name, o_flags, 0666)) < 0) {
519 int myerrno = errno;
520
521 HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to open file: name = '%s', errno = %d, error message = '%s', flags = %x, o_flags = %x", name, myerrno, HDstrerror(myerrno), flags, (unsigned)o_flags);
522 } /* end if */
523 #ifdef H5_HAVE_GETTIMEOFDAY
524 if(fa->flags & H5FD_LOG_TIME_OPEN) {
525 struct timeval timeval_stop;
526
527 HDgettimeofday(&timeval_stop, NULL);
528
529 /* Calculate the elapsed gettimeofday time */
530 open_timeval_diff.tv_usec = timeval_stop.tv_usec - timeval_start.tv_usec;
531 open_timeval_diff.tv_sec = timeval_stop.tv_sec - timeval_start.tv_sec;
532 if(open_timeval_diff.tv_usec < 0) {
533 open_timeval_diff.tv_usec += 1000000;
534 open_timeval_diff.tv_sec--;
535 } /* end if */
536 } /* end if */
537 #endif /* H5_HAVE_GETTIMEOFDAY */
538
539 #ifdef H5_HAVE_GETTIMEOFDAY
540 if(fa->flags & H5FD_LOG_TIME_STAT)
541 HDgettimeofday(&timeval_start, NULL);
542 #endif /* H5_HAVE_GETTIMEOFDAY */
543 /* Get the file stats */
544 if(HDfstat(fd, &sb) < 0)
545 HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, NULL, "unable to fstat file")
546 #ifdef H5_HAVE_GETTIMEOFDAY
547 if(fa->flags & H5FD_LOG_TIME_STAT) {
548 struct timeval timeval_stop;
549
550 HDgettimeofday(&timeval_stop, NULL);
551
552 /* Calculate the elapsed gettimeofday time */
553 stat_timeval_diff.tv_usec = timeval_stop.tv_usec - timeval_start.tv_usec;
554 stat_timeval_diff.tv_sec = timeval_stop.tv_sec - timeval_start.tv_sec;
555 if(stat_timeval_diff.tv_usec < 0) {
556 stat_timeval_diff.tv_usec += 1000000;
557 stat_timeval_diff.tv_sec--;
558 } /* end if */
559 } /* end if */
560 #endif /* H5_HAVE_GETTIMEOFDAY */
561
562 /* Create the new file struct */
563 if(NULL == (file = H5FL_CALLOC(H5FD_log_t)))
564 HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to allocate file struct")
565
566 file->fd = fd;
567 H5_ASSIGN_OVERFLOW(file->eof, sb.st_size, h5_stat_size_t, haddr_t);
568 file->pos = HADDR_UNDEF;
569 file->op = OP_UNKNOWN;
570 #ifdef H5_HAVE_WIN32_API
571 file->hFile = (HANDLE)_get_osfhandle(fd);
572 if(INVALID_HANDLE_VALUE == file->hFile)
573 HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to get Windows file handle")
574
575 if(!GetFileInformationByHandle((HANDLE)file->hFile, &fileinfo))
576 HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to get Windows file information")
577
578 file->nFileIndexHigh = fileinfo.nFileIndexHigh;
579 file->nFileIndexLow = fileinfo.nFileIndexLow;
580 file->dwVolumeSerialNumber = fileinfo.dwVolumeSerialNumber;
581 #else /* H5_HAVE_WIN32_API */
582 file->device = sb.st_dev;
583 #ifdef H5_VMS
584 file->inode[0] = sb.st_ino[0];
585 file->inode[1] = sb.st_ino[1];
586 file->inode[2] = sb.st_ino[2];
587 #else
588 file->inode = sb.st_ino;
589 #endif /*H5_VMS*/
590
591 #endif /* H5_HAVE_WIN32_API */
592
593 /* Retain a copy of the name used to open the file, for possible error reporting */
594 HDstrncpy(file->filename, name, sizeof(file->filename));
595 file->filename[sizeof(file->filename) - 1] = '\0';
596
597 /* Get the flags for logging */
598 file->fa.flags = fa->flags;
599
600 /* Check if we are doing any logging at all */
601 if(file->fa.flags != 0) {
602 /* Allocate buffers for tracking file accesses and data "flavor" */
603 file->iosize = fa->buf_size;
604 if(file->fa.flags & H5FD_LOG_FILE_READ) {
605 file->nread = (unsigned char *)H5MM_calloc(file->iosize);
606 HDassert(file->nread);
607 } /* end if */
608 if(file->fa.flags & H5FD_LOG_FILE_WRITE) {
609 file->nwrite = (unsigned char *)H5MM_calloc(file->iosize);
610 HDassert(file->nwrite);
611 } /* end if */
612 if(file->fa.flags & H5FD_LOG_FLAVOR) {
613 file->flavor = (unsigned char *)H5MM_calloc(file->iosize);
614 HDassert(file->flavor);
615 } /* end if */
616
617 /* Set the log file pointer */
618 if(fa->logfile)
619 file->logfp = HDfopen(fa->logfile, "w");
620 else
621 file->logfp = stderr;
622
623 #ifdef H5_HAVE_GETTIMEOFDAY
624 if(file->fa.flags & H5FD_LOG_TIME_OPEN)
625 HDfprintf(file->logfp, "Open took: (%f s)\n", (double)open_timeval_diff.tv_sec + ((double)open_timeval_diff.tv_usec / (double)1000000.0f));
626 if(file->fa.flags & H5FD_LOG_TIME_STAT)
627 HDfprintf(file->logfp, "Stat took: (%f s)\n", (double)stat_timeval_diff.tv_sec + ((double)stat_timeval_diff.tv_usec / (double)1000000.0f));
628 #endif /* H5_HAVE_GETTIMEOFDAY */
629
630 } /* end if */
631
632 /* Check for non-default FAPL */
633 if(H5P_FILE_ACCESS_DEFAULT != fapl_id) {
634 /* This step is for h5repart tool only. If user wants to change file driver from
635 * family to sec2 while using h5repart, this private property should be set so that
636 * in the later step, the library can ignore the family driver information saved
637 * in the superblock.
638 */
639 if(H5P_exist_plist(plist, H5F_ACS_FAMILY_TO_SEC2_NAME) > 0)
640 if(H5P_get(plist, H5F_ACS_FAMILY_TO_SEC2_NAME, &file->fam_to_sec2) < 0)
641 HGOTO_ERROR(H5E_VFL, H5E_CANTGET, NULL, "can't get property of changing family to sec2")
642 } /* end if */
643
644 /* Set return value */
645 ret_value = (H5FD_t*)file;
646
647 done:
648 if(NULL == ret_value) {
649 if(fd >= 0)
650 HDclose(fd);
651 if(file)
652 file = H5FL_FREE(H5FD_log_t, file);
653 } /* end if */
654
655 FUNC_LEAVE_NOAPI(ret_value)
656 } /* end H5FD_log_open() */
657
658
659 /*-------------------------------------------------------------------------
660 * Function: H5FD_log_close
661 *
662 * Purpose: Closes an HDF5 file.
663 *
664 * Return: Success: SUCCEED
665 * Failure: FAIL, file not closed.
666 *
667 * Programmer: Robb Matzke
668 * Thursday, July 29, 1999
669 *
670 *-------------------------------------------------------------------------
671 */
672 static herr_t
H5FD_log_close(H5FD_t * _file)673 H5FD_log_close(H5FD_t *_file)
674 {
675 H5FD_log_t *file = (H5FD_log_t *)_file;
676 #ifdef H5_HAVE_GETTIMEOFDAY
677 struct timeval timeval_start, timeval_stop;
678 #endif /* H5_HAVE_GETTIMEOFDAY */
679 herr_t ret_value = SUCCEED; /* Return value */
680
681 FUNC_ENTER_NOAPI_NOINIT
682
683 /* Sanity check */
684 HDassert(file);
685
686 #ifdef H5_HAVE_GETTIMEOFDAY
687 if(file->fa.flags&H5FD_LOG_TIME_CLOSE)
688 HDgettimeofday(&timeval_start, NULL);
689 #endif /* H5_HAVE_GETTIMEOFDAY */
690 /* Close the underlying file */
691 if(HDclose(file->fd) < 0)
692 HSYS_GOTO_ERROR(H5E_IO, H5E_CANTCLOSEFILE, FAIL, "unable to close file")
693 #ifdef H5_HAVE_GETTIMEOFDAY
694 if(file->fa.flags&H5FD_LOG_TIME_CLOSE)
695 HDgettimeofday(&timeval_stop, NULL);
696 #endif /* H5_HAVE_GETTIMEOFDAY */
697
698 /* Dump I/O information */
699 if(file->fa.flags != 0) {
700 haddr_t addr;
701 haddr_t last_addr;
702 unsigned char last_val;
703
704 #ifdef H5_HAVE_GETTIMEOFDAY
705 if(file->fa.flags & H5FD_LOG_TIME_CLOSE) {
706 struct timeval timeval_diff;
707
708 /* Calculate the elapsed gettimeofday time */
709 timeval_diff.tv_usec = timeval_stop.tv_usec - timeval_start.tv_usec;
710 timeval_diff.tv_sec = timeval_stop.tv_sec - timeval_start.tv_sec;
711 if(timeval_diff.tv_usec < 0) {
712 timeval_diff.tv_usec += 1000000;
713 timeval_diff.tv_sec--;
714 } /* end if */
715 HDfprintf(file->logfp, "Close took: (%f s)\n", (double)timeval_diff.tv_sec + ((double)timeval_diff.tv_usec / (double)1000000.0f));
716 } /* end if */
717 #endif /* H5_HAVE_GETTIMEOFDAY */
718
719 /* Dump the total number of seek/read/write operations */
720 if(file->fa.flags & H5FD_LOG_NUM_READ)
721 HDfprintf(file->logfp, "Total number of read operations: %llu\n", file->total_read_ops);
722 if(file->fa.flags & H5FD_LOG_NUM_WRITE)
723 HDfprintf(file->logfp, "Total number of write operations: %llu\n", file->total_write_ops);
724 if(file->fa.flags & H5FD_LOG_NUM_SEEK)
725 HDfprintf(file->logfp, "Total number of seek operations: %llu\n", file->total_seek_ops);
726 if(file->fa.flags & H5FD_LOG_NUM_TRUNCATE)
727 HDfprintf(file->logfp, "Total number of truncate operations: %llu\n", file->total_truncate_ops);
728
729 /* Dump the total time in seek/read/write */
730 if(file->fa.flags & H5FD_LOG_TIME_READ)
731 HDfprintf(file->logfp, "Total time in read operations: %f s\n", file->total_read_time);
732 if(file->fa.flags & H5FD_LOG_TIME_WRITE)
733 HDfprintf(file->logfp, "Total time in write operations: %f s\n", file->total_write_time);
734 if(file->fa.flags & H5FD_LOG_TIME_SEEK)
735 HDfprintf(file->logfp, "Total time in seek operations: %f s\n", file->total_seek_time);
736
737 /* Dump the write I/O information */
738 if(file->fa.flags & H5FD_LOG_FILE_WRITE) {
739 HDfprintf(file->logfp, "Dumping write I/O information:\n");
740 last_val = file->nwrite[0];
741 last_addr = 0;
742 addr = 1;
743 while(addr < file->eoa) {
744 if(file->nwrite[addr] != last_val) {
745 HDfprintf(file->logfp, "\tAddr %10a-%10a (%10lu bytes) written to %3d times\n", last_addr, (addr - 1), (unsigned long)(addr - last_addr), (int)last_val);
746 last_val = file->nwrite[addr];
747 last_addr = addr;
748 } /* end if */
749 addr++;
750 } /* end while */
751 HDfprintf(file->logfp, "\tAddr %10a-%10a (%10lu bytes) written to %3d times\n", last_addr, (addr - 1), (unsigned long)(addr - last_addr), (int)last_val);
752 } /* end if */
753
754 /* Dump the read I/O information */
755 if(file->fa.flags & H5FD_LOG_FILE_READ) {
756 HDfprintf(file->logfp, "Dumping read I/O information:\n");
757 last_val = file->nread[0];
758 last_addr = 0;
759 addr = 1;
760 while(addr < file->eoa) {
761 if(file->nread[addr] != last_val) {
762 HDfprintf(file->logfp, "\tAddr %10a-%10a (%10lu bytes) read from %3d times\n", last_addr, (addr - 1), (unsigned long)(addr - last_addr), (int)last_val);
763 last_val = file->nread[addr];
764 last_addr = addr;
765 } /* end if */
766 addr++;
767 } /* end while */
768 HDfprintf(file->logfp, "\tAddr %10a-%10a (%10lu bytes) read from %3d times\n", last_addr, (addr - 1), (unsigned long)(addr - last_addr), (int)last_val);
769 } /* end if */
770
771 /* Dump the I/O flavor information */
772 if(file->fa.flags & H5FD_LOG_FLAVOR) {
773 HDfprintf(file->logfp, "Dumping I/O flavor information:\n");
774 last_val = file->flavor[0];
775 last_addr = 0;
776 addr = 1;
777 while(addr < file->eoa) {
778 if(file->flavor[addr] != last_val) {
779 HDfprintf(file->logfp, "\tAddr %10a-%10a (%10lu bytes) flavor is %s\n", last_addr, (addr - 1), (unsigned long)(addr - last_addr), flavors[last_val]);
780 last_val = file->flavor[addr];
781 last_addr = addr;
782 } /* end if */
783 addr++;
784 } /* end while */
785 HDfprintf(file->logfp, "\tAddr %10a-%10a (%10lu bytes) flavor is %s\n", last_addr, (addr - 1), (unsigned long)(addr - last_addr), flavors[last_val]);
786 } /* end if */
787
788 /* Free the logging information */
789 if(file->fa.flags & H5FD_LOG_FILE_WRITE)
790 file->nwrite = (unsigned char *)H5MM_xfree(file->nwrite);
791 if(file->fa.flags & H5FD_LOG_FILE_READ)
792 file->nread = (unsigned char *)H5MM_xfree(file->nread);
793 if(file->fa.flags & H5FD_LOG_FLAVOR)
794 file->flavor = (unsigned char *)H5MM_xfree(file->flavor);
795 if(file->logfp != stderr)
796 HDfclose(file->logfp);
797 } /* end if */
798
799 /* Release the file info */
800 file = H5FL_FREE(H5FD_log_t, file);
801
802 done:
803 FUNC_LEAVE_NOAPI(ret_value)
804 } /* end H5FD_log_close() */
805
806
807 /*-------------------------------------------------------------------------
808 * Function: H5FD_log_cmp
809 *
810 * Purpose: Compares two files belonging to this driver using an
811 * arbitrary (but consistent) ordering.
812 *
813 * Return: Success: A value like strcmp()
814 * Failure: never fails (arguments were checked by the
815 * caller).
816 *
817 * Programmer: Robb Matzke
818 * Thursday, July 29, 1999
819 *
820 *-------------------------------------------------------------------------
821 */
822 static int
H5FD_log_cmp(const H5FD_t * _f1,const H5FD_t * _f2)823 H5FD_log_cmp(const H5FD_t *_f1, const H5FD_t *_f2)
824 {
825 const H5FD_log_t *f1 = (const H5FD_log_t *)_f1;
826 const H5FD_log_t *f2 = (const H5FD_log_t *)_f2;
827 int ret_value = 0;
828
829 FUNC_ENTER_NOAPI_NOINIT_NOERR
830
831 #ifdef H5_HAVE_WIN32_API
832 if(f1->dwVolumeSerialNumber < f2->dwVolumeSerialNumber) HGOTO_DONE(-1)
833 if(f1->dwVolumeSerialNumber > f2->dwVolumeSerialNumber) HGOTO_DONE(1)
834
835 if(f1->nFileIndexHigh < f2->nFileIndexHigh) HGOTO_DONE(-1)
836 if(f1->nFileIndexHigh > f2->nFileIndexHigh) HGOTO_DONE(1)
837
838 if(f1->nFileIndexLow < f2->nFileIndexLow) HGOTO_DONE(-1)
839 if(f1->nFileIndexLow > f2->nFileIndexLow) HGOTO_DONE(1)
840 #else
841 #ifdef H5_DEV_T_IS_SCALAR
842 if(f1->device < f2->device) HGOTO_DONE(-1)
843 if(f1->device > f2->device) HGOTO_DONE(1)
844 #else /* H5_DEV_T_IS_SCALAR */
845 /* If dev_t isn't a scalar value on this system, just use memcmp to
846 * determine if the values are the same or not. The actual return value
847 * shouldn't really matter...
848 */
849 if(HDmemcmp(&(f1->device),&(f2->device),sizeof(dev_t)) < 0) HGOTO_DONE(-1)
850 if(HDmemcmp(&(f1->device),&(f2->device),sizeof(dev_t)) > 0) HGOTO_DONE(1)
851 #endif /* H5_DEV_T_IS_SCALAR */
852
853 #ifndef H5_VMS
854 if(f1->inode < f2->inode) HGOTO_DONE(-1)
855 if(f1->inode > f2->inode) HGOTO_DONE(1)
856 #else
857 if(HDmemcmp(&(f1->inode), &(f2->inode), 3 * sizeof(ino_t)) < 0) HGOTO_DONE(-1)
858 if(HDmemcmp(&(f1->inode), &(f2->inode), 3 * sizeof(ino_t)) > 0) HGOTO_DONE(1)
859 #endif /*H5_VMS*/
860
861 #endif
862
863 done:
864 FUNC_LEAVE_NOAPI(ret_value)
865 } /* end H5FD_log_cmp() */
866
867
868 /*-------------------------------------------------------------------------
869 * Function: H5FD_log_query
870 *
871 * Purpose: Set the flags that this VFL driver is capable of supporting.
872 * (listed in H5FDpublic.h)
873 *
874 * Return: SUCCEED (Can't fail)
875 *
876 * Programmer: Quincey Koziol
877 * Friday, August 25, 2000
878 *
879 *-------------------------------------------------------------------------
880 */
881 static herr_t
H5FD_log_query(const H5FD_t * _file,unsigned long * flags)882 H5FD_log_query(const H5FD_t *_file, unsigned long *flags /* out */)
883 {
884 const H5FD_log_t *file = (const H5FD_log_t *)_file;
885
886 FUNC_ENTER_NOAPI_NOINIT_NOERR
887
888 /* Set the VFL feature flags that this driver supports */
889 if(flags) {
890 *flags = 0;
891 *flags |= H5FD_FEAT_AGGREGATE_METADATA; /* OK to aggregate metadata allocations */
892 *flags |= H5FD_FEAT_ACCUMULATE_METADATA; /* OK to accumulate metadata for faster writes */
893 *flags |= H5FD_FEAT_DATA_SIEVE; /* OK to perform data sieving for faster raw data reads & writes */
894 *flags |= H5FD_FEAT_AGGREGATE_SMALLDATA; /* OK to aggregate "small" raw data allocations */
895 *flags |= H5FD_FEAT_POSIX_COMPAT_HANDLE; /* VFD handle is POSIX I/O call compatible */
896
897 /* Check for flags that are set by h5repart */
898 if(file && file->fam_to_sec2)
899 *flags |= H5FD_FEAT_IGNORE_DRVRINFO; /* Ignore the driver info when file is opened (which eliminates it) */
900 } /* end if */
901
902 FUNC_LEAVE_NOAPI(SUCCEED)
903 } /* end H5FD_log_query() */
904
905
906 /*-------------------------------------------------------------------------
907 * Function: H5FD_log_alloc
908 *
909 * Purpose: Allocate file memory.
910 *
911 * Return: Success: Address of new memory
912 * Failure: HADDR_UNDEF
913 *
914 * Programmer: Quincey Koziol
915 * Monday, April 17, 2000
916 *
917 *-------------------------------------------------------------------------
918 */
919 static haddr_t
H5FD_log_alloc(H5FD_t * _file,H5FD_mem_t type,hid_t UNUSED dxpl_id,hsize_t size)920 H5FD_log_alloc(H5FD_t *_file, H5FD_mem_t type, hid_t UNUSED dxpl_id, hsize_t size)
921 {
922 H5FD_log_t *file = (H5FD_log_t *)_file;
923 haddr_t addr;
924 haddr_t ret_value; /* Return value */
925
926 FUNC_ENTER_NOAPI_NOINIT_NOERR
927
928 /* Compute the address for the block to allocate */
929 addr = file->eoa;
930
931 /* Check if we need to align this block */
932 if(size >= file->pub.threshold) {
933 /* Check for an already aligned block */
934 if(addr % file->pub.alignment != 0)
935 addr = ((addr / file->pub.alignment) + 1) * file->pub.alignment;
936 } /* end if */
937
938 file->eoa = addr + size;
939
940 /* Retain the (first) flavor of the information written to the file */
941 if(file->fa.flags != 0) {
942 if(file->fa.flags & H5FD_LOG_FLAVOR) {
943 HDassert(addr < file->iosize);
944 H5_CHECK_OVERFLOW(size, hsize_t, size_t);
945 HDmemset(&file->flavor[addr], (int)type, (size_t)size);
946 } /* end if */
947
948 if(file->fa.flags & H5FD_LOG_ALLOC)
949 HDfprintf(file->logfp, "%10a-%10a (%10Hu bytes) (%s) Allocated\n", addr, (addr + size) - 1, size, flavors[type]);
950 } /* end if */
951
952 /* Set return value */
953 ret_value = addr;
954
955 FUNC_LEAVE_NOAPI(ret_value)
956 } /* end H5FD_log_alloc() */
957
958
959 /*-------------------------------------------------------------------------
960 * Function: H5FD_log_get_eoa
961 *
962 * Purpose: Gets the end-of-address marker for the file. The EOA marker
963 * is the first address past the last byte allocated in the
964 * format address space.
965 *
966 * Return: Success: The end-of-address marker.
967 * Failure: HADDR_UNDEF
968 *
969 * Programmer: Robb Matzke
970 * Monday, August 2, 1999
971 *
972 *-------------------------------------------------------------------------
973 */
974 static haddr_t
H5FD_log_get_eoa(const H5FD_t * _file,H5FD_mem_t UNUSED type)975 H5FD_log_get_eoa(const H5FD_t *_file, H5FD_mem_t UNUSED type)
976 {
977 const H5FD_log_t *file = (const H5FD_log_t *)_file;
978
979 FUNC_ENTER_NOAPI_NOINIT_NOERR
980
981 FUNC_LEAVE_NOAPI(file->eoa)
982 } /* end H5FD_log_get_eoa() */
983
984
985 /*-------------------------------------------------------------------------
986 * Function: H5FD_log_set_eoa
987 *
988 * Purpose: Set the end-of-address marker for the file. This function is
989 * called shortly after an existing HDF5 file is opened in order
990 * to tell the driver where the end of the HDF5 data is located.
991 *
992 * Return: SUCCEED (Can't fail)
993 *
994 * Programmer: Robb Matzke
995 * Thursday, July 29, 1999
996 *
997 *-------------------------------------------------------------------------
998 */
999 static herr_t
H5FD_log_set_eoa(H5FD_t * _file,H5FD_mem_t type,haddr_t addr)1000 H5FD_log_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr)
1001 {
1002 H5FD_log_t *file = (H5FD_log_t *)_file;
1003
1004 FUNC_ENTER_NOAPI_NOINIT_NOERR
1005
1006 if(file->fa.flags != 0) {
1007 if(H5F_addr_gt(addr, file->eoa) && H5F_addr_gt(addr, 0)) {
1008 hsize_t size = addr - file->eoa;
1009
1010 /* Retain the flavor of the space allocated by the extension */
1011 if(file->fa.flags & H5FD_LOG_FLAVOR) {
1012 HDassert(addr < file->iosize);
1013 H5_CHECK_OVERFLOW(size, hsize_t, size_t);
1014 HDmemset(&file->flavor[file->eoa], (int)type, (size_t)size);
1015 } /* end if */
1016
1017 /* Log the extension like an allocation */
1018 if(file->fa.flags & H5FD_LOG_ALLOC)
1019 HDfprintf(file->logfp, "%10a-%10a (%10Hu bytes) (%s) Allocated\n", file->eoa, addr, size, flavors[type]);
1020 } /* end if */
1021 } /* end if */
1022
1023 file->eoa = addr;
1024
1025 FUNC_LEAVE_NOAPI(SUCCEED)
1026 } /* end H5FD_log_set_eoa() */
1027
1028
1029 /*-------------------------------------------------------------------------
1030 * Function: H5FD_log_get_eof
1031 *
1032 * Purpose: Returns the end-of-file marker, which is the greater of
1033 * either the filesystem end-of-file or the HDF5 end-of-address
1034 * markers.
1035 *
1036 * Return: Success: End of file address, the first address past
1037 * the end of the "file", either the filesystem file
1038 * or the HDF5 file.
1039 * Failure: HADDR_UNDEF
1040 *
1041 * Programmer: Robb Matzke
1042 * Thursday, July 29, 1999
1043 *
1044 *-------------------------------------------------------------------------
1045 */
1046 static haddr_t
H5FD_log_get_eof(const H5FD_t * _file)1047 H5FD_log_get_eof(const H5FD_t *_file)
1048 {
1049 const H5FD_log_t *file = (const H5FD_log_t *)_file;
1050
1051 FUNC_ENTER_NOAPI_NOINIT_NOERR
1052
1053 FUNC_LEAVE_NOAPI(MAX(file->eof, file->eoa))
1054 } /* end H5FD_log_get_eof() */
1055
1056
1057 /*-------------------------------------------------------------------------
1058 * Function: H5FD_log_get_handle
1059 *
1060 * Purpose: Returns the file handle of LOG file driver.
1061 *
1062 * Returns: SUCCEED/FAIL
1063 *
1064 * Programmer: Raymond Lu
1065 * Sept. 16, 2002
1066 *
1067 *-------------------------------------------------------------------------
1068 */
1069 static herr_t
H5FD_log_get_handle(H5FD_t * _file,hid_t UNUSED fapl,void ** file_handle)1070 H5FD_log_get_handle(H5FD_t *_file, hid_t UNUSED fapl, void **file_handle)
1071 {
1072 H5FD_log_t *file = (H5FD_log_t *)_file;
1073 herr_t ret_value = SUCCEED;
1074
1075 FUNC_ENTER_NOAPI_NOINIT
1076
1077 if(!file_handle)
1078 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file handle not valid")
1079
1080 *file_handle = &(file->fd);
1081
1082 done:
1083 FUNC_LEAVE_NOAPI(ret_value)
1084 } /* end H5FD_log_get_handle() */
1085
1086
1087 /*-------------------------------------------------------------------------
1088 * Function: H5FD_log_read
1089 *
1090 * Purpose: Reads SIZE bytes of data from FILE beginning at address ADDR
1091 * into buffer BUF according to data transfer properties in
1092 * DXPL_ID.
1093 *
1094 * Return: Success: SUCCEED. Result is stored in caller-supplied
1095 * buffer BUF.
1096 * Failure: FAIL, Contents of buffer BUF are undefined.
1097 *
1098 * Programmer: Robb Matzke
1099 * Thursday, July 29, 1999
1100 *
1101 *-------------------------------------------------------------------------
1102 */
1103 static herr_t
H5FD_log_read(H5FD_t * _file,H5FD_mem_t type,hid_t UNUSED dxpl_id,haddr_t addr,size_t size,void * buf)1104 H5FD_log_read(H5FD_t *_file, H5FD_mem_t type, hid_t UNUSED dxpl_id, haddr_t addr,
1105 size_t size, void *buf/*out*/)
1106 {
1107 H5FD_log_t *file = (H5FD_log_t *)_file;
1108 size_t orig_size = size; /* Save the original size for later */
1109 haddr_t orig_addr = addr;
1110 #ifdef H5_HAVE_GETTIMEOFDAY
1111 struct timeval timeval_start, timeval_stop;
1112 #endif /* H5_HAVE_GETTIMEOFDAY */
1113 herr_t ret_value = SUCCEED; /* Return value */
1114
1115 FUNC_ENTER_NOAPI_NOINIT
1116
1117 HDassert(file && file->pub.cls);
1118 HDassert(buf);
1119
1120 /* Check for overflow conditions */
1121 if(!H5F_addr_defined(addr))
1122 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addr undefined, addr = %llu", (unsigned long long)addr)
1123 if(REGION_OVERFLOW(addr, size))
1124 HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, addr = %llu", (unsigned long long)addr)
1125 if((addr + size) > file->eoa)
1126 HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, addr = %llu", (unsigned long long)addr)
1127
1128 /* Log the I/O information about the read */
1129 if(file->fa.flags != 0) {
1130 size_t tmp_size = size;
1131 haddr_t tmp_addr = addr;
1132
1133 /* Log information about the number of times these locations are read */
1134 if(file->fa.flags & H5FD_LOG_FILE_READ) {
1135 HDassert((addr + size) < file->iosize);
1136 while(tmp_size-- > 0)
1137 file->nread[tmp_addr++]++;
1138 } /* end if */
1139 } /* end if */
1140
1141 /* Seek to the correct location */
1142 if(addr != file->pos || OP_READ != file->op) {
1143 #ifdef H5_HAVE_GETTIMEOFDAY
1144 if(file->fa.flags & H5FD_LOG_TIME_SEEK)
1145 HDgettimeofday(&timeval_start, NULL);
1146 #endif /* H5_HAVE_GETTIMEOFDAY */
1147 if(HDlseek(file->fd, (HDoff_t)addr, SEEK_SET) < 0)
1148 HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
1149 #ifdef H5_HAVE_GETTIMEOFDAY
1150 if(file->fa.flags & H5FD_LOG_TIME_SEEK)
1151 HDgettimeofday(&timeval_stop, NULL);
1152 #endif /* H5_HAVE_GETTIMEOFDAY */
1153
1154 /* Log information about the seek */
1155 if(file->fa.flags & H5FD_LOG_NUM_SEEK)
1156 file->total_seek_ops++;
1157 if(file->fa.flags & H5FD_LOG_LOC_SEEK) {
1158 HDfprintf(file->logfp, "Seek: From %10a To %10a", file->pos, addr);
1159 #ifdef H5_HAVE_GETTIMEOFDAY
1160 if(file->fa.flags & H5FD_LOG_TIME_SEEK) {
1161 struct timeval timeval_diff;
1162 double time_diff;
1163
1164 /* Calculate the elapsed gettimeofday time */
1165 timeval_diff.tv_usec = timeval_stop.tv_usec - timeval_start.tv_usec;
1166 timeval_diff.tv_sec = timeval_stop.tv_sec - timeval_start.tv_sec;
1167 if(timeval_diff.tv_usec < 0) {
1168 timeval_diff.tv_usec += 1000000;
1169 timeval_diff.tv_sec--;
1170 } /* end if */
1171 time_diff = (double)timeval_diff.tv_sec + ((double)timeval_diff.tv_usec / (double)1000000.0f);
1172 HDfprintf(file->logfp, " (%f s)\n", time_diff);
1173
1174 /* Add to total seek time */
1175 file->total_seek_time += time_diff;
1176 } /* end if */
1177 else
1178 HDfprintf(file->logfp, "\n");
1179 #else /* H5_HAVE_GETTIMEOFDAY */
1180 HDfprintf(file->logfp, "\n");
1181 #endif /* H5_HAVE_GETTIMEOFDAY */
1182 } /* end if */
1183 } /* end if */
1184
1185 /*
1186 * Read data, being careful of interrupted system calls, partial results,
1187 * and the end of the file.
1188 */
1189 #ifdef H5_HAVE_GETTIMEOFDAY
1190 if(file->fa.flags & H5FD_LOG_TIME_READ)
1191 HDgettimeofday(&timeval_start, NULL);
1192 #endif /* H5_HAVE_GETTIMEOFDAY */
1193 while(size > 0) {
1194
1195 h5_posix_io_t bytes_in = 0; /* # of bytes to read */
1196 h5_posix_io_ret_t bytes_read = -1; /* # of bytes actually read */
1197
1198 /* Trying to read more bytes than the return type can handle is
1199 * undefined behavior in POSIX.
1200 */
1201 if(size > H5_POSIX_MAX_IO_BYTES)
1202 bytes_in = H5_POSIX_MAX_IO_BYTES;
1203 else
1204 bytes_in = (h5_posix_io_t)size;
1205
1206 do {
1207 bytes_read = HDread(file->fd, buf, bytes_in);
1208 } while(-1 == bytes_read && EINTR == errno);
1209
1210 if(-1 == bytes_read) { /* error */
1211 int myerrno = errno;
1212 time_t mytime = HDtime(NULL);
1213 HDoff_t myoffset = HDlseek(file->fd, (HDoff_t)0, SEEK_CUR);
1214
1215 if(file->fa.flags & H5FD_LOG_LOC_READ)
1216 HDfprintf(file->logfp, "Error! Reading: %10a-%10a (%10Zu bytes)\n", orig_addr, (orig_addr + orig_size) - 1, orig_size);
1217
1218 HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file read failed: time = %s, filename = '%s', file descriptor = %d, errno = %d, error message = '%s', buf = %p, total read size = %llu, bytes this sub-read = %llu, bytes actually read = %llu, offset = %llu", HDctime(&mytime), file->filename, file->fd, myerrno, HDstrerror(myerrno), buf, (unsigned long long)size, (unsigned long long)bytes_in, (unsigned long long)bytes_read, (unsigned long long)myoffset);
1219 } /* end if */
1220
1221 if(0 == bytes_read) {
1222 /* end of file but not end of format address space */
1223 HDmemset(buf, 0, size);
1224 break;
1225 } /* end if */
1226
1227 HDassert(bytes_read >= 0);
1228 HDassert((size_t)bytes_read <= size);
1229
1230 size -= (size_t)bytes_read;
1231 addr += (haddr_t)bytes_read;
1232 buf = (char *)buf + bytes_read;
1233
1234 } /* end while */
1235 #ifdef H5_HAVE_GETTIMEOFDAY
1236 if(file->fa.flags & H5FD_LOG_TIME_READ)
1237 HDgettimeofday(&timeval_stop, NULL);
1238 #endif /* H5_HAVE_GETTIMEOFDAY */
1239
1240 /* Log information about the read */
1241 if(file->fa.flags & H5FD_LOG_NUM_READ)
1242 file->total_read_ops++;
1243 if(file->fa.flags & H5FD_LOG_LOC_READ) {
1244 HDfprintf(file->logfp, "%10a-%10a (%10Zu bytes) (%s) Read", orig_addr, (orig_addr + orig_size) - 1, orig_size, flavors[type]);
1245
1246 /* XXX: Verify the flavor information, if we have it? */
1247
1248 #ifdef H5_HAVE_GETTIMEOFDAY
1249 if(file->fa.flags & H5FD_LOG_TIME_READ) {
1250 struct timeval timeval_diff;
1251 double time_diff;
1252
1253 /* Calculate the elapsed gettimeofday time */
1254 timeval_diff.tv_usec = timeval_stop.tv_usec - timeval_start.tv_usec;
1255 timeval_diff.tv_sec = timeval_stop.tv_sec - timeval_start.tv_sec;
1256 if(timeval_diff.tv_usec < 0) {
1257 timeval_diff.tv_usec += 1000000;
1258 timeval_diff.tv_sec--;
1259 } /* end if */
1260 time_diff = (double)timeval_diff.tv_sec + ((double)timeval_diff.tv_usec / (double)1000000.0f);
1261 HDfprintf(file->logfp, " (%f s)\n", time_diff);
1262
1263 /* Add to total read time */
1264 file->total_read_time += time_diff;
1265 } /* end if */
1266 else
1267 HDfprintf(file->logfp, "\n");
1268 #else /* H5_HAVE_GETTIMEOFDAY */
1269 HDfprintf(file->logfp, "\n");
1270 #endif /* H5_HAVE_GETTIMEOFDAY */
1271 } /* end if */
1272
1273 /* Update current position */
1274 file->pos = addr;
1275 file->op = OP_READ;
1276
1277 done:
1278 if(ret_value < 0) {
1279 /* Reset last file I/O information */
1280 file->pos = HADDR_UNDEF;
1281 file->op = OP_UNKNOWN;
1282 } /* end if */
1283
1284 FUNC_LEAVE_NOAPI(ret_value)
1285 } /* end H5FD_log_read() */
1286
1287
1288 /*-------------------------------------------------------------------------
1289 * Function: H5FD_log_write
1290 *
1291 * Purpose: Writes SIZE bytes of data to FILE beginning at address ADDR
1292 * from buffer BUF according to data transfer properties in
1293 * DXPL_ID.
1294 *
1295 * Return: SUCCEED/FAIL
1296 *
1297 * Programmer: Robb Matzke
1298 * Thursday, July 29, 1999
1299 *
1300 *-------------------------------------------------------------------------
1301 */
1302 static herr_t
H5FD_log_write(H5FD_t * _file,H5FD_mem_t type,hid_t UNUSED dxpl_id,haddr_t addr,size_t size,const void * buf)1303 H5FD_log_write(H5FD_t *_file, H5FD_mem_t type, hid_t UNUSED dxpl_id, haddr_t addr,
1304 size_t size, const void *buf)
1305 {
1306 H5FD_log_t *file = (H5FD_log_t *)_file;
1307 size_t orig_size = size; /* Save the original size for later */
1308 haddr_t orig_addr = addr;
1309 #ifdef H5_HAVE_GETTIMEOFDAY
1310 struct timeval timeval_start, timeval_stop;
1311 #endif /* H5_HAVE_GETTIMEOFDAY */
1312 herr_t ret_value = SUCCEED; /* Return value */
1313
1314 FUNC_ENTER_NOAPI_NOINIT
1315
1316 HDassert(file && file->pub.cls);
1317 HDassert(size > 0);
1318 HDassert(buf);
1319
1320 /* Verify that we are writing out the type of data we allocated in this location */
1321 if(file->flavor) {
1322 HDassert(type == H5FD_MEM_DEFAULT || type == (H5FD_mem_t)file->flavor[addr] || (H5FD_mem_t)file->flavor[addr] == H5FD_MEM_DEFAULT);
1323 HDassert(type == H5FD_MEM_DEFAULT || type == (H5FD_mem_t)file->flavor[(addr + size) - 1] || (H5FD_mem_t)file->flavor[(addr + size) - 1] == H5FD_MEM_DEFAULT);
1324 } /* end if */
1325
1326 /* Check for overflow conditions */
1327 if(!H5F_addr_defined(addr))
1328 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addr undefined, addr = %llu", (unsigned long long)addr)
1329 if(REGION_OVERFLOW(addr, size))
1330 HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, addr = %llu, size = %llu", (unsigned long long)addr, (unsigned long long)size)
1331 if((addr + size) > file->eoa)
1332 HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, addr = %llu, size = %llu, eoa = %llu", (unsigned long long)addr, (unsigned long long)size, (unsigned long long)file->eoa)
1333
1334 /* Log the I/O information about the write */
1335 if(file->fa.flags & H5FD_LOG_FILE_WRITE) {
1336 size_t tmp_size = size;
1337 haddr_t tmp_addr = addr;
1338
1339 /* Log information about the number of times these locations are read */
1340 HDassert((addr + size) < file->iosize);
1341 while(tmp_size-- > 0)
1342 file->nwrite[tmp_addr++]++;
1343 } /* end if */
1344
1345 /* Seek to the correct location */
1346 if(addr != file->pos || OP_WRITE != file->op) {
1347 #ifdef H5_HAVE_GETTIMEOFDAY
1348 if(file->fa.flags & H5FD_LOG_TIME_SEEK)
1349 HDgettimeofday(&timeval_start, NULL);
1350 #endif /* H5_HAVE_GETTIMEOFDAY */
1351 if(HDlseek(file->fd, (HDoff_t)addr, SEEK_SET) < 0)
1352 HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
1353 #ifdef H5_HAVE_GETTIMEOFDAY
1354 if(file->fa.flags & H5FD_LOG_TIME_SEEK)
1355 HDgettimeofday(&timeval_stop, NULL);
1356 #endif /* H5_HAVE_GETTIMEOFDAY */
1357
1358 /* Log information about the seek */
1359 if(file->fa.flags & H5FD_LOG_NUM_SEEK)
1360 file->total_seek_ops++;
1361 if(file->fa.flags & H5FD_LOG_LOC_SEEK) {
1362 HDfprintf(file->logfp, "Seek: From %10a To %10a", file->pos, addr);
1363 #ifdef H5_HAVE_GETTIMEOFDAY
1364 if(file->fa.flags & H5FD_LOG_TIME_SEEK) {
1365 struct timeval timeval_diff;
1366 double time_diff;
1367
1368 /* Calculate the elapsed gettimeofday time */
1369 timeval_diff.tv_usec = timeval_stop.tv_usec - timeval_start.tv_usec;
1370 timeval_diff.tv_sec = timeval_stop.tv_sec - timeval_start.tv_sec;
1371 if(timeval_diff.tv_usec < 0) {
1372 timeval_diff.tv_usec += 1000000;
1373 timeval_diff.tv_sec--;
1374 } /* end if */
1375 time_diff = (double)timeval_diff.tv_sec + ((double)timeval_diff.tv_usec / (double)1000000.0f);
1376 HDfprintf(file->logfp, " (%f s)\n", time_diff);
1377
1378 /* Add to total seek time */
1379 file->total_seek_time += time_diff;
1380 } /* end if */
1381 else
1382 HDfprintf(file->logfp, "\n");
1383 #else /* H5_HAVE_GETTIMEOFDAY */
1384 HDfprintf(file->logfp, "\n");
1385 #endif /* H5_HAVE_GETTIMEOFDAY */
1386 } /* end if */
1387 } /* end if */
1388
1389 /*
1390 * Write the data, being careful of interrupted system calls and partial
1391 * results
1392 */
1393 #ifdef H5_HAVE_GETTIMEOFDAY
1394 if(file->fa.flags&H5FD_LOG_TIME_WRITE)
1395 HDgettimeofday(&timeval_start, NULL);
1396 #endif /* H5_HAVE_GETTIMEOFDAY */
1397 while(size > 0) {
1398
1399 h5_posix_io_t bytes_in = 0; /* # of bytes to write */
1400 h5_posix_io_ret_t bytes_wrote = -1; /* # of bytes written */
1401
1402 /* Trying to write more bytes than the return type can handle is
1403 * undefined behavior in POSIX.
1404 */
1405 if(size > H5_POSIX_MAX_IO_BYTES)
1406 bytes_in = H5_POSIX_MAX_IO_BYTES;
1407 else
1408 bytes_in = (h5_posix_io_t)size;
1409
1410 do {
1411 bytes_wrote = HDwrite(file->fd, buf, bytes_in);
1412 } while(-1 == bytes_wrote && EINTR == errno);
1413
1414 if(-1 == bytes_wrote) { /* error */
1415 int myerrno = errno;
1416 time_t mytime = HDtime(NULL);
1417 HDoff_t myoffset = HDlseek(file->fd, (HDoff_t)0, SEEK_CUR);
1418
1419 if(file->fa.flags & H5FD_LOG_LOC_WRITE)
1420 HDfprintf(file->logfp, "Error! Writing: %10a-%10a (%10Zu bytes)\n", orig_addr, (orig_addr + orig_size) - 1, orig_size);
1421
1422 HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed: time = %s, filename = '%s', file descriptor = %d, errno = %d, error message = '%s', buf = %p, total write size = %llu, bytes this sub-write = %llu, bytes actually written = %llu, offset = %llu", HDctime(&mytime), file->filename, file->fd, myerrno, HDstrerror(myerrno), buf, (unsigned long long)size, (unsigned long long)bytes_in, (unsigned long long)bytes_wrote, (unsigned long long)myoffset);
1423 } /* end if */
1424
1425 HDassert(bytes_wrote > 0);
1426 HDassert((size_t)bytes_wrote <= size);
1427
1428 size -= (size_t)bytes_wrote;
1429 addr += (haddr_t)bytes_wrote;
1430 buf = (const char *)buf + bytes_wrote;
1431 } /* end while */
1432 #ifdef H5_HAVE_GETTIMEOFDAY
1433 if(file->fa.flags & H5FD_LOG_TIME_WRITE)
1434 HDgettimeofday(&timeval_stop, NULL);
1435 #endif /* H5_HAVE_GETTIMEOFDAY */
1436
1437 /* Log information about the write */
1438 if(file->fa.flags & H5FD_LOG_NUM_WRITE)
1439 file->total_write_ops++;
1440 if(file->fa.flags & H5FD_LOG_LOC_WRITE) {
1441 HDfprintf(file->logfp, "%10a-%10a (%10Zu bytes) (%s) Written", orig_addr, (orig_addr + orig_size) - 1, orig_size, flavors[type]);
1442
1443 /* Check if this is the first write into a "default" section, grabbed by the metadata agregation algorithm */
1444 if(file->fa.flags & H5FD_LOG_FLAVOR) {
1445 if((H5FD_mem_t)file->flavor[orig_addr] == H5FD_MEM_DEFAULT)
1446 HDmemset(&file->flavor[orig_addr], (int)type, orig_size);
1447 } /* end if */
1448
1449 #ifdef H5_HAVE_GETTIMEOFDAY
1450 if(file->fa.flags & H5FD_LOG_TIME_WRITE) {
1451 struct timeval timeval_diff;
1452 double time_diff;
1453
1454 /* Calculate the elapsed gettimeofday time */
1455 timeval_diff.tv_usec = timeval_stop.tv_usec - timeval_start.tv_usec;
1456 timeval_diff.tv_sec = timeval_stop.tv_sec - timeval_start.tv_sec;
1457 if(timeval_diff.tv_usec < 0) {
1458 timeval_diff.tv_usec += 1000000;
1459 timeval_diff.tv_sec--;
1460 } /* end if */
1461 time_diff = (double)timeval_diff.tv_sec + ((double)timeval_diff.tv_usec / (double)1000000.0f);
1462 HDfprintf(file->logfp, " (%f s)\n", time_diff);
1463
1464 /* Add to total write time */
1465 file->total_write_time += time_diff;
1466 } /* end if */
1467 else
1468 HDfprintf(file->logfp, "\n");
1469 #else /* H5_HAVE_GETTIMEOFDAY */
1470 HDfprintf(file->logfp, "\n");
1471 #endif /* H5_HAVE_GETTIMEOFDAY */
1472 } /* end if */
1473
1474 /* Update current position and eof */
1475 file->pos = addr;
1476 file->op = OP_WRITE;
1477 if(file->pos > file->eof)
1478 file->eof = file->pos;
1479
1480 done:
1481 if(ret_value < 0) {
1482 /* Reset last file I/O information */
1483 file->pos = HADDR_UNDEF;
1484 file->op = OP_UNKNOWN;
1485 } /* end if */
1486
1487 FUNC_LEAVE_NOAPI(ret_value)
1488 } /* end H5FD_log_write() */
1489
1490
1491 /*-------------------------------------------------------------------------
1492 * Function: H5FD_log_truncate
1493 *
1494 * Purpose: Makes sure that the true file size is the same (or larger)
1495 * than the end-of-address.
1496 *
1497 * Return: SUCCEED/FAIL
1498 *
1499 * Programmer: Robb Matzke
1500 * Wednesday, August 4, 1999
1501 *
1502 *-------------------------------------------------------------------------
1503 */
1504 static herr_t
H5FD_log_truncate(H5FD_t * _file,hid_t UNUSED dxpl_id,hbool_t UNUSED closing)1505 H5FD_log_truncate(H5FD_t *_file, hid_t UNUSED dxpl_id, hbool_t UNUSED closing)
1506 {
1507 H5FD_log_t *file = (H5FD_log_t *)_file;
1508 herr_t ret_value = SUCCEED; /* Return value */
1509
1510 FUNC_ENTER_NOAPI_NOINIT
1511
1512 HDassert(file);
1513
1514 /* Extend the file to make sure it's large enough */
1515 if(!H5F_addr_eq(file->eoa, file->eof)) {
1516 #ifdef H5_HAVE_WIN32_API
1517 LARGE_INTEGER li; /* 64-bit (union) integer for SetFilePointer() call */
1518 DWORD dwPtrLow; /* Low-order pointer bits from SetFilePointer()
1519 * Only used as an error code here.
1520 */
1521 DWORD dwError; /* DWORD error code from GetLastError() */
1522 BOOL bError; /* Boolean error flag */
1523
1524 /* Windows uses this odd QuadPart union for 32/64-bit portability */
1525 li.QuadPart = (__int64)file->eoa;
1526
1527 /* Extend the file to make sure it's large enough.
1528 *
1529 * Since INVALID_SET_FILE_POINTER can technically be a valid return value
1530 * from SetFilePointer(), we also need to check GetLastError().
1531 */
1532 dwPtrLow = SetFilePointer(file->hFile, li.LowPart, &li.HighPart, FILE_BEGIN);
1533 if(INVALID_SET_FILE_POINTER == dwPtrLow) {
1534 dwError = GetLastError();
1535 if(dwError != NO_ERROR )
1536 HGOTO_ERROR(H5E_FILE, H5E_FILEOPEN, FAIL, "unable to set file pointer")
1537 }
1538
1539 bError = SetEndOfFile(file->hFile);
1540 if(0 == bError)
1541 HGOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly")
1542 #else /* H5_HAVE_WIN32_API */
1543 #ifdef H5_VMS
1544 /* Reset seek offset to the beginning of the file, so that the file isn't
1545 * re-extended later. This may happen on Open VMS. */
1546 if(-1 == HDlseek(file->fd, (HDoff_t)0, SEEK_SET))
1547 HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position")
1548 #endif
1549
1550 if(-1 == HDftruncate(file->fd, (HDoff_t)file->eoa))
1551 HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly")
1552 #endif /* H5_HAVE_WIN32_API */
1553
1554 /* Log information about the truncate */
1555 if(file->fa.flags & H5FD_LOG_NUM_TRUNCATE)
1556 file->total_truncate_ops++;
1557
1558 /* Update the eof value */
1559 file->eof = file->eoa;
1560
1561 /* Reset last file I/O information */
1562 file->pos = HADDR_UNDEF;
1563 file->op = OP_UNKNOWN;
1564 } /* end if */
1565
1566 done:
1567 FUNC_LEAVE_NOAPI(ret_value)
1568 } /* end H5FD_log_truncate() */
1569