Coverage Report

Created: 2026-03-04 00:50

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
0
#ifndef H5_HAVE_PREADWRITE
494
0
    file->pos = HADDR_UNDEF;
495
0
    file->op  = OP_UNKNOWN;
496
0
#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
            file->logfp = fopen(fa->logfile, "w");
545
0
        else
546
0
            file->logfp = stderr;
547
548
        /* Log the timer values */
549
0
        if (file->fa.flags & H5FD_LOG_TIME_OPEN) {
550
0
            H5_timevals_t open_times; /* Elapsed time for open() call */
551
552
0
            H5_timer_get_times(open_timer, &open_times);
553
0
            fprintf(file->logfp, "Open took: (%f s)\n", open_times.elapsed);
554
0
        }
555
0
        if (file->fa.flags & H5FD_LOG_TIME_STAT) {
556
0
            H5_timevals_t stat_times; /* Elapsed time for stat() call */
557
558
0
            H5_timer_get_times(stat_timer, &stat_times);
559
0
            fprintf(file->logfp, "Stat took: (%f s)\n", stat_times.elapsed);
560
0
        }
561
0
    }
562
563
    /* Check the file locking flags in the fapl */
564
0
    if (H5FD_ignore_disabled_file_locks_p != FAIL)
565
        /* The environment variable was set, so use that preferentially */
566
0
        file->ignore_disabled_file_locks = H5FD_ignore_disabled_file_locks_p;
567
0
    else {
568
        /* Use the value in the property list */
569
0
        if (H5P_get(plist, H5F_ACS_IGNORE_DISABLED_FILE_LOCKS_NAME, &file->ignore_disabled_file_locks) < 0)
570
0
            HGOTO_ERROR(H5E_VFL, H5E_CANTGET, NULL, "can't get ignore disabled file locks property");
571
0
    }
572
573
    /* Check for non-default FAPL */
574
0
    if (H5P_FILE_ACCESS_DEFAULT != fapl_id) {
575
        /* This step is for h5repart tool only. If user wants to change file driver from
576
         * family to one that uses single files (sec2, etc.) while using h5repart, this
577
         * private property should be set so that in the later step, the library can ignore
578
         * the family driver information saved in the superblock.
579
         */
580
0
        if (H5P_exist_plist(plist, H5F_ACS_FAMILY_TO_SINGLE_NAME) > 0)
581
0
            if (H5P_get(plist, H5F_ACS_FAMILY_TO_SINGLE_NAME, &file->fam_to_single) < 0)
582
0
                HGOTO_ERROR(H5E_VFL, H5E_CANTGET, NULL, "can't get property of changing family to single");
583
0
    }
584
585
    /* Set return value */
586
0
    ret_value = (H5FD_t *)file;
587
588
0
done:
589
0
    if (NULL == ret_value) {
590
0
        if (fd >= 0)
591
0
            HDclose(fd);
592
0
        if (file)
593
0
            file = H5FL_FREE(H5FD_log_t, file);
594
0
    }
595
596
0
    FUNC_LEAVE_NOAPI(ret_value)
597
0
} /* end H5FD__log_open() */
598
599
/*-------------------------------------------------------------------------
600
 * Function:    H5FD__log_close
601
 *
602
 * Purpose:     Closes an HDF5 file.
603
 *
604
 * Return:      Success:    SUCCEED
605
 *              Failure:    FAIL, file not closed.
606
 *
607
 *-------------------------------------------------------------------------
608
 */
