/src/gdal/netcdf-c-4.7.4/libhdf5/hdf5create.c
Line | Count | Source |
1 | | /* Copyright 2003-2018, University Corporation for Atmospheric |
2 | | * Research. See COPYRIGHT file for copying and redistribution |
3 | | * conditions. */ |
4 | | /** |
5 | | * @file |
6 | | * @internal The netCDF-4 file functions relating to file creation. |
7 | | * |
8 | | * @author Ed Hartnett |
9 | | */ |
10 | | |
11 | | #include "config.h" |
12 | | #include "hdf5internal.h" |
13 | | |
14 | | /* From hdf5file.c. */ |
15 | | extern size_t nc4_chunk_cache_size; |
16 | | extern size_t nc4_chunk_cache_nelems; |
17 | | extern float nc4_chunk_cache_preemption; |
18 | | |
19 | | /** @internal These flags may not be set for create. */ |
20 | | static const int ILLEGAL_CREATE_FLAGS = (NC_NOWRITE|NC_MMAP|NC_64BIT_OFFSET|NC_CDF5); |
21 | | |
22 | | /* From nc4mem.c */ |
23 | | extern int NC4_create_image_file(NC_FILE_INFO_T* h5, size_t); |
24 | | |
25 | | /** |
26 | | * @internal Create a netCDF-4/HDF5 file. |
27 | | * |
28 | | * @param path The file name of the new file. |
29 | | * @param cmode The creation mode flag. |
30 | | * @param initialsz The proposed initial file size (advisory, for |
31 | | * in-memory netCDF-4/HDF5 files only). |
32 | | * @param parameters extra parameter info (like MPI communicator). |
33 | | * @param ncid The already-assigned ncid for this file (aka ext_ncid). |
34 | | * |
35 | | * @return ::NC_NOERR No error. |
36 | | * @return ::NC_EINVAL Invalid input (check cmode). |
37 | | * @return ::NC_EEXIST File exists and NC_NOCLOBBER used. |
38 | | * @return ::NC_EHDFERR HDF5 returned error. |
39 | | * @ingroup netcdf4 |
40 | | * @author Ed Hartnett, Dennis Heimbigner |
41 | | */ |
42 | | static int |
43 | | nc4_create_file(const char *path, int cmode, size_t initialsz, |
44 | | void* parameters, int ncid) |
45 | 6.69k | { |
46 | 6.69k | hid_t fcpl_id, fapl_id = -1; |
47 | 6.69k | unsigned flags; |
48 | 6.69k | FILE *fp; |
49 | 6.69k | int retval = NC_NOERR; |
50 | 6.69k | NC_FILE_INFO_T *nc4_info; |
51 | 6.69k | NC_HDF5_FILE_INFO_T *hdf5_info; |
52 | 6.69k | NC_HDF5_GRP_INFO_T *hdf5_grp; |
53 | | |
54 | | #ifdef USE_PARALLEL4 |
55 | | NC_MPI_INFO *mpiinfo = NULL; |
56 | | MPI_Comm comm; |
57 | | MPI_Info info; |
58 | | int comm_duped = 0; /* Whether the MPI Communicator was duplicated */ |
59 | | int info_duped = 0; /* Whether the MPI Info object was duplicated */ |
60 | | #endif /* !USE_PARALLEL4 */ |
61 | | |
62 | 6.69k | assert(path); |
63 | 6.69k | LOG((3, "%s: path %s mode 0x%x", __func__, path, cmode)); |
64 | | |
65 | | /* Add necessary structs to hold netcdf-4 file data. */ |
66 | 6.69k | if ((retval = nc4_file_list_add(ncid, path, NC_WRITE | cmode, |
67 | 6.69k | (void **)&nc4_info))) |
68 | 0 | BAIL(retval); |
69 | 6.69k | assert(nc4_info && nc4_info->root_grp); |
70 | 6.69k | nc4_info->root_grp->atts_read = 1; |
71 | | |
72 | | /* Add struct to hold HDF5-specific file metadata. */ |
73 | 6.69k | if (!(nc4_info->format_file_info = calloc(1, sizeof(NC_HDF5_FILE_INFO_T)))) |
74 | 0 | BAIL(NC_ENOMEM); |
75 | 6.69k | hdf5_info = (NC_HDF5_FILE_INFO_T *)nc4_info->format_file_info; |
76 | | |
77 | | /* Add struct to hold HDF5-specific group info. */ |
78 | 6.69k | if (!(nc4_info->root_grp->format_grp_info = calloc(1, sizeof(NC_HDF5_GRP_INFO_T)))) |
79 | 0 | return NC_ENOMEM; |
80 | 6.69k | hdf5_grp = (NC_HDF5_GRP_INFO_T *)nc4_info->root_grp->format_grp_info; |
81 | | |
82 | 6.69k | nc4_info->mem.inmemory = (cmode & NC_INMEMORY) == NC_INMEMORY; |
83 | 6.69k | nc4_info->mem.diskless = (cmode & NC_DISKLESS) == NC_DISKLESS; |
84 | 6.69k | nc4_info->mem.persist = (cmode & NC_PERSIST) == NC_PERSIST; |
85 | 6.69k | nc4_info->mem.created = 1; |
86 | 6.69k | nc4_info->mem.initialsize = initialsz; |
87 | | |
88 | | /* diskless => !inmemory */ |
89 | 6.69k | if(nc4_info->mem.inmemory && nc4_info->mem.diskless) |
90 | 0 | BAIL(NC_EINTERNAL); |
91 | | |
92 | 6.69k | if(nc4_info->mem.inmemory && parameters) |
93 | 0 | nc4_info->mem.memio = *(NC_memio*)parameters; |
94 | | #ifdef USE_PARALLEL4 |
95 | | else if(parameters) { |
96 | | mpiinfo = (NC_MPI_INFO *)parameters; |
97 | | comm = mpiinfo->comm; |
98 | | info = mpiinfo->info; |
99 | | } |
100 | | #endif |
101 | 6.69k | if(nc4_info->mem.diskless) |
102 | 0 | flags = H5F_ACC_TRUNC; |
103 | 6.69k | else if(cmode & NC_NOCLOBBER) |
104 | 0 | flags = H5F_ACC_EXCL; |
105 | 6.69k | else |
106 | 6.69k | flags = H5F_ACC_TRUNC; |
107 | | |
108 | | /* If this file already exists, and NC_NOCLOBBER is specified, |
109 | | return an error (unless diskless|inmemory) */ |
110 | 6.69k | if (!nc4_info->mem.diskless && !nc4_info->mem.inmemory) { |
111 | 6.69k | if ((cmode & NC_NOCLOBBER) && (fp = fopen(path, "r"))) { |
112 | 0 | fclose(fp); |
113 | 0 | BAIL(NC_EEXIST); |
114 | 0 | } |
115 | 6.69k | } |
116 | | |
117 | | /* Need this access plist to control how HDF5 handles open objects |
118 | | * on file close. Setting H5F_CLOSE_SEMI will cause H5Fclose to |
119 | | * fail if there are any open objects in the file. */ |
120 | 6.69k | if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) |
121 | 0 | BAIL(NC_EHDFERR); |
122 | 6.69k | if (H5Pset_fclose_degree(fapl_id, H5F_CLOSE_SEMI)) |
123 | 0 | BAIL(NC_EHDFERR); |
124 | | |
125 | | #ifdef USE_PARALLEL4 |
126 | | /* If this is a parallel file create, set up the file creation |
127 | | property list. */ |
128 | | if (mpiinfo != NULL) { |
129 | | nc4_info->parallel = NC_TRUE; |
130 | | LOG((4, "creating parallel file with MPI/IO")); |
131 | | if (H5Pset_fapl_mpio(fapl_id, comm, info) < 0) |
132 | | BAIL(NC_EPARINIT); |
133 | | |
134 | | /* Keep copies of the MPI Comm & Info objects */ |
135 | | if (MPI_SUCCESS != MPI_Comm_dup(comm, &nc4_info->comm)) |
136 | | BAIL(NC_EMPI); |
137 | | comm_duped++; |
138 | | if (MPI_INFO_NULL != info) |
139 | | { |
140 | | if (MPI_SUCCESS != MPI_Info_dup(info, &nc4_info->info)) |
141 | | BAIL(NC_EMPI); |
142 | | info_duped++; |
143 | | } |
144 | | else |
145 | | { |
146 | | /* No dup, just copy it. */ |
147 | | nc4_info->info = info; |
148 | | } |
149 | | } |
150 | | #else /* only set cache for non-parallel... */ |
151 | 6.69k | if (H5Pset_cache(fapl_id, 0, nc4_chunk_cache_nelems, nc4_chunk_cache_size, |
152 | 6.69k | nc4_chunk_cache_preemption) < 0) |
153 | 0 | BAIL(NC_EHDFERR); |
154 | 6.69k | LOG((4, "%s: set HDF raw chunk cache to size %d nelems %d preemption %f", |
155 | 6.69k | __func__, nc4_chunk_cache_size, nc4_chunk_cache_nelems, |
156 | 6.69k | nc4_chunk_cache_preemption)); |
157 | 6.69k | #endif /* USE_PARALLEL4 */ |
158 | | |
159 | | #ifdef HAVE_H5PSET_LIBVER_BOUNDS |
160 | | #if H5_VERSION_GE(1,10,2) |
161 | | if (H5Pset_libver_bounds(fapl_id, H5F_LIBVER_EARLIEST, H5F_LIBVER_V18) < 0) |
162 | | #else |
163 | | if (H5Pset_libver_bounds(fapl_id, H5F_LIBVER_EARLIEST, |
164 | | H5F_LIBVER_LATEST) < 0) |
165 | | #endif |
166 | | BAIL(NC_EHDFERR); |
167 | | #endif |
168 | | |
169 | | /* Create the property list. */ |
170 | 6.69k | if ((fcpl_id = H5Pcreate(H5P_FILE_CREATE)) < 0) |
171 | 0 | BAIL(NC_EHDFERR); |
172 | | |
173 | | /* RJ: this suppose to be FALSE that is defined in H5 private.h as 0 */ |
174 | 6.69k | if (H5Pset_obj_track_times(fcpl_id,0)<0) |
175 | 0 | BAIL(NC_EHDFERR); |
176 | | |
177 | | /* Set latest_format in access propertly list and |
178 | | * H5P_CRT_ORDER_TRACKED in the creation property list. This turns |
179 | | * on HDF5 creation ordering. */ |
180 | 6.69k | if (H5Pset_link_creation_order(fcpl_id, (H5P_CRT_ORDER_TRACKED | |
181 | 6.69k | H5P_CRT_ORDER_INDEXED)) < 0) |
182 | 0 | BAIL(NC_EHDFERR); |
183 | 6.69k | if (H5Pset_attr_creation_order(fcpl_id, (H5P_CRT_ORDER_TRACKED | |
184 | 6.69k | H5P_CRT_ORDER_INDEXED)) < 0) |
185 | 0 | BAIL(NC_EHDFERR); |
186 | | |
187 | | #ifdef HDF5_HAS_COLL_METADATA_OPS |
188 | | /* If HDF5 supports collective metadata operations, turn them |
189 | | * on. This is only relevant for parallel I/O builds of HDF5. */ |
190 | | if (H5Pset_all_coll_metadata_ops(fapl_id, 1) < 0) |
191 | | BAIL(NC_EHDFERR); |
192 | | if (H5Pset_coll_metadata_write(fapl_id, 1) < 0) |
193 | | BAIL(NC_EHDFERR); |
194 | | #endif |
195 | | |
196 | 6.69k | if(nc4_info->mem.inmemory) { |
197 | 0 | retval = NC4_create_image_file(nc4_info,initialsz); |
198 | 0 | if(retval) |
199 | 0 | BAIL(retval); |
200 | 0 | } |
201 | 6.69k | else |
202 | 6.69k | if(nc4_info->mem.diskless) { |
203 | 0 | size_t alloc_incr; /* Buffer allocation increment */ |
204 | 0 | size_t min_incr = 65536; /* Minimum buffer increment */ |
205 | 0 | double buf_prcnt = 0.1f; /* Percentage of buffer size to set as increment */ |
206 | | /* set allocation increment to a percentage of the supplied buffer size, or |
207 | | * a pre-defined minimum increment value, whichever is larger |
208 | | */ |
209 | 0 | if ((buf_prcnt * initialsz) > min_incr) |
210 | 0 | alloc_incr = (size_t)(buf_prcnt * initialsz); |
211 | 0 | else |
212 | 0 | alloc_incr = min_incr; |
213 | | /* Configure FAPL to use the core file driver */ |
214 | 0 | if (H5Pset_fapl_core(fapl_id, alloc_incr, (nc4_info->mem.persist?1:0)) < 0) |
215 | 0 | BAIL(NC_EHDFERR); |
216 | 0 | if ((hdf5_info->hdfid = H5Fcreate(path, flags, fcpl_id, fapl_id)) < 0) |
217 | 0 | BAIL(EACCES); |
218 | 0 | } |
219 | 6.69k | else /* Normal file */ |
220 | 6.69k | { |
221 | | /* Create the HDF5 file. */ |
222 | 6.69k | if ((hdf5_info->hdfid = H5Fcreate(path, flags, fcpl_id, fapl_id)) < 0) |
223 | 0 | BAIL(EACCES); |
224 | 6.69k | } |
225 | | |
226 | | /* Open the root group. */ |
227 | 6.69k | if ((hdf5_grp->hdf_grpid = H5Gopen2(hdf5_info->hdfid, "/", H5P_DEFAULT)) < 0) |
228 | 0 | BAIL(NC_EFILEMETA); |
229 | | |
230 | | /* Release the property lists. */ |
231 | 6.69k | if (H5Pclose(fapl_id) < 0 || H5Pclose(fcpl_id) < 0) |
232 | 0 | BAIL(NC_EHDFERR); |
233 | | |
234 | | /* Define mode gets turned on automatically on create. */ |
235 | 6.69k | nc4_info->flags |= NC_INDEF; |
236 | | |
237 | | /* Save the HDF5 superblock number and set the _NCProperties attribute. */ |
238 | 6.69k | if ((retval = NC4_new_provenance(nc4_info))) |
239 | 0 | BAIL(retval); |
240 | | |
241 | 6.69k | return NC_NOERR; |
242 | | |
243 | 0 | exit: /*failure exit*/ |
244 | | #ifdef USE_PARALLEL4 |
245 | | if (comm_duped) MPI_Comm_free(&nc4_info->comm); |
246 | | if (info_duped) MPI_Info_free(&nc4_info->info); |
247 | | #endif |
248 | 0 | if (fapl_id != H5P_DEFAULT) H5Pclose(fapl_id); |
249 | 0 | if(!nc4_info) return retval; |
250 | 0 | nc4_close_hdf5_file(nc4_info, 1, NULL); /* treat like abort */ |
251 | 0 | return retval; |
252 | 0 | } |
253 | | |
254 | | /** |
255 | | * @internal Create a netCDF-4/HDF5 file. |
256 | | * |
257 | | * @param path The file name of the new file. |
258 | | * @param cmode The creation mode flag. |
259 | | * @param initialsz Ignored by this function. |
260 | | * @param basepe Ignored by this function. |
261 | | * @param chunksizehintp Ignored by this function. |
262 | | * @param parameters pointer to struct holding extra data (e.g. for |
263 | | * parallel I/O) layer. Ignored if NULL. |
264 | | * @param dispatch Pointer to the dispatch table for this file. |
265 | | * @param ncid The ncid that has been assigned by the dispatch layer |
266 | | * (aka ext_ncid). |
267 | | * |
268 | | * @return ::NC_NOERR No error. |
269 | | * @return ::NC_EINVAL Invalid input (check cmode). |
270 | | * @ingroup netcdf4 |
271 | | * @author Ed Hartnett |
272 | | */ |
273 | | int |
274 | | NC4_create(const char* path, int cmode, size_t initialsz, int basepe, |
275 | | size_t *chunksizehintp, void *parameters, |
276 | | const NC_Dispatch *dispatch, int ncid) |
277 | 6.69k | { |
278 | 6.69k | int res; |
279 | | |
280 | 6.69k | assert(path); |
281 | | |
282 | 6.69k | LOG((1, "%s: path %s cmode 0x%x parameters %p", |
283 | 6.69k | __func__, path, cmode, parameters)); |
284 | | |
285 | | /* If this is our first file, turn off HDF5 error messages. */ |
286 | 6.69k | if (!nc4_hdf5_initialized) |
287 | 0 | nc4_hdf5_initialize(); |
288 | | |
289 | | #ifdef LOGGING |
290 | | /* If nc logging level has changed, see if we need to turn on |
291 | | * HDF5's error messages. */ |
292 | | hdf5_set_log_level(); |
293 | | #endif /* LOGGING */ |
294 | | |
295 | | /* Check the cmode for validity. Checking parallel against |
296 | | * NC_DISKLESS already done in NC_create(). */ |
297 | 6.69k | if (cmode & ILLEGAL_CREATE_FLAGS) |
298 | 0 | return NC_EINVAL; |
299 | | |
300 | | /* Create the netCDF-4/HDF5 file. */ |
301 | 6.69k | res = nc4_create_file(path, cmode, initialsz, parameters, ncid); |
302 | | |
303 | 6.69k | return res; |
304 | 6.69k | } |