Coverage Report

Created: 2026-09-04 06:51

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