609
static herr_t
610
H5FD__log_close(H5FD_t *_file)
611
0
{
612
0
    H5FD_log_t *file = (H5FD_log_t *)_file;
613
0
    H5_timer_t  close_timer;         /* Timer for close() call */
614
0
    herr_t      ret_value = SUCCEED; /* Return value */
615
616
0
    FUNC_ENTER_PACKAGE
617
618
    /* Sanity check */
619
0
    assert(file);
620
621
    /* Initialize timer */
622
0
    H5_timer_init(&close_timer);
623
624
    /* Start timer for close() call */
625
0
    if (file->fa.flags & H5FD_LOG_TIME_CLOSE)
626
0
        H5_timer_start(&close_timer);
627
628
    /* Close the underlying file */
629
0
    if (HDclose(file->fd) < 0)
630
0
        HSYS_GOTO_ERROR(H5E_IO, H5E_CANTCLOSEFILE, FAIL, "unable to close file");
631
632
    /* Stop timer for close() call */
633
0
    if (file->fa.flags & H5FD_LOG_TIME_CLOSE)
634
0
        H5_timer_stop(&close_timer);
635
636
    /* Dump I/O information */
637
0
    if (file->fa.flags != 0) {
638
0
        haddr_t       addr;
639
0
        haddr_t       last_addr;
640
0
        unsigned char last_val;
641
642
0
        if (file->fa.flags & H5FD_LOG_TIME_CLOSE) {
643
0
            H5_timevals_t close_times; /* Elapsed time for close() call */
644
645
0
            H5_timer_get_times(close_timer, &close_times);
646
0
            fprintf(file->logfp, "Close took: (%f s)\n", close_times.elapsed);
647
0
        }
648
649
        /* Dump the total number of seek/read/write operations */
650
0
        if (file->fa.flags & H5FD_LOG_NUM_READ)
651
0
            fprintf(file->logfp, "Total number of read operations: %llu\n", file->total_read_ops);
652
0
        if (file->fa.flags & H5FD_LOG_NUM_WRITE)
653
0
            fprintf(file->logfp, "Total number of write operations: %llu\n", file->total_write_ops);
654
0
        if (file->fa.flags & H5FD_LOG_NUM_SEEK)
655
0
            fprintf(file->logfp, "Total number of seek operations: %llu\n", file->total_seek_ops);
656
0
        if (file->fa.flags & H5FD_LOG_NUM_TRUNCATE)
657
0
            fprintf(file->logfp, "Total number of truncate operations: %llu\n", file->total_truncate_ops);
658
659
        /* Dump the total time in seek/read/write */
660
0
        if (file->fa.flags & H5FD_LOG_TIME_READ)
661
0
            fprintf(file->logfp, "Total time in read operations: %f s\n", file->total_read_time);
662
0
        if (file->fa.flags & H5FD_LOG_TIME_WRITE)
663
0
            fprintf(file->logfp, "Total time in write operations: %f s\n", file->total_write_time);
664
0
        if (file->fa.flags & H5FD_LOG_TIME_SEEK)
665
0
            fprintf(file->logfp, "Total time in seek operations: %f s\n", file->total_seek_time);
666
0
        if (file->fa.flags & H5FD_LOG_TIME_TRUNCATE)
667
0
            fprintf(file->logfp, "Total time in truncate operations: %f s\n", file->total_truncate_time);
668
669
        /* Dump the write I/O information */
670
0
        if (file->fa.flags & H5FD_LOG_FILE_WRITE) {
671
0
            fprintf(file->logfp, "Dumping write I/O information:\n");
672
0
            last_val  = file->nwrite[0];
673
0
            last_addr = 0;
674
0
            addr      = 1;
675
0
            while (addr < file->eoa) {
676
0
                if (file->nwrite[addr] != last_val) {
677
0
                    fprintf(file->logfp,
678
0
                            "\tAddr %10" PRIuHADDR "-%10" PRIuHADDR " (%10lu bytes) written to %3d times\n",
679
0
                            last_addr, (addr - 1), (unsigned long)(addr - last_addr), (int)last_val);
680
0
                    last_val  = file->nwrite[addr];
681
0
                    last_addr = addr;
682
0
                }
683
0
                addr++;
684
0
            }
685
0
            fprintf(file->logfp,
686
0
                    "\tAddr %10" PRIuHADDR "-%10" PRIuHADDR " (%10lu bytes) written to %3d times\n",
687
0
                    last_addr, (addr - 1), (unsigned long)(addr - last_addr), (int)last_val);
688
0
        }
689
690
        /* Dump the read I/O information */
691
0
        if (file->fa.flags & H5FD_LOG_FILE_READ) {
692
0
            fprintf(file->logfp, "Dumping read I/O information:\n");
693
0
            last_val  = file->nread[0];
694
0
            last_addr = 0;
695
0
            addr      = 1;
696
0
            while (addr < file->eoa) {
697
0
                if (file->nread[addr] != last_val) {
698
0
                    fprintf(file->logfp,
699
0
                            "\tAddr %10" PRIuHADDR "-%10" PRIuHADDR " (%10lu bytes) read from %3d times\n",
700
0
                            last_addr, (addr - 1), (unsigned long)(addr - last_addr), (int)last_val);
701
0
                    last_val  = file->nread[addr];
702
0
                    last_addr = addr;
703
0
                }
704
0
                addr++;
705
0
            }
706
0
            fprintf(file->logfp,
707
0
                    "\tAddr %10" PRIuHADDR "-%10" PRIuHADDR " (%10lu bytes) read from %3d times\n", last_addr,
708
0
                    (addr - 1), (unsigned long)(addr - last_addr), (int)last_val);
709
0
        }
710
711
        /* Dump the I/O flavor information */
712
0
        if (file->fa.flags & H5FD_LOG_FLAVOR) {
713
0
            fprintf(file->logfp, "Dumping I/O flavor information:\n");
714
0
            last_val  = file->flavor[0];
715
0
            last_addr = 0;
716
0
            addr      = 1;
717
0
            while (addr < file->eoa) {
718
0
                if (file->flavor[addr] != last_val) {
719
0
                    fprintf(file->logfp,
720
0
                            "\tAddr %10" PRIuHADDR "-%10" PRIuHADDR " (%10lu bytes) flavor is %s\n",
721
0
                            last_addr, (addr - 1), (unsigned long)(addr - last_addr), flavors[last_val]);
722
0
                    last_val  = file->flavor[addr];
723
0
                    last_addr = addr;
724
0
                }
725
0
                addr++;
726
0
            }
727
0
            fprintf(file->logfp, "\tAddr %10" PRIuHADDR "-%10" PRIuHADDR " (%10lu bytes) flavor is %s\n",
728
0
                    last_addr, (addr - 1), (unsigned long)(addr - last_addr), flavors[last_val]);
729
0
        }
730
731
        /* Free the logging information */
732
0
        if (file->fa.flags & H5FD_LOG_FILE_WRITE)
733
0
            file->nwrite = (unsigned char *)H5MM_xfree(file->nwrite);
734
0
        if (file->fa.flags & H5FD_LOG_FILE_READ)
735
0
            file->nread = (unsigned char *)H5MM_xfree(file->nread);
736
0
        if (file->fa.flags & H5FD_LOG_FLAVOR)
737
0
            file->flavor = (unsigned char *)H5MM_xfree(file->flavor);
738
0
        if (file->logfp != stderr)
739
0
            fclose(file->logfp);
740
0
    } /* end if */
741
742
0
    if (file->fa.logfile)
743
0
        file->fa.logfile = (char *)H5MM_xfree(file->fa.logfile);
744
745
    /* Release the file info */
746
0
    file = H5FL_FREE(H5FD_log_t, file);
747
748
0
done:
749
0
    FUNC_LEAVE_NOAPI(ret_value)
750
0
} /* end H5FD__log_close() */
751
752
/*-------------------------------------------------------------------------
753
 * Function:    H5FD__log_cmp
754
 *
755
 * Purpose:     Compares two files belonging to this driver using an
756
 *              arbitrary (but consistent) ordering.
757
 *
758
 * Return:      Success:    A value like strcmp()
759
 *              Failure:    never fails (arguments were checked by the
760
 *                          caller).
761
 *
762
 *-------------------------------------------------------------------------
763
 */
764
static int
765
H5FD__log_cmp(const H5FD_t *_f1, const H5FD_t *_f2)
766
0
{
767
0
    const H5FD_log_t *f1        = (const H5FD_log_t *)_f1;
768
0
    const H5FD_log_t *f2        = (const H5FD_log_t *)_f2;
769
0
    int               ret_value = 0;
770
771
0
    FUNC_ENTER_PACKAGE_NOERR
772
773
#ifdef H5_HAVE_WIN32_API
774
    if (f1->dwVolumeSerialNumber < f2->dwVolumeSerialNumber)
775
        HGOTO_DONE(-1);
776
    if (f1->dwVolumeSerialNumber > f2->dwVolumeSerialNumber)
777
        HGOTO_DONE(1);
778
779
    if (f1->nFileIndexHigh < f2->nFileIndexHigh)
780
        HGOTO_DONE(-1);
781
    if (f1->nFileIndexHigh > f2->nFileIndexHigh)
782
        HGOTO_DONE(1);
783
784
    if (f1->nFileIndexLow < f2->nFileIndexLow)
785
        HGOTO_DONE(-1);
786
    if (f1->nFileIndexLow > f2->nFileIndexLow)
787
        HGOTO_DONE(1);
788
#else
789
0
    if (f1->device < f2->device)
790
0
        HGOTO_DONE(-1);
791
0
    if (f1->device > f2->device)
792
0
        HGOTO_DONE(1);
793
794
0
    if (f1->inode < f2->inode)
795
0
        HGOTO_DONE(-1);
796
0
    if (f1->inode > f2->inode)
797
0
        HGOTO_DONE(1);
798
799
0
#endif
800
801
0
done:
802
0
    FUNC_LEAVE_NOAPI(ret_value)
803
0
} /* end H5FD__log_cmp() */
804
805
/*-------------------------------------------------------------------------
806
 * Function:    H5FD__log_query
807
 *
808
 * Purpose:     Set the flags that this VFL driver is capable of supporting.
809
 *              (listed in H5FDpublic.h)
810
 *
811
 * Return:      SUCCEED (Can't fail)
812
 *
813
 *-------------------------------------------------------------------------
814
 */
