1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  * Copyright by The HDF Group.                                               *
3  * Copyright by the Board of Trustees of the University of Illinois.         *
4  * All rights reserved.                                                      *
5  *                                                                           *
6  * This file is part of HDF5.  The full HDF5 copyright notice, including     *
7  * terms governing use, modification, and redistribution, is contained in    *
8  * the COPYING file, which can be found at the root of the source code       *
9  * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases.  *
10  * If you do not have access to either file, you may request a copy from     *
11  * help@hdfgroup.org.                                                        *
12  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13 
14 /*
15  * Programmer:  Raymond Lu <songyulu@hdfgroup.org>
16  *              7 September 2010
17  *
18  * Purpose:     Make sure dataset, file, and library can close properly when a
19  *              mandatory filter fails.
20  */
21 
22 #include "h5test.h"
23 
24 #define DSET_NAME 		"dset_fail"
25 #define H5Z_FILTER_FAIL_TEST    312
26 #define DIM                     10
27 #define FILTER_CHUNK_DIM        2
28 
29 const char *FILENAME[] = {
30     "filter_fail_with_cache",
31     "filter_fail_without_cache",
32     NULL
33 };
34 
35 static size_t filter_fail(unsigned int flags, size_t cd_nelmts,
36     const unsigned int *cd_values, size_t nbytes, size_t *buf_size, void **buf);
37 
38 /* This message derives from H5Z */
39 const H5Z_class2_t H5Z_FAIL_TEST[1] = {{
40     H5Z_CLASS_T_VERS,           /* H5Z_class_t version */
41     H5Z_FILTER_FAIL_TEST,	/* Filter id number		*/
42     1, 1,                       /* Encoding and decoding enabled */
43     "filter_fail_test",		/* Filter name for debugging	*/
44     NULL,                       /* The "can apply" callback     */
45     NULL,                       /* The "set local" callback     */
46     filter_fail,		/* The actual filter function	*/
47 }};
48 
49 
50 /*-------------------------------------------------------------------------
51  * Function:    filter_fail
52  *
53  * Purpose:     For testing library's behavior when a mandatory filter
54  *              fails to write a chunk.
55  *
56  * Return:	Success:	Data chunk size
57  *		Failure:	0
58  *
59  * Programmer:	Raymond Lu
60  *              7 September 2010
61  *
62  *-------------------------------------------------------------------------
63  */
64 static size_t
filter_fail(unsigned int flags,size_t H5_ATTR_UNUSED cd_nelmts,const unsigned int H5_ATTR_UNUSED * cd_values,size_t nbytes,size_t * buf_size,void ** buf)65 filter_fail(unsigned int flags, size_t H5_ATTR_UNUSED cd_nelmts,
66       const unsigned int H5_ATTR_UNUSED *cd_values, size_t nbytes,
67       size_t *buf_size, void **buf)
68 {
69     int   *dst = (int*)(*buf);
70     size_t         ret_value = 0;
71 
72     if(flags & H5Z_FLAG_REVERSE) { /* do nothing during read */
73         *buf_size = nbytes;
74         ret_value = nbytes;
75     }  /* end if */
76     else { /* Write data */
77         /* If it's the last chunk, pretend to fail. Otherwise, do nothing. */
78         if(*dst == 8 || *dst == 9) {
79             ret_value = 0;
80         } else {
81             *buf_size = nbytes;
82             ret_value = *buf_size;
83         }
84     } /* end else */
85 
86     return ret_value;
87 } /* end filter_fail() */
88 
89 
90 /*-------------------------------------------------------------------------
91  * Function:    test_filter_write_failure
92  *
93  * Purpose:     Tests the library's behavior when a mandate filter returns
94  *              failure.  There're only 5 chunks with each of them having
95  *              2 integers.  The filter will fail in the last chunk.  The
96  *              dataset should release all resources even though the last
97  *              chunk can't be flushed to file.  The file should close
98  *              successfully.
99  *
100  * Return:
101  *              Success:         0
102  *              Failure:         -1
103  *
104  * Programmer:  Raymond Lu
105  *              25 August 2010
106  *
107  * Modifications:
108  *              Raymond Lu
109  *              5 Oct 2010
110  *              Test when the chunk cache is enable and disabled to make
111  *              sure the library behaves properly.
112  *-------------------------------------------------------------------------
113  */
114 static herr_t
test_filter_write(char * file_name,hid_t my_fapl,hbool_t cache_enabled)115 test_filter_write(char *file_name, hid_t my_fapl, hbool_t cache_enabled)
116 {
117     hid_t        file = -1;
118     hid_t        dataset=-1;                /* dataset ID */
119     hid_t        sid=-1;                   /* dataspace ID */
120     hid_t        dcpl=-1;                  /* dataset creation property list ID */
121     hsize_t      dims[1]={DIM};           /* dataspace dimension - 10*/
122     hsize_t      chunk_dims[1]={FILTER_CHUNK_DIM}; /* chunk dimension - 2*/
123     int          points[DIM];          /* Data */
124     herr_t       ret;                   /* generic return value */
125     int          i;
126 
127     if(cache_enabled) {
128         TESTING("data writing when a mandatory filter fails and chunk cache is enabled");
129     } else {
130         TESTING("data writing when a mandatory filter fails and chunk cache is disabled");
131     }
132 
133     /* Create file */
134     if((file = H5Fcreate(file_name, H5F_ACC_TRUNC, H5P_DEFAULT, my_fapl)) < 0) TEST_ERROR
135 
136     /* create the data space */
137     if((sid = H5Screate_simple(1, dims, NULL)) < 0) TEST_ERROR
138 
139     /* Create dcpl and register the filter */
140     if((dcpl = H5Pcreate(H5P_DATASET_CREATE)) < 0) TEST_ERROR
141 
142     if(H5Pset_chunk(dcpl, 1, chunk_dims) < 0) TEST_ERROR
143 
144     if(H5Zregister (H5Z_FAIL_TEST) < 0) TEST_ERROR
145 
146     /* Check that the filter was registered */
147     if(TRUE != H5Zfilter_avail(H5Z_FILTER_FAIL_TEST)) FAIL_STACK_ERROR
148 
149     /* Enable the filter as mandatory */
150     if(H5Pset_filter(dcpl, H5Z_FILTER_FAIL_TEST, 0, (size_t)0, NULL) < 0)
151         TEST_ERROR
152 
153     /* create a dataset */
154     if((dataset = H5Dcreate2(file, DSET_NAME, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT)) < 0) TEST_ERROR
155 
156     /* Initialize the write buffer */
157     for(i = 0; i < DIM; i++)
158         points[i] = i;
159 
160     /* Write data.  If the chunk cache is enabled, H5Dwrite should succeed.  If it is
161      * diabled, H5Dwrite should fail. */
162     if(cache_enabled) {
163         if(H5Dwrite(dataset, H5T_NATIVE_INT, H5S_ALL, sid, H5P_DEFAULT, points) < 0)
164             TEST_ERROR
165     } else {
166         /* Data writing should fail */
167         H5E_BEGIN_TRY {
168             ret = H5Dwrite(dataset, H5T_NATIVE_INT, H5S_ALL, sid, H5P_DEFAULT, points);
169         } H5E_END_TRY;
170         if(ret >= 0) {
171 	    H5_FAILED();
172 	    puts("    Data writing is supposed to fail because the chunk can't be written to file.");
173 	    TEST_ERROR
174         }
175     }
176 
177     /* clean up objects used for this test */
178     if(H5Pclose (dcpl) < 0) TEST_ERROR
179     if(H5Sclose (sid) < 0) TEST_ERROR
180 
181     /* Close dataset.  If the chunk cache is enabled, the flushing of chunks should fail
182      * during H5Dclose.  If it is diabled, H5Dwrite should fail but H5Dclose should succeed. */
183     if(cache_enabled) {
184         H5E_BEGIN_TRY {
185             ret = H5Dclose (dataset);
186         } H5E_END_TRY;
187         if(ret >= 0) {
188 	    H5_FAILED();
189 	    puts("    Dataset is supposed to fail because the chunk can't be flushed to file.");
190 	    TEST_ERROR
191         }
192     } else {
193         if(H5Dclose (dataset) < 0)
194             TEST_ERROR
195     }
196 
197     /* Even though H5Dclose or H5Dwrite fails, it should release all resources.
198      * So the file should close successfully. */
199     if(H5Fclose (file) < 0) TEST_ERROR
200 
201     PASSED();
202     return 0;
203 
204 error:
205     H5E_BEGIN_TRY {
206         H5Pclose(dcpl);
207         H5Sclose(sid);
208         H5Dclose(dataset);
209         H5Fclose(file);
210     } H5E_END_TRY;
211     return -1;
212 } /* end test_filter_write() */
213 
214 
215 /*-------------------------------------------------------------------------
216  * Function:    test_filter_read
217  *
218  * Purpose:     Tests the library's behavior when a mandate filter returns
219  *              failure.  The first 4 chunks should be in the file.  The
220  *              last chunk should not.
221  *
222  * Return:
223  *              Success:         0
224  *              Failure:         -1
225  *
226  * Programmer:  Raymond Lu
227  *              25 August 2010
228  *
229  * Modifications:
230  *
231  *-------------------------------------------------------------------------
232  */
233 static herr_t
test_filter_read(char * file_name,hid_t my_fapl)234 test_filter_read(char *file_name, hid_t my_fapl)
235 {
236     hid_t        file = -1;
237     hid_t        dataset=-1;                /* dataset ID */
238     hid_t        sid = -1;
239     hid_t        mspace = -1;
240     hsize_t      dims[1]={DIM};           /* dataspace dimension - 10*/
241     int          rbuf[DIM];          /* Data */
242     hsize_t      dset_size = 0;          /* Dataset storage size */
243     hsize_t      hs_offset[H5S_MAX_RANK];
244     hsize_t      hs_size[H5S_MAX_RANK];
245     hsize_t      stride[1] = {2};
246     hsize_t      zero[8];
247     hsize_t      nelmts = DIM/2;
248     int          i;
249 
250     TESTING("data reading when a mandatory filter fails");
251 
252     /* Open file */
253     if((file = H5Fopen(file_name, H5F_ACC_RDONLY, my_fapl)) < 0) TEST_ERROR
254 
255     /* Open dataset */
256     if((dataset = H5Dopen2(file, DSET_NAME, H5P_DEFAULT)) < 0) TEST_ERROR
257 
258     /* Verify the storage size is equal to 4 chunks */
259     if((dset_size = H5Dget_storage_size(dataset)) == 0) TEST_ERROR
260 
261     if(dset_size != 4 * FILTER_CHUNK_DIM * sizeof(int)) TEST_ERROR
262 
263     /* Read the chunks */
264     HDmemset(rbuf, 0, DIM * sizeof(int));
265     if(H5Dread(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf) < 0)
266         TEST_ERROR
267 
268     /* Check that the values read are the same as the values written.
269      * The last chunk should not be in the file. */
270     for(i = 0; i < DIM; i++) {
271         if(i < DIM-2 && rbuf[i] != i) {
272             H5_FAILED();
273             HDprintf("    Read different values than written.\n");
274             HDprintf("    At index %d\n", i);
275             HDprintf("    rbuf[%d]=%d\n", i, rbuf[i]);
276             TEST_ERROR
277         } else if(i >= DIM-2 && rbuf[i] != 0) {
278             H5_FAILED();
279             HDprintf("    No value should be read.\n");
280             HDprintf("    At index %d\n", i);
281             HDprintf("    rbuf[%d]=%d\n", i, rbuf[i]);
282             TEST_ERROR
283         }
284     }
285 
286     /* Try to read in hyperslab simulating the h5dump's way of printing data */
287     if((sid = H5Dget_space(dataset)) < 0) TEST_ERROR
288 
289     HDmemset(hs_offset, 0, sizeof(hs_offset));
290     HDmemset(hs_size,   0, sizeof(hs_size));
291     hs_size[0] = DIM/2;
292 
293     if(H5Sselect_hyperslab(sid, H5S_SELECT_SET, hs_offset, stride, hs_size, NULL) < 0)
294         TEST_ERROR
295 
296     /* create the data space */
297     if((mspace = H5Screate_simple(1, dims, NULL)) < 0) TEST_ERROR
298 
299     HDmemset(zero, 0, sizeof zero);
300 
301     if(H5Sselect_hyperslab(mspace, H5S_SELECT_SET, zero, stride, &nelmts, NULL) < 0)
302         TEST_ERROR
303 
304     HDmemset(rbuf, 0, DIM * sizeof(int));
305     if(H5Dread(dataset, H5T_NATIVE_INT, H5S_ALL, sid, H5P_DEFAULT, rbuf) < 0)
306         TEST_ERROR
307 
308     /* Check that the values read are the same as the values written.
309      * The last chunk should not be in the file. */
310     for(i = 0; i < DIM; i+=2) {
311         if(i < DIM-2 && rbuf[i] != i) {
312             H5_FAILED();
313             HDprintf("    Read different values than written.\n");
314             HDprintf("    At index %d\n", i);
315             HDprintf("    rbuf[%d]=%d\n", i, rbuf[i]);
316             TEST_ERROR
317         } else if(i >= DIM-2 && rbuf[i] != 0) {
318             H5_FAILED();
319             HDprintf("    No value should be read.\n");
320             HDprintf("    At index %d\n", i);
321             HDprintf("    rbuf[%d]=%d\n", i, rbuf[i]);
322             TEST_ERROR
323         }
324     }
325 
326     if(H5Sclose (sid) < 0) TEST_ERROR
327     if(H5Sclose (mspace) < 0) TEST_ERROR
328     if(H5Dclose (dataset) < 0) TEST_ERROR
329     if(H5Fclose (file) < 0) TEST_ERROR
330 
331     PASSED();
332     return 0;
333 
334 error:
335     H5E_BEGIN_TRY {
336         H5Sclose(sid);
337         H5Sclose(mspace);
338         H5Dclose(dataset);
339         H5Fclose(file);
340     } H5E_END_TRY;
341     return -1;
342 } /* end test_filter_read() */
343 
344 /*-------------------------------------------------------------------------
345  * Function:    main
346  *
347  * Purpose:     Tests the library's behavior when a mandate filter returns
348  *              failure.
349  *
350  * Return:      EXIT_SUCCESS/EXIT_FAILURE
351  *
352  * Programmer:  Raymond Lu
353  *              25 August 2010
354  *
355  *-------------------------------------------------------------------------
356  */
357 int
main(void)358 main(void)
359 {
360     hid_t       fapl;
361     int         mdc_nelmts  = 0;
362     size_t      rdcc_nelmts = 0;
363     size_t      rdcc_nbytes = 0;
364     double      rdcc_w0     = 0;
365     char        filename[1024];
366     unsigned 	nerrors = 0;
367 
368     h5_reset();
369     fapl = h5_fileaccess();
370 
371     h5_fixname(FILENAME[0], fapl, filename, sizeof filename);
372 
373     /* The chunk cache is used so that the flushing of data chunks happens
374      * during H5Dclose.  All values are default. */
375     nerrors += (test_filter_write(filename, fapl, TRUE) < 0	? 1 : 0);
376     nerrors += (test_filter_read(filename, fapl) < 0		? 1 : 0);
377 
378     h5_fixname(FILENAME[1], fapl, filename, sizeof filename);
379 
380     /* Disable the chunk cache so that the writing of data chunks happens
381      * during H5Dwrite. */
382     if(H5Pset_cache(fapl, mdc_nelmts, rdcc_nelmts, rdcc_nbytes, rdcc_w0) < 0)
383         TEST_ERROR
384 
385     /* Run the test again. */
386     nerrors += (test_filter_write(filename, fapl, FALSE) < 0	? 1 : 0);
387     nerrors += (test_filter_read(filename, fapl) < 0		? 1 : 0);
388 
389     /* Verify symbol table messages are cached */
390     nerrors += (h5_verify_cached_stabs(FILENAME, fapl) < 0 ? 1 : 0);
391 
392     h5_cleanup(FILENAME, fapl);
393 
394     /* Make sure we can close the library */
395     if(H5close() < 0) TEST_ERROR
396 
397     if (nerrors) TEST_ERROR
398 
399     HDexit(EXIT_SUCCESS);
400 
401 error:
402     if (nerrors) {
403         HDprintf("***** %u FAILURE%s! *****\n",
404                nerrors, 1==nerrors?"":"S");
405         HDexit(EXIT_FAILURE);
406     }
407 } /* end main() */
408