summaryrefslogtreecommitdiffstats
path: root/src/H5Dsingle.c
blob: 2996ca5107b4bf12704f514e32477578ce3eab68 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright by The HDF Group.                                               *
 * Copyright by the Board of Trustees of the University of Illinois.         *
 * All rights reserved.                                                      *
 *                                                                           *
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
 * terms governing use, modification, and redistribution, is contained in    *
 * the COPYING file, which can be found at the root of the source code       *
 * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases.  *
 * If you do not have access to either file, you may request a copy from     *
 * help@hdfgroup.org.                                                        *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/* Programmer: 	Vailin Choi
 *	       	May 2011; updated 10/2015
 *
 * Purpose:	Single Chunk I/O functions.
 *		This is used when the dataset has only 1 chunk (with or without filter):
 *			cur_dims[] is equal to max_dims[] is equal to the chunk dims[]
 *		non-filter chunk record: [address of the chunk]
 *		filtered chunk record: 	[address of the chunk, chunk size, filter mask]
 *
 */

/****************/
/* Module Setup */
/****************/

#include "H5Dmodule.h" /* This source code file is part of the H5D module */

/***********/
/* Headers */
/***********/
#include "H5private.h"   /* Generic Functions			*/
#include "H5Dpkg.h"      /* Datasets				*/
#include "H5Eprivate.h"  /* Error handling		  	*/
#include "H5FLprivate.h" /* Free Lists                           */
#include "H5MFprivate.h" /* File space management		*/
#include "H5VMprivate.h" /* Vector functions			*/

/****************/
/* Local Macros */
/****************/

/******************/
/* Local Typedefs */
/******************/

/********************/
/* Local Prototypes */
/********************/

/* Single Chunk Index chunking I/O ops */
static herr_t  H5D__single_idx_init(const H5D_chk_idx_info_t *idx_info, const H5S_t *space,
                                    haddr_t dset_ohdr_addr);
static herr_t  H5D__single_idx_create(const H5D_chk_idx_info_t *idx_info);
static hbool_t H5D__single_idx_is_space_alloc(const H5O_storage_chunk_t *storage);
static herr_t  H5D__single_idx_insert(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata,
                                      const H5D_t *dset);
static herr_t  H5D__single_idx_get_addr(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata);
static int     H5D__single_idx_iterate(const H5D_chk_idx_info_t *idx_info, H5D_chunk_cb_func_t chunk_cb,
                                       void *chunk_udata);
static herr_t  H5D__single_idx_remove(const H5D_chk_idx_info_t *idx_info, H5D_chunk_common_ud_t *udata);
static herr_t  H5D__single_idx_delete(const H5D_chk_idx_info_t *idx_info);
static herr_t  H5D__single_idx_copy_setup(const H5D_chk_idx_info_t *idx_info_src,
                                          const H5D_chk_idx_info_t *idx_info_dst);
static herr_t  H5D__single_idx_size(const H5D_chk_idx_info_t *idx_info, hsize_t *size);
static herr_t  H5D__single_idx_reset(H5O_storage_chunk_t *storage, hbool_t reset_addr);
static herr_t  H5D__single_idx_dump(const H5O_storage_chunk_t *storage, FILE *stream);

/*********************/
/* Package Variables */
/*********************/

/* Non Index chunk I/O ops */
const H5D_chunk_ops_t H5D_COPS_SINGLE[1] = {{
    FALSE,                          /* Single Chunk indexing doesn't current support SWMR access */
    H5D__single_idx_init,           /* init */
    H5D__single_idx_create,         /* create */
    H5D__single_idx_is_space_alloc, /* is_space_alloc */
    H5D__single_idx_insert,         /* insert */
    H5D__single_idx_get_addr,       /* get_addr */
    NULL,                           /* resize */
    H5D__single_idx_iterate,        /* iterate */
    H5D__single_idx_remove,         /* remove */
    H5D__single_idx_delete,         /* delete */
    H5D__single_idx_copy_setup,     /* copy_setup */
    NULL,                           /* copy_shutdown */
    H5D__single_idx_size,           /* size */
    H5D__single_idx_reset,          /* reset */
    H5D__single_idx_dump,           /* dump */
    NULL                            /* destroy */
}};

/*****************************/
/* Library Private Variables */
/*****************************/

/*******************/
/* Local Variables */
/*******************/

/*-------------------------------------------------------------------------
 * Function:    H5D__single_idx_init
 *
 * Purpose:     Initialize the indexing information for a dataset.
 *
 * Return:      Non-negative on success/Negative on failure
 *
 * Programmer:  Vailin Choi
 *              July, 2011
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5D__single_idx_init(const H5D_chk_idx_info_t *idx_info, const H5S_t H5_ATTR_UNUSED *space,
                     haddr_t H5_ATTR_UNUSED dset_ohdr_addr)
{
    FUNC_ENTER_STATIC_NOERR

    /* Check args */
    HDassert(idx_info);
    HDassert(idx_info->f);
    HDassert(idx_info->pline);
    HDassert(idx_info->layout);
    HDassert(idx_info->storage);

    if (idx_info->pline->nused)
        idx_info->layout->flags |= H5O_LAYOUT_CHUNK_SINGLE_INDEX_WITH_FILTER;
    else
        idx_info->layout->flags = 0;

    FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5D__single_idx_init() */

/*-------------------------------------------------------------------------
 * Function:	H5D__single_idx_create
 *
 * Purpose:	Set up Single Chunk Index: filtered or non-filtered
 *
 * Return:	Non-negative on success
 *		Negative on failure.
 *
 * Programmer:	Vailin Choi; July 2011
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5D__single_idx_create(const H5D_chk_idx_info_t *idx_info)
{
    FUNC_ENTER_STATIC_NOERR

    /* Check args */
    HDassert(idx_info);
    HDassert(idx_info->f);
    HDassert(idx_info->pline);
    HDassert(idx_info->layout);
    HDassert(idx_info->storage);
    HDassert(idx_info->layout->max_nchunks == idx_info->layout->nchunks);
    HDassert(idx_info->layout->nchunks == 1);
    HDassert(!H5F_addr_defined(idx_info->storage->idx_addr));

    if (idx_info->pline->nused)
        HDassert(idx_info->layout->flags & H5O_LAYOUT_CHUNK_SINGLE_INDEX_WITH_FILTER);
    else
        HDassert(!(idx_info->layout->flags & H5O_LAYOUT_CHUNK_SINGLE_INDEX_WITH_FILTER));

    FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5D__single_idx_create() */

/*-------------------------------------------------------------------------
 * Function:	H5D__single_idx_is_space_alloc
 *
 * Purpose:	Query if space is allocated for the single chunk
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Vailin Choi; July 2011
 *
 *-------------------------------------------------------------------------
 */
static hbool_t
H5D__single_idx_is_space_alloc(const H5O_storage_chunk_t *storage)
{
    FUNC_ENTER_STATIC_NOERR

    /* Check args */
    HDassert(storage);

    FUNC_LEAVE_NOAPI((hbool_t)H5F_addr_defined(storage->idx_addr))
} /* end H5D__single_idx_is_space_alloc() */

/*-------------------------------------------------------------------------
 * Function:	H5D__single_idx_insert
 *
 * Purpose:	Allocate space for the single chunk
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Vailin Choi; July 2011
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5D__single_idx_insert(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata, const H5D_t *dset)
{
    herr_t ret_value = SUCCEED; /* Return value */

    FUNC_ENTER_STATIC

    /* Sanity checks */
    HDassert(idx_info);
    HDassert(idx_info->f);
    HDassert(idx_info->pline);
    HDassert(idx_info->layout);
    HDassert(idx_info->storage);
    HDassert(idx_info->layout->nchunks == 1);
    HDassert(idx_info->layout->max_nchunks == 1);
    HDassert(udata);

    /* Set the address for the chunk */
    HDassert(H5F_addr_defined(udata->chunk_block.offset));
    idx_info->storage->idx_addr = udata->chunk_block.offset;

    if (idx_info->pline->nused > 0) {
        H5_CHECKED_ASSIGN(idx_info->storage->u.single.nbytes, uint32_t, udata->chunk_block.length, hsize_t);
        idx_info->storage->u.single.filter_mask = udata->filter_mask;
    } /* end if */

    if (dset)
        if (dset->shared->dcpl_cache.fill.alloc_time != H5D_ALLOC_TIME_EARLY || idx_info->pline->nused > 0)
            /* Mark the layout dirty so that the address of the single chunk will be flushed later */
            if (H5D__mark(dset, H5D_MARK_LAYOUT) < 0)
                HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to mark layout as dirty")

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* H5D__single_idx_insert() */

/*-------------------------------------------------------------------------
 * Function:	H5D__single_idx_get_addr
 *
 * Purpose:	Get the file address of a chunk.
 *		Save the retrieved information in the udata supplied.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Vailin Choi; July 2010
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5D__single_idx_get_addr(const H5D_chk_idx_info_t *idx_info, H5D_chunk_ud_t *udata)
{
    FUNC_ENTER_STATIC_NOERR

    /* Sanity checks */
    HDassert(idx_info);
    HDassert(idx_info->f);
    HDassert(idx_info->pline);
    HDassert(idx_info->layout);
    HDassert(idx_info->storage);
    HDassert(idx_info->layout->nchunks == 1);
    HDassert(idx_info->layout->max_nchunks == 1);
    HDassert(udata);

    udata->chunk_block.offset = idx_info->storage->idx_addr;
    if (idx_info->layout->flags & H5O_LAYOUT_CHUNK_SINGLE_INDEX_WITH_FILTER) {
        udata->chunk_block.length = idx_info->storage->u.single.nbytes;
        udata->filter_mask        = idx_info->storage->u.single.filter_mask;
    } /* end if */
    else {
        udata->chunk_block.length = idx_info->layout->size;
        udata->filter_mask        = 0;
    } /* end else */
    if (!H5F_addr_defined(udata->chunk_block.offset))
        udata->chunk_block.length = 0;

    FUNC_LEAVE_NOAPI(SUCCEED)
} /* H5D__single_idx_get_addr() */

