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 COPYING file, which can be found at the root of the source code       *
8  * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases.  *
9  * If you do not have access to either file, you may request a copy from     *
10  * help@hdfgroup.org.                                                        *
11  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12 
13 /*
14  * This is copied from use_append_chunk.c with modifications to show
15  * the usage of H5Odisable_mdc_flushes/H5Oenable_mdc_flushes/H5Oare_mdc_flushes_disabled public routines.
16  */
17 
18 #include "h5test.h"
19 
20 /* This test uses many POSIX things that are not available on
21  * Windows. We're using a check for fork(2) here as a proxy for
22  * all POSIX/Unix/Linux things until this test can be made
23  * more platform-independent.
24  */
25 #ifdef H5_HAVE_FORK
26 
27 #define H5D_FRIEND        /*suppress error about including H5Dpkg      */
28 #define H5D_TESTING
29 #include "H5Dpkg.h"
30 
31 /* Global Variable definitions */
32 const char *progname_g="use_disable_mdc_flushes";    /* program name */
33 
34 /* these two definitions must match each other */
35 #define UC_DATATYPE             H5T_NATIVE_SHORT    /* use case HDF5 data type */
36 #define UC_CTYPE                short               /* use case C data type */
37 #define UC_RANK                 3                   /* use case dataset rank */
38 #define Chunksize_DFT           256     /* chunksize default */
39 #define Hgoto_error(val)        {ret_value=val; goto done;}
40 
41 
42 char *filename_g;
43 hsize_t nplanes_g;
44 int use_swmr_g;
45 int chunkplanes_g;
46 int chunksize_g;
47 hsize_t dims_g[UC_RANK];
48 hsize_t max_dims_g[UC_RANK];
49 hsize_t chunkdims_g[UC_RANK];
50 
51 static void usage(const char *prog);
52 static int parse_option(int argc, char * const argv[]);
53 static void show_parameters(void);
54 static int create_file(void);
55 static int setup_parameters(int argc, char * const argv[]);
56 
57 /*
58  * Note: Long options are not yet implemented.
59  *
60  * usage: use_disable_mdc_flushes [OPTIONS]
61  * OPTIONS
62  *  -h, --help           Print a usage message and exit
63  *  -f FN                 Test file name [default: use_disable_mdc_flushes.h5]
64  *  -n N, --nplanes=N     Number of planes to write. [default: 1000]
65  *  -s N, --swmr=N        Use SWMR mode (0: no, non-0: yes) default is yes
66  *  -z N, --chunksize=N   Chunk size [default: 256]
67  *  -y N, --chunkplanes=N Number of planes per chunk [default: 1]
68  */
69 static void
usage(const char * prog)70 usage(const char *prog)
71 {
72     HDfprintf(stderr, "usage: %s [OPTIONS]\n", prog);
73     HDfprintf(stderr, "  OPTIONS\n");
74     HDfprintf(stderr, "     -h          Print a usage message and exit\n");
75     HDfprintf(stderr, "     -f FN       Test file name [default: %s.h5]\n", prog);
76     HDfprintf(stderr, "     -n N        Number of planes to write. [default: 1000]\n");
77     HDfprintf(stderr, "     -s N        Use SWMR mode (0: no, non-0: yes) default is yes\n");
78     HDfprintf(stderr, "     -z N        Chunk size [default: %d]\n", Chunksize_DFT);
79     HDfprintf(stderr, "     -y N        Number of planes per chunk [default: 1]\n");
80     HDfprintf(stderr, "\n");
81 } /* usage() */
82 
83 
84 /*
85  * Setup Use Case parameters by parsing command line options.
86  * Setup default values if not set by options. */
87 static int
parse_option(int argc,char * const argv[])88 parse_option(int argc, char * const argv[])
89 {
90     int ret_value=0;
91     int c;
92     /* command line options: See function usage for a description */
93     const char *cmd_options = "f:hn:s:y:z:";
94 
95     /* suppress getopt from printing error */
96     opterr = 0;
97 
98     while (1){
99     c = getopt (argc, argv, cmd_options);
100     if (-1 == c)
101         break;
102     switch (c) {
103     case 'h':
104         usage(progname_g);
105         HDexit(EXIT_SUCCESS);
106         break;
107     case 'f':    /* usecase data file name */
108         filename_g = optarg;
109         break;
110     case 'n':    /* number of planes to write/read */
111         if ((nplanes_g = HDatoi(optarg)) <= 0){
112         HDfprintf(stderr, "bad number of planes %s, must be a positive integer\n", optarg);
113         usage(progname_g);
114         Hgoto_error(-1);
115         };
116         break;
117     case 's':    /* use swmr file open mode */
118         if ((use_swmr_g = HDatoi(optarg)) < 0){
119         HDfprintf(stderr, "swmr value should be 0(no) or 1(yes)\n");
120         usage(progname_g);
121         Hgoto_error(-1);
122         };
123         break;
124     case 'y':    /* Number of planes per chunk */
125         if ((chunkplanes_g = HDatoi(optarg)) <= 0){
126         HDfprintf(stderr, "bad number of planes per chunk %s, must be a positive integer\n", optarg);
127         usage(progname_g);
128         Hgoto_error(-1);
129         };
130         break;
131     case 'z':    /* size of chunk=(z,z) */
132         if ((chunksize_g = HDatoi(optarg)) <= 0){
133         HDfprintf(stderr, "bad chunksize %s, must be a positive integer\n", optarg);
134         usage(progname_g);
135         Hgoto_error(-1);
136         };
137         break;
138     case '?':
139         HDfprintf(stderr, "getopt returned '%c'.\n", c);
140         Hgoto_error(-1);
141     default:
142         HDfprintf(stderr, "getopt returned unexpected value.\n");
143         HDfprintf(stderr, "Unexpected value is %d\n", c);
144         Hgoto_error(-1);
145     }
146     }
147 
148     /* set test file name if not given */
149     if (!filename_g){
150     /* default data file name is <progname>.h5 */
151     if ((filename_g = (char*)HDmalloc(HDstrlen(progname_g)+4))==NULL) {
152         HDfprintf(stderr, "malloc: failed\n");
153         Hgoto_error(-1);
154     };
155     HDstrcpy(filename_g, progname_g);
156     HDstrcat(filename_g, ".h5");
157     }
158 
159 done:
160     /* All done. */
161     return(ret_value);
162 } /* parse_option() */
163 
164 /* Show parameters used for this use case */
165 static void
show_parameters(void)166 show_parameters(void)
167 {
168     HDprintf("===Parameters used:===\n");
169     HDprintf("chunk dims=(%llu, %llu, %llu)\n", (unsigned long long)chunkdims_g[0],
170         (unsigned long long)chunkdims_g[1], (unsigned long long)chunkdims_g[2]);
171     HDprintf("dataset max dims=(%llu, %llu, %llu)\n", (unsigned long long)max_dims_g[0],
172         (unsigned long long)max_dims_g[1], (unsigned long long)max_dims_g[2]);
173     HDprintf("number of planes to write=%llu\n", (unsigned long long)nplanes_g);
174     HDprintf("using SWMR mode=%s\n", use_swmr_g ? "yes(1)" : "no(0)");
175     HDprintf("data filename=%s\n", filename_g);
176     HDprintf("===Parameters shown===\n");
177 } /* show_parameters() */
178 
179 /*
180  * Setup parameters for the use case.
181  * Return: 0 succeed; -1 fail.
182  */
183 static int
setup_parameters(int argc,char * const argv[])184 setup_parameters(int argc, char * const argv[])
185 {
186     /* use case defaults */
187     chunksize_g = Chunksize_DFT;
188     use_swmr_g = 1;    /* use swmr open */
189     chunkplanes_g = 1;
190 
191     /* parse options */
192     if (parse_option(argc, argv) < 0){
193     return(-1);
194     }
195     /* set chunk dims */
196     chunkdims_g[0] = chunkplanes_g;
197     chunkdims_g[1]= chunkdims_g[2] = chunksize_g;
198 
199     /* set dataset initial and max dims */
200     dims_g[0] = 0;
201     max_dims_g[0] = H5S_UNLIMITED;
202     dims_g[1] = dims_g[2] = max_dims_g[1] = max_dims_g[2] = chunksize_g;
203 
204     /* set nplanes */
205     if (nplanes_g == 0)
206         nplanes_g = chunksize_g;
207 
208     /* show parameters and return */
209     show_parameters();
210     return(0);
211 } /* setup_parameters() */
212 
213 /*
214  * Create the skeleton use case file for testing.
215  * It has one 3d dataset using chunked storage.
216  * The dataset is (unlimited, chunksize, chunksize).
217  * Dataset type is 2 bytes integer.
218  * It starts out "empty", i.e., first dimension is 0.
219  *
220  * Return: 0 succeed; -1 fail.
221  */
222 static int
create_file(void)223 create_file(void)
224 {
225     hsize_t dims[3];        /* Dataset starting dimensions */
226     hid_t fid;          /* File ID for new HDF5 file */
227     hid_t dcpl;         /* Dataset creation property list */
228     hid_t sid;          /* Dataspace ID */
229     hid_t dsid;         /* Dataset ID */
230     hid_t fapl;         /* File access property list */
231     H5D_chunk_index_t idx_type; /* Chunk index type */
232 
233     /* Create the file */
234     if((fapl = H5Pcreate(H5P_FILE_ACCESS)) < 0)
235         return -1;
236     if(H5Pset_libver_bounds(fapl, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0)
237         return -1;
238     if((fid = H5Fcreate(filename_g, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0)
239         return -1;
240 
241     /* Set up dimension sizes */
242     dims[0] = 0;
243     dims[1] = dims[2] = max_dims_g[1];
244 
245     /* Create dataspace for creating datasets */
246     if((sid = H5Screate_simple(3, dims, max_dims_g)) < 0)
247         return -1;
248 
249     /* Create dataset creation property list */
250     if((dcpl = H5Pcreate(H5P_DATASET_CREATE)) < 0)
251         return -1;
252     if(H5Pset_chunk(dcpl, 3, chunkdims_g) < 0)
253         return -1;
254 
255     /* create dataset of progname */
256     if((dsid = H5Dcreate2(fid, progname_g, UC_DATATYPE, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT)) < 0)
257     return -1;
258 
259     /* Check that the chunk index type is not version 1 B-tree.
260      * Version 1 B-trees are not supported under SWMR.
261      */
262     if(H5D__layout_idx_type_test(dsid, &idx_type) < 0)
263         return -1;
264     if(idx_type == H5D_CHUNK_IDX_BTREE) {
265         HDfprintf(stderr, "ERROR: Chunk index is version 1 B-tree: aborting.\n");
266         return -1;
267     }
268 
269     /* Close everything */
270     if(H5Dclose(dsid) < 0)
271     return -1;
272     if(H5Pclose(fapl) < 0)
273         return -1;
274     if(H5Pclose(dcpl) < 0)
275         return -1;
276     if(H5Sclose(sid) < 0)
277         return -1;
278     if(H5Fclose(fid) < 0)
279         return -1;
280 
281     return 0;
282 } /* create_file() */
283 
284 /*
285  * Append planes, each of (1,2*chunksize,2*chunksize) to the dataset.
286  * In other words, 4 chunks are appended to the dataset at a time.
287  * Fill each plane with the plane number and then write it at the nth plane.
288  * Increase the plane number and repeat till the end of dataset, when it
289  * reaches chunksize long. End product is a (2*chunksize)^3 cube.
290  *
291  * Return: 0 succeed; -1 fail.
292  */
293 static int
write_file(void)294 write_file(void)
295 {
296     hid_t    fid;              /* File ID for new HDF5 file */
297     hid_t    dsid;             /* dataset ID */
298     hid_t       fapl;             /* File access property list */
299     hid_t    dcpl;          /* Dataset creation property list */
300     char    *name;
301     UC_CTYPE    *buffer, *bufptr;    /* data buffer */
302     hsize_t    cz=chunksize_g;        /* Chunk size */
303     hid_t    f_sid;            /* dataset file space id */
304     hid_t    m_sid;            /* memory space id */
305     int        rank;            /* rank */
306     hsize_t     chunk_dims[3];    /* Chunk dimensions */
307     hsize_t    dims[3];        /* Dataspace dimensions */
308     hsize_t    memdims[3];     /* Memory space dimensions */
309     hsize_t    start[3] = {0,0,0}, count[3];    /* Hyperslab selection values */
310     hbool_t     disabled;       /* Object's disabled status */
311     hsize_t     i, j, k;
312 
313     name = filename_g;
314 
315     /* Open the file */
316     if((fapl = H5Pcreate(H5P_FILE_ACCESS)) < 0)
317         return -1;
318     if(use_swmr_g)
319         if(H5Pset_libver_bounds(fapl, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0)
320             return -1;
321     if((fid = H5Fopen(name, H5F_ACC_RDWR | (use_swmr_g ? H5F_ACC_SWMR_WRITE : 0), fapl)) < 0){
322     HDfprintf(stderr, "H5Fopen failed\n");
323         return -1;
324     }
325 
326     /* Open the dataset of the program name */
327     if((dsid = H5Dopen2(fid, progname_g, H5P_DEFAULT)) < 0){
328     HDfprintf(stderr, "H5Dopen2 failed\n");
329     return -1;
330     }
331 
332     /* Disabled mdc flushed for the dataset */
333     if(H5Odisable_mdc_flushes(dsid) < 0) {
334     HDfprintf(stderr, "H5Odisable_mdc_flushes failed\n");
335     return -1;
336     }
337 
338     /* Get mdc disabled status of the dataset */
339     if(H5Oare_mdc_flushes_disabled(dsid, &disabled) < 0) {
340     HDfprintf(stderr, "H5Oare_mdc_flushes_disabled failed\n");
341     return -1;
342     } else if(disabled)
343     HDprintf("Dataset has disabled mdc flushes.\n");
344     else
345     HDprintf("Dataset should have disabled its mdc flushes.\n");
346 
347     /* Find chunksize used */
348     if ((dcpl = H5Dget_create_plist(dsid)) < 0){
349     HDfprintf(stderr, "H5Dget_create_plist failed\n");
350     return -1;
351     }
352     if (H5D_CHUNKED != H5Pget_layout(dcpl)){
353     HDfprintf(stderr, "storage layout is not chunked\n");
354     return -1;
355     }
356     if ((rank = H5Pget_chunk(dcpl, 3, chunk_dims)) != 3){
357     HDfprintf(stderr, "storage rank is not 3\n");
358     return -1;
359     }
360 
361     /* verify chunk_dims against set paramenters */
362     if (chunk_dims[0]!= chunkdims_g[0] || chunk_dims[1] != cz || chunk_dims[2] != cz){
363     HDfprintf(stderr, "chunk size is not as expected. Got dims=(%llu,%llu,%llu)\n",
364         (unsigned long long)chunk_dims[0], (unsigned long long)chunk_dims[1],
365             (unsigned long long)chunk_dims[2]);
366     return -1;
367     }
368 
369     /* allocate space for data buffer 1 X dims[1] X dims[2] of UC_CTYPE */
370     memdims[0]=1;
371     memdims[1] = dims_g[1];
372     memdims[2] = dims_g[2];
373     if ((buffer=(UC_CTYPE*)HDmalloc((size_t)memdims[1]*(size_t)memdims[2]*sizeof(UC_CTYPE)))==NULL) {
374     HDfprintf(stderr, "malloc: failed\n");
375     return -1;
376     };
377 
378     /*
379      * Get dataset rank and dimension.
380      */
381     f_sid = H5Dget_space(dsid);    /* Get filespace handle first. */
382     rank  = H5Sget_simple_extent_ndims(f_sid);
383     if (rank != UC_RANK){
384     HDfprintf(stderr, "rank(%d) of dataset does not match\n", rank);
385     return -1;
386     }
387     if (H5Sget_simple_extent_dims(f_sid, dims, NULL) < 0){
388     HDfprintf(stderr, "H5Sget_simple_extent_dims got error\n");
389     return -1;
390     }
391     HDprintf("dataset rank %d, dimensions %llu x %llu x %llu\n",
392     rank, (unsigned long long)(dims[0]), (unsigned long long)(dims[1]),
393            (unsigned long long)(dims[2]));
394     /* verify that file space dims are as expected and are consistent with memory space dims */
395     if (dims[0] != 0 || dims[1] != memdims[1] || dims[2] != memdims[2]){
396     HDfprintf(stderr, "dataset is not empty. Got dims=(%llu,%llu,%llu)\n",
397         (unsigned long long)dims[0], (unsigned long long)dims[1],
398             (unsigned long long)dims[2]);
399     return -1;
400     }
401 
402     /* setup mem-space for buffer */
403     if ((m_sid=H5Screate_simple(rank, memdims, NULL))<0){
404     HDfprintf(stderr, "H5Screate_simple for memory failed\n");
405     return -1;
406     };
407 
408     /* write planes */
409     count[0]=1;
410     count[1]=dims[1];
411     count[2]=dims[2];
412     for (i=0; i<nplanes_g; i++){
413     /* fill buffer with value i+1 */
414     bufptr = buffer;
415     for (j=0; j<dims[1]; j++)
416         for (k=0; k<dims[2]; k++)
417         *bufptr++ = i;
418 
419     /* extend the dataset by one for new plane */
420     dims[0]=i+1;
421         if(H5Dset_extent(dsid, dims) < 0){
422         HDfprintf(stderr, "H5Dset_extent failed\n");
423             return -1;
424     }
425 
426         /* Get the dataset's dataspace */
427         if((f_sid = H5Dget_space(dsid)) < 0){
428         HDfprintf(stderr, "H5Dset_extent failed\n");
429             return -1;
430     }
431 
432     start[0]=i;
433         /* Choose the next plane to write */
434         if(H5Sselect_hyperslab(f_sid, H5S_SELECT_SET, start, NULL, count, NULL) < 0){
435         HDfprintf(stderr, "Failed H5Sselect_hyperslab\n");
436             return -1;
437     }
438 
439         /* Write plane to the dataset */
440         if(H5Dwrite(dsid, UC_DATATYPE, m_sid, f_sid, H5P_DEFAULT, buffer) < 0){
441         HDfprintf(stderr, "Failed H5Dwrite\n");
442             return -1;
443     }
444 
445     /* Flush the dataset for every "chunkplanes_g" planes */
446     if(!((i + 1) % (hsize_t)chunkplanes_g)) {
447         if(H5Dflush(dsid) < 0) {
448         HDfprintf(stderr, "Failed to H5Dflush dataset\n");
449         return -1;
450         }
451     }
452     }
453 
454     if(H5Dflush(dsid) < 0) {
455     HDfprintf(stderr, "Failed to H5Dflush dataset\n");
456     return -1;
457     }
458 
459     /* Enable mdc flushes for the dataset */
460     /* Closing the dataset later will enable mdc flushes automatically if this is not done */
461     if(disabled)
462     if(H5Oenable_mdc_flushes(dsid) < 0) {
463         HDfprintf(stderr, "Failed to H5Oenable_mdc_flushes\n");
464         return -1;
465     }
466 
467     /* Done writing. Free/Close all resources including data file */
468     HDfree(buffer);
469 
470     if(H5Dclose(dsid) < 0){
471     HDfprintf(stderr, "Failed to close datasete\n");
472     return -1;
473     }
474     if(H5Sclose(m_sid) < 0){
475     HDfprintf(stderr, "Failed to close memory space\n");
476     return -1;
477     }
478     if(H5Sclose(f_sid) < 0){
479     HDfprintf(stderr, "Failed to close file space\n");
480     return -1;
481     }
482     if(H5Pclose(fapl) < 0){
483     HDfprintf(stderr, "Failed to property list\n");
484     return -1;
485     }
486     if(H5Fclose(fid) < 0){
487     HDfprintf(stderr, "Failed to close file id\n");
488     return -1;
489     }
490 
491     return 0;
492 } /* write_file() */
493 
494 
495 
496 /* Overall Algorithm:
497  * Parse options from user;
498  * Generate/pre-created test files needed and close it;
499  * Write to the file.
500  */
501 int
main(int argc,char * argv[])502 main(int argc, char *argv[])
503 {
504     int ret_value = 0;
505 
506     /* initialization */
507     if(setup_parameters(argc, argv) < 0)
508     Hgoto_error(1);
509 
510     /* ============*/
511     /* Create file */
512     /* ============*/
513     HDprintf("Creating skeleton data file for testing H5Odisable_mdc_flushes()...\n");
514     if(create_file() < 0) {
515         HDfprintf(stderr, "***encounter error\n");
516         Hgoto_error(1);
517     } /* end if */
518     else
519         HDprintf("File created.\n");
520 
521     HDprintf("writing to the file\n");
522     if(write_file() < 0) {
523         HDfprintf(stderr, "write_file encountered error\n");
524         Hgoto_error(1);
525     }
526 
527 done:
528     /* Print result and exit */
529     if(ret_value != 0)
530         HDprintf("Error(s) encountered\n");
531     else
532         HDprintf("All passed\n");
533 
534     return(ret_value);
535 }
536 
537 #else /* H5_HAVE_FORK */
538 
539 int
main(void)540 main(void)
541 {
542     HDfprintf(stderr, "Non-POSIX platform. Skipping.\n");
543     HDexit(EXIT_SUCCESS);
544 } /* end main() */
545 
546 #endif /* H5_HAVE_FORK */
547 
548