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  * Use Case 1.7	Appending a single chunk
15  * Description:
16  *     Appending a single chunk of raw data to a dataset along an unlimited
17  *     dimension within a pre-created file and reading the new data back.
18  * Goal:
19  *     Read data appended by the Writer to a pre-existing dataset in a
20  *     file. The dataset has one or more unlimited dimensions. The data is
21  *     appended by a hyperslab that is contained in one chunk (for example,
22  *     appending 2-dim planes along the slowest changing dimension in the
23  *     3-dim dataset).
24  * Level:
25  *     User Level
26  * Guarantees:
27  *     o	Readers will see the modified dimension sizes after the Writer
28  * 	finishes HDF5 metadata updates and issues H5Fflush or H5Oflush calls.
29  *     o	Readers will see newly appended data after the Writer finishes
30  * 	the flush operation.
31  *
32  * Preconditions:
33  *     o	Readers are not allowed to modify the file.  o	 All datasets
34  * 	that are modified by the Writer exist when the Writer opens the file.
35  *     o	All datasets that are modified by the Writer exist when a Reader
36  * 	opens the file.  o	 Data is written by a hyperslab contained in
37  * 	one chunk.
38  *
39  * Main Success Scenario:
40  *     1.	An application creates a file with required objects (groups,
41  * 	datasets, and attributes).
42  *     2.	The Writer application opens the file and datasets in the file
43  * 	and starts adding data along the unlimited dimension using a hyperslab
44  * 	selection that corresponds to an HDF5 chunk.
45  *     3.	A Reader opens the file and a dataset in a file, and queries
46  * 	the sizes of the dataset; if the extent of the dataset has changed,
47  * 	reads the appended data back.
48  *
49  * Discussion points:
50  *     1.	Since the new data is written to the file, and metadata update
51  * 	operation of adding pointer to the newly written chunk is atomic and
52  * 	happens after the chunk is on the disk, only two things may happen
53  * 	to the Reader:
54  * 	    o	The Reader will not see new data.
55  * 	    o	The Reader will see all new data written by Writer.
56  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
57 
58 /* Created: Albert Cheng, 2013/5/28 */
59 
60 #include "h5test.h"
61 
62 /* This test uses many POSIX things that are not available on
63  * Windows. We're using a check for fork(2) here as a proxy for
64  * all POSIX/Unix/Linux things until this test can be made
65  * more platform-independent.
66  */
67 #ifdef H5_HAVE_FORK
68 
69 #include "use.h"
70 
71 /* Global Variable definitions */
72 options_t UC_opts;	/* Use Case Options */
73 const char *progname_g="use_append_chunk";	/* program name */
74 
75 /* Setup parameters for the use case.
76  * Return: 0 succeed; -1 fail.
77  */
setup_parameters(int argc,char * const argv[])78 int setup_parameters(int argc, char * const argv[])
79 {
80     /* use case defaults */
81     HDmemset(&UC_opts, 0, sizeof(options_t));
82     UC_opts.chunksize = Chunksize_DFT;
83     UC_opts.use_swmr = TRUE;	/* use swmr open */
84     UC_opts.iterations = 1;
85     UC_opts.chunkplanes = 1;
86 
87     /* parse options */
88     if (parse_option(argc, argv) < 0)
89 	return(-1);
90 
91     /* set chunk dims */
92     UC_opts.chunkdims[0] = UC_opts.chunkplanes;
93     UC_opts.chunkdims[1] = UC_opts.chunkdims[2] = UC_opts.chunksize;
94 
95     /* set dataset initial and max dims */
96     UC_opts.dims[0] = 0;
97     UC_opts.max_dims[0] = H5S_UNLIMITED;
98     UC_opts.dims[1] = UC_opts.dims[2] = UC_opts.max_dims[1] = UC_opts.max_dims[2] = UC_opts.chunksize;
99 
100     /* set nplanes */
101     if (UC_opts.nplanes == 0)
102         UC_opts.nplanes = (hsize_t)UC_opts.chunksize;
103 
104     /* show parameters and return */
105     show_parameters();
106     return(0);
107 }
108 
109 
110 /* Overall Algorithm:
111  * Parse options from user;
112  * Generate/pre-created test files needed and close it;
113  * fork: child process becomes the reader process;
114  *       while parent process continues as the writer process;
115  * both run till ending conditions are met.
116  */
117 int
main(int argc,char * argv[])118 main(int argc, char *argv[])
119 {
120     pid_t childpid=0;
121     pid_t mypid, tmppid;
122     int	child_status;
123     int child_wait_option=0;
124     int ret_value = 0;
125     int child_ret_value;
126     hbool_t send_wait = FALSE;
127     hid_t fapl = -1;    /* File access property list */
128     hid_t fid = -1;     /* File ID */
129     char *name;         /* Test file name */
130 
131     /* initialization */
132     if (setup_parameters(argc, argv) < 0){
133         Hgoto_error(1);
134     }
135 
136     /* Determine the need to send/wait message file*/
137     if(UC_opts.launch == UC_READWRITE) {
138         HDunlink(WRITER_MESSAGE);
139         send_wait = TRUE;
140     }
141 
142     /* ==============================================================*/
143     /* UC_READWRITE: create datafile, launch both reader and writer. */
144     /* UC_WRITER:    create datafile, skip reader, launch writer.    */
145     /* UC_READER:    skip create, launch reader, exit.               */
146     /* ==============================================================*/
147     /* ============*/
148     /* Create file */
149     /* ============*/
150     if (UC_opts.launch != UC_READER){
151         HDprintf("Creating skeleton data file for test...\n");
152         if (create_uc_file() < 0){
153             HDfprintf(stderr, "***encounter error\n");
154             Hgoto_error(1);
155         }else
156             HDprintf("File created.\n");
157     }
158 
159     if (UC_opts.launch==UC_READWRITE){
160         /* fork process */
161         if((childpid = HDfork()) < 0) {
162             HDperror("fork");
163             Hgoto_error(1);
164         };
165     };
166     mypid = HDgetpid();
167 
168     /* ============= */
169     /* launch reader */
170     /* ============= */
171     if (UC_opts.launch != UC_WRITER){
172         /* child process launch the reader */
173         if(0 == childpid) {
174             HDprintf("%d: launch reader process\n", mypid);
175             if (read_uc_file(send_wait) < 0){
176                 HDfprintf(stderr, "read_uc_file encountered error\n");
177                 HDexit(EXIT_FAILURE);
178             }
179             HDexit(EXIT_SUCCESS);
180         }
181     }
182 
183     /* ============= */
184     /* launch writer */
185     /* ============= */
186     /* this process continues to launch the writer */
187     HDprintf("%d: continue as the writer process\n", mypid);
188 
189     name = UC_opts.filename;
190 
191     /* Set file access proeprty list */
192     if((fapl = h5_fileaccess()) < 0)
193         Hgoto_error(1);
194 
195     if(UC_opts.use_swmr)
196         if(H5Pset_libver_bounds(fapl, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0)
197             Hgoto_error(1);
198 
199     /* Open the file */
200     if((fid = H5Fopen(name, H5F_ACC_RDWR | (UC_opts.use_swmr ? H5F_ACC_SWMR_WRITE : 0), fapl)) < 0) {
201         HDfprintf(stderr, "H5Fopen failed\n");
202         Hgoto_error(1);
203     }
204 
205     if(write_uc_file(send_wait, fid) < 0) {
206         HDfprintf(stderr, "write_uc_file encountered error\n");
207         Hgoto_error(1);
208     }
209 
210     /* ================================================ */
211     /* If readwrite, collect exit code of child process */
212     /* ================================================ */
213     if (UC_opts.launch == UC_READWRITE){
214         if ((tmppid = HDwaitpid(childpid, &child_status, child_wait_option)) < 0){
215             HDperror("waitpid");
216             Hgoto_error(1);
217         }
218 
219         /* Close the file */
220         if(H5Fclose(fid) < 0) {
221             HDfprintf(stderr, "Failed to close file id\n");
222             Hgoto_error(1);
223         }
224 
225         /* Close the property list */
226         if(H5Pclose(fapl) < 0) {
227             HDfprintf(stderr, "Failed to close the property list\n");
228             Hgoto_error(1);
229         }
230 
231         if (WIFEXITED(child_status)){
232             if ((child_ret_value=WEXITSTATUS(child_status)) != 0){
233                 HDprintf("%d: child process exited with non-zero code (%d)\n",
234                         mypid, child_ret_value);
235                 Hgoto_error(2);
236             }
237          } else {
238                 HDprintf("%d: child process terminated abnormally\n", mypid);
239                 Hgoto_error(2);
240          }
241     }
242 
243 done:
244     /* Print result and exit */
245     if (ret_value != 0){
246         HDprintf("Error(s) encountered\n");
247     }else{
248         HDprintf("All passed\n");
249     }
250 
251     return(ret_value);
252 }
253 
254 #else /* H5_HAVE_FORK */
255 
256 int
main(void)257 main(void)
258 {
259     HDfprintf(stderr, "Non-POSIX platform. Skipping.\n");
260     return EXIT_SUCCESS;
261 } /* end main() */
262 
263 #endif /* H5_HAVE_FORK */
264 
265