/*-------------------------------------------------------------------------
 * Function:	H5D__single_idx_iterate
 *
 * Purpose:	Make callback for the single chunk
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Vailin Choi; July 2010
 *
 *-------------------------------------------------------------------------
 */
static int
H5D__single_idx_iterate(const H5D_chk_idx_info_t *idx_info, H5D_chunk_cb_func_t chunk_cb, void *chunk_udata)
{
    H5D_chunk_rec_t chunk_rec;      /* generic chunk record  */
    int             ret_value = -1; /* Return value */

    FUNC_ENTER_STATIC_NOERR

    /* Sanity checks */
    HDassert(idx_info);
    HDassert(idx_info->f);
    HDassert(idx_info->pline);
    HDassert(idx_info->layout);
    HDassert(idx_info->storage);
    HDassert(chunk_cb);
    HDassert(chunk_udata);
    HDassert(H5F_addr_defined(idx_info->storage->idx_addr));

    /* Initialize generic chunk record */
    HDmemset(&chunk_rec, 0, sizeof(chunk_rec));
    chunk_rec.chunk_addr = idx_info->storage->idx_addr;

    if (idx_info->layout->flags & H5O_LAYOUT_CHUNK_SINGLE_INDEX_WITH_FILTER) {
        chunk_rec.nbytes      = idx_info->storage->u.single.nbytes;
        chunk_rec.filter_mask = idx_info->storage->u.single.filter_mask;
    } /* end if */
    else {
        chunk_rec.nbytes      = idx_info->layout->size;
        chunk_rec.filter_mask = 0;
    } /* end else */

    /* Make "generic chunk" callback */
    if ((ret_value = (*chunk_cb)(&chunk_rec, chunk_udata)) < 0)
        HERROR(H5E_DATASET, H5E_CALLBACK, "failure in generic chunk iterator callback");

    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5D__single_idx_iterate() */

/*-------------------------------------------------------------------------
 * Function:	H5D__single_idx_remove
 *
 * Purpose:	Remove the single chunk
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Vailin Choi; July 2011
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5D__single_idx_remove(const H5D_chk_idx_info_t *idx_info, H5D_chunk_common_ud_t H5_ATTR_UNUSED *udata)
{
    hsize_t nbytes;              /* Size of all chunks */
    herr_t  ret_value = SUCCEED; /* Return value */

    FUNC_ENTER_STATIC

    /* Sanity checks */
    HDassert(idx_info);
    HDassert(idx_info->f);
    HDassert(idx_info->pline);
    HDassert(idx_info->layout);
    HDassert(idx_info->storage);
    HDassert(H5F_addr_defined(idx_info->storage->idx_addr));

    if (idx_info->layout->flags & H5O_LAYOUT_CHUNK_SINGLE_INDEX_WITH_FILTER)
        nbytes = idx_info->storage->u.single.nbytes;
    else
        nbytes = idx_info->layout->size;

    if (H5MF_xfree(idx_info->f, H5FD_MEM_DRAW, idx_info->storage->idx_addr, nbytes) < 0)
        HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, H5_ITER_ERROR, "unable to free dataset chunks")

    idx_info->storage->idx_addr = HADDR_UNDEF;

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* H5D__single_idx_remove() */

/*-------------------------------------------------------------------------
 * Function:	H5D__single_idx_delete
 *
 * Purpose:	Delete raw data storage for entire dataset (i.e. the only chunk)
 *
 * Return:	Success:	Non-negative
 *		Failure:	negative
 *
 * Programmer:	Vailin Choi; Sept 2011
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5D__single_idx_delete(const H5D_chk_idx_info_t *idx_info)
{
    herr_t ret_value = SUCCEED; /* Return value */

    FUNC_ENTER_STATIC_NOERR

    /* Sanity checks */
    HDassert(idx_info);
    HDassert(idx_info->f);
    HDassert(idx_info->pline);
    HDassert(idx_info->layout);
    HDassert(idx_info->storage);

    if (H5F_addr_defined(idx_info->storage->idx_addr))
        ret_value = H5D__single_idx_remove(idx_info, NULL);
    else
        HDassert(!H5F_addr_defined(idx_info->storage->idx_addr));

    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5D__single_idx_delete() */

/*-------------------------------------------------------------------------
 * Function:	H5D__single_idx_copy_setup
 *
 * Purpose:	Set up any necessary information for copying the single chunk
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Vailin Choi; Sept 2011
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5D__single_idx_copy_setup(const H5D_chk_idx_info_t H5_ATTR_NDEBUG_UNUSED *idx_info_src,
                           const H5D_chk_idx_info_t *                      idx_info_dst)
{
    herr_t ret_value = SUCCEED; /* Return value */

    FUNC_ENTER_STATIC

    /* Check args */
    HDassert(idx_info_src);
    HDassert(idx_info_src->f);
    HDassert(idx_info_src->pline);
    HDassert(idx_info_src->layout);
    HDassert(idx_info_src->storage);
    HDassert(H5F_addr_defined(idx_info_src->storage->idx_addr));

    HDassert(idx_info_dst);
    HDassert(idx_info_dst->f);
    HDassert(idx_info_dst->pline);
    HDassert(idx_info_dst->layout);
    HDassert(idx_info_dst->storage);

    /* Set copied metadata tag */
    H5_BEGIN_TAG(H5AC__COPIED_TAG);

    /* Set up information at the destination file */
    if (H5D__single_idx_create(idx_info_dst) < 0)
        HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize chunked storage")

    /* Reset metadata tag */
    H5_END_TAG

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5D__single_idx_copy_setup() */

/*-------------------------------------------------------------------------
 * Function:    H5D__single_idx_size
 *
 * Purpose:     Retrieve the amount of index storage for the chunked dataset
 *
 * Return:      Success:        Non-negative
 *              Failure:        negative
 *
 * Programmer:	Vailin Choi; Sept 2011
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5D__single_idx_size(const H5D_chk_idx_info_t H5_ATTR_UNUSED *idx_info, hsize_t *index_size)
{
    FUNC_ENTER_STATIC_NOERR

    /* Check args */
    HDassert(index_size);

    *index_size = 0;

    FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5D__single_idx_size() */

/*-------------------------------------------------------------------------
 * Function:	H5D__single_idx_reset
 *
 * Purpose:	Reset indexing information.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Vailin Choi; Sept 2011
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5D__single_idx_reset(H5O_storage_chunk_t *storage, hbool_t reset_addr)
{
    FUNC_ENTER_STATIC_NOERR

    /* Check args */
    HDassert(storage);

    /* Reset index info */
    if (reset_addr)
        storage->idx_addr = HADDR_UNDEF;

    FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5D__single_idx_reset() */

/*-------------------------------------------------------------------------
 * Function:	H5D__single_idx_dump
 *
 * Purpose:	Dump the address of the single chunk
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Vailin Choi; September 2011
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5D__single_idx_dump(const H5O_storage_chunk_t *storage, FILE *stream)
{
    FUNC_ENTER_STATIC_NOERR

    /* Check args */
    HDassert(storage);
    HDassert(stream);

    HDfprintf(stream, "    Address: %" PRIuHADDR "\n", storage->idx_addr);

    FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5D__single_idx_dump() */
ot;H5FD_MEM_LHEAP", "H5FD_MEM_OHDR", }; /* The description of a file belonging to this driver. The `eoa' and `eof' * determine the amount of hdf5 address space in use and the high-water mark * of the file (the current size of the underlying filesystem file). The * `pos' value is used to eliminate file position updates when they would be a * no-op. Unfortunately we've found systems that use separate file position * indicators for reading and writing so the lseek can only be eliminated if * the current operation is the same as the previous operation. When opening * a file the `eof' will be set to the current file size, `eoa' will be set * to zero, `pos' will be set to H5F_ADDR_UNDEF (as it is when an error * occurs), and `op' will be set to H5F_OP_UNKNOWN. */ typedef struct H5FD_log_t { H5FD_t pub; /* public stuff, must be first */ int fd; /* the unix file */ haddr_t eoa; /* end of allocated region */ haddr_t eof; /* end of file; current file size */ haddr_t pos; /* current file I/O position */ H5FD_file_op_t op; /* last operation */ hbool_t ignore_disabled_file_locks; char filename[H5FD_MAX_FILENAME_LEN]; /* Copy of file name from open operation */ #ifndef H5_HAVE_WIN32_API /* On most systems the combination of device and i-node number uniquely * identify a file. Note that Cygwin, MinGW and other Windows POSIX * environments have the stat function (which fakes inodes) * and will use the 'device + inodes' scheme as opposed to the * Windows code further below. */ dev_t device; /* file device number */ ino_t inode; /* file i-node number */ #else /* Files in windows are uniquely identified by the volume serial * number and the file index (both low and high parts). * * There are caveats where these numbers can change, especially * on FAT file systems. On NTFS, however, a file should keep * those numbers the same until renamed or deleted (though you * can use ReplaceFile() on NTFS to keep the numbers the same * while renaming). * * See the MSDN "BY_HANDLE_FILE_INFORMATION Structure" entry for * more information. * * http://msdn.microsoft.com/en-us/library/aa363788(v=VS.85).aspx */ DWORD nFileIndexLow; DWORD nFileIndexHigh; DWORD dwVolumeSerialNumber; HANDLE hFile; /* Native windows file handle */ #endif /* H5_HAVE_WIN32_API */ /* Information from properties set by 'h5repart' tool * * Whether to eliminate the family driver info and convert this file to * a single file */ hbool_t fam_to_single; /* Fields for tracking I/O operations */ unsigned char * nread; /* Number of reads from a file location */ unsigned char * nwrite; /* Number of write to a file location */ unsigned char * flavor; /* Flavor of information written to file location */ unsigned long long total_read_ops; /* Total number of read operations */ unsigned long long total_write_ops; /* Total number of write operations */ unsigned long long total_seek_ops; /* Total number of seek operations */ unsigned long long total_truncate_ops; /* Total number of truncate operations */ double total_read_time; /* Total time spent in read operations */ double total_write_time; /* Total time spent in write operations */ double total_seek_time; /* Total time spent in seek operations */ double total_truncate_time; /* Total time spent in truncate operations */ size_t iosize; /* Size of I/O information buffers */ FILE * logfp; /* Log file pointer */ H5FD_log_fapl_t fa; /* Driver-specific file access properties */ } H5FD_log_t; /* * These macros check for overflow of various quantities. These macros * assume that HDoff_t is signed and haddr_t and size_t are unsigned. * * ADDR_OVERFLOW: Checks whether a file address of type `haddr_t' * is too large to be represented by the second argument * of the file seek function. * * SIZE_OVERFLOW: Checks whether a buffer size of type `hsize_t' is too * large to be represented by the `size_t' type. * * REGION_OVERFLOW: Checks whether an address and size pair describe data * which can be addressed entirely by the second * argument of the file seek function. */ #define MAXADDR (((haddr_t)1 << (8 * sizeof(HDoff_t) - 1)) - 1) #define ADDR_OVERFLOW(A) (HADDR_UNDEF == (A) || ((A) & ~(haddr_t)MAXADDR)) #define SIZE_OVERFLOW(Z) ((Z) & ~(hsize_t)MAXADDR) #define REGION_OVERFLOW(A, Z) \ (ADDR_OVERFLOW(A) || SIZE_OVERFLOW(Z) || HADDR_UNDEF == (A) + (Z) || (HDoff_t)((A) + (Z)) < (HDoff_t)(A)) /* Prototypes */ static herr_t H5FD__log_term(void); static void * H5FD__log_fapl_get(H5FD_t *file); static void * H5FD__log_fapl_copy(const void *_old_fa); static herr_t H5FD__log_fapl_free(void *_fa); static H5FD_t *H5FD__log_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr); static herr_t H5FD__log_close(H5FD_t *_file); static int H5FD__log_cmp(const H5FD_t *_f1, const H5FD_t *_f2); static herr_t H5FD__log_query(const H5FD_t *_f1, unsigned long *flags); static haddr_t H5FD__log_alloc(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, hsize_t size); static herr_t H5FD__log_free(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, hsize_t size); static haddr_t H5FD__log_get_eoa(const H5FD_t *_file, H5FD_mem_t type); static herr_t H5FD__log_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr); static haddr_t H5FD__log_get_eof(const H5FD_t *_file, H5FD_mem_t type); static herr_t H5FD__log_get_handle(H5FD_t *_file, hid_t fapl, void **file_handle); static herr_t H5FD__log_read(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, haddr_t addr, size_t size, void *buf); static herr_t H5FD__log_write(H5FD_t *_file, H5FD_mem_t type, hid_t fapl_id, haddr_t addr, size_t size, const void *buf); static herr_t H5FD__log_truncate(H5FD_t *_file, hid_t dxpl_id, hbool_t closing); static herr_t H5FD__log_lock(H5FD_t *_file, hbool_t rw); static herr_t H5FD__log_unlock(H5FD_t *_file); static const H5FD_class_t H5FD_log_g = { "log", /* name */ MAXADDR, /* maxaddr */ H5F_CLOSE_WEAK, /* fc_degree */ H5FD__log_term, /* terminate */ NULL, /* sb_size */ NULL, /* sb_encode */ NULL, /* sb_decode */ sizeof(H5FD_log_fapl_t), /* fapl_size */ H5FD__log_fapl_get, /* fapl_get */ H5FD__log_fapl_copy, /* fapl_copy */ H5FD__log_fapl_free, /* fapl_free */ 0, /* dxpl_size */ NULL, /* dxpl_copy */ NULL, /* dxpl_free */ H5FD__log_open, /* open */ H5FD__log_close, /* close */ H5FD__log_cmp, /* cmp */ H5FD__log_query, /* query */ NULL, /* get_type_map */ H5FD__log_alloc, /* alloc */ H5FD__log_free, /* free */ H5FD__log_get_eoa, /* get_eoa */ H5FD__log_set_eoa, /* set_eoa */ H5FD__log_get_eof, /* get_eof */ H5FD__log_get_handle, /* get_handle */ H5FD__log_read, /* read */ H5FD__log_write, /* write */ NULL, /* flush */ H5FD__log_truncate, /* truncate */ H5FD__log_lock, /* lock */ H5FD__log_unlock, /* unlock */ H5FD_FLMAP_DICHOTOMY /* fl_map */ }; /* Declare a free list to manage the H5FD_log_t struct */ H5FL_DEFINE_STATIC(H5FD_log_t); /*------------------------------------------------------------------------- * Function: H5FD__init_package * * Purpose: Initializes any interface-specific data or routines. * * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ static herr_t H5FD__init_package(void) { char * lock_env_var = NULL; /* Environment variable pointer */ herr_t ret_value = SUCCEED; FUNC_ENTER_STATIC /* Check the use disabled file locks environment variable */ lock_env_var = HDgetenv("HDF5_USE_FILE_LOCKING"); if (lock_env_var && !HDstrcmp(lock_env_var, "BEST_EFFORT")) ignore_disabled_file_locks_s = TRUE; /* Override: Ignore disabled locks */ else if (lock_env_var && (!HDstrcmp(lock_env_var, "TRUE") || !HDstrcmp(lock_env_var, "1"))) ignore_disabled_file_locks_s = FALSE; /* Override: Don't ignore disabled locks */ else ignore_disabled_file_locks_s = FAIL; /* Environment variable not set, or not set correctly */ if (H5FD_log_init() < 0) HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "unable to initialize log VFD") done: FUNC_LEAVE_NOAPI(ret_value) } /* H5FD__init_package() */ /*------------------------------------------------------------------------- * Function: H5FD_log_init * * Purpose: Initialize this driver by registering the driver with the * library. * * Return: Success: The driver ID for the log driver * Failure: H5I_INVALID_HID * * Programmer: Robb Matzke * Thursday, July 29, 1999 * *------------------------------------------------------------------------- */ hid_t H5FD_log_init(void) { hid_t ret_value = H5I_INVALID_HID; /* Return value */ FUNC_ENTER_NOAPI(H5I_INVALID_HID) if (H5I_VFL != H5I_get_type(H5FD_LOG_g)) H5FD_LOG_g = H5FD_register(&H5FD_log_g, sizeof(H5FD_class_t), FALSE); /* Set return value */ ret_value = H5FD_LOG_g; done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5FD_log_init() */ /*--------------------------------------------------------------------------- * Function: H5FD__log_term * * Purpose: Shut down the VFD * * Returns: SUCCEED (Can't fail) * * Programmer: Quincey Koziol * Friday, Jan 30, 2004 * *--------------------------------------------------------------------------- */ static herr_t H5FD__log_term(void) { FUNC_ENTER_STATIC_NOERR /* Reset VFL ID */ H5FD_LOG_g = 0; FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5FD__log_term() */ /*------------------------------------------------------------------------- * Function: H5Pset_fapl_log * * Purpose: Modify the file access property list to use the H5FD_LOG * driver defined in this source file. * * Return: SUCCEED/FAIL * * Programmer: Robb Matzke * Thursday, February 19, 1998 * *------------------------------------------------------------------------- */ herr_t H5Pset_fapl_log(hid_t fapl_id, const char *logfile, unsigned long long flags, size_t buf_size) { H5FD_log_fapl_t fa; /* File access property list information */ H5P_genplist_t *plist; /* Property list pointer */ herr_t ret_value; /* Return value */ FUNC_ENTER_API(FAIL) H5TRACE4("e", "i*sULz", fapl_id, logfile, flags, buf_size); /* Check arguments */ if (NULL == (plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a file access property list") HDmemset(&fa, 0, sizeof(H5FD_log_fapl_t)); /* Duplicate the log file string * A little wasteful, since this string will just be copied later, but * passing it in as a pointer sets off a chain of impossible-to-resolve * const cast warnings. */ if (logfile != NULL && NULL == (fa.logfile = H5MM_xstrdup(logfile))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to copy log file name") fa.flags = flags; fa.buf_size = buf_size; ret_value = H5P_set_driver(plist, H5FD_LOG, &fa); done: if (fa.logfile) H5MM_free(fa.logfile); FUNC_LEAVE_API(ret_value) } /* end H5Pset_fapl_log() */ /*------------------------------------------------------------------------- * Function: H5FD__log_fapl_get * * Purpose: Returns a file access property list which indicates how the * specified file is being accessed. The return list could be * used to access another file the same way. * * Return: Success: Ptr to new file access property list with all * members copied from the file struct. * Failure: NULL * * Programmer: Quincey Koziol * Thursday, April 20, 2000 * *------------------------------------------------------------------------- */ static void * H5FD__log_fapl_get(H5FD_t *_file) { H5FD_log_t *file = (H5FD_log_t *)_file; void * ret_value = NULL; /* Return value */ FUNC_ENTER_STATIC_NOERR /* Set return value */ ret_value = H5FD__log_fapl_copy(&(file->fa)); FUNC_LEAVE_NOAPI(ret_value) } /* end H5FD__log_fapl_get() */ /*------------------------------------------------------------------------- * Function: H5FD__log_fapl_copy * * Purpose: Copies the log-specific file access properties. * * Return: Success: Ptr to a new property list * Failure: NULL * * Programmer: Quincey Koziol * Thursday, April 20, 2000 * *------------------------------------------------------------------------- */ static void * H5FD__log_fapl_copy(const void *_old_fa) { const H5FD_log_fapl_t *old_fa = (const H5FD_log_fapl_t *)_old_fa; H5FD_log_fapl_t * new_fa = NULL; /* New FAPL info */ void * ret_value = NULL; /* Return value */ FUNC_ENTER_STATIC HDassert(old_fa); /* Allocate the new FAPL info */ if (NULL == (new_fa = (H5FD_log_fapl_t *)H5MM_calloc(sizeof(H5FD_log_fapl_t)))) HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, NULL, "unable to allocate log file FAPL") /* Copy the general information */ H5MM_memcpy(new_fa, old_fa, sizeof(H5FD_log_fapl_t)); /* Deep copy the log file name */ if (old_fa->logfile != NULL) if (NULL == (new_fa->logfile = H5MM_strdup(old_fa->logfile))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to allocate log file name") /* Set return value */ ret_value = new_fa; done: if (NULL == ret_value) if (new_fa) { if (new_fa->logfile) new_fa->logfile = (char *)H5MM_xfree(new_fa->logfile); H5MM_free(new_fa); } /* end if */ FUNC_LEAVE_NOAPI(ret_value) } /* end H5FD__log_fapl_copy() */ /*------------------------------------------------------------------------- * Function: H5FD__log_fapl_free * * Purpose: Frees the log-specific file access properties. * * Return: SUCCEED (Can't fail) * * Programmer: Quincey Koziol * Thursday, April 20, 2000 * *------------------------------------------------------------------------- */ static herr_t H5FD__log_fapl_free(void *_fa) { H5FD_log_fapl_t *fa = (H5FD_log_fapl_t *)_fa; FUNC_ENTER_STATIC_NOERR /* Free the fapl information */ if (fa->logfile) fa->logfile = (char *)H5MM_xfree(fa->logfile); H5MM_xfree(fa); FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5FD__log_fapl_free() */ /*------------------------------------------------------------------------- * Function: H5FD__log_open * * Purpose: Create and/or opens a file as an HDF5 file. * * Return: Success: A pointer to a new file data structure. The * public fields will be initialized by the * caller, which is always H5FD_open(). * Failure: NULL * * Programmer: Robb Matzke * Thursday, July 29, 1999 * *------------------------------------------------------------------------- */ static H5FD_t * H5FD__log_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr) { H5FD_log_t * file = NULL; H5P_genplist_t * plist; /* Property list */ const H5FD_log_fapl_t *fa; /* File access property list information */ int fd = -1; /* File descriptor */ int o_flags; /* Flags for open() call */ #ifdef H5_HAVE_WIN32_API struct _BY_HANDLE_FILE_INFORMATION fileinfo; #endif H5_timer_t open_timer; /* Timer for open() call */ H5_timer_t stat_timer; /* Timer for stat() call */ h5_stat_t sb; H5FD_t * ret_value = NULL; /* Return value */ FUNC_ENTER_STATIC /* Sanity check on file offsets */ HDcompile_assert(sizeof(HDoff_t) >= sizeof(size_t)); /* Check arguments */ if (!name || !*name) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "invalid file name") if (0 == maxaddr || HADDR_UNDEF == maxaddr) HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "bogus maxaddr") if (ADDR_OVERFLOW(maxaddr)) HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, NULL, "bogus maxaddr") /* Build the open flags */ o_flags = (H5F_ACC_RDWR & flags) ? O_RDWR : O_RDONLY; if (H5F_ACC_TRUNC & flags) o_flags |= O_TRUNC; if (H5F_ACC_CREAT & flags) o_flags |= O_CREAT; if (H5F_ACC_EXCL & flags) o_flags |= O_EXCL; /* Get the driver specific information */ if (NULL == (plist = H5P_object_verify(fapl_id, H5P_FILE_ACCESS))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a file access property list") if (NULL == (fa = (const H5FD_log_fapl_t *)H5P_peek_driver_info(plist))) HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, NULL, "bad VFL driver info") /* Start timer for open() call */ if (fa->flags & H5FD_LOG_TIME_OPEN) { H5_timer_init(&open_timer); H5_timer_start(&open_timer); } /* end if */ /* Open the file */ if ((fd = HDopen(name, o_flags, H5_POSIX_CREATE_MODE_RW)) < 0) { int myerrno = errno; HGOTO_ERROR( H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to open file: name = '%s', errno = %d, error message = '%s', flags = %x, o_flags = %x", name, myerrno, HDstrerror(myerrno), flags, (unsigned)o_flags); } /* end if */ /* Stop timer for open() call */ if (fa->flags & H5FD_LOG_TIME_OPEN) H5_timer_stop(&open_timer); /* Start timer for stat() call */ if (fa->flags & H5FD_LOG_TIME_STAT) { H5_timer_init(&stat_timer); H5_timer_start(&stat_timer); } /* end if */ /* Get the file stats */ if (HDfstat(fd, &sb) < 0) HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, NULL, "unable to fstat file") /* Stop timer for stat() call */ if (fa->flags & H5FD_LOG_TIME_STAT) H5_timer_stop(&stat_timer); /* Create the new file struct */ if (NULL == (file = H5FL_CALLOC(H5FD_log_t))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to allocate file struct") file->fd = fd; H5_CHECKED_ASSIGN(file->eof, haddr_t, sb.st_size, h5_stat_size_t); file->pos = HADDR_UNDEF; file->op = OP_UNKNOWN; #ifdef H5_HAVE_WIN32_API file->hFile = (HANDLE)_get_osfhandle(fd); if (INVALID_HANDLE_VALUE == file->hFile) HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to get Windows file handle") if (!GetFileInformationByHandle((HANDLE)file->hFile, &fileinfo)) HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to get Windows file information") file->nFileIndexHigh = fileinfo.nFileIndexHigh; file->nFileIndexLow = fileinfo.nFileIndexLow; file->dwVolumeSerialNumber = fileinfo.dwVolumeSerialNumber; #else /* H5_HAVE_WIN32_API */ file->device = sb.st_dev; file->inode = sb.st_ino; #endif /* H5_HAVE_WIN32_API */ /* Retain a copy of the name used to open the file, for possible error reporting */ HDstrncpy(file->filename, name, sizeof(file->filename)); file->filename[sizeof(file->filename) - 1] = '\0'; /* Get the flags for logging */ file->fa.flags = fa->flags; if (fa->logfile) file->fa.logfile = H5MM_strdup(fa->logfile); else file->fa.logfile = NULL; file->fa.buf_size = fa->buf_size; /* Check if we are doing any logging at all */ if (file->fa.flags != 0) { /* Allocate buffers for tracking file accesses and data "flavor" */ file->iosize = fa->buf_size; if (file->fa.flags & H5FD_LOG_FILE_READ) { file->nread = (unsigned char *)H5MM_calloc(file->iosize); HDassert(file->nread); } /* end if */ if (file->fa.flags & H5FD_LOG_FILE_WRITE) { file->nwrite = (unsigned char *)H5MM_calloc(file->iosize); HDassert(file->nwrite); } /* end if */ if (file->fa.flags & H5FD_LOG_FLAVOR) { file->flavor = (unsigned char *)H5MM_calloc(file->iosize); HDassert(file->flavor); } /* end if */ /* Set the log file pointer */ if (fa->logfile) file->logfp = HDfopen(fa->logfile, "w"); else file->logfp = stderr; /* Log the timer values */ if (file->fa.flags & H5FD_LOG_TIME_OPEN) { H5_timevals_t open_times; /* Elapsed time for open() call */ H5_timer_get_times(open_timer, &open_times); HDfprintf(file->logfp, "Open took: (%f s)\n", open_times.elapsed); } /* end if */ if (file->fa.flags & H5FD_LOG_TIME_STAT) { H5_timevals_t stat_times; /* Elapsed time for stat() call */ H5_timer_get_times(stat_timer, &stat_times); HDfprintf(file->logfp, "Stat took: (%f s)\n", stat_times.elapsed); } /* end if */ } /* end if */ /* Check the file locking flags in the fapl */ if (ignore_disabled_file_locks_s != FAIL) /* The environment variable was set, so use that preferentially */ file->ignore_disabled_file_locks = ignore_disabled_file_locks_s; else { /* Use the value in the property list */ if (H5P_get(plist, H5F_ACS_IGNORE_DISABLED_FILE_LOCKS_NAME, &file->ignore_disabled_file_locks) < 0) HGOTO_ERROR(H5E_VFL, H5E_CANTGET, NULL, "can't get ignore disabled file locks property") } /* Check for non-default FAPL */ if (H5P_FILE_ACCESS_DEFAULT != fapl_id) { /* This step is for h5repart tool only. If user wants to change file driver from * family to one that uses single files (sec2, etc.) while using h5repart, this * private property should be set so that in the later step, the library can ignore * the family driver information saved in the superblock. */ if (H5P_exist_plist(plist, H5F_ACS_FAMILY_TO_SINGLE_NAME) > 0) if (H5P_get(plist, H5F_ACS_FAMILY_TO_SINGLE_NAME, &file->fam_to_single) < 0) HGOTO_ERROR(H5E_VFL, H5E_CANTGET, NULL, "can't get property of changing family to single") } /* end if */ /* Set return value */ ret_value = (H5FD_t *)file; done: if (NULL == ret_value) { if (fd >= 0) HDclose(fd); if (file) file = H5FL_FREE(H5FD_log_t, file); } /* end if */ FUNC_LEAVE_NOAPI(ret_value) } /* end H5FD__log_open() */ /*------------------------------------------------------------------------- * Function: H5FD__log_close * * Purpose: Closes an HDF5 file. * * Return: Success: SUCCEED * Failure: FAIL, file not closed. * * Programmer: Robb Matzke * Thursday, July 29, 1999 * *------------------------------------------------------------------------- */ static herr_t H5FD__log_close(H5FD_t *_file) { H5FD_log_t *file = (H5FD_log_t *)_file; H5_timer_t close_timer; /* Timer for close() call */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC /* Sanity check */ HDassert(file); /* Start timer for close() call */ if (file->fa.flags & H5FD_LOG_TIME_CLOSE) { H5_timer_init(&close_timer); H5_timer_start(&close_timer); } /* end if */ /* Close the underlying file */ if (HDclose(file->fd) < 0) HSYS_GOTO_ERROR(H5E_IO, H5E_CANTCLOSEFILE, FAIL, "unable to close file") /* Stop timer for close() call */ if (file->fa.flags & H5FD_LOG_TIME_CLOSE) H5_timer_stop(&close_timer); /* Dump I/O information */ if (file->fa.flags != 0) { haddr_t addr; haddr_t last_addr; unsigned char last_val; if (file->fa.flags & H5FD_LOG_TIME_CLOSE) { H5_timevals_t close_times; /* Elapsed time for close() call */ H5_timer_get_times(close_timer, &close_times); HDfprintf(file->logfp, "Close took: (%f s)\n", close_times.elapsed); } /* end if */ /* Dump the total number of seek/read/write operations */ if (file->fa.flags & H5FD_LOG_NUM_READ) HDfprintf(file->logfp, "Total number of read operations: %llu\n", file->total_read_ops); if (file->fa.flags & H5FD_LOG_NUM_WRITE) HDfprintf(file->logfp, "Total number of write operations: %llu\n", file->total_write_ops); if (file->fa.flags & H5FD_LOG_NUM_SEEK) HDfprintf(file->logfp, "Total number of seek operations: %llu\n", file->total_seek_ops); if (file->fa.flags & H5FD_LOG_NUM_TRUNCATE) HDfprintf(file->logfp, "Total number of truncate operations: %llu\n", file->total_truncate_ops); /* Dump the total time in seek/read/write */ if (file->fa.flags & H5FD_LOG_TIME_READ) HDfprintf(file->logfp, "Total time in read operations: %f s\n", file->total_read_time); if (file->fa.flags & H5FD_LOG_TIME_WRITE) HDfprintf(file->logfp, "Total time in write operations: %f s\n", file->total_write_time); if (file->fa.flags & H5FD_LOG_TIME_SEEK) HDfprintf(file->logfp, "Total time in seek operations: %f s\n", file->total_seek_time); if (file->fa.flags & H5FD_LOG_TIME_TRUNCATE) HDfprintf(file->logfp, "Total time in truncate operations: %f s\n", file->total_truncate_time); /* Dump the write I/O information */ if (file->fa.flags & H5FD_LOG_FILE_WRITE) { HDfprintf(file->logfp, "Dumping write I/O information:\n"); last_val = file->nwrite[0]; last_addr = 0; addr = 1; while (addr < file->eoa) { if (file->nwrite[addr] != last_val) { HDfprintf(file->logfp, "\tAddr %10" PRIuHADDR "-%10" PRIuHADDR " (%10lu bytes) written to %3d times\n", last_addr, (addr - 1), (unsigned long)(addr - last_addr), (int)last_val); last_val = file->nwrite[addr]; last_addr = addr; } /* end if */ addr++; } /* end while */ HDfprintf(file->logfp, "\tAddr %10" PRIuHADDR "-%10" PRIuHADDR " (%10lu bytes) written to %3d times\n", last_addr, (addr - 1), (unsigned long)(addr - last_addr), (int)last_val); } /* end if */ /* Dump the read I/O information */ if (file->fa.flags & H5FD_LOG_FILE_READ) { HDfprintf(file->logfp, "Dumping read I/O information:\n"); last_val = file->nread[0]; last_addr = 0; addr = 1; while (addr < file->eoa) { if (file->nread[addr] != last_val) { HDfprintf(file->logfp, "\tAddr %10" PRIuHADDR "-%10" PRIuHADDR " (%10lu bytes) read from %3d times\n", last_addr, (addr - 1), (unsigned long)(addr - last_addr), (int)last_val); last_val = file->nread[addr]; last_addr = addr; } /* end if */ addr++; } /* end while */ HDfprintf(file->logfp, "\tAddr %10" PRIuHADDR "-%10" PRIuHADDR " (%10lu bytes) read from %3d times\n", last_addr, (addr - 1), (unsigned long)(addr - last_addr), (int)last_val); } /* end if */ /* Dump the I/O flavor information */ if (file->fa.flags & H5FD_LOG_FLAVOR) { HDfprintf(file->logfp, "Dumping I/O flavor information:\n"); last_val = file->flavor[0]; last_addr = 0; addr = 1; while (addr < file->eoa) { if (file->flavor[addr] != last_val) { HDfprintf(file->logfp, "\tAddr %10" PRIuHADDR "-%10" PRIuHADDR " (%10lu bytes) flavor is %s\n", last_addr, (addr - 1), (unsigned long)(addr - last_addr), flavors[last_val]); last_val = file->flavor[addr]; last_addr = addr; } /* end if */ addr++; } /* end while */ HDfprintf(file->logfp, "\tAddr %10" PRIuHADDR "-%10" PRIuHADDR " (%10lu bytes) flavor is %s\n", last_addr, (addr - 1), (unsigned long)(addr - last_addr), flavors[last_val]); } /* end if */ /* Free the logging information */ if (file->fa.flags & H5FD_LOG_FILE_WRITE) file->nwrite = (unsigned char *)H5MM_xfree(file->nwrite); if (file->fa.flags & H5FD_LOG_FILE_READ) file->nread = (unsigned char *)H5MM_xfree(file->nread); if (file->fa.flags & H5FD_LOG_FLAVOR) file->flavor = (unsigned char *)H5MM_xfree(file->flavor); if (file->logfp != stderr) HDfclose(file->logfp); } /* end if */ if (file->fa.logfile) file->fa.logfile = (char *)H5MM_xfree(file->fa.logfile); /* Release the file info */ file = H5FL_FREE(H5FD_log_t, file); done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5FD__log_close() */ /*------------------------------------------------------------------------- * Function: H5FD__log_cmp * * Purpose: Compares two files belonging to this driver using an * arbitrary (but consistent) ordering. * * Return: Success: A value like strcmp() * Failure: never fails (arguments were checked by the * caller). * * Programmer: Robb Matzke * Thursday, July 29, 1999 * *------------------------------------------------------------------------- */ static int H5FD__log_cmp(const H5FD_t *_f1, const H5FD_t *_f2) { const H5FD_log_t *f1 = (const H5FD_log_t *)_f1; const H5FD_log_t *f2 = (const H5FD_log_t *)_f2; int ret_value = 0; FUNC_ENTER_STATIC_NOERR #ifdef H5_HAVE_WIN32_API if (f1->dwVolumeSerialNumber < f2->dwVolumeSerialNumber) HGOTO_DONE(-1) if (f1->dwVolumeSerialNumber > f2->dwVolumeSerialNumber) HGOTO_DONE(1) if (f1->nFileIndexHigh < f2->nFileIndexHigh) HGOTO_DONE(-1) if (f1->nFileIndexHigh > f2->nFileIndexHigh) HGOTO_DONE(1) if (f1->nFileIndexLow < f2->nFileIndexLow) HGOTO_DONE(-1) if (f1->nFileIndexLow > f2->nFileIndexLow) HGOTO_DONE(1) #else #ifdef H5_DEV_T_IS_SCALAR if (f1->device < f2->device) HGOTO_DONE(-1) if (f1->device > f2->device) HGOTO_DONE(1) #else /* H5_DEV_T_IS_SCALAR */ /* If dev_t isn't a scalar value on this system, just use memcmp to * determine if the values are the same or not. The actual return value * shouldn't really matter... */ if (HDmemcmp(&(f1->device), &(f2->device), sizeof(dev_t)) < 0) HGOTO_DONE(-1) if (HDmemcmp(&(f1->device), &(f2->device), sizeof(dev_t)) > 0) HGOTO_DONE(1) #endif /* H5_DEV_T_IS_SCALAR */ if (f1->inode < f2->inode) HGOTO_DONE(-1) if (f1->inode > f2->inode) HGOTO_DONE(1) #endif done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5FD__log_cmp() */ /*------------------------------------------------------------------------- * Function: H5FD__log_query * * Purpose: Set the flags that this VFL driver is capable of supporting. * (listed in H5FDpublic.h) * * Return: SUCCEED (Can't fail) * * Programmer: Quincey Koziol * Friday, August 25, 2000 * *------------------------------------------------------------------------- */ static herr_t H5FD__log_query(const H5FD_t *_file, unsigned long *flags /* out */) { const H5FD_log_t *file = (const H5FD_log_t *)_file; FUNC_ENTER_STATIC_NOERR /* Set the VFL feature flags that this driver supports */ if (flags) { *flags = 0; *flags |= H5FD_FEAT_AGGREGATE_METADATA; /* OK to aggregate metadata allocations */ *flags |= H5FD_FEAT_ACCUMULATE_METADATA; /* OK to accumulate metadata for faster writes */ *flags |= H5FD_FEAT_DATA_SIEVE; /* OK to perform data sieving for faster raw data reads & writes */ *flags |= H5FD_FEAT_AGGREGATE_SMALLDATA; /* OK to aggregate "small" raw data allocations */ *flags |= H5FD_FEAT_POSIX_COMPAT_HANDLE; /* get_handle callback returns a POSIX file descriptor */ *flags |= H5FD_FEAT_SUPPORTS_SWMR_IO; /* VFD supports the single-writer/multiple-readers (SWMR) pattern */ *flags |= H5FD_FEAT_DEFAULT_VFD_COMPATIBLE; /* VFD creates a file which can be opened with the default VFD */ /* Check for flags that are set by h5repart */ if (file && file->fam_to_single) *flags |= H5FD_FEAT_IGNORE_DRVRINFO; /* Ignore the driver info when file is opened (which eliminates it) */ } /* end if */ FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5FD__log_query() */ /*------------------------------------------------------------------------- * Function: H5FD__log_alloc * * Purpose: Allocate file memory. * * Return: Success: Address of new memory * Failure: HADDR_UNDEF * * Programmer: Quincey Koziol * Monday, April 17, 2000 * *------------------------------------------------------------------------- */ static haddr_t H5FD__log_alloc(H5FD_t *_file, H5FD_mem_t type, hid_t H5_ATTR_UNUSED dxpl_id, hsize_t size) { H5FD_log_t *file = (H5FD_log_t *)_file; haddr_t addr; haddr_t ret_value = HADDR_UNDEF; /* Return value */ FUNC_ENTER_STATIC_NOERR /* Compute the address for the block to allocate */ addr = file->eoa; /* Extend the end-of-allocated space address */ file->eoa = addr + size; /* Retain the (first) flavor of the information written to the file */ if (file->fa.flags != 0) { if (file->fa.flags & H5FD_LOG_FLAVOR) { HDassert(addr < file->iosize); H5_CHECK_OVERFLOW(size, hsize_t, size_t); HDmemset(&file->flavor[addr], (int)type, (size_t)size); } /* end if */ if (file->fa.flags & H5FD_LOG_ALLOC) HDfprintf(file->logfp, "%10" PRIuHADDR "-%10" PRIuHADDR " (%10" PRIuHSIZE " bytes) (%s) Allocated\n", addr, (haddr_t)((addr + size) - 1), size, flavors[type]); } /* end if */ /* Set return value */ ret_value = addr; FUNC_LEAVE_NOAPI(ret_value) } /* end H5FD__log_alloc() */ /*------------------------------------------------------------------------- * Function: H5FD__log_free * * Purpose: Release file memory. * * Return: SUCCEED/FAIL * * Programmer: Quincey Koziol * Wednesday, September 28, 2016 * *------------------------------------------------------------------------- */ static herr_t H5FD__log_free(H5FD_t *_file, H5FD_mem_t type, hid_t H5_ATTR_UNUSED dxpl_id, haddr_t addr, hsize_t size) { H5FD_log_t *file = (H5FD_log_t *)_file; FUNC_ENTER_STATIC_NOERR if (file->fa.flags != 0) { /* Reset the flavor of the information in the file */ if (file->fa.flags & H5FD_LOG_FLAVOR) { HDassert(addr < file->iosize); H5_CHECK_OVERFLOW(size, hsize_t, size_t); HDmemset(&file->flavor[addr], H5FD_MEM_DEFAULT, (size_t)size); } /* end if */ /* Log the file memory freed */ if (file->fa.flags & H5FD_LOG_FREE) HDfprintf(file->logfp, "%10" PRIuHADDR "-%10" PRIuHADDR " (%10" PRIuHSIZE " bytes) (%s) Freed\n", addr, (haddr_t)((addr + size) - 1), size, flavors[type]); } /* end if */ FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5FD__log_free() */ /*------------------------------------------------------------------------- * Function: H5FD__log_get_eoa * * Purpose: Gets the end-of-address marker for the file. The EOA marker * is the first address past the last byte allocated in the * format address space. * * Return: Success: The end-of-address marker. * Failure: HADDR_UNDEF * * Programmer: Robb Matzke * Monday, August 2, 1999 * *------------------------------------------------------------------------- */ static haddr_t H5FD__log_get_eoa(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type) { const H5FD_log_t *file = (const H5FD_log_t *)_file; FUNC_ENTER_STATIC_NOERR FUNC_LEAVE_NOAPI(file->eoa) } /* end H5FD__log_get_eoa() */ /*------------------------------------------------------------------------- * Function: H5FD__log_set_eoa * * Purpose: Set the end-of-address marker for the file. This function is * called shortly after an existing HDF5 file is opened in order * to tell the driver where the end of the HDF5 data is located. * * Return: SUCCEED (Can't fail) * * Programmer: Robb Matzke * Thursday, July 29, 1999 * *------------------------------------------------------------------------- */ static herr_t H5FD__log_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr) { H5FD_log_t *file = (H5FD_log_t *)_file; FUNC_ENTER_STATIC_NOERR if (file->fa.flags != 0) { /* Check for increasing file size */ if (H5F_addr_gt(addr, file->eoa) && H5F_addr_gt(addr, 0)) { hsize_t size = addr - file->eoa; /* Retain the flavor of the space allocated by the extension */ if (file->fa.flags & H5FD_LOG_FLAVOR) { HDassert(addr < file->iosize); H5_CHECK_OVERFLOW(size, hsize_t, size_t); HDmemset(&file->flavor[file->eoa], (int)type, (size_t)size); } /* end if */ /* Log the extension like an allocation */ if (file->fa.flags & H5FD_LOG_ALLOC) HDfprintf(file->logfp, "%10" PRIuHADDR "-%10" PRIuHADDR " (%10" PRIuHSIZE " bytes) (%s) Allocated\n", file->eoa, addr, size, flavors[type]); } /* end if */ /* Check for decreasing file size */ if (H5F_addr_lt(addr, file->eoa) && H5F_addr_gt(addr, 0)) { hsize_t size = file->eoa - addr; /* Reset the flavor of the space freed by the shrink */ if (file->fa.flags & H5FD_LOG_FLAVOR) { HDassert((addr + size) < file->iosize); H5_CHECK_OVERFLOW(size, hsize_t, size_t); HDmemset(&file->flavor[addr], H5FD_MEM_DEFAULT, (size_t)size); } /* end if */ /* Log the shrink like a free */ if (file->fa.flags & H5FD_LOG_FREE) HDfprintf(file->logfp, "%10" PRIuHADDR "-%10" PRIuHADDR " (%10" PRIuHSIZE " bytes) (%s) Freed\n", file->eoa, addr, size, flavors[type]); } /* end if */ } /* end if */ file->eoa = addr; FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5FD__log_set_eoa() */ /*------------------------------------------------------------------------- * Function: H5FD__log_get_eof * * Purpose: Returns the end-of-file marker, which is the greater of * either the filesystem end-of-file or the HDF5 end-of-address * markers. * * Return: Success: End of file address, the first address past * the end of the "file", either the filesystem file * or the HDF5 file. * Failure: HADDR_UNDEF * * Programmer: Robb Matzke * Thursday, July 29, 1999 * *------------------------------------------------------------------------- */ static haddr_t H5FD__log_get_eof(const H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type) { const H5FD_log_t *file = (const H5FD_log_t *)_file; FUNC_ENTER_STATIC_NOERR FUNC_LEAVE_NOAPI(file->eof) } /* end H5FD__log_get_eof() */ /*------------------------------------------------------------------------- * Function: H5FD__log_get_handle * * Purpose: Returns the file handle of LOG file driver. * * Returns: SUCCEED/FAIL * * Programmer: Raymond Lu * Sept. 16, 2002 * *------------------------------------------------------------------------- */ static herr_t H5FD__log_get_handle(H5FD_t *_file, hid_t H5_ATTR_UNUSED fapl, void **file_handle) { H5FD_log_t *file = (H5FD_log_t *)_file; herr_t ret_value = SUCCEED; FUNC_ENTER_STATIC if (!file_handle) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "file handle not valid") *file_handle = &(file->fd); done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5FD__log_get_handle() */ /*------------------------------------------------------------------------- * Function: H5FD__log_read * * Purpose: Reads SIZE bytes of data from FILE beginning at address ADDR * into buffer BUF according to data transfer properties in * DXPL_ID. * * Return: Success: SUCCEED. Result is stored in caller-supplied * buffer BUF. * Failure: FAIL, Contents of buffer BUF are undefined. * * Programmer: Robb Matzke * Thursday, July 29, 1999 * *------------------------------------------------------------------------- */ static herr_t H5FD__log_read(H5FD_t *_file, H5FD_mem_t type, hid_t H5_ATTR_UNUSED dxpl_id, haddr_t addr, size_t size, void *buf /*out*/) { H5FD_log_t * file = (H5FD_log_t *)_file; size_t orig_size = size; /* Save the original size for later */ haddr_t orig_addr = addr; H5_timer_t read_timer; /* Timer for read operation */ H5_timevals_t read_times; /* Elapsed time for read operation */ #ifndef H5_HAVE_PREADWRITE H5_timer_t seek_timer; /* Timer for seek operation */ H5_timevals_t seek_times; /* Elapsed time for seek operation */ #endif /* H5_HAVE_PREADWRITE */ HDoff_t offset = (HDoff_t)addr; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC HDassert(file && file->pub.cls); HDassert(buf); /* Check for overflow conditions */ if (!H5F_addr_defined(addr)) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addr undefined, addr = %llu", (unsigned long long)addr) if (REGION_OVERFLOW(addr, size)) HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, addr = %llu", (unsigned long long)addr) /* Log the I/O information about the read */ if (file->fa.flags != 0) { size_t tmp_size = size; haddr_t tmp_addr = addr; /* Log information about the number of times these locations are read */ if (file->fa.flags & H5FD_LOG_FILE_READ) { HDassert((addr + size) < file->iosize); while (tmp_size-- > 0) file->nread[tmp_addr++]++; } /* end if */ } /* end if */ #ifndef H5_HAVE_PREADWRITE /* Seek to the correct location (if we don't have pread) */ if (addr != file->pos || OP_READ != file->op) { /* Start timer for seek() call */ if (file->fa.flags & H5FD_LOG_TIME_SEEK) { H5_timer_init(&seek_timer); H5_timer_start(&seek_timer); } /* end if */ if (HDlseek(file->fd, (HDoff_t)addr, SEEK_SET) < 0) HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position") /* Stop timer for seek() call */ if (file->fa.flags & H5FD_LOG_TIME_SEEK) H5_timer_stop(&seek_timer); /* Add to the number of seeks, when tracking that */ if (file->fa.flags & H5FD_LOG_NUM_SEEK) file->total_seek_ops++; /* Add to the total seek time, when tracking that */ if (file->fa.flags & H5FD_LOG_TIME_SEEK) { H5_timer_get_times(seek_timer, &seek_times); file->total_seek_time += seek_times.elapsed; } /* end if */ /* Emit log string if we're tracking individual seek events. */ if (file->fa.flags & H5FD_LOG_LOC_SEEK) { HDfprintf(file->logfp, "Seek: From %10" PRIuHADDR " To %10" PRIuHADDR, file->pos, addr); /* Add the seek time, if we're tracking that. * Note that the seek time is NOT emitted for when just H5FD_LOG_TIME_SEEK * is set. */ if (file->fa.flags & H5FD_LOG_TIME_SEEK) HDfprintf(file->logfp, " (%fs @ %f)\n", seek_times.elapsed, seek_timer.initial.elapsed); else HDfprintf(file->logfp, "\n"); } /* end if */ } /* end if */ #endif /* H5_HAVE_PREADWRITE */ /* Start timer for read operation */ if (file->fa.flags & H5FD_LOG_TIME_READ) { H5_timer_init(&read_timer); H5_timer_start(&read_timer); } /* end if */ /* * Read data, being careful of interrupted system calls, partial results, * and the end of the file. */ while (size > 0) { h5_posix_io_t bytes_in = 0; /* # of bytes to read */ h5_posix_io_ret_t bytes_read = -1; /* # of bytes actually read */ /* Trying to read more bytes than the return type can handle is * undefined behavior in POSIX. */ if (size > H5_POSIX_MAX_IO_BYTES) bytes_in = H5_POSIX_MAX_IO_BYTES; else bytes_in = (h5_posix_io_t)size; do { #ifdef H5_HAVE_PREADWRITE bytes_read = HDpread(file->fd, buf, bytes_in, offset); if (bytes_read > 0) offset += bytes_read; #else bytes_read = HDread(file->fd, buf, bytes_in); #endif /* H5_HAVE_PREADWRITE */ } while (-1 == bytes_read && EINTR == errno); if (-1 == bytes_read) { /* error */ int myerrno = errno; time_t mytime = HDtime(NULL); offset = HDlseek(file->fd, (HDoff_t)0, SEEK_CUR); if (file->fa.flags & H5FD_LOG_LOC_READ) HDfprintf(file->logfp, "Error! Reading: %10" PRIuHADDR "-%10" PRIuHADDR " (%10zu bytes)\n", orig_addr, (orig_addr + orig_size) - 1, orig_size); HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file read failed: time = %s, filename = '%s', file descriptor = %d, errno = %d, " "error message = '%s', buf = %p, total read size = %llu, bytes this sub-read = %llu, " "bytes actually read = %llu, offset = %llu", HDctime(&mytime), file->filename, file->fd, myerrno, HDstrerror(myerrno), buf, (unsigned long long)size, (unsigned long long)bytes_in, (unsigned long long)bytes_read, (unsigned long long)offset); } /* end if */ if (0 == bytes_read) { /* end of file but not end of format address space */ HDmemset(buf, 0, size); break; } /* end if */ HDassert(bytes_read >= 0); HDassert((size_t)bytes_read <= size); size -= (size_t)bytes_read; addr += (haddr_t)bytes_read; buf = (char *)buf + bytes_read; } /* end while */ /* Stop timer for read operation */ if (file->fa.flags & H5FD_LOG_TIME_READ) H5_timer_stop(&read_timer); /* Add to the number of reads, when tracking that */ if (file->fa.flags & H5FD_LOG_NUM_READ) file->total_read_ops++; /* Add to the total read time, when tracking that */ if (file->fa.flags & H5FD_LOG_TIME_READ) { H5_timer_get_times(read_timer, &read_times); file->total_read_time += read_times.elapsed; } /* end if */ /* Log information about the read */ if (file->fa.flags & H5FD_LOG_LOC_READ) { HDfprintf(file->logfp, "%10" PRIuHADDR "-%10" PRIuHADDR " (%10zu bytes) (%s) Read", orig_addr, (orig_addr + orig_size) - 1, orig_size, flavors[type]); /* Verify that we are reading in the type of data we allocated in this location */ if (file->flavor) { HDassert(type == H5FD_MEM_DEFAULT || type == (H5FD_mem_t)file->flavor[orig_addr] || (H5FD_mem_t)file->flavor[orig_addr] == H5FD_MEM_DEFAULT); HDassert(type == H5FD_MEM_DEFAULT || type == (H5FD_mem_t)file->flavor[(orig_addr + orig_size) - 1] || (H5FD_mem_t)file->flavor[(orig_addr + orig_size) - 1] == H5FD_MEM_DEFAULT); } /* end if */ /* Add the read time, if we're tracking that. * Note that the read time is NOT emitted for when just H5FD_LOG_TIME_READ * is set. */ if (file->fa.flags & H5FD_LOG_TIME_READ) HDfprintf(file->logfp, " (%fs @ %f)\n", read_times.elapsed, read_timer.initial.elapsed); else HDfprintf(file->logfp, "\n"); } /* end if */ /* Update current position */ file->pos = addr; file->op = OP_READ; done: if (ret_value < 0) { /* Reset last file I/O information */ file->pos = HADDR_UNDEF; file->op = OP_UNKNOWN; } /* end if */ FUNC_LEAVE_NOAPI(ret_value) } /* end H5FD__log_read() */ /*------------------------------------------------------------------------- * Function: H5FD__log_write * * Purpose: Writes SIZE bytes of data to FILE beginning at address ADDR * from buffer BUF according to data transfer properties in * DXPL_ID. * * Return: SUCCEED/FAIL * * Programmer: Robb Matzke * Thursday, July 29, 1999 * *------------------------------------------------------------------------- */ static herr_t H5FD__log_write(H5FD_t *_file, H5FD_mem_t type, hid_t H5_ATTR_UNUSED dxpl_id, haddr_t addr, size_t size, const void *buf) { H5FD_log_t * file = (H5FD_log_t *)_file; size_t orig_size = size; /* Save the original size for later */ haddr_t orig_addr = addr; H5_timer_t write_timer; /* Timer for write operation */ H5_timevals_t write_times; /* Elapsed time for write operation */ #ifndef H5_HAVE_PREADWRITE H5_timer_t seek_timer; /* Timer for seek operation */ H5_timevals_t seek_times; /* Elapsed time for seek operation */ #endif /* H5_HAVE_PREADWRITE */ HDoff_t offset = (HDoff_t)addr; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC HDassert(file && file->pub.cls); HDassert(size > 0); HDassert(buf); /* Verify that we are writing out the type of data we allocated in this location */ if (file->flavor) { HDassert(type == H5FD_MEM_DEFAULT || type == (H5FD_mem_t)file->flavor[addr] || (H5FD_mem_t)file->flavor[addr] == H5FD_MEM_DEFAULT); HDassert(type == H5FD_MEM_DEFAULT || type == (H5FD_mem_t)file->flavor[(addr + size) - 1] || (H5FD_mem_t)file->flavor[(addr + size) - 1] == H5FD_MEM_DEFAULT); } /* end if */ /* Check for overflow conditions */ if (!H5F_addr_defined(addr)) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "addr undefined, addr = %llu", (unsigned long long)addr) if (REGION_OVERFLOW(addr, size)) HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, addr = %llu, size = %llu", (unsigned long long)addr, (unsigned long long)size) /* Log the I/O information about the write */ if (file->fa.flags & H5FD_LOG_FILE_WRITE) { size_t tmp_size = size; haddr_t tmp_addr = addr; /* Log information about the number of times these locations are read */ HDassert((addr + size) < file->iosize); while (tmp_size-- > 0) file->nwrite[tmp_addr++]++; } /* end if */ #ifndef H5_HAVE_PREADWRITE /* Seek to the correct location (if we don't have pwrite) */ if (addr != file->pos || OP_WRITE != file->op) { /* Start timer for seek() call */ if (file->fa.flags & H5FD_LOG_TIME_SEEK) { H5_timer_init(&seek_timer); H5_timer_start(&seek_timer); } /* end if */ if (HDlseek(file->fd, (HDoff_t)addr, SEEK_SET) < 0) HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to seek to proper position") /* Stop timer for seek() call */ if (file->fa.flags & H5FD_LOG_TIME_SEEK) H5_timer_stop(&seek_timer); /* Add to the number of seeks, when tracking that */ if (file->fa.flags & H5FD_LOG_NUM_SEEK) file->total_seek_ops++; /* Add to the total seek time, when tracking that */ if (file->fa.flags & H5FD_LOG_TIME_SEEK) { H5_timer_get_times(seek_timer, &seek_times); file->total_seek_time += seek_times.elapsed; } /* end if */ /* Emit log string if we're tracking individual seek events. */ if (file->fa.flags & H5FD_LOG_LOC_SEEK) { HDfprintf(file->logfp, "Seek: From %10" PRIuHADDR " To %10" PRIuHADDR, file->pos, addr); /* Add the seek time, if we're tracking that. * Note that the seek time is NOT emitted for when just H5FD_LOG_TIME_SEEK * is set. */ if (file->fa.flags & H5FD_LOG_TIME_SEEK) HDfprintf(file->logfp, " (%fs @ %f)\n", seek_times.elapsed, seek_timer.initial.elapsed); else HDfprintf(file->logfp, "\n"); } /* end if */ } /* end if */ #endif /* H5_HAVE_PREADWRITE */ /* Start timer for write operation */ if (file->fa.flags & H5FD_LOG_TIME_WRITE) { H5_timer_init(&write_timer); H5_timer_start(&write_timer); } /* end if */ /* * Write the data, being careful of interrupted system calls and partial * results */ while (size > 0) { h5_posix_io_t bytes_in = 0; /* # of bytes to write */ h5_posix_io_ret_t bytes_wrote = -1; /* # of bytes written */ /* Trying to write more bytes than the return type can handle is * undefined behavior in POSIX. */ if (size > H5_POSIX_MAX_IO_BYTES) bytes_in = H5_POSIX_MAX_IO_BYTES; else bytes_in = (h5_posix_io_t)size; do { #ifdef H5_HAVE_PREADWRITE bytes_wrote = HDpwrite(file->fd, buf, bytes_in, offset); if (bytes_wrote > 0) offset += bytes_wrote; #else bytes_wrote = HDwrite(file->fd, buf, bytes_in); #endif /* H5_HAVE_PREADWRITE */ } while (-1 == bytes_wrote && EINTR == errno); if (-1 == bytes_wrote) { /* error */ int myerrno = errno; time_t mytime = HDtime(NULL); offset = HDlseek(file->fd, (HDoff_t)0, SEEK_CUR); if (file->fa.flags & H5FD_LOG_LOC_WRITE) HDfprintf(file->logfp, "Error! Writing: %10" PRIuHADDR "-%10" PRIuHADDR " (%10zu bytes)\n", orig_addr, (orig_addr + orig_size) - 1, orig_size); HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed: time = %s, filename = '%s', file descriptor = %d, errno = %d, " "error message = '%s', buf = %p, total write size = %llu, bytes this sub-write = " "%llu, bytes actually written = %llu, offset = %llu", HDctime(&mytime), file->filename, file->fd, myerrno, HDstrerror(myerrno), buf, (unsigned long long)size, (unsigned long long)bytes_in, (unsigned long long)bytes_wrote, (unsigned long long)offset); } /* end if */ HDassert(bytes_wrote > 0); HDassert((size_t)bytes_wrote <= size); size -= (size_t)bytes_wrote; addr += (haddr_t)bytes_wrote; buf = (const char *)buf + bytes_wrote; } /* end while */ /* Stop timer for write operation */ if (file->fa.flags & H5FD_LOG_TIME_WRITE) H5_timer_stop(&write_timer); /* Add to the number of writes, when tracking that */ if (file->fa.flags & H5FD_LOG_NUM_WRITE) file->total_write_ops++; /* Add to the total write time, when tracking that */ if (file->fa.flags & H5FD_LOG_TIME_WRITE) { H5_timer_get_times(write_timer, &write_times); file->total_write_time += write_times.elapsed; } /* end if */ /* Log information about the write */ if (file->fa.flags & H5FD_LOG_LOC_WRITE) { HDfprintf(file->logfp, "%10" PRIuHADDR "-%10" PRIuHADDR " (%10zu bytes) (%s) Written", orig_addr, (orig_addr + orig_size) - 1, orig_size, flavors[type]); /* Check if this is the first write into a "default" section, grabbed by the metadata agregation * algorithm */ if (file->fa.flags & H5FD_LOG_FLAVOR) { if ((H5FD_mem_t)file->flavor[orig_addr] == H5FD_MEM_DEFAULT) { HDmemset(&file->flavor[orig_addr], (int)type, orig_size); HDfprintf(file->logfp, " (fresh)"); } /* end if */ } /* end if */ /* Add the write time, if we're tracking that. * Note that the write time is NOT emitted for when just H5FD_LOG_TIME_WRITE * is set. */ if (file->fa.flags & H5FD_LOG_TIME_WRITE) HDfprintf(file->logfp, " (%fs @ %f)\n", write_times.elapsed, write_timer.initial.elapsed); else HDfprintf(file->logfp, "\n"); } /* end if */ /* Update current position and eof */ file->pos = addr; file->op = OP_WRITE; if (file->pos > file->eof) file->eof = file->pos; done: if (ret_value < 0) { /* Reset last file I/O information */ file->pos = HADDR_UNDEF; file->op = OP_UNKNOWN; } /* end if */ FUNC_LEAVE_NOAPI(ret_value) } /* end H5FD__log_write() */ /*------------------------------------------------------------------------- * Function: H5FD__log_truncate * * Purpose: Makes sure that the true file size is the same (or larger) * than the end-of-address. * * Return: SUCCEED/FAIL * * Programmer: Robb Matzke * Wednesday, August 4, 1999 * *------------------------------------------------------------------------- */ static herr_t H5FD__log_truncate(H5FD_t *_file, hid_t H5_ATTR_UNUSED dxpl_id, hbool_t H5_ATTR_UNUSED closing) { H5FD_log_t *file = (H5FD_log_t *)_file; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC HDassert(file); /* Extend the file to make sure it's large enough */ if (!H5F_addr_eq(file->eoa, file->eof)) { H5_timer_t trunc_timer; /* Timer for truncate operation */ H5_timevals_t trunc_times; /* Elapsed time for truncate operation */ /* Start timer for truncate operation */ if (file->fa.flags & H5FD_LOG_TIME_TRUNCATE) { H5_timer_init(&trunc_timer); H5_timer_start(&trunc_timer); } /* end if */ #ifdef H5_HAVE_WIN32_API { LARGE_INTEGER li; /* 64-bit (union) integer for SetFilePointer() call */ DWORD dwPtrLow; /* Low-order pointer bits from SetFilePointer() * Only used as an error code here. */ /* Windows uses this odd QuadPart union for 32/64-bit portability */ li.QuadPart = (__int64)file->eoa; /* Extend the file to make sure it's large enough. * * Since INVALID_SET_FILE_POINTER can technically be a valid return value * from SetFilePointer(), we also need to check GetLastError(). */ dwPtrLow = SetFilePointer(file->hFile, li.LowPart, &li.HighPart, FILE_BEGIN); if (INVALID_SET_FILE_POINTER == dwPtrLow) { DWORD dwError; /* DWORD error code from GetLastError() */ dwError = GetLastError(); if (dwError != NO_ERROR) HGOTO_ERROR(H5E_FILE, H5E_FILEOPEN, FAIL, "unable to set file pointer") } /* end if */ if (0 == SetEndOfFile(file->hFile)) HGOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly") } #else /* H5_HAVE_WIN32_API */ /* Truncate/extend the file */ if (-1 == HDftruncate(file->fd, (HDoff_t)file->eoa)) HSYS_GOTO_ERROR(H5E_IO, H5E_SEEKERROR, FAIL, "unable to extend file properly") #endif /* H5_HAVE_WIN32_API */ /* Stop timer for truncate operation */ if (file->fa.flags & H5FD_LOG_TIME_TRUNCATE) H5_timer_stop(&trunc_timer); /* Add to the number of truncates, when tracking that */ if (file->fa.flags & H5FD_LOG_NUM_TRUNCATE) file->total_truncate_ops++; /* Add to the total truncate time, when tracking that */ if (file->fa.flags & H5FD_LOG_TIME_TRUNCATE) { H5_timer_get_times(trunc_timer, &trunc_times); file->total_truncate_time += trunc_times.elapsed; } /* end if */ /* Emit log string if we're tracking individual truncate events. */ if (file->fa.flags & H5FD_LOG_TRUNCATE) { HDfprintf(file->logfp, "Truncate: To %10" PRIuHADDR, file->eoa); /* Add the truncate time, if we're tracking that. * Note that the truncate time is NOT emitted for when just H5FD_LOG_TIME_TRUNCATE * is set. */ if (file->fa.flags & H5FD_LOG_TIME_TRUNCATE) HDfprintf(file->logfp, " (%fs @ %f)\n", trunc_times.elapsed, trunc_timer.initial.elapsed); else HDfprintf(file->logfp, "\n"); } /* end if */ /* Update the eof value */ file->eof = file->eoa; /* Reset last file I/O information */ file->pos = HADDR_UNDEF; file->op = OP_UNKNOWN; } /* end if */ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5FD__log_truncate() */ /*------------------------------------------------------------------------- * Function: H5FD__log_lock * * Purpose: Place a lock on the file * * Return: Success: SUCCEED * Failure: FAIL, file not locked. * * Programmer: Vailin Choi; May 2013 * *------------------------------------------------------------------------- */ static herr_t H5FD__log_lock(H5FD_t *_file, hbool_t rw) { H5FD_log_t *file = (H5FD_log_t *)_file; /* VFD file struct */ int lock_flags; /* file locking flags */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC /* Sanity check */ HDassert(file); /* Set exclusive or shared lock based on rw status */ lock_flags = rw ? LOCK_EX : LOCK_SH; /* Place a non-blocking lock on the file */ if (HDflock(file->fd, lock_flags | LOCK_NB) < 0) { if (file->ignore_disabled_file_locks && ENOSYS == errno) { /* When errno is set to ENOSYS, the file system does not support * locking, so ignore it. */ errno = 0; } else HSYS_GOTO_ERROR(H5E_VFL, H5E_CANTLOCKFILE, FAIL, "unable to lock file") } done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5FD__log_lock() */ /*------------------------------------------------------------------------- * Function: H5FD__log_unlock * * Purpose: Remove the existing lock on the file * * Return: SUCCEED/FAIL * * Programmer: Vailin Choi; May 2013 * *------------------------------------------------------------------------- */ static herr_t H5FD__log_unlock(H5FD_t *_file) { H5FD_log_t *file = (H5FD_log_t *)_file; /* VFD file struct */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC HDassert(file); if (HDflock(file->fd, LOCK_UN) < 0) { if (file->ignore_disabled_file_locks && ENOSYS == errno) { /* When errno is set to ENOSYS, the file system does not support * locking, so ignore it. */ errno = 0; } else HSYS_GOTO_ERROR(H5E_VFL, H5E_CANTUNLOCKFILE, FAIL, "unable to unlock file") } done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5FD__log_unlock() */