815
static herr_t
816
H5FD__log_query(const H5FD_t *_file, unsigned long *flags /* out */)
817
0
{
818
0
    const H5FD_log_t *file = (const H5FD_log_t *)_file;
819
820
0
    FUNC_ENTER_PACKAGE_NOERR
821
822
    /* Set the VFL feature flags that this driver supports */
823
0
    if (flags) {
824
0
        *flags = 0;
825
0
        *flags |= H5FD_FEAT_AGGREGATE_METADATA;  /* OK to aggregate metadata allocations  */
826
0
        *flags |= H5FD_FEAT_ACCUMULATE_METADATA; /* OK to accumulate metadata for faster writes */
827
0
        *flags |= H5FD_FEAT_DATA_SIEVE; /* OK to perform data sieving for faster raw data reads & writes    */
828
0
        *flags |= H5FD_FEAT_AGGREGATE_SMALLDATA; /* OK to aggregate "small" raw data allocations */
829
0
        *flags |= H5FD_FEAT_POSIX_COMPAT_HANDLE; /* get_handle callback returns a POSIX file descriptor */
830
0
        *flags |=
831
0
            H5FD_FEAT_SUPPORTS_SWMR_IO; /* VFD supports the single-writer/multiple-readers (SWMR) pattern   */
832
0
        *flags |= H5FD_FEAT_DEFAULT_VFD_COMPATIBLE; /* VFD creates a file which can be opened with the default
833
                                                       VFD      */
834
835
        /* Check for flags that are set by h5repart */
836
0
        if (file && file->fam_to_single)
837
0
            *flags |= H5FD_FEAT_IGNORE_DRVRINFO; /* Ignore the driver info when file is opened (which
838
                                                    eliminates it) */
839
0
    }
840
841
0
    FUNC_LEAVE_NOAPI(SUCCEED)
842
0
} /* end H5FD__log_query() */
843
844
/*-------------------------------------------------------------------------
845
 * Function:    H5FD__log_alloc
846
 *
847
 * Purpose:     Allocate file memory.
848
 *
849
 * Return:      Success:    Address of new memory
850
 *              Failure:    HADDR_UNDEF
851
 *
852
 *-------------------------------------------------------------------------
853
 */
854
static haddr_t
855
H5FD__log_alloc(H5FD_t *_file, H5FD_mem_t type, hid_t H5_ATTR_UNUSED dxpl_id, hsize_t size)
856
0
{
857
0
    H5FD_log_t *file = (H5FD_log_t *)_file;
858
0
    haddr_t     addr;
859
0
    haddr_t     ret_value = HADDR_UNDEF; /* Return value */
860
861
0
    FUNC_ENTER_PACKAGE_NOERR
862
863
    /* Compute the address for the block to allocate */
864
0
    addr = file->eoa;
865
866
    /* Extend the end-of-allocated space address */
867
0
    file->eoa = addr + size;
868
869
    /* Retain the (first) flavor of the information written to the file */
870
0
    if (file->fa.flags != 0) {
871
0
        if (file->fa.flags & H5FD_LOG_FLAVOR) {
872
0
            assert(addr < file->iosize);
873
0
            H5_CHECK_OVERFLOW(size, hsize_t, size_t);
874
0
            memset(&file->flavor[addr], (int)type, (size_t)size);
875
0
        }
876
877
0
        if (file->fa.flags & H5FD_LOG_ALLOC)
878
0
            fprintf(file->logfp,
879
0
                    "%10" PRIuHADDR "-%10" PRIuHADDR " (%10" PRIuHSIZE " bytes) (%s) Allocated\n", addr,
880
0
                    (haddr_t)((addr + size) - 1), size, flavors[type]);
881
0
    }
882
883
    /* Set return value */
884
0
    ret_value = addr;
885
886
0
    FUNC_LEAVE_NOAPI(ret_value)
887
0
} /* end H5FD__log_alloc() */
888
889
/*-------------------------------------------------------------------------
890
 * Function:    H5FD__log_free
891
 *
892
 * Purpose:     Release file memory.
893
 *
894
 * Return:      SUCCEED/FAIL
895
 *
896
 *-------------------------------------------------------------------------
897
 */
898
static herr_t
899
H5FD__log_free(H5FD_t *_file, H5FD_mem_t type, hid_t H5_ATTR_UNUSED dxpl_id, haddr_t addr, hsize_t size)
900
0
{
901
0
    H5FD_log_t *file = (H5FD_log_t *)_file;
902
903
0
    FUNC_ENTER_PACKAGE_NOERR
904
905
0
    if (file->fa.flags != 0) {
906
        /* Reset the flavor of the information in the file */
907
0
        if (file->fa.flags & H5FD_LOG_FLAVOR) {
908
0
            assert(addr < file->iosize);
909
0
            H5_CHECK_OVERFLOW(size, hsize_t, size_t);
910
0
            memset(&file->flavor[addr], H5FD_MEM_DEFAULT, (size_t)size);
911
0
        }
912
913
        /* Log the file memory freed */
914
0
        if (file->fa.flags & H5FD_LOG_FREE)
915
0
            fprintf(file->logfp, "%10" PRIuHADDR "-%10" PRIuHADDR " (%10" PRIuHSIZE " bytes) (%s) Freed\n",
916
0
                    addr, (haddr_t)((addr + size) - 1), size, flavors[type]);
917
0
    }
918
919
0
    FUNC_LEAVE_NOAPI(SUCCEED)
920
0
} /* end H5FD__log_free() */
921
922
/*-------------------------------------------------------------------------
923
 * Function:    H5FD__log_get_eoa
924
 *
925
 * Purpose:     Gets the end-of-address marker for the file. The EOA marker
926
 *              is the first address past the last byte allocated in the
927
 *              format address space.
928
 *
929
 * Return:      Success:    The end-of-address marker.
930
 *              Failure:    HADDR_UNDEF
931
 *
932
 *-------------------------------------------------------------------------
933
 */
934
static haddr_t
935
H5FD__log_get_eoa(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type)
936
0
{
937
0
    const H5FD_log_t *file = (const H5FD_log_t *)_file;
938
939
0
    FUNC_ENTER_PACKAGE_NOERR
940
941
0
    FUNC_LEAVE_NOAPI(file->eoa)
942
0
} /* end H5FD__log_get_eoa() */
943
944
/*-------------------------------------------------------------------------
945
 * Function:    H5FD__log_set_eoa
946
 *
947
 * Purpose:     Set the end-of-address marker for the file. This function is
948
 *              called shortly after an existing HDF5 file is opened in order
949
 *              to tell the driver where the end of the HDF5 data is located.
950
 *
951
 * Return:      SUCCEED (Can't fail)
952
 *
953
 *-------------------------------------------------------------------------
954
 */
955
static herr_t
956
H5FD__log_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr)
957
0
{
958
0
    H5FD_log_t *file = (H5FD_log_t *)_file;
959
960
0
    FUNC_ENTER_PACKAGE_NOERR
961
962
0
    if (file->fa.flags != 0) {
963
        /* Check for increasing file size */
964
0
        if (H5_addr_gt(addr, file->eoa) && H5_addr_gt(addr, 0)) {
965
0
            hsize_t size = addr - file->eoa;
966
967
            /* Retain the flavor of the space allocated by the extension */
968
0
            if (file->fa.flags & H5FD_LOG_FLAVOR) {
969
0
                assert(addr < file->iosize);
970
0
                H5_CHECK_OVERFLOW(size, hsize_t, size_t);
971
0
                memset(&file->flavor[file->eoa], (int)type, (size_t)size);
972
0
            }
973
974
            /* Log the extension like an allocation */
975
0
            if (file->fa.flags & H5FD_LOG_ALLOC)
976
0
                fprintf(file->logfp,
977
0
                        "%10" PRIuHADDR "-%10" PRIuHADDR " (%10" PRIuHSIZE " bytes) (%s) Allocated\n",
978
0
                        file->eoa, addr, size, flavors[type]);
979
0
        }
980
981
        /* Check for decreasing file size */
982
0
        if (H5_addr_lt(addr, file->eoa) && H5_addr_gt(addr, 0)) {
983
0
            hsize_t size = file->eoa - addr;
984
985
            /* Reset the flavor of the space freed by the shrink */
986
0
            if (file->fa.flags & H5FD_LOG_FLAVOR) {
987
0
                assert((addr + size) < file->iosize);
988
0
                H5_CHECK_OVERFLOW(size, hsize_t, size_t);
989
0
                memset(&file->flavor[addr], H5FD_MEM_DEFAULT, (size_t)size);
990
0
            }
991
992
            /* Log the shrink like a free */
993
0
            if (file->fa.flags & H5FD_LOG_FREE)
994
0
                fprintf(file->logfp,
995
0
                        "%10" PRIuHADDR "-%10" PRIuHADDR " (%10" PRIuHSIZE " bytes) (%s) Freed\n", file->eoa,
996
0
                        addr, size, flavors[type]);
997
0
        }
998
0
    }
999
1000
0
    file->eoa = addr;
1001
1002
0
    FUNC_LEAVE_NOAPI(SUCCEED)
1003
0
} /* end H5FD__log_set_eoa() */
1004
1005
/*-------------------------------------------------------------------------
1006
 * Function:    H5FD__log_get_eof
1007
 *
1008
 * Purpose:     Returns the end-of-file marker, which is the greater of
1009
 *              either the filesystem end-of-file or the HDF5 end-of-address
1010
 *              markers.
1011
 *
1012
 * Return:      Success:    End of file address, the first address past
1013
 *                          the end of the "file", either the filesystem file
1014
 *                          or the HDF5 file.
1015
 *              Failure:    HADDR_UNDEF
1016
 *
1017
 *-------------------------------------------------------------------------
1018
 */
1019
static haddr_t
1020
H5FD__log_get_eof(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type)
1021
0
{
1022
0
    const H5FD_log_t *file = (const H5FD_log_t *)_file;
1023
1024
0
    FUNC_ENTER_PACKAGE_NOERR
1025
1026
0
    FUNC_LEAVE_NOAPI(file->eof)
1027
0
} /* end H5FD__log_get_eof() */
1028
1029
/*-------------------------------------------------------------------------
1030
 * Function:       H5FD__log_get_handle
1031
 *
1032
 * Purpose:        Returns the file handle of LOG file driver.
1033
 *
1034
 * Returns:        SUCCEED/FAIL
1035
 *
1036
 *-------------------------------------------------------------------------
1037
 */
1038
static herr_t
1039
H5FD__log_get_handle(H5FD_t *_file, hid_t H5_ATTR_UNUSED fapl, void **file_handle)
1040
0
{
1041
0
    H5FD_log_t *file      = (H5FD_log_t *)_file;
1042
0
    herr_t      ret_value = SUCCEED;
1043
1044
0
    FUNC_ENTER_PACKAGE
1045
1046
0
    if (!file_handle)
1047
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file handle not valid");
1048
1049
0
    *file_handle = &(file->fd);
1050
1051
0
done:
1052
0
    FUNC_LEAVE_NOAPI(ret_value)
1053
0
} /* end H5FD__log_get_handle() */
1054
1055
/*-------------------------------------------------------------------------
1056
 * Function:    H5FD__log_read
1057
 *
1058
 * Purpose:     Reads SIZE bytes of data from FILE beginning at address ADDR
1059
 *              into buffer BUF according to data transfer properties in
1060
 *              DXPL_ID.
1061
 *
1062
 * Return:      Success:    SUCCEED. Result is stored in caller-supplied
1063
 *                          buffer BUF.
1064
 *              Failure:    FAIL, Contents of buffer BUF are undefined.
1065
 *
1066
 *-------------------------------------------------------------------------
1067
 */
1068
static herr_t
1069
H5FD__log_read(H5FD_t *_file, H5FD_mem_t type, hid_t H5_ATTR_UNUSED dxpl_id, haddr_t addr, size_t size,
1070
               void *buf /*out*/)
1071
0
{
1072
0
    H5FD_log_t   *file      = (H5FD_log_t *)_file;
1073
0
    size_t        orig_size = size; /* Save the original size for later */
1074
0
    haddr_t       orig_addr = addr;
1075
0
    H5_timer_t    read_timer; /* Timer for read operation */
1076
0
    H5_timevals_t read_times; /* Elapsed time for read operation */
1077
0
    HDoff_t       offset    = (HDoff_t)addr;
1078
0
    herr_t        ret_value = SUCCEED; /* Return value */
1079
1080
0
    FUNC_ENTER_PACKAGE
1081
1082
0
    assert(file && file->pub.cls);
1083
0
    assert(buf);
1084
1085
    /* Initialize timer */
1086
0
    H5_timer_init(&read_timer);
1087
1088
    /* Check for overflow conditions */
1089
0
    if (!H5_addr_defined(addr))
1090
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addr undefined, addr = %llu", (unsigned long long)addr);
1091
0
    if (H5FD_REGION_OVERFLOW(addr, size))
1092
0
        HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, addr = %llu", (unsigned long long)addr);
1093
1094
    /* Log the I/O information about the read */
1095
0
    if (file->fa.flags != 0) {
1096
0
        size_t  tmp_size = size;
1097
0
        haddr_t tmp_addr = addr;
1098
1099
        /* Log information about the number of times these locations are read */
1100
0
        if (file->fa.flags & H5FD_LOG_FILE_READ) {
1101
0
            assert((addr + size) < file->iosize);
1102
0
            while (tmp_size-- > 0)
1103
0
                file->nread[tmp_addr++]++;
1104
0
        }
1105
0
    }
1106
1107
0
#ifndef H5_HAVE_PREADWRITE
1108
    /* Seek to the correct location (if we don't have pread) */
1109
0
    if (addr != file->pos || OP_READ != file->op) {
1110
0
        H5_timer_t    seek_timer; /* Timer for seek operation */
1111
0
        H5_timevals_t seek_times; /* Elapsed time for seek operation */
1112
1113
        /* Initialize timer */
1114
0
        H5_timer_init(&seek_timer);
1115
1116
        /* Start timer for seek() call */
1117
0
        if (file->fa.flags & H5FD_LOG_TIME_SEEK)
1118
0
            H5_timer_start(&seek_timer);
1119
1120
0
        if (HDlseek(file->fd, (HDoff_t)addr, SEEK_SET) < 0)
1121
0
            HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position");
1122
1123
        /* Stop timer for seek() call */
1124
0
        if (file->fa.flags & H5FD_LOG_TIME_SEEK)
1125
0
            H5_timer_stop(&seek_timer);
1126
1127
        /* Add to the number of seeks, when tracking that */
1128
0
        if (file->fa.flags & H5FD_LOG_NUM_SEEK)
1129
0
            file->total_seek_ops++;
1130
1131
        /* Add to the total seek time, when tracking that */
1132
0
        if (file->fa.flags & H5FD_LOG_TIME_SEEK) {
1133
0
            H5_timer_get_times(seek_timer, &seek_times);
1134
0
            file->total_seek_time += seek_times.elapsed;
1135
0
        }
1136
1137
        /* Emit log string if we're tracking individual seek events. */
1138
0
        if (file->fa.flags & H5FD_LOG_LOC_SEEK) {
1139
0
            fprintf(file->logfp, "Seek: From %10" PRIuHADDR " To %10" PRIuHADDR, file->pos, addr);
1140
1141
            /* Add the seek time, if we're tracking that.
1142
             * Note that the seek time is NOT emitted for when just H5FD_LOG_TIME_SEEK
1143
             * is set.
1144
             */
1145
0
            if (file->fa.flags & H5FD_LOG_TIME_SEEK)
1146
0
                fprintf(file->logfp, " (%fs @ %f)\n", seek_times.elapsed, seek_timer.initial.elapsed);
1147
0
            else
1148
0
                fprintf(file->logfp, "\n");
1149
0
        }
1150
0
    }
1151
0
#endif /* H5_HAVE_PREADWRITE */
1152
1153
    /* Start timer for read operation */
1154
0
    if (file->fa.flags & H5FD_LOG_TIME_READ)
1155
0
        H5_timer_start(&read_timer);
1156
1157
    /*
1158
     * Read data, being careful of interrupted system calls, partial results,
1159
     * and the end of the file.
1160
     */
1161
0
    while (size > 0) {
1162
0
        h5_posix_io_t     bytes_in   = 0;  /* # of bytes to read       */
1163
0
        h5_posix_io_ret_t bytes_read = -1; /* # of bytes actually read */
1164
1165
        /* Trying to read more bytes than the return type can handle is
1166
         * undefined behavior in POSIX.
1167
         */
1168
0
        if (size > H5_POSIX_MAX_IO_BYTES)
1169
0
            bytes_in = H5_POSIX_MAX_IO_BYTES;
1170
0
        else
1171
0
            bytes_in = (h5_posix_io_t)size;
1172
1173
0
        do {
1174
#ifdef H5_HAVE_PREADWRITE
1175
            bytes_read = HDpread(file->fd, buf, bytes_in, offset);
1176
            if (bytes_read > 0)
1177
                offset += bytes_read;
1178
#else
1179
0
            bytes_read = HDread(file->fd, buf, bytes_in);
1180
0
#endif /* H5_HAVE_PREADWRITE */
1181
0
        } while (-1 == bytes_read && EINTR == errno);
1182
1183
0
        if (-1 == bytes_read) { /* error */
1184
0
            int    myerrno = errno;
1185
0
            time_t mytime  = time(NULL);
1186
1187
0
            offset = HDlseek(file->fd, 0, SEEK_CUR);
1188
1189
0
            if (file->fa.flags & H5FD_LOG_LOC_READ)
1190
0
                fprintf(file->logfp, "Error! Reading: %10" PRIuHADDR "-%10" PRIuHADDR " (%10zu bytes)\n",
1191
0
                        orig_addr, (orig_addr + orig_size) - 1, orig_size);
1192
1193
0
            HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL,
1194
0
                        "file read failed: time = %s, filename = '%s', file descriptor = %d, errno = %d, "
1195
0
                        "error message = '%s', buf = %p, total read size = %llu, bytes this sub-read = %llu, "
1196
0
                        "bytes actually read = %llu, offset = %llu",
1197
0
                        ctime(&mytime), file->filename, file->fd, myerrno, strerror(myerrno), buf,
1198
0
                        (unsigned long long)size, (unsigned long long)bytes_in,
1199
0
                        (unsigned long long)bytes_read, (unsigned long long)offset);
1200
0
        }
1201
1202
0
        if (0 == bytes_read) {
1203
            /* End of file but not end of format address space */
1204
0
            memset(buf, 0, size);
1205
0
            break;
1206
0
        }
1207
1208
0
        assert(bytes_read >= 0);
1209
0
        assert((size_t)bytes_read <= size);
1210
1211
0
        size -= (size_t)bytes_read;
1212
0
        addr += (haddr_t)bytes_read;
1213
0
        buf = (char *)buf + bytes_read;
1214
0
    }
1215
1216
    /* Stop timer for read operation */
1217
0
    if (file->fa.flags & H5FD_LOG_TIME_READ)
1218
0
        H5_timer_stop(&read_timer);
1219
1220
    /* Add to the number of reads, when tracking that */
1221
0
    if (file->fa.flags & H5FD_LOG_NUM_READ)
1222
0
        file->total_read_ops++;
1223
1224
    /* Add to the total read time, when tracking that */
1225
0
    if (file->fa.flags & H5FD_LOG_TIME_READ) {
1226
0
        H5_timer_get_times(read_timer, &read_times);
1227
0
        file->total_read_time += read_times.elapsed;
1228
0
    }
1229
1230
    /* Log information about the read */
1231
0
    if (file->fa.flags & H5FD_LOG_LOC_READ) {
1232
0
        fprintf(file->logfp, "%10" PRIuHADDR "-%10" PRIuHADDR " (%10zu bytes) (%s) Read", orig_addr,
1233
0
                (orig_addr + orig_size) - 1, orig_size, flavors[type]);
1234
1235
        /* Verify that we are reading in the type of data we allocated in this location */
1236
0
        if (file->flavor) {
1237
0
            assert(type == H5FD_MEM_DEFAULT || type == (H5FD_mem_t)file->flavor[orig_addr] ||
1238
0
                   (H5FD_mem_t)file->flavor[orig_addr] == H5FD_MEM_DEFAULT);
1239
0
            assert(type == H5FD_MEM_DEFAULT ||
1240
0
                   type == (H5FD_mem_t)file->flavor[(orig_addr + orig_size) - 1] ||
1241
0
                   (H5FD_mem_t)file->flavor[(orig_addr + orig_size) - 1] == H5FD_MEM_DEFAULT);
1242
0
        }
1243
1244
        /* Add the read time, if we're tracking that.
1245
         * Note that the read time is NOT emitted for when just H5FD_LOG_TIME_READ
1246
         * is set.
1247
         */
1248
0
        if (file->fa.flags & H5FD_LOG_TIME_READ)
1249
0
            fprintf(file->logfp, " (%fs @ %f)\n", read_times.elapsed, read_timer.initial.elapsed);
1250
0
        else
1251
0
            fprintf(file->logfp, "\n");
1252
0
    }
1253
1254
0
#ifndef H5_HAVE_PREADWRITE
1255
    /* Update current position */
1256
0
    file->pos = addr;
1257
0
    file->op  = OP_READ;
1258
0
#endif /* H5_HAVE_PREADWRITE */
1259
1260
0
done:
1261
0
#ifndef H5_HAVE_PREADWRITE
1262
0
    if (ret_value < 0) {
1263
        /* Reset last file I/O information */
1264
0
        file->pos = HADDR_UNDEF;
1265
0
        file->op  = OP_UNKNOWN;
1266
0
    }
1267
0
#endif /* H5_HAVE_PREADWRITE */
1268
1269
0
    FUNC_LEAVE_NOAPI(ret_value)
1270
0
} /* end H5FD__log_read() */
1271
1272
/*-------------------------------------------------------------------------
1273
 * Function:    H5FD__log_write
1274
 *
1275
 * Purpose:     Writes SIZE bytes of data to FILE beginning at address ADDR
1276
 *              from buffer BUF according to data transfer properties in
1277
 *              DXPL_ID.
1278
 *
1279
 * Return:      SUCCEED/FAIL
1280
 *
1281
 *-------------------------------------------------------------------------
1282
 */
1283
static herr_t
1284
H5FD__log_write(H5FD_t *_file, H5FD_mem_t type, hid_t H5_ATTR_UNUSED dxpl_id, haddr_t addr, size_t size,
1285
                const void *buf)
1286
0
{
1287
0
    H5FD_log_t   *file      = (H5FD_log_t *)_file;
1288
0
    size_t        orig_size = size; /* Save the original size for later */
1289
0
    haddr_t       orig_addr = addr;
1290
0
    H5_timer_t    write_timer; /* Timer for write operation */
1291
0
    H5_timevals_t write_times; /* Elapsed time for write operation */
1292
0
    HDoff_t       offset    = (HDoff_t)addr;
1293
0
    herr_t        ret_value = SUCCEED; /* Return value */
1294
1295
0
    FUNC_ENTER_PACKAGE
1296
1297
0
    assert(file && file->pub.cls);
1298
0
    assert(size > 0);
1299
0
    assert(buf);
1300
1301
    /* Initialize timer */
1302
0
    H5_timer_init(&write_timer);
1303
1304
    /* Verify that we are writing out the type of data we allocated in this location */
1305
0
    if (file->flavor) {
1306
0
        assert(type == H5FD_MEM_DEFAULT || type == (H5FD_mem_t)file->flavor[addr] ||
1307
0
               (H5FD_mem_t)file->flavor[addr] == H5FD_MEM_DEFAULT);
1308
0
        assert(type == H5FD_MEM_DEFAULT || type == (H5FD_mem_t)file->flavor[(addr + size) - 1] ||
1309
0
               (H5FD_mem_t)file->flavor[(addr + size) - 1] == H5FD_MEM_DEFAULT);
1310
0
    }
1311
1312
    /* Check for overflow conditions */
1313
0
    if (!H5_addr_defined(addr))
1314
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addr undefined, addr = %llu", (unsigned long long)addr);
1315
0
    if (H5FD_REGION_OVERFLOW(addr, size))
1316
0
        HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, addr = %llu, size = %llu",
1317
0
                    (unsigned long long)addr, (unsigned long long)size);
1318
1319
    /* Log the I/O information about the write */
1320
0
    if (file->fa.flags & H5FD_LOG_FILE_WRITE) {
1321
0
        size_t  tmp_size = size;
1322
0
        haddr_t tmp_addr = addr;
1323
1324
        /* Log information about the number of times these locations are read */
1325
0
        assert((addr + size) < file->iosize);
1326
0
        while (tmp_size-- > 0)
1327
0
            file->nwrite[tmp_addr++]++;
1328
0
    }
1329
1330
0
#ifndef H5_HAVE_PREADWRITE
1331
    /* Seek to the correct location (if we don't have pwrite) */
1332
0
    if (addr != file->pos || OP_WRITE != file->op) {
1333
0
        H5_timer_t    seek_timer; /* Timer for seek operation */
1334
0
        H5_timevals_t seek_times; /* Elapsed time for seek operation */
1335
1336
        /* Initialize timer */
1337
0
        H5_timer_init(&seek_timer);
1338
1339
        /* Start timer for seek() call */
1340
0
        if (file->fa.flags & H5FD_LOG_TIME_SEEK)
1341
0
            H5_timer_start(&seek_timer);
1342
1343
0
        if (HDlseek(file->fd, (HDoff_t)addr, SEEK_SET) < 0)
1344
0
            HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position");
1345
1346
        /* Stop timer for seek() call */
1347
0
        if (file->fa.flags & H5FD_LOG_TIME_SEEK)
1348
0
            H5_timer_stop(&seek_timer);
1349
1350
        /* Add to the number of seeks, when tracking that */
1351
0
        if (file->fa.flags & H5FD_LOG_NUM_SEEK)
1352
0
            file->total_seek_ops++;
1353
1354
        /* Add to the total seek time, when tracking that */
1355
0
        if (file->fa.flags & H5FD_LOG_TIME_SEEK) {
1356
0
            H5_timer_get_times(seek_timer, &seek_times);
1357
0
            file->total_seek_time += seek_times.elapsed;
1358
0
        }
1359
1360
        /* Emit log string if we're tracking individual seek events. */
1361
0
        if (file->fa.flags & H5FD_LOG_LOC_SEEK) {
1362
0
            fprintf(file->logfp, "Seek: From %10" PRIuHADDR " To %10" PRIuHADDR, file->pos, addr);
1363
1364
            /* Add the seek time, if we're tracking that.
1365
             * Note that the seek time is NOT emitted for when just H5FD_LOG_TIME_SEEK
1366
             * is set.
1367
             */
1368
0
            if (file->fa.flags & H5FD_LOG_TIME_SEEK)
1369
0
                fprintf(file->logfp, " (%fs @ %f)\n", seek_times.elapsed, seek_timer.initial.elapsed);
1370
0
            else
1371
0
                fprintf(file->logfp, "\n");
1372
0
        }
1373
0
    }
1374
0
#endif /* H5_HAVE_PREADWRITE */
1375
1376
    /* Start timer for write operation */
1377
0
    if (file->fa.flags & H5FD_LOG_TIME_WRITE)
1378
0
        H5_timer_start(&write_timer);
1379
1380
    /*
1381
     * Write the data, being careful of interrupted system calls and partial
1382
     * results
1383
     */
1384
0
    while (size > 0) {
1385
0
        h5_posix_io_t     bytes_in    = 0;  /* # of bytes to write  */
1386
0
        h5_posix_io_ret_t bytes_wrote = -1; /* # of bytes written   */
1387
1388
        /* Trying to write more bytes than the return type can handle is
1389
         * undefined behavior in POSIX.
1390
         */
1391
0
        if (size > H5_POSIX_MAX_IO_BYTES)
1392
0
            bytes_in = H5_POSIX_MAX_IO_BYTES;
1393
0
        else
1394
0
            bytes_in = (h5_posix_io_t)size;
1395
1396
0
        do {
1397
#ifdef H5_HAVE_PREADWRITE
1398
            bytes_wrote = HDpwrite(file->fd, buf, bytes_in, offset);
1399
            if (bytes_wrote > 0)
1400
                offset += bytes_wrote;
1401
#else
1402
0
            bytes_wrote = HDwrite(file->fd, buf, bytes_in);
1403
0
#endif /* H5_HAVE_PREADWRITE */
1404
0
        } while (-1 == bytes_wrote && EINTR == errno);
1405
1406
0
        if (-1 == bytes_wrote) { /* error */
1407
0
            int    myerrno = errno;
1408
0
            time_t mytime  = time(NULL);
1409
1410
0
            offset = HDlseek(file->fd, 0, SEEK_CUR);
1411
1412
0
            if (file->fa.flags & H5FD_LOG_LOC_WRITE)
1413
0
                fprintf(file->logfp, "Error! Writing: %10" PRIuHADDR "-%10" PRIuHADDR " (%10zu bytes)\n",
1414
0
                        orig_addr, (orig_addr + orig_size) - 1, orig_size);
1415
1416
0
            HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL,
1417
0
                        "file write failed: time = %s, filename = '%s', file descriptor = %d, errno = %d, "
1418
0
                        "error message = '%s', buf = %p, total write size = %llu, bytes this sub-write = "
1419
0
                        "%llu, bytes actually written = %llu, offset = %llu",
1420
0
                        ctime(&mytime), file->filename, file->fd, myerrno, strerror(myerrno), buf,
1421
0
                        (unsigned long long)size, (unsigned long long)bytes_in,
1422
0
                        (unsigned long long)bytes_wrote, (unsigned long long)offset);
1423
0
        } /* end if */
1424
1425
0
        assert(bytes_wrote > 0);
1426
0
        assert((size_t)bytes_wrote <= size);
1427
1428
0
        size -= (size_t)bytes_wrote;
1429
0
        addr += (haddr_t)bytes_wrote;
1430
0
        buf = (const char *)buf + bytes_wrote;
1431
0
    } /* end while */
1432
1433
    /* Stop timer for write operation */
1434
0
    if (file->fa.flags & H5FD_LOG_TIME_WRITE)
1435
0
        H5_timer_stop(&write_timer);
1436
1437
    /* Add to the number of writes, when tracking that */
1438
0
    if (file->fa.flags & H5FD_LOG_NUM_WRITE)
1439
0
        file->total_write_ops++;
1440
1441
    /* Add to the total write time, when tracking that */
1442
0
    if (file->fa.flags & H5FD_LOG_TIME_WRITE) {
1443
0
        H5_timer_get_times(write_timer, &write_times);
1444
0
        file->total_write_time += write_times.elapsed;
1445
0
    }
1446
1447
    /* Log information about the write */
1448
0
    if (file->fa.flags & H5FD_LOG_LOC_WRITE) {
1449
0
        fprintf(file->logfp, "%10" PRIuHADDR "-%10" PRIuHADDR " (%10zu bytes) (%s) Written", orig_addr,
1450
0
                (orig_addr + orig_size) - 1, orig_size, flavors[type]);
1451
1452
        /* Check if this is the first write into a "default" section, grabbed by the metadata aggregation
1453
         * algorithm */
1454
0
        if (file->fa.flags & H5FD_LOG_FLAVOR) {
1455
0
            if ((H5FD_mem_t)file->flavor[orig_addr] == H5FD_MEM_DEFAULT) {
1456
0
                memset(&file->flavor[orig_addr], (int)type, orig_size);
1457
0
                fprintf(file->logfp, " (fresh)");
1458
0
            }
1459
0
        }
1460
1461
        /* Add the write time, if we're tracking that.
1462
         * Note that the write time is NOT emitted for when just H5FD_LOG_TIME_WRITE
1463
         * is set.
1464
         */
1465
0
        if (file->fa.flags & H5FD_LOG_TIME_WRITE)
1466
0
            fprintf(file->logfp, " (%fs @ %f)\n", write_times.elapsed, write_timer.initial.elapsed);
1467
0
        else
1468
0
            fprintf(file->logfp, "\n");
1469
0
    }
1470
1471
    /* Update current position and eof */
1472
0
#ifndef H5_HAVE_PREADWRITE
1473
0
    file->pos = addr;
1474
0
    file->op  = OP_WRITE;
1475
0
#endif /* H5_HAVE_PREADWRITE */
1476
0
    if (addr > file->eof)
1477
0
        file->eof = addr;
1478
1479
0
done:
1480
0
#ifndef H5_HAVE_PREADWRITE
1481
0
    if (ret_value < 0) {
1482
        /* Reset last file I/O information */
1483
0
        file->pos = HADDR_UNDEF;
1484
0
        file->op  = OP_UNKNOWN;
1485
0
    }
1486
0
#endif /* H5_HAVE_PREADWRITE */
1487
1488
0
    FUNC_LEAVE_NOAPI(ret_value)
1489
0
} /* end H5FD__log_write() */
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
 *-------------------------------------------------------------------------
1500
 */
1501
static herr_t
1502
H5FD__log_truncate(H5FD_t *_file, hid_t H5_ATTR_UNUSED dxpl_id, bool H5_ATTR_UNUSED closing)
1503
0
{
1504
0
    H5FD_log_t *file      = (H5FD_log_t *)_file;
1505
0
    herr_t      ret_value = SUCCEED; /* Return value */
1506
1507
0
    FUNC_ENTER_PACKAGE
1508
1509
0
    assert(file);
1510
1511
    /* Extend the file to make sure it's large enough */
1512
0
    if (!H5_addr_eq(file->eoa, file->eof)) {
1513
0
        H5_timer_t    trunc_timer; /* Timer for truncate operation */
1514
0
        H5_timevals_t trunc_times; /* Elapsed time for truncate operation */
1515
1516
        /* Initialize timer */
1517
0
        H5_timer_init(&trunc_timer);
1518
1519
        /* Start timer for truncate operation */
1520
0
        if (file->fa.flags & H5FD_LOG_TIME_TRUNCATE)
1521
0
            H5_timer_start(&trunc_timer);
1522
1523
#ifdef H5_HAVE_WIN32_API
1524
        {
1525
            LARGE_INTEGER li;       /* 64-bit (union) integer for SetFilePointer() call */
1526
            DWORD         dwPtrLow; /* Low-order pointer bits from SetFilePointer()
1527
                                     * Only used as an error code here.
1528
                                     */
1529
1530
            /* Windows uses this odd QuadPart union for 32/64-bit portability */
1531
            li.QuadPart = (LONGLONG)file->eoa;
1532
1533
            /* Extend the file to make sure it's large enough.
1534
             *
1535
             * Since INVALID_SET_FILE_POINTER can technically be a valid return value
1536
             * from SetFilePointer(), we also need to check GetLastError().
1537
             */
1538
            dwPtrLow = SetFilePointer(file->hFile, li.LowPart, &li.HighPart, FILE_BEGIN);
1539
            if (INVALID_SET_FILE_POINTER == dwPtrLow) {
1540
                DWORD dwError; /* DWORD error code from GetLastError() */
1541
1542
                dwError = GetLastError();
1543
                if (dwError != NO_ERROR)
1544
                    HGOTO_ERROR(H5E_FILE, H5E_FILEOPEN, FAIL, "unable to set file pointer");
1545
            }
1546
1547
            if (0 == SetEndOfFile(file->hFile))
1548
                HGOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly");
1549
        }
1550
#else  /* H5_HAVE_WIN32_API */
1551
        /* Truncate/extend the file */
1552
0
        if (-1 == HDftruncate(file->fd, (HDoff_t)file->eoa))
1553
0
            HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly");
1554
0
#endif /* H5_HAVE_WIN32_API */
1555
1556
        /* Stop timer for truncate operation */
1557
0
        if (file->fa.flags & H5FD_LOG_TIME_TRUNCATE)
1558
0
            H5_timer_stop(&trunc_timer);
1559
1560
        /* Add to the number of truncates, when tracking that */
1561
0
        if (file->fa.flags & H5FD_LOG_NUM_TRUNCATE)
1562
0
            file->total_truncate_ops++;
1563
1564
        /* Add to the total truncate time, when tracking that */
1565
0
        if (file->fa.flags & H5FD_LOG_TIME_TRUNCATE) {
1566
0
            H5_timer_get_times(trunc_timer, &trunc_times);
1567
0
            file->total_truncate_time += trunc_times.elapsed;
1568
0
        }
1569
1570
        /* Emit log string if we're tracking individual truncate events. */
1571
0
        if (file->fa.flags & H5FD_LOG_TRUNCATE) {
1572
0
            fprintf(file->logfp, "Truncate: To %10" PRIuHADDR, file->eoa);
1573
1574
            /* Add the truncate time, if we're tracking that.
1575
             * Note that the truncate time is NOT emitted for when just H5FD_LOG_TIME_TRUNCATE
1576
             * is set.
1577
             */
1578
0
            if (file->fa.flags & H5FD_LOG_TIME_TRUNCATE)
1579
0
                fprintf(file->logfp, " (%fs @ %f)\n", trunc_times.elapsed, trunc_timer.initial.elapsed);
1580
0
            else
1581
0
                fprintf(file->logfp, "\n");
1582
0
        }
1583
1584
        /* Update the eof value */
1585
0
        file->eof = file->eoa;
1586
1587
0
#ifndef H5_HAVE_PREADWRITE
1588
        /* Reset last file I/O information */
1589
0
        file->pos = HADDR_UNDEF;
1590
0
        file->op  = OP_UNKNOWN;
1591
0
#endif /* H5_HAVE_PREADWRITE */
1592
0
    }  /* end if */
1593
1594
0
done:
1595
0
    FUNC_LEAVE_NOAPI(ret_value)
1596
0
} /* end H5FD__log_truncate() */
1597
1598
/*-------------------------------------------------------------------------
1599
 * Function:    H5FD__log_lock
1600
 *
1601
 * Purpose:     Place a lock on the file
1602
 *
1603
 * Return:      Success:    SUCCEED
1604
 *              Failure:    FAIL, file not locked.
1605
 *
1606
 *-------------------------------------------------------------------------
1607
 */
1608
static herr_t
1609
H5FD__log_lock(H5FD_t *_file, bool rw)
1610
0
{
1611
0
    H5FD_log_t *file = (H5FD_log_t *)_file; /* VFD file struct          */
1612
0
    int         lock_flags;                 /* file locking flags       */
1613
0
    herr_t      ret_value = SUCCEED;        /* Return value             */
1614
1615
0
    FUNC_ENTER_PACKAGE
1616
1617
    /* Sanity check */
1618
0
    assert(file);
1619
1620
    /* Set exclusive or shared lock based on rw status */
1621
0
    lock_flags = rw ? LOCK_EX : LOCK_SH;
1622
1623
    /* Place a non-blocking lock on the file */
1624
0
    if (HDflock(file->fd, lock_flags | LOCK_NB) < 0) {
1625
0
        if (file->ignore_disabled_file_locks && ENOSYS == errno) {
1626
            /* When errno is set to ENOSYS, the file system does not support
1627
             * locking, so ignore it.
1628
             */
1629
0
            errno = 0;
1630
0
        }
1631
0
        else
1632
0
            HSYS_GOTO_ERROR(H5E_VFL, H5E_CANTLOCKFILE, FAIL, "unable to lock file");
1633
0
    }
1634
1635
0
done:
1636
0
    FUNC_LEAVE_NOAPI(ret_value)
1637
0
} /* end H5FD__log_lock() */
1638
1639
/*-------------------------------------------------------------------------
1640
 * Function:    H5FD__log_unlock
1641
 *
1642
 * Purpose:     Remove the existing lock on the file
1643
 *
1644
 * Return:      SUCCEED/FAIL
1645
 *
1646
 *-------------------------------------------------------------------------
1647
 */
1648
static herr_t
1649
H5FD__log_unlock(H5FD_t *_file)
1650
0
{
1651
0
    H5FD_log_t *file      = (H5FD_log_t *)_file; /* VFD file struct          */
1652
0
    herr_t      ret_value = SUCCEED;             /* Return value             */
1653
1654
0
    FUNC_ENTER_PACKAGE
1655
1656
0
    assert(file);
1657
1658
0
    if (HDflock(file->fd, LOCK_UN) < 0) {
1659
0
        if (file->ignore_disabled_file_locks && ENOSYS == errno) {
1660
            /* When errno is set to ENOSYS, the file system does not support
1661
             * locking, so ignore it.
1662
             */
1663
0
            errno = 0;
1664
0
        }
1665
0
        else
1666
0
            HSYS_GOTO_ERROR(H5E_VFL, H5E_CANTUNLOCKFILE, FAIL, "unable to unlock file");
1667
0
    }
1668
1669
0
done:
1670
0
    FUNC_LEAVE_NOAPI(ret_value)
1671
0
} /* end H5FD__log_unlock() */
1672
1673
/*-------------------------------------------------------------------------
1674
 * Function:    H5FD__log_delete
1675
 *
1676
 * Purpose:     Delete a file
1677
 *
1678
 * Return:      SUCCEED/FAIL
1679
 *
1680
 *-------------------------------------------------------------------------
1681
 */
1682
static herr_t
1683
H5FD__log_delete(const char *filename, hid_t H5_ATTR_UNUSED fapl_id)
1684
0
{
1685
0
    herr_t ret_value = SUCCEED; /* Return value */
1686
1687
0
    FUNC_ENTER_PACKAGE
1688
1689
0
    assert(filename);
1690
1691
0
    if (HDremove(filename) < 0)
1692
0
        HSYS_GOTO_ERROR(H5E_VFL, H5E_CANTDELETEFILE, FAIL, "unable to delete file");
1693
1694
0
done:
1695
0
    FUNC_LEAVE_NOAPI(ret_value)
1696
0
} /* end H5FD__log_delete() */