bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
h5dds.cc
Go to the documentation of this file.
1// This file is part of hdf5_handler a HDF5 file handler for the OPeNDAP
2// data server.
3
4// Copyright (c) 2007-2015 The HDF Group, Inc. and OPeNDAP, Inc.
5//
6// This is free software; you can redistribute it and/or modify it under the
7// terms of the GNU Lesser General Public License as published by the Free
8// Software Foundation; either version 2.1 of the License, or (at your
9// option) any later version.
10//
11// This software is distributed in the hope that it will be useful, but
12// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14// License for more details.
15//
16// You should have received a copy of the GNU Lesser General Public
17// License along with this library; if not, write to the Free Software
18// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19//
20// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
21// You can contact The HDF Group, Inc. at 410 E University Ave,
22// Suite 200, Champaign, IL 61820
23
37
38#include<memory>
39#include <libdap/InternalErr.h>
40#include <BESDebug.h>
41
42#include <libdap/mime_util.h>
43
44#include "hdf5_handler.h"
45#include "HDF5Int32.h"
46#include "HDF5UInt32.h"
47#include "HDF5UInt16.h"
48#include "HDF5Int16.h"
49#include "HDF5Byte.h"
50#include "HDF5Array.h"
51#include "HDF5Float32.h"
52#include "HDF5Float64.h"
53#include "HDF5Url.h"
54#include "HDF5Structure.h"
55
56#include "HDF5CFUtil.h"
57
58
59using namespace std;
60using namespace libdap;
61
63static DS_t dt_inst;
64
86bool depth_first(hid_t pid,const char *gname, DDS & dds, const char *fname)
87{
88 BESDEBUG("h5",
89 ">depth_first()"
90 << " pid: " << pid
91 << " gname: " << gname
92 << " fname: " << fname
93 << endl);
94
95 // Iterate through the file to see the members of the group from the root.
96 H5G_info_t g_info;
97 hsize_t nelems = 0;
98 if(H5Gget_info(pid,&g_info) <0) {
99 string msg =
100 "h5_dds handler: counting hdf5 group elements error for ";
101 msg += gname;
102 throw InternalErr(__FILE__, __LINE__, msg);
103 }
104
105 nelems = g_info.nlinks;
106
107 ssize_t oname_size;
108 for (hsize_t i = 0; i < nelems; i++) {
109
110 vector <char>oname;
111
112 // Query the length of object name.
113 oname_size =
114 H5Lget_name_by_idx(pid,".",H5_INDEX_NAME,H5_ITER_NATIVE,i,nullptr,
115 (size_t)DODS_NAMELEN, H5P_DEFAULT);
116 if (oname_size <= 0) {
117 string msg = "h5_dds handler: Error getting the size of the hdf5 object from the group: ";
118 msg += gname;
119 throw InternalErr(__FILE__, __LINE__, msg);
120 }
121
122 // Obtain the name of the object
123 oname.resize((size_t) oname_size + 1);
124
125 if (H5Lget_name_by_idx(pid,".",H5_INDEX_NAME,H5_ITER_NATIVE,i,oname.data(),
126 (size_t)(oname_size+1), H5P_DEFAULT) < 0){
127 string msg =
128 "h5_dds handler: Error getting the hdf5 object name from the group: ";
129 msg += gname;
130 throw InternalErr(__FILE__, __LINE__, msg);
131 }
132
133 // Check if it is the hard link or the soft link
134 H5L_info_t linfo;
135 if (H5Lget_info(pid,oname.data(),&linfo,H5P_DEFAULT)<0) {
136 string msg = "hdf5 link name error from: ";
137 msg += gname;
138 throw InternalErr(__FILE__, __LINE__, msg);
139 }
140
141 // External links are not supported in this release
142 if(linfo.type == H5L_TYPE_EXTERNAL)
143 continue;
144
145 // Remember the information of soft links in DAS, not in DDS
146 if(linfo.type == H5L_TYPE_SOFT)
147 continue;
148
149 // Obtain the object type, such as group or dataset.
150 H5O_info_t oinfo;
151
152 if (H5OGET_INFO_BY_IDX(pid, ".", H5_INDEX_NAME, H5_ITER_NATIVE,
153 i, &oinfo, H5P_DEFAULT)<0) {
154 string msg = "h5_dds handler: Error obtaining the info for the object";
155 msg += string(oname.begin(),oname.end());
156 throw InternalErr(__FILE__, __LINE__, msg);
157 }
158
159 H5O_type_t obj_type = oinfo.type;
160 switch (obj_type) {
161
162 case H5O_TYPE_GROUP:
163 {
164
165 // Obtain the full path name
166 string full_path_name =
167 string(gname) + string(oname.begin(),oname.end()-1) + "/";
168
169 BESDEBUG("h5", "=depth_first():H5G_GROUP " << full_path_name
170 << endl);
171
172 vector <char>t_fpn;
173 t_fpn.resize(full_path_name.size()+1);
174 copy(full_path_name.begin(),full_path_name.end(),t_fpn.begin());
175
176 t_fpn[full_path_name.size()] = '\0';
177
178 hid_t cgroup = H5Gopen(pid, t_fpn.data(),H5P_DEFAULT);
179 if (cgroup < 0){
180 throw InternalErr(__FILE__, __LINE__, "h5_dds handler: H5Gopen() failed.");
181 }
182
183 // Check the hard link loop and break the loop if it exists.
184 // Note the function get_hardlink is defined in h5das.cc
185 string oid = get_hardlink(pid, oname.data());
186 if (oid == "") {
187 try {
188 depth_first(cgroup, t_fpn.data(), dds, fname);
189 }
190 catch(...) {
191 H5Gclose(cgroup);
192 throw;
193 }
194 }
195
196 if (H5Gclose(cgroup) < 0){
197 throw InternalErr(__FILE__, __LINE__, "Could not close the group.");
198 }
199 break;
200 }
201
202 case H5O_TYPE_DATASET:
203 {
204
205 // Obtain the absolute path of the HDF5 dataset
206 string full_path_name = string(gname) + string(oname.begin(),oname.end()-1);
207
208 // Obtain the hdf5 dataset handle stored in the structure dt_inst.
209 // All the metadata information in the handler is stored in dt_inst.
210 // Don't consider the dim. scale support for DAP2 now.
211#if 0
212 //get_dataset(pid, full_path_name, &dt_inst,false);
213#endif
214 get_dataset(pid, full_path_name, &dt_inst);
215
216 // Put the hdf5 dataset structure into DODS dds.
217 read_objects(dds, full_path_name, fname);
218 break;
219 }
220
221 case H5O_TYPE_NAMED_DATATYPE:
222 // ignore the named datatype
223 break;
224 default:
225 break;
226 }
227
228 } // for i is 0 ... nelems
229
230 BESDEBUG("h5", "<depth_first() " << endl);
231 return true;
232}
233
255void
256read_objects_base_type(DDS & dds_table, const string & varname,
257 const string & filename)
258{
259 // Obtain the DDS dataset name.
260 dds_table.set_dataset_name(name_path(filename));
261
262 // Get a base type. It should be atomic datatype
263 // DDS: varname is the absolute path
264 BaseType *bt = Get_bt(varname, varname,filename, dt_inst.type,false);
265
266 if (!bt) {
267 // NB: We're throwing InternalErr even though it's possible that
268 // someone might ask for an HDF5 varaible which this server cannot
269 // handle.
270 throw
271 InternalErr(__FILE__, __LINE__,
272 "Unable to convert hdf5 datatype to dods basetype");
273 }
274
275 // First deal with scalar data.
276 if (dt_inst.ndims == 0) {
277 dds_table.add_var(bt);
278 delete bt;
279 }
280 else {
281
282 // Next, deal with Array data. This 'else clause' runs to
283 // the end of the method. jhrg
284 auto ar_unique = make_unique<HDF5Array>(varname, filename, bt);
285 auto ar = ar_unique.get();
286 delete bt;
287 ar->set_memneed(dt_inst.need);
288 ar->set_numdim(dt_inst.ndims);
289 ar->set_numelm((int) (dt_inst.nelmts));
290 for (int dim_index = 0; dim_index < dt_inst.ndims; dim_index++)
291 ar->append_dim(dt_inst.size[dim_index]);
292 dds_table.add_var(ar);
293 }
294 BESDEBUG("h5", "<read_objects_base_type(dds)" << endl);
295}
296
308void
309read_objects_structure(DDS & dds_table, const string & varname,
310 const string & filename)
311{
312 dds_table.set_dataset_name(name_path(filename));
313
314 Structure *structure = Get_structure(varname, varname,filename, dt_inst.type,false);
315
316 try {
317 // Assume Get_structure() uses exceptions to signal an error. jhrg
318 BESDEBUG("h5", "=read_objects_structure(): Dimension is "
319 << dt_inst.ndims << endl);
320
321 if (dt_inst.ndims != 0) { // Array of Structure
322 BESDEBUG("h5", "=read_objects_structure(): array of size " <<
323 dt_inst.nelmts << endl);
324 BESDEBUG("h5", "=read_objects_structure(): memory needed = " <<
325 dt_inst.need << endl);
326 auto ar_unique = make_unique<HDF5Array>(varname, filename, structure);
327 auto ar = ar_unique.get();
328 delete structure; structure = nullptr;
329
330 ar->set_memneed(dt_inst.need);
331 ar->set_numdim(dt_inst.ndims);
332 ar->set_numelm((int) (dt_inst.nelmts));
333 ar->set_length((int) (dt_inst.nelmts));
334
335 for (int dim_index = 0; dim_index < dt_inst.ndims; dim_index++) {
336 ar->append_dim(dt_inst.size[dim_index]);
337 BESDEBUG("h5", "=read_objects_structure(): append_dim = " <<
338 dt_inst.size[dim_index] << endl);
339 }
340
341 dds_table.add_var(ar);
342
343 }
344 else {// A scalar structure
345
346 dds_table.add_var(structure);
347 delete structure; structure = nullptr;
348 }
349
350 } // try Structure *structure is Get_structure(...)
351 catch (...) {
352 delete structure;
353 throw;
354 }
355}
356
368void
369read_objects(DDS & dds_table, const string &varname, const string &filename)
370{
371
372 switch (H5Tget_class(dt_inst.type)) {
373
374 // HDF5 compound maps to DAP structure.
375 case H5T_COMPOUND:
376 read_objects_structure(dds_table, varname, filename);
377 break;
378
379 case H5T_ARRAY:
380 {
381 H5Tclose(dt_inst.type);
382 throw InternalErr(__FILE__, __LINE__, "Currently don't support accessing data of Array datatype when array datatype is not inside the compound.");
383 }
384 default:
385 read_objects_base_type(dds_table, varname, filename);
386 break;
387 }
388 // We must close the datatype obtained in the get_dataset routine since this is the end of reading DDS.
389 if(H5Tclose(dt_inst.type)<0) {
390 throw InternalErr(__FILE__, __LINE__, "Cannot close the HDF5 datatype.");
391 }
392}
393
A class for handling all types of array in HDF5 for the default option.
This class provides a way to map HDF5 byte to DAP Byte for the default option.
This file includes several helper functions for translating HDF5 to CF-compliant.
A class for mapping HDF5 32-bit float to DAP for the default option.
A class for mapping HDF5 64-bit float to DAP for the default option.
A class for HDF5 signed 16 bit integer type.
This class provides a way to map HDF5 32 bit integer to DAP Int32 for the default option.
This class converts HDF5 compound type into DAP structure for the default option.
This class provides a way to map unsigned HDF5 16 bit integer to DAP UInt16 for the default option.
This class provides a way to map unsigned HDF5 32 bit integer to DAP UInt32.
This class generates DAP URL type for the default option.
string get_hardlink(hid_t pgroup, const string &oname)
Definition h5das.cc:569
bool depth_first(hid_t pid, const char *gname, DDS &dds, const char *fname)
Definition h5dds.cc:86
void read_objects(DDS &dds_table, const string &varname, const string &filename)
Definition h5dds.cc:369
void read_objects_base_type(DDS &dds_table, const string &varname, const string &filename)
Definition h5dds.cc:256
void read_objects_structure(DDS &dds_table, const string &varname, const string &filename)
Definition h5dds.cc:309
The main header of the HDF5 OPeNDAP handler.
const int DODS_NAMELEN
Maximum length of variable or attribute name(default option only).
struct DS DS_t
A structure for DDS generation.