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