Line | Count | Source (jump to first uncovered line) |
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://www.hdfgroup.org/licenses. * |
9 | | * If you do not have access to either file, you may request a copy from * |
10 | | * help@hdfgroup.org. * |
11 | | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
12 | | |
13 | | #include "H5Zmodule.h" /* This source code file is part of the H5Z module */ |
14 | | |
15 | | #include "H5private.h" /* Generic Functions */ |
16 | | #include "H5Dprivate.h" /* Dataset functions */ |
17 | | #include "H5Eprivate.h" /* Error handling */ |
18 | | #include "H5Fprivate.h" /* File */ |
19 | | #include "H5Iprivate.h" /* IDs */ |
20 | | #include "H5MMprivate.h" /* Memory management */ |
21 | | #include "H5Oprivate.h" /* Object headers */ |
22 | | #include "H5Pprivate.h" /* Property lists */ |
23 | | #include "H5PLprivate.h" /* Plugins */ |
24 | | #include "H5Sprivate.h" /* Dataspace functions */ |
25 | | #include "H5Zpkg.h" /* Data filters */ |
26 | | |
27 | | #ifdef H5_HAVE_SZLIB_H |
28 | | #include "szlib.h" |
29 | | #endif |
30 | | |
31 | | /* This module can collect and optionally dump some simple filter statistics |
32 | | * to stdout. If you want to do this, you need to define H5Z_DEBUG and set |
33 | | * the DUMP_DEBUG_STATS_g flag to true. |
34 | | */ |
35 | | |
36 | | /* Local typedefs */ |
37 | | #ifdef H5Z_DEBUG |
38 | | typedef struct H5Z_stats_t { |
39 | | struct { |
40 | | hsize_t total; /* total number of bytes processed */ |
41 | | hsize_t errors; /* bytes of total attributable to errors */ |
42 | | H5_timevals_t times; /* execution time including errors */ |
43 | | } stats[2]; /* 0 = output, 1 = input */ |
44 | | } H5Z_stats_t; |
45 | | #endif /* H5Z_DEBUG */ |
46 | | |
47 | | typedef struct H5Z_object_t { |
48 | | H5Z_filter_t filter_id; /* ID of the filter we're looking for */ |
49 | | htri_t found; /* Whether we find an object using the filter */ |
50 | | #ifdef H5_HAVE_PARALLEL |
51 | | bool sanity_checked; /* Whether the sanity check for collectively calling H5Zunregister has been done */ |
52 | | #endif /* H5_HAVE_PARALLEL */ |
53 | | } H5Z_object_t; |
54 | | |
55 | | /* Enumerated type for dataset creation prelude callbacks */ |
56 | | typedef enum { |
57 | | H5Z_PRELUDE_CAN_APPLY, /* Call "can apply" callback */ |
58 | | H5Z_PRELUDE_SET_LOCAL /* Call "set local" callback */ |
59 | | } H5Z_prelude_type_t; |
60 | | |
61 | | /* Local variables */ |
62 | | static size_t H5Z_table_alloc_g = 0; |
63 | | static size_t H5Z_table_used_g = 0; |
64 | | static H5Z_class2_t *H5Z_table_g = NULL; |
65 | | #ifdef H5Z_DEBUG |
66 | | static H5Z_stats_t *H5Z_stat_table_g = NULL; |
67 | | /* Set to true if you want to dump compression statistics to stdout */ |
68 | | static const bool DUMP_DEBUG_STATS_g = false; |
69 | | #endif /* H5Z_DEBUG */ |
70 | | |
71 | | /* Local functions */ |
72 | | static int H5Z__find_idx(H5Z_filter_t id); |
73 | | static int H5Z__check_unregister_dset_cb(void *obj_ptr, hid_t obj_id, void *key); |
74 | | static int H5Z__check_unregister_group_cb(void *obj_ptr, hid_t obj_id, void *key); |
75 | | static int H5Z__flush_file_cb(void *obj_ptr, hid_t obj_id, void *key); |
76 | | |
77 | | /*------------------------------------------------------------------------- |
78 | | * Function: H5Z_init |
79 | | * |
80 | | * Purpose: Initialize the interface from some other layer. |
81 | | * |
82 | | * Return: Success: non-negative |
83 | | * Failure: negative |
84 | | *------------------------------------------------------------------------- |
85 | | */ |
86 | | herr_t |
87 | | H5Z_init(void) |
88 | 1 | { |
89 | 1 | herr_t ret_value = SUCCEED; /* Return value */ |
90 | | |
91 | 1 | FUNC_ENTER_NOAPI(FAIL) |
92 | | |
93 | 1 | if (H5_TERM_GLOBAL) |
94 | 0 | HGOTO_DONE(SUCCEED); |
95 | | |
96 | | /* Internal filters */ |
97 | 1 | if (H5Z_register(H5Z_SHUFFLE) < 0) |
98 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to register shuffle filter"); |
99 | 1 | if (H5Z_register(H5Z_FLETCHER32) < 0) |
100 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to register fletcher32 filter"); |
101 | 1 | if (H5Z_register(H5Z_NBIT) < 0) |
102 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to register nbit filter"); |
103 | 1 | if (H5Z_register(H5Z_SCALEOFFSET) < 0) |
104 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to register scaleoffset filter"); |
105 | | |
106 | | /* External filters */ |
107 | 1 | #ifdef H5_HAVE_FILTER_DEFLATE |
108 | 1 | if (H5Z_register(H5Z_DEFLATE) < 0) |
109 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to register deflate filter"); |
110 | 1 | #endif /* H5_HAVE_FILTER_DEFLATE */ |
111 | | #ifdef H5_HAVE_FILTER_SZIP |
112 | | { |
113 | | int encoder_enabled = SZ_encoder_enabled(); |
114 | | if (encoder_enabled < 0) |
115 | | HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "check for szip encoder failed"); |
116 | | |
117 | | H5Z_SZIP->encoder_present = (unsigned)encoder_enabled; |
118 | | if (H5Z_register(H5Z_SZIP) < 0) |
119 | | HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to register szip filter"); |
120 | | } |
121 | | #endif /* H5_HAVE_FILTER_SZIP */ |
122 | | |
123 | 1 | done: |
124 | 1 | FUNC_LEAVE_NOAPI(ret_value) |
125 | 1 | } |
126 | | |
127 | | /*------------------------------------------------------------------------- |
128 | | * Function: H5Z_term_package |
129 | | * |
130 | | * Purpose: Terminate the H5Z layer. |
131 | | * |
132 | | * Return: void |
133 | | *------------------------------------------------------------------------- |
134 | | */ |
135 | | int |
136 | | H5Z_term_package(void) |
137 | 2 | { |
138 | 2 | int n = 0; |
139 | | |
140 | 2 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
141 | | |
142 | | #ifdef H5Z_DEBUG |
143 | | char comment[16], bandwidth[32]; |
144 | | int dir, nprint = 0; |
145 | | size_t i; |
146 | | |
147 | | if (DUMP_DEBUG_STATS_g) { |
148 | | for (i = 0; i < H5Z_table_used_g; i++) { |
149 | | for (dir = 0; dir < 2; dir++) { |
150 | | struct { |
151 | | char *user; |
152 | | char *system; |
153 | | char *elapsed; |
154 | | } timestrs = {H5_timer_get_time_string(H5Z_stat_table_g[i].stats[dir].times.user), |
155 | | H5_timer_get_time_string(H5Z_stat_table_g[i].stats[dir].times.system), |
156 | | H5_timer_get_time_string(H5Z_stat_table_g[i].stats[dir].times.elapsed)}; |
157 | | if (0 == H5Z_stat_table_g[i].stats[dir].total) |
158 | | goto next; |
159 | | |
160 | | if (0 == nprint++) { |
161 | | /* Print column headers */ |
162 | | fprintf(stdout, "H5Z: filter statistics " |
163 | | "accumulated over life of library:\n"); |
164 | | fprintf(stdout, " %-16s %10s %10s %8s %8s %8s %10s\n", "Filter", "Total", "Errors", |
165 | | "User", "System", "Elapsed", "Bandwidth"); |
166 | | fprintf(stdout, " %-16s %10s %10s %8s %8s %8s %10s\n", "------", "-----", "------", |
167 | | "----", "------", "-------", "---------"); |
168 | | } /* end if */ |
169 | | |
170 | | /* Truncate the comment to fit in the field */ |
171 | | strncpy(comment, H5Z_table_g[i].name, sizeof comment); |
172 | | comment[sizeof(comment) - 1] = '\0'; |
173 | | |
174 | | /* |
175 | | * Format bandwidth to have four significant digits and |
176 | | * units of `B/s', `kB/s', `MB/s', `GB/s', or `TB/s' or |
177 | | * the word `Inf' if the elapsed time is zero. |
178 | | */ |
179 | | H5_bandwidth(bandwidth, sizeof(bandwidth), (double)(H5Z_stat_table_g[i].stats[dir].total), |
180 | | H5Z_stat_table_g[i].stats[dir].times.elapsed); |
181 | | |
182 | | /* Print the statistics */ |
183 | | fprintf(stdout, " %s%-15s %10" PRIdHSIZE " %10" PRIdHSIZE " %8s %8s %8s %10s\n", |
184 | | (dir ? "<" : ">"), comment, H5Z_stat_table_g[i].stats[dir].total, |
185 | | H5Z_stat_table_g[i].stats[dir].errors, timestrs.user, timestrs.system, |
186 | | timestrs.elapsed, bandwidth); |
187 | | next: |
188 | | free(timestrs.user); |
189 | | free(timestrs.system); |
190 | | free(timestrs.elapsed); |
191 | | } /* end for */ |
192 | | } /* end for */ |
193 | | } /* end if */ |
194 | | #endif /* H5Z_DEBUG */ |
195 | | |
196 | | /* Free the table of filters */ |
197 | 2 | if (H5Z_table_g) { |
198 | 1 | H5Z_table_g = (H5Z_class2_t *)H5MM_xfree(H5Z_table_g); |
199 | | |
200 | | #ifdef H5Z_DEBUG |
201 | | H5Z_stat_table_g = (H5Z_stats_t *)H5MM_xfree(H5Z_stat_table_g); |
202 | | #endif /* H5Z_DEBUG */ |
203 | 1 | H5Z_table_used_g = H5Z_table_alloc_g = 0; |
204 | | |
205 | 1 | n++; |
206 | 1 | } /* end if */ |
207 | | |
208 | 2 | FUNC_LEAVE_NOAPI(n) |
209 | 2 | } /* end H5Z_term_package() */ |
210 | | |
211 | | /*------------------------------------------------------------------------- |
212 | | * Function: H5Zregister |
213 | | * |
214 | | * Purpose: This function registers a new filter |
215 | | * |
216 | | * Return: Non-negative on success/Negative on failure |
217 | | *------------------------------------------------------------------------- |
218 | | */ |
219 | | herr_t |
220 | | H5Zregister(const void *cls) |
221 | 0 | { |
222 | 0 | const H5Z_class2_t *cls_real = (const H5Z_class2_t *)cls; /* "Real" class pointer */ |
223 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
224 | | #ifndef H5_NO_DEPRECATED_SYMBOLS |
225 | | H5Z_class2_t cls_new; /* Translated class struct */ |
226 | | #endif |
227 | |
|
228 | 0 | FUNC_ENTER_API(FAIL) |
229 | | |
230 | | /* Check args */ |
231 | 0 | if (cls_real == NULL) |
232 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid filter class"); |
233 | | |
234 | | /* Check H5Z_class_t version number; this is where a function to convert |
235 | | * from an outdated version should be called. |
236 | | * |
237 | | * If the version number is invalid, we assume that the target of cls is the |
238 | | * old style "H5Z_class1_t" structure, which did not contain a version |
239 | | * field. In this structure, the first field is the id. Since both version |
240 | | * and id are integers they will have the same value, and since id must be |
241 | | * at least 256, there should be no overlap and the version of the struct |
242 | | * can be determined by the value of the first field. |
243 | | */ |
244 | 0 | if (cls_real->version != H5Z_CLASS_T_VERS) { |
245 | | #ifndef H5_NO_DEPRECATED_SYMBOLS |
246 | | /* Assume it is an old "H5Z_class1_t" instead */ |
247 | | const H5Z_class1_t *cls_old = (const H5Z_class1_t *)cls; |
248 | | |
249 | | /* Translate to new H5Z_class2_t */ |
250 | | cls_new.version = H5Z_CLASS_T_VERS; |
251 | | cls_new.id = cls_old->id; |
252 | | cls_new.encoder_present = 1; |
253 | | cls_new.decoder_present = 1; |
254 | | cls_new.name = cls_old->name; |
255 | | cls_new.can_apply = cls_old->can_apply; |
256 | | cls_new.set_local = cls_old->set_local; |
257 | | cls_new.filter = cls_old->filter; |
258 | | |
259 | | /* Set cls_real to point to the translated structure */ |
260 | | cls_real = &cls_new; |
261 | | |
262 | | #else /* H5_NO_DEPRECATED_SYMBOLS */ |
263 | | /* Deprecated symbols not allowed, throw an error */ |
264 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid H5Z_class_t version number"); |
265 | 0 | #endif /* H5_NO_DEPRECATED_SYMBOLS */ |
266 | 0 | } /* end if */ |
267 | | |
268 | 0 | if (cls_real->id < 0 || cls_real->id > H5Z_FILTER_MAX) |
269 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid filter identification number"); |
270 | 0 | if (cls_real->id < H5Z_FILTER_RESERVED) |
271 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to modify predefined filters"); |
272 | 0 | if (cls_real->filter == NULL) |
273 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no filter function specified"); |
274 | | |
275 | | /* Do it */ |
276 | 0 | if (H5Z_register(cls_real) < 0) |
277 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to register filter"); |
278 | | |
279 | 0 | done: |
280 | 0 | FUNC_LEAVE_API(ret_value) |
281 | 0 | } |
282 | | |
283 | | /*------------------------------------------------------------------------- |
284 | | * Function: H5Z_register |
285 | | * |
286 | | * Purpose: Same as the public version except this one allows filters |
287 | | * to be set for predefined method numbers < H5Z_FILTER_RESERVED |
288 | | * |
289 | | * Return: Non-negative on success |
290 | | * Negative on failure |
291 | | *------------------------------------------------------------------------- |
292 | | */ |
293 | | herr_t |
294 | | H5Z_register(const H5Z_class2_t *cls) |
295 | 5 | { |
296 | 5 | size_t i; |
297 | 5 | herr_t ret_value = SUCCEED; /* Return value */ |
298 | | |
299 | 5 | FUNC_ENTER_NOAPI(FAIL) |
300 | | |
301 | 5 | assert(cls); |
302 | 5 | assert(cls->id >= 0 && cls->id <= H5Z_FILTER_MAX); |
303 | | |
304 | | /* Is the filter already registered? */ |
305 | 15 | for (i = 0; i < H5Z_table_used_g; i++) |
306 | 10 | if (H5Z_table_g[i].id == cls->id) |
307 | 0 | break; |
308 | | |
309 | | /* Filter not already registered */ |
310 | 5 | if (i >= H5Z_table_used_g) { |
311 | 5 | if (H5Z_table_used_g >= H5Z_table_alloc_g) { |
312 | 1 | size_t n = MAX(H5Z_MAX_NFILTERS, 2 * H5Z_table_alloc_g); |
313 | 1 | H5Z_class2_t *table = (H5Z_class2_t *)H5MM_realloc(H5Z_table_g, n * sizeof(H5Z_class2_t)); |
314 | | #ifdef H5Z_DEBUG |
315 | | H5Z_stats_t *stat_table = (H5Z_stats_t *)H5MM_realloc(H5Z_stat_table_g, n * sizeof(H5Z_stats_t)); |
316 | | #endif /* H5Z_DEBUG */ |
317 | 1 | if (!table) |
318 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to extend filter table"); |
319 | 1 | H5Z_table_g = table; |
320 | | #ifdef H5Z_DEBUG |
321 | | if (!stat_table) |
322 | | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to extend filter statistics table"); |
323 | | H5Z_stat_table_g = stat_table; |
324 | | #endif /* H5Z_DEBUG */ |
325 | 1 | H5Z_table_alloc_g = n; |
326 | 1 | } /* end if */ |
327 | | |
328 | | /* Initialize */ |
329 | 5 | i = H5Z_table_used_g++; |
330 | 5 | H5MM_memcpy(H5Z_table_g + i, cls, sizeof(H5Z_class2_t)); |
331 | | #ifdef H5Z_DEBUG |
332 | | memset(H5Z_stat_table_g + i, 0, sizeof(H5Z_stats_t)); |
333 | | #endif /* H5Z_DEBUG */ |
334 | 5 | } /* end if */ |
335 | | /* Filter already registered */ |
336 | 0 | else { |
337 | | /* Replace old contents */ |
338 | 0 | H5MM_memcpy(H5Z_table_g + i, cls, sizeof(H5Z_class2_t)); |
339 | 0 | } /* end else */ |
340 | | |
341 | 5 | done: |
342 | 5 | FUNC_LEAVE_NOAPI(ret_value) |
343 | 5 | } |
344 | | |
345 | | /*------------------------------------------------------------------------- |
346 | | * Function: H5Zunregister |
347 | | * |
348 | | * Purpose: This function unregisters a filter. |
349 | | * |
350 | | * Return: Non-negative on success |
351 | | * Negative on failure |
352 | | *------------------------------------------------------------------------- |
353 | | */ |
354 | | herr_t |
355 | | H5Zunregister(H5Z_filter_t id) |
356 | 0 | { |
357 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
358 | |
|
359 | 0 | FUNC_ENTER_API(FAIL) |
360 | | |
361 | | /* Check args */ |
362 | 0 | if (id < 0 || id > H5Z_FILTER_MAX) |
363 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid filter identification number"); |
364 | 0 | if (id < H5Z_FILTER_RESERVED) |
365 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to modify predefined filters"); |
366 | | |
367 | | /* Do it */ |
368 | 0 | if (H5Z__unregister(id) < 0) |
369 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to unregister filter"); |
370 | | |
371 | 0 | done: |
372 | 0 | FUNC_LEAVE_API(ret_value) |
373 | 0 | } /* end H5Zunregister() */ |
374 | | |
375 | | /*------------------------------------------------------------------------- |
376 | | * Function: H5Z__unregister |
377 | | * |
378 | | * Purpose: Same as the public version except this one allows filters |
379 | | * to be unset for predefined method numbers <H5Z_FILTER_RESERVED |
380 | | * |
381 | | * Return: SUCCEED/FAIL |
382 | | * |
383 | | *------------------------------------------------------------------------- |
384 | | */ |
385 | | herr_t |
386 | | H5Z__unregister(H5Z_filter_t filter_id) |
387 | 0 | { |
388 | 0 | size_t filter_index; /* Local index variable for filter */ |
389 | 0 | H5Z_object_t object; /* Object to pass to callbacks */ |
390 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
391 | |
|
392 | 0 | FUNC_ENTER_PACKAGE |
393 | |
|
394 | 0 | assert(filter_id >= 0 && filter_id <= H5Z_FILTER_MAX); |
395 | | |
396 | | /* Is the filter already registered? */ |
397 | 0 | for (filter_index = 0; filter_index < H5Z_table_used_g; filter_index++) |
398 | 0 | if (H5Z_table_g[filter_index].id == filter_id) |
399 | 0 | break; |
400 | | |
401 | | /* Fail if filter not found */ |
402 | 0 | if (filter_index >= H5Z_table_used_g) |
403 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_NOTFOUND, FAIL, "filter is not registered"); |
404 | | |
405 | | /* Initialize the structure object for iteration */ |
406 | 0 | object.filter_id = filter_id; |
407 | 0 | object.found = false; |
408 | | #ifdef H5_HAVE_PARALLEL |
409 | | object.sanity_checked = false; |
410 | | #endif /* H5_HAVE_PARALLEL */ |
411 | | |
412 | | /* Iterate through all opened datasets, returns a failure if any of them uses the filter */ |
413 | 0 | if (H5I_iterate(H5I_DATASET, H5Z__check_unregister_dset_cb, &object, false) < 0) |
414 | 0 | HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "iteration failed"); |
415 | | |
416 | 0 | if (object.found) |
417 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANTRELEASE, FAIL, |
418 | 0 | "can't unregister filter because a dataset is still using it"); |
419 | | |
420 | | /* Iterate through all opened groups, returns a failure if any of them uses the filter */ |
421 | 0 | if (H5I_iterate(H5I_GROUP, H5Z__check_unregister_group_cb, &object, false) < 0) |
422 | 0 | HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "iteration failed"); |
423 | | |
424 | 0 | if (object.found) |
425 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANTRELEASE, FAIL, |
426 | 0 | "can't unregister filter because a group is still using it"); |
427 | | |
428 | | /* Iterate through all opened files and flush them */ |
429 | 0 | if (H5I_iterate(H5I_FILE, H5Z__flush_file_cb, &object, false) < 0) |
430 | 0 | HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "iteration failed"); |
431 | | |
432 | | /* Remove filter from table */ |
433 | | /* Don't worry about shrinking table size (for now) */ |
434 | 0 | memmove(&H5Z_table_g[filter_index], &H5Z_table_g[filter_index + 1], |
435 | 0 | sizeof(H5Z_class2_t) * ((H5Z_table_used_g - 1) - filter_index)); |
436 | | #ifdef H5Z_DEBUG |
437 | | memmove(&H5Z_stat_table_g[filter_index], &H5Z_stat_table_g[filter_index + 1], |
438 | | sizeof(H5Z_stats_t) * ((H5Z_table_used_g - 1) - filter_index)); |
439 | | #endif /* H5Z_DEBUG */ |
440 | 0 | H5Z_table_used_g--; |
441 | |
|
442 | 0 | done: |
443 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
444 | 0 | } /* end H5Z__unregister() */ |
445 | | |
446 | | /*------------------------------------------------------------------------- |
447 | | * Function: H5Z__check_unregister |
448 | | * |
449 | | * Purpose: Check if an object uses the filter to be unregistered. |
450 | | * |
451 | | * Return: true if the object uses the filter |
452 | | * false if not |
453 | | * NEGATIVE on error |
454 | | * |
455 | | *------------------------------------------------------------------------- |
456 | | */ |
457 | | static htri_t |
458 | | H5Z__check_unregister(hid_t ocpl_id, H5Z_filter_t filter_id) |
459 | 0 | { |
460 | 0 | H5P_genplist_t *plist; /* Property list */ |
461 | 0 | htri_t ret_value = false; /* Return value */ |
462 | |
|
463 | 0 | FUNC_ENTER_PACKAGE |
464 | | |
465 | | /* Get the plist structure of object creation */ |
466 | 0 | if (NULL == (plist = H5P_object_verify(ocpl_id, H5P_OBJECT_CREATE))) |
467 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_BADID, FAIL, "can't find object for ID"); |
468 | | |
469 | | /* Check if the object creation property list uses the filter */ |
470 | 0 | if ((ret_value = H5P_filter_in_pline(plist, filter_id)) < 0) |
471 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "can't check filter in pipeline"); |
472 | | |
473 | 0 | done: |
474 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
475 | 0 | } /* end H5Z__check_unregister() */ |
476 | | |
477 | | /*------------------------------------------------------------------------- |
478 | | * Function: H5Z__check_unregister_group_cb |
479 | | * |
480 | | * Purpose: The callback function for H5Z__unregister. It iterates |
481 | | * through all opened objects. If the object is a dataset |
482 | | * or a group and it uses the filter to be unregistered, the |
483 | | * function returns true. |
484 | | * |
485 | | * Return: true if the object uses the filter |
486 | | * false if not |
487 | | * NEGATIVE on error |
488 | | * |
489 | | *------------------------------------------------------------------------- |
490 | | */ |
491 | | static int |
492 | | H5Z__check_unregister_group_cb(void H5_ATTR_UNUSED *obj_ptr, hid_t obj_id, void *key) |
493 | 0 | { |
494 | 0 | hid_t ocpl_id = -1; |
495 | 0 | H5Z_object_t *object = (H5Z_object_t *)key; |
496 | 0 | H5VL_object_t *vol_obj; /* Object for loc_id */ |
497 | 0 | H5VL_group_get_args_t vol_cb_args; /* Arguments to VOL callback */ |
498 | 0 | htri_t filter_in_pline = false; |
499 | 0 | int ret_value = false; /* Return value */ |
500 | |
|
501 | 0 | FUNC_ENTER_PACKAGE |
502 | | |
503 | | /* Get the group creation property */ |
504 | 0 | if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(obj_id, H5I_GROUP))) |
505 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "invalid group identifier"); |
506 | | |
507 | | /* Set up VOL callback arguments */ |
508 | 0 | vol_cb_args.op_type = H5VL_GROUP_GET_GCPL; |
509 | 0 | vol_cb_args.args.get_gcpl.gcpl_id = H5I_INVALID_HID; |
510 | | |
511 | | /* Get the group creation property list */ |
512 | 0 | if (H5VL_group_get(vol_obj, &vol_cb_args, H5P_DATASET_XFER_DEFAULT, H5_REQUEST_NULL) < 0) |
513 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, H5I_INVALID_HID, "unable to get group creation properties"); |
514 | | |
515 | 0 | if ((ocpl_id = vol_cb_args.args.get_gcpl.gcpl_id) < 0) |
516 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "can't get group creation property list"); |
517 | | |
518 | | /* Check if the filter is in the group creation property list */ |
519 | 0 | if ((filter_in_pline = H5Z__check_unregister(ocpl_id, object->filter_id)) < 0) |
520 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "can't check filter in pipeline"); |
521 | | |
522 | | /* H5I_iterate expects true to stop the loop over objects. Stop the loop and |
523 | | * let H5Z__unregister return failure. |
524 | | */ |
525 | 0 | if (filter_in_pline) { |
526 | 0 | object->found = true; |
527 | 0 | ret_value = true; |
528 | 0 | } |
529 | |
|
530 | 0 | done: |
531 | 0 | if (ocpl_id > 0) |
532 | 0 | if (H5I_dec_app_ref(ocpl_id) < 0) |
533 | 0 | HDONE_ERROR(H5E_PLINE, H5E_CANTDEC, FAIL, "can't release plist"); |
534 | |
|
535 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
536 | 0 | } /* end H5Z__check_unregister_group_cb() */ |
537 | | |
538 | | /*------------------------------------------------------------------------- |
539 | | * Function: H5Z__check_unregister_dset_cb |
540 | | * |
541 | | * Purpose: The callback function for H5Z__unregister. It iterates |
542 | | * through all opened objects. If the object is a dataset |
543 | | * or a group and it uses the filter to be unregistered, the |
544 | | * function returns true. |
545 | | * |
546 | | * Return: true if the object uses the filter |
547 | | * false if not |
548 | | * NEGATIVE on error |
549 | | * |
550 | | *------------------------------------------------------------------------- |
551 | | */ |
552 | | static int |
553 | | H5Z__check_unregister_dset_cb(void H5_ATTR_UNUSED *obj_ptr, hid_t obj_id, void *key) |
554 | 0 | { |
555 | 0 | hid_t ocpl_id = -1; |
556 | 0 | H5Z_object_t *object = (H5Z_object_t *)key; |
557 | 0 | H5VL_object_t *vol_obj; /* Object for loc_id */ |
558 | 0 | H5VL_dataset_get_args_t vol_cb_args; /* Arguments to VOL callback */ |
559 | 0 | htri_t filter_in_pline = false; |
560 | 0 | int ret_value = false; /* Return value */ |
561 | |
|
562 | 0 | FUNC_ENTER_PACKAGE |
563 | | |
564 | | /* Get the dataset creation property */ |
565 | 0 | if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(obj_id, H5I_DATASET))) |
566 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "invalid dataset identifier"); |
567 | | |
568 | | /* Set up VOL callback arguments */ |
569 | 0 | vol_cb_args.op_type = H5VL_DATASET_GET_DCPL; |
570 | 0 | vol_cb_args.args.get_dcpl.dcpl_id = H5I_INVALID_HID; |
571 | | |
572 | | /* Get the dataset creation property list */ |
573 | 0 | if (H5VL_dataset_get(vol_obj, &vol_cb_args, H5P_DATASET_XFER_DEFAULT, H5_REQUEST_NULL) < 0) |
574 | 0 | HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, H5I_INVALID_HID, "unable to get dataset creation properties"); |
575 | | |
576 | 0 | if ((ocpl_id = vol_cb_args.args.get_dcpl.dcpl_id) < 0) |
577 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "can't get dataset creation property list"); |
578 | | |
579 | | /* Check if the filter is in the dataset creation property list */ |
580 | 0 | if ((filter_in_pline = H5Z__check_unregister(ocpl_id, object->filter_id)) < 0) |
581 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "can't check filter in pipeline"); |
582 | | |
583 | | /* H5I_iterate expects true to stop the loop over objects. Stop the loop and |
584 | | * let H5Z__unregister return failure. |
585 | | */ |
586 | 0 | if (filter_in_pline) { |
587 | 0 | object->found = true; |
588 | 0 | ret_value = true; |
589 | 0 | } |
590 | |
|
591 | 0 | done: |
592 | 0 | if (ocpl_id > 0) |
593 | 0 | if (H5I_dec_app_ref(ocpl_id) < 0) |
594 | 0 | HDONE_ERROR(H5E_PLINE, H5E_CANTDEC, FAIL, "can't release plist"); |
595 | |
|
596 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
597 | 0 | } /* end H5Z__check_unregister_dset_cb() */ |
598 | | |
599 | | /*------------------------------------------------------------------------- |
600 | | * Function: H5Z__flush_file_cb |
601 | | * |
602 | | * Purpose: The callback function for H5Z__unregister. It iterates |
603 | | * through all opened files and flush them. |
604 | | * |
605 | | * Return: NON-NEGATIVE if finishes flushing and moves on |
606 | | * NEGATIVE if there is an error |
607 | | *------------------------------------------------------------------------- |
608 | | */ |
609 | | static int |
610 | | H5Z__flush_file_cb(void H5_ATTR_UNUSED *obj_ptr, hid_t obj_id, void H5_ATTR_PARALLEL_USED *key) |
611 | 0 | { |
612 | |
|
613 | | #ifdef H5_HAVE_PARALLEL |
614 | | H5Z_object_t *object = (H5Z_object_t *)key; |
615 | | #endif /* H5_HAVE_PARALLEL */ |
616 | 0 | int ret_value = false; /* Return value */ |
617 | 0 | H5VL_file_specific_args_t vol_cb_args_specific; /* Arguments to VOL callback */ |
618 | 0 | H5VL_object_t *vol_obj; /* File for file_id */ |
619 | 0 | H5VL_file_get_args_t vol_cb_args; /* Arguments to VOL callback */ |
620 | 0 | bool is_native_vol_obj = true; |
621 | 0 | unsigned int intent = 0; |
622 | |
|
623 | 0 | FUNC_ENTER_PACKAGE |
624 | | |
625 | | /* Sanity checks */ |
626 | 0 | assert(key); |
627 | | |
628 | | /* Get the internal file structure */ |
629 | 0 | if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(obj_id))) |
630 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid file identifier"); |
631 | | |
632 | | /* Get intent */ |
633 | 0 | vol_cb_args.op_type = H5VL_FILE_GET_INTENT; |
634 | 0 | vol_cb_args.args.get_intent.flags = &intent; |
635 | | |
636 | | /* Get the flags */ |
637 | 0 | if (H5VL_file_get(vol_obj, &vol_cb_args, H5P_DATASET_XFER_DEFAULT, H5_REQUEST_NULL) < 0) |
638 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get file's intent flags"); |
639 | | |
640 | 0 | if (H5VL_object_is_native(vol_obj, &is_native_vol_obj) < 0) |
641 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, H5I_INVALID_HID, |
642 | 0 | "can't determine if VOL object is native connector object"); |
643 | | |
644 | | /* Do a global flush if the file is opened for write */ |
645 | 0 | if (H5F_ACC_RDWR & intent) { |
646 | |
|
647 | | #ifdef H5_HAVE_PARALLEL |
648 | | /* Checking MPI flag requires native VOL */ |
649 | | if (is_native_vol_obj) { |
650 | | H5F_t *f = (H5F_t *)obj_ptr; /* File object for native VOL operation */ |
651 | | |
652 | | /* Check if MPIO driver is used */ |
653 | | if (H5F_HAS_FEATURE(f, H5FD_FEAT_HAS_MPI)) { |
654 | | |
655 | | /* Sanity check for collectively calling H5Zunregister, if requested */ |
656 | | /* (Sanity check assumes that a barrier on one file's comm |
657 | | * is sufficient (i.e. that there aren't different comms for |
658 | | * different files). -QAK, 2018/02/14) |
659 | | */ |
660 | | if (H5_coll_api_sanity_check_g && !object->sanity_checked) { |
661 | | MPI_Comm mpi_comm; /* File's communicator */ |
662 | | |
663 | | /* Retrieve the file communicator */ |
664 | | if (H5F_mpi_retrieve_comm(obj_id, H5P_DEFAULT, &mpi_comm) < 0) |
665 | | HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "can't get MPI communicator"); |
666 | | |
667 | | /* Issue the barrier */ |
668 | | if (mpi_comm != MPI_COMM_NULL) |
669 | | MPI_Barrier(mpi_comm); |
670 | | |
671 | | /* Set the "sanity checked" flag */ |
672 | | object->sanity_checked = true; |
673 | | } /* end if */ |
674 | | } /* end if */ |
675 | | } |
676 | | #endif /* H5_HAVE_PARALLEL */ |
677 | | |
678 | | /* Call the flush routine for mounted file hierarchies */ |
679 | 0 | vol_cb_args_specific.op_type = H5VL_FILE_FLUSH; |
680 | 0 | vol_cb_args_specific.args.flush.obj_type = H5I_FILE; |
681 | 0 | vol_cb_args_specific.args.flush.scope = H5F_SCOPE_GLOBAL; |
682 | | |
683 | | /* Flush the object */ |
684 | 0 | if (H5VL_file_specific(vol_obj, &vol_cb_args_specific, H5P_DATASET_XFER_DEFAULT, NULL) < 0) |
685 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush file hierarchy"); |
686 | |
|
687 | 0 | } /* end if */ |
688 | | |
689 | 0 | done: |
690 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
691 | 0 | } /* end H5Z__flush_file_cb() */ |
692 | | |
693 | | /*------------------------------------------------------------------------- |
694 | | * Function: H5Zfilter_avail |
695 | | * |
696 | | * Purpose: Check if a filter is available |
697 | | * |
698 | | * Return: Non-negative (true/false) on success/Negative on failure |
699 | | *------------------------------------------------------------------------- |
700 | | */ |
701 | | htri_t |
702 | | H5Zfilter_avail(H5Z_filter_t id) |
703 | 0 | { |
704 | 0 | htri_t ret_value = false; /* Return value */ |
705 | |
|
706 | 0 | FUNC_ENTER_API(FAIL) |
707 | | |
708 | | /* Check args */ |
709 | 0 | if (id < 0 || id > H5Z_FILTER_MAX) |
710 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid filter identification number"); |
711 | | |
712 | 0 | if ((ret_value = H5Z_filter_avail(id)) < 0) |
713 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_NOTFOUND, FAIL, "unable to check the availability of the filter"); |
714 | | |
715 | 0 | done: |
716 | 0 | FUNC_LEAVE_API(ret_value) |
717 | 0 | } /* end H5Zfilter_avail() */ |
718 | | |
719 | | /*------------------------------------------------------------------------- |
720 | | * Function: H5Z_filter_avail |
721 | | * |
722 | | * Purpose: Private function to check if a filter is available |
723 | | * |
724 | | * Return: Non-negative (true/false) on success/Negative on failure |
725 | | *------------------------------------------------------------------------- |
726 | | */ |
727 | | htri_t |
728 | | H5Z_filter_avail(H5Z_filter_t id) |
729 | 0 | { |
730 | 0 | H5PL_key_t key; /* Key for finding a plugin */ |
731 | 0 | const H5Z_class2_t *filter_info; /* Filter information */ |
732 | 0 | size_t i; /* Local index variable */ |
733 | 0 | htri_t ret_value = false; /* Return value */ |
734 | |
|
735 | 0 | FUNC_ENTER_NOAPI(FAIL) |
736 | | |
737 | | /* Is the filter already registered? */ |
738 | 0 | for (i = 0; i < H5Z_table_used_g; i++) |
739 | 0 | if (H5Z_table_g[i].id == id) |
740 | 0 | HGOTO_DONE(true); |
741 | | |
742 | 0 | key.id = (int)id; |
743 | 0 | if (NULL != (filter_info = (const H5Z_class2_t *)H5PL_load(H5PL_TYPE_FILTER, &key))) { |
744 | 0 | if (H5Z_register(filter_info) < 0) |
745 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to register loaded filter"); |
746 | 0 | HGOTO_DONE(true); |
747 | 0 | } /* end if */ |
748 | | |
749 | 0 | done: |
750 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
751 | 0 | } /* end H5Z_filter_avail() */ |
752 | | |
753 | | /*------------------------------------------------------------------------- |
754 | | * Function: H5Z__prelude_callback |
755 | | * |
756 | | * Purpose: Makes a dataset creation "prelude" callback for the "can_apply" |
757 | | * or "set_local" routines. |
758 | | * |
759 | | * Return: Non-negative on success/Negative on failure |
760 | | * |
761 | | * Notes: The chunk dimensions are used to create a dataspace, instead |
762 | | * of passing in the dataset's dataspace, since the chunk |
763 | | * dimensions are what the I/O filter will actually see |
764 | | *------------------------------------------------------------------------- |
765 | | */ |
766 | | static herr_t |
767 | | H5Z__prelude_callback(const H5O_pline_t *pline, hid_t dcpl_id, hid_t type_id, hid_t space_id, |
768 | | H5Z_prelude_type_t prelude_type) |
769 | 0 | { |
770 | 0 | H5Z_class2_t *fclass; /* Individual filter information */ |
771 | 0 | size_t u; /* Local index variable */ |
772 | 0 | htri_t ret_value = true; /* Return value */ |
773 | |
|
774 | 0 | FUNC_ENTER_PACKAGE |
775 | |
|
776 | 0 | assert(pline->nused > 0); |
777 | | |
778 | | /* Iterate over filters */ |
779 | 0 | for (u = 0; u < pline->nused; u++) { |
780 | | /* Get filter information */ |
781 | 0 | if (NULL == (fclass = H5Z_find(pline->filter[u].id))) { |
782 | | /* Ignore errors from optional filters */ |
783 | 0 | if (pline->filter[u].flags & H5Z_FLAG_OPTIONAL) |
784 | 0 | H5E_clear_stack(); |
785 | 0 | else |
786 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_NOTFOUND, FAIL, "required filter was not located"); |
787 | 0 | } /* end if */ |
788 | 0 | else { |
789 | | /* Make correct callback */ |
790 | 0 | switch (prelude_type) { |
791 | 0 | case H5Z_PRELUDE_CAN_APPLY: |
792 | | /* Check if filter is configured to be able to encode */ |
793 | 0 | if (!fclass->encoder_present) |
794 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_NOENCODER, FAIL, |
795 | 0 | "Filter present but encoding is disabled."); |
796 | | |
797 | | /* Check if there is a "can apply" callback */ |
798 | 0 | if (fclass->can_apply) { |
799 | | /* Make callback to filter's "can apply" function */ |
800 | 0 | htri_t status = (fclass->can_apply)(dcpl_id, type_id, space_id); |
801 | | |
802 | | /* Indicate error during filter callback */ |
803 | 0 | if (status < 0) |
804 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANAPPLY, FAIL, "error during user callback"); |
805 | | |
806 | | /* Indicate filter can't apply to this combination of parameters. |
807 | | * If the filter is NOT optional, returns failure. */ |
808 | 0 | if (status == false && !(pline->filter[u].flags & H5Z_FLAG_OPTIONAL)) |
809 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANAPPLY, FAIL, "filter parameters not appropriate"); |
810 | 0 | } /* end if */ |
811 | 0 | break; |
812 | | |
813 | 0 | case H5Z_PRELUDE_SET_LOCAL: |
814 | | /* Check if there is a "set local" callback */ |
815 | 0 | if (fclass->set_local) { |
816 | | /* Make callback to filter's "set local" function */ |
817 | 0 | if ((fclass->set_local)(dcpl_id, type_id, space_id) < 0) |
818 | | /* Indicate error during filter callback */ |
819 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_SETLOCAL, FAIL, "error during user callback"); |
820 | 0 | } /* end if */ |
821 | 0 | break; |
822 | | |
823 | 0 | default: |
824 | 0 | assert("invalid prelude type" && 0); |
825 | 0 | } /* end switch */ |
826 | 0 | } /* end else */ |
827 | 0 | } /* end for */ |
828 | | |
829 | 0 | done: |
830 | |
|
831 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
832 | 0 | } /* end H5Z__prelude_callback() */ |
833 | | |
834 | | /*------------------------------------------------------------------------- |
835 | | * Function: H5Z__prepare_prelude_callback_dcpl |
836 | | * |
837 | | * Purpose: Prepares to make a dataset creation "prelude" callback |
838 | | * for the "can_apply" or "set_local" routines. |
839 | | * |
840 | | * Return: Non-negative on success/Negative on failure |
841 | | * |
842 | | * Notes: The chunk dimensions are used to create a dataspace, instead |
843 | | * of passing in the dataset's dataspace, since the chunk |
844 | | * dimensions are what the I/O filter will actually see |
845 | | *------------------------------------------------------------------------- |
846 | | */ |
847 | | static herr_t |
848 | | H5Z__prepare_prelude_callback_dcpl(hid_t dcpl_id, hid_t type_id, H5Z_prelude_type_t prelude_type) |
849 | 0 | { |
850 | 0 | hid_t space_id = -1; /* ID for dataspace describing chunk */ |
851 | 0 | H5O_layout_t *dcpl_layout = NULL; /* Dataset's layout information */ |
852 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
853 | |
|
854 | 0 | FUNC_ENTER_PACKAGE |
855 | |
|
856 | 0 | assert(H5I_GENPROP_LST == H5I_get_type(dcpl_id)); |
857 | 0 | assert(H5I_DATATYPE == H5I_get_type(type_id)); |
858 | | |
859 | | /* Check if the property list is non-default */ |
860 | 0 | if (dcpl_id != H5P_DATASET_CREATE_DEFAULT) { |
861 | 0 | H5P_genplist_t *dc_plist; /* Dataset creation property list object */ |
862 | | |
863 | | /* Get memory for the layout */ |
864 | 0 | if (NULL == (dcpl_layout = (H5O_layout_t *)H5MM_calloc(sizeof(H5O_layout_t)))) |
865 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate dcpl layout buffer"); |
866 | | |
867 | | /* Get dataset creation property list object */ |
868 | 0 | if (NULL == (dc_plist = (H5P_genplist_t *)H5I_object(dcpl_id))) |
869 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get dataset creation property list"); |
870 | | |
871 | | /* Peek at the layout information */ |
872 | 0 | if (H5P_peek(dc_plist, H5D_CRT_LAYOUT_NAME, dcpl_layout) < 0) |
873 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't retrieve layout"); |
874 | | |
875 | | /* Check if the dataset is chunked */ |
876 | 0 | if (H5D_CHUNKED == dcpl_layout->type) { |
877 | 0 | H5O_pline_t dcpl_pline; /* Object's I/O pipeline information */ |
878 | | |
879 | | /* Get I/O pipeline information */ |
880 | 0 | if (H5P_peek(dc_plist, H5O_CRT_PIPELINE_NAME, &dcpl_pline) < 0) |
881 | 0 | HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't retrieve pipeline filter"); |
882 | | |
883 | | /* Check if the chunks have filters */ |
884 | 0 | if (dcpl_pline.nused > 0) { |
885 | 0 | hsize_t chunk_dims[H5O_LAYOUT_NDIMS]; /* Size of chunk dimensions */ |
886 | 0 | H5S_t *space; /* Dataspace describing chunk */ |
887 | 0 | size_t u; /* Local index variable */ |
888 | | |
889 | | /* Create a dataspace for a chunk & set the extent */ |
890 | 0 | for (u = 0; u < dcpl_layout->u.chunk.ndims; u++) |
891 | 0 | chunk_dims[u] = dcpl_layout->u.chunk.dim[u]; |
892 | 0 | if (NULL == (space = H5S_create_simple(dcpl_layout->u.chunk.ndims, chunk_dims, NULL))) |
893 | 0 | HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, FAIL, "can't create simple dataspace"); |
894 | | |
895 | | /* Get ID for dataspace to pass to filter routines */ |
896 | 0 | if ((space_id = H5I_register(H5I_DATASPACE, space, false)) < 0) { |
897 | 0 | (void)H5S_close(space); |
898 | 0 | HGOTO_ERROR(H5E_ID, H5E_CANTREGISTER, FAIL, "unable to register dataspace ID"); |
899 | 0 | } |
900 | | |
901 | | /* Make the callbacks */ |
902 | 0 | if (H5Z__prelude_callback(&dcpl_pline, dcpl_id, type_id, space_id, prelude_type) < 0) |
903 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANAPPLY, FAIL, "unable to apply filter"); |
904 | 0 | } |
905 | 0 | } |
906 | 0 | } |
907 | | |
908 | 0 | done: |
909 | 0 | if (space_id > 0 && H5I_dec_ref(space_id) < 0) |
910 | 0 | HDONE_ERROR(H5E_PLINE, H5E_CANTRELEASE, FAIL, "unable to close dataspace"); |
911 | |
|
912 | 0 | if (dcpl_layout) |
913 | 0 | dcpl_layout = (H5O_layout_t *)H5MM_xfree(dcpl_layout); |
914 | |
|
915 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
916 | 0 | } /* end H5Z__prepare_prelude_callback_dcpl() */ |
917 | | |
918 | | /*------------------------------------------------------------------------- |
919 | | * Function: H5Z_can_apply |
920 | | * |
921 | | * Purpose: Checks if all the filters defined in the dataset creation |
922 | | * property list can be applied to a particular combination of |
923 | | * datatype and dataspace for a dataset. |
924 | | * |
925 | | * Return: Non-negative on success |
926 | | * Negative on failure |
927 | | * |
928 | | * Notes: The chunk dimensions are used to create a dataspace, instead |
929 | | * of passing in the dataset's dataspace, since the chunk |
930 | | * dimensions are what the I/O filter will actually see |
931 | | *------------------------------------------------------------------------- |
932 | | */ |
933 | | herr_t |
934 | | H5Z_can_apply(hid_t dcpl_id, hid_t type_id) |
935 | 0 | { |
936 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
937 | |
|
938 | 0 | FUNC_ENTER_NOAPI(FAIL) |
939 | | |
940 | | /* Make "can apply" callbacks for filters in pipeline */ |
941 | 0 | if (H5Z__prepare_prelude_callback_dcpl(dcpl_id, type_id, H5Z_PRELUDE_CAN_APPLY) < 0) |
942 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANAPPLY, FAIL, "unable to apply filter"); |
943 | | |
944 | 0 | done: |
945 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
946 | 0 | } /* end H5Z_can_apply() */ |
947 | | |
948 | | /*------------------------------------------------------------------------- |
949 | | * Function: H5Z_set_local |
950 | | * |
951 | | * Purpose: Makes callbacks to modify dataset creation list property |
952 | | * settings for filters on a new dataset, based on the datatype |
953 | | * and dataspace of that dataset (chunk). |
954 | | * |
955 | | * Return: Non-negative on success |
956 | | * Negative on failure |
957 | | * |
958 | | * Notes: The chunk dimensions are used to create a dataspace, instead |
959 | | * of passing in the dataset's dataspace, since the chunk |
960 | | * dimensions are what the I/O filter will actually see |
961 | | *------------------------------------------------------------------------- |
962 | | */ |
963 | | herr_t |
964 | | H5Z_set_local(hid_t dcpl_id, hid_t type_id) |
965 | 0 | { |
966 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
967 | |
|
968 | 0 | FUNC_ENTER_NOAPI(FAIL) |
969 | | |
970 | | /* Make "set local" callbacks for filters in pipeline */ |
971 | 0 | if (H5Z__prepare_prelude_callback_dcpl(dcpl_id, type_id, H5Z_PRELUDE_SET_LOCAL) < 0) |
972 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_SETLOCAL, FAIL, "local filter parameters not set"); |
973 | | |
974 | 0 | done: |
975 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
976 | 0 | } /* end H5Z_set_local() */ |
977 | | |
978 | | /*------------------------------------------------------------------------- |
979 | | * Function: H5Z_can_apply_direct |
980 | | * |
981 | | * Purpose: Checks if all the filters defined in the pipeline can be |
982 | | * applied to an opaque byte stream (currently only a group). |
983 | | * The pipeline is assumed to have at least one filter. |
984 | | * |
985 | | * Return: Non-negative on success |
986 | | * Negative on failure |
987 | | *------------------------------------------------------------------------- |
988 | | */ |
989 | | herr_t |
990 | | H5Z_can_apply_direct(const H5O_pline_t *pline) |
991 | 0 | { |
992 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
993 | |
|
994 | 0 | FUNC_ENTER_NOAPI(FAIL) |
995 | |
|
996 | 0 | assert(pline->nused > 0); |
997 | | |
998 | | /* Make "can apply" callbacks for filters in pipeline */ |
999 | 0 | if (H5Z__prelude_callback(pline, (hid_t)-1, (hid_t)-1, (hid_t)-1, H5Z_PRELUDE_CAN_APPLY) < 0) |
1000 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANAPPLY, FAIL, "unable to apply filter"); |
1001 | | |
1002 | 0 | done: |
1003 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1004 | 0 | } /* end H5Z_can_apply_direct() */ |
1005 | | |
1006 | | /*------------------------------------------------------------------------- |
1007 | | * Function: H5Z_set_local_direct |
1008 | | * |
1009 | | * Purpose: Makes callbacks to modify local settings for filters on a |
1010 | | * new opaque object. The pipeline is assumed to have at |
1011 | | * least one filter. |
1012 | | * |
1013 | | * Return: Non-negative on success |
1014 | | * Negative on failure |
1015 | | * |
1016 | | * Notes: This callback will almost certainly not do anything |
1017 | | * useful, other than to make certain that the filter will |
1018 | | * accept opaque data. |
1019 | | *------------------------------------------------------------------------- |
1020 | | */ |
1021 | | herr_t |
1022 | | H5Z_set_local_direct(const H5O_pline_t *pline) |
1023 | 0 | { |
1024 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1025 | |
|
1026 | 0 | FUNC_ENTER_NOAPI(FAIL) |
1027 | |
|
1028 | 0 | assert(pline->nused > 0); |
1029 | | |
1030 | | /* Make "set local" callbacks for filters in pipeline */ |
1031 | 0 | if (H5Z__prelude_callback(pline, (hid_t)-1, (hid_t)-1, (hid_t)-1, H5Z_PRELUDE_SET_LOCAL) < 0) |
1032 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_SETLOCAL, FAIL, "local filter parameters not set"); |
1033 | | |
1034 | 0 | done: |
1035 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1036 | 0 | } /* end H5Z_set_local_direct() */ |
1037 | | |
1038 | | /*------------------------------------------------------------------------- |
1039 | | * Function: H5Z_ignore_filters |
1040 | | * |
1041 | | * Purpose: Determine whether filters can be ignored. |
1042 | | * |
1043 | | * Description: |
1044 | | * When the filters are optional (i.e., H5Z_FLAG_OPTIONAL is provided,) |
1045 | | * if any of the following conditions is met, the filters will be ignored: |
1046 | | * - dataspace is either H5S_NULL or H5S_SCALAR |
1047 | | * - datatype is variable-length (string or non-string) |
1048 | | * However, if any of these conditions exists and a filter is not |
1049 | | * optional, the function will produce an error. |
1050 | | * |
1051 | | * Return: Non-negative(true/false) on success |
1052 | | * Negative on failure |
1053 | | * |
1054 | | *------------------------------------------------------------------------- |
1055 | | */ |
1056 | | htri_t |
1057 | | H5Z_ignore_filters(hid_t dcpl_id, const H5T_t *type, const H5S_t *space) |
1058 | 0 | { |
1059 | 0 | H5P_genplist_t *dc_plist; /* Dataset creation property list object */ |
1060 | 0 | H5O_pline_t pline; /* Object's I/O pipeline information */ |
1061 | 0 | H5S_class_t space_class; /* To check class of space */ |
1062 | 0 | H5T_class_t type_class; /* To check if type is VL */ |
1063 | 0 | bool bad_for_filters = false; /* Suitable to have filters */ |
1064 | 0 | htri_t ret_value = false; /* true for ignoring filters */ |
1065 | |
|
1066 | 0 | FUNC_ENTER_NOAPI(FAIL) |
1067 | |
|
1068 | 0 | if (NULL == (dc_plist = (H5P_genplist_t *)H5I_object(dcpl_id))) |
1069 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get dataset creation property list"); |
1070 | | |
1071 | | /* Get pipeline information */ |
1072 | 0 | if (H5P_peek(dc_plist, H5O_CRT_PIPELINE_NAME, &pline) < 0) |
1073 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "can't retrieve pipeline filter"); |
1074 | | |
1075 | | /* Get datatype and dataspace classes for quick access */ |
1076 | 0 | space_class = H5S_GET_EXTENT_TYPE(space); |
1077 | 0 | type_class = H5T_get_class(type, false); |
1078 | | |
1079 | | /* These conditions are not suitable for filters */ |
1080 | 0 | bad_for_filters = (H5S_NULL == space_class || H5S_SCALAR == space_class || H5T_VLEN == type_class || |
1081 | 0 | (H5T_STRING == type_class && true == H5T_is_variable_str(type))); |
1082 | | |
1083 | | /* When these conditions occur, if there are required filters in pline, |
1084 | | then report a failure, otherwise, set flag that they can be ignored */ |
1085 | 0 | if (bad_for_filters) { |
1086 | 0 | size_t ii; |
1087 | 0 | if (pline.nused > 0) { |
1088 | 0 | for (ii = 0; ii < pline.nused; ii++) { |
1089 | 0 | if (!(pline.filter[ii].flags & H5Z_FLAG_OPTIONAL)) |
1090 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANTFILTER, FAIL, "not suitable for filters"); |
1091 | 0 | } |
1092 | | |
1093 | | /* All filters are optional, we can ignore them */ |
1094 | 0 | ret_value = true; |
1095 | 0 | } |
1096 | 0 | } /* bad for filters */ |
1097 | | |
1098 | 0 | done: |
1099 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1100 | 0 | } /* end H5Z_ignore_filters() */ |
1101 | | |
1102 | | /*------------------------------------------------------------------------- |
1103 | | * Function: H5Z_modify |
1104 | | * |
1105 | | * Purpose: Modify filter parameters for specified pipeline. |
1106 | | * |
1107 | | * Return: Non-negative on success |
1108 | | * Negative on failure |
1109 | | *------------------------------------------------------------------------- |
1110 | | */ |
1111 | | herr_t |
1112 | | H5Z_modify(const H5O_pline_t *pline, H5Z_filter_t filter, unsigned flags, size_t cd_nelmts, |
1113 | | const unsigned int cd_values[/*cd_nelmts*/]) |
1114 | 0 | { |
1115 | 0 | size_t idx; /* Index of filter in pipeline */ |
1116 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1117 | |
|
1118 | 0 | FUNC_ENTER_NOAPI(FAIL) |
1119 | |
|
1120 | 0 | assert(pline); |
1121 | 0 | assert(filter >= 0 && filter <= H5Z_FILTER_MAX); |
1122 | 0 | assert(0 == (flags & ~((unsigned)H5Z_FLAG_DEFMASK))); |
1123 | 0 | assert(0 == cd_nelmts || cd_values); |
1124 | | |
1125 | | /* Locate the filter in the pipeline */ |
1126 | 0 | for (idx = 0; idx < pline->nused; idx++) |
1127 | 0 | if (pline->filter[idx].id == filter) |
1128 | 0 | break; |
1129 | | |
1130 | | /* Check if the filter was not already in the pipeline */ |
1131 | 0 | if (idx > pline->nused) |
1132 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_NOTFOUND, FAIL, "filter not in pipeline"); |
1133 | | |
1134 | | /* Change parameters for filter */ |
1135 | 0 | pline->filter[idx].flags = flags; |
1136 | 0 | pline->filter[idx].cd_nelmts = cd_nelmts; |
1137 | | |
1138 | | /* Free any existing parameters */ |
1139 | 0 | if (pline->filter[idx].cd_values != NULL && pline->filter[idx].cd_values != pline->filter[idx]._cd_values) |
1140 | 0 | H5MM_xfree(pline->filter[idx].cd_values); |
1141 | | |
1142 | | /* Set parameters */ |
1143 | 0 | if (cd_nelmts > 0) { |
1144 | 0 | size_t i; /* Local index variable */ |
1145 | | |
1146 | | /* Allocate memory or point at internal buffer */ |
1147 | 0 | if (cd_nelmts > H5Z_COMMON_CD_VALUES) { |
1148 | 0 | pline->filter[idx].cd_values = (unsigned *)H5MM_malloc(cd_nelmts * sizeof(unsigned)); |
1149 | 0 | if (NULL == pline->filter[idx].cd_values) |
1150 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, |
1151 | 0 | "memory allocation failed for filter parameters"); |
1152 | 0 | } /* end if */ |
1153 | 0 | else |
1154 | 0 | pline->filter[idx].cd_values = pline->filter[idx]._cd_values; |
1155 | | |
1156 | | /* Copy client data values */ |
1157 | 0 | for (i = 0; i < cd_nelmts; i++) |
1158 | 0 | pline->filter[idx].cd_values[i] = cd_values[i]; |
1159 | 0 | } /* end if */ |
1160 | 0 | else |
1161 | 0 | pline->filter[idx].cd_values = NULL; |
1162 | | |
1163 | 0 | done: |
1164 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1165 | 0 | } /* end H5Z_modify() */ |
1166 | | |
1167 | | /*------------------------------------------------------------------------- |
1168 | | * Function: H5Z_append |
1169 | | * |
1170 | | * Purpose: Append another filter to the specified pipeline. |
1171 | | * |
1172 | | * Return: Non-negative on success |
1173 | | * Negative on failure |
1174 | | *------------------------------------------------------------------------- |
1175 | | */ |
1176 | | herr_t |
1177 | | H5Z_append(H5O_pline_t *pline, H5Z_filter_t filter, unsigned flags, size_t cd_nelmts, |
1178 | | const unsigned int cd_values[/*cd_nelmts*/]) |
1179 | 0 | { |
1180 | 0 | size_t idx; |
1181 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1182 | |
|
1183 | 0 | FUNC_ENTER_NOAPI(FAIL) |
1184 | |
|
1185 | 0 | assert(pline); |
1186 | 0 | assert(filter >= 0 && filter <= H5Z_FILTER_MAX); |
1187 | 0 | assert(0 == (flags & ~((unsigned)H5Z_FLAG_DEFMASK))); |
1188 | 0 | assert(0 == cd_nelmts || cd_values); |
1189 | | |
1190 | | /* |
1191 | | * Check filter limit. We do it here for early warnings although we may |
1192 | | * decide to relax this restriction in the future. |
1193 | | */ |
1194 | 0 | if (pline->nused >= H5Z_MAX_NFILTERS) |
1195 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "too many filters in pipeline"); |
1196 | | |
1197 | | /* Check for freshly allocated filter pipeline */ |
1198 | 0 | if (pline->version == 0) |
1199 | 0 | pline->version = H5O_PLINE_VERSION_1; |
1200 | | |
1201 | | /* Allocate additional space in the pipeline if it's full */ |
1202 | 0 | if (pline->nused >= pline->nalloc) { |
1203 | 0 | H5O_pline_t x; |
1204 | 0 | size_t n; |
1205 | | |
1206 | | /* Each filter's data may be stored internally or may be |
1207 | | * a separate block of memory. |
1208 | | * For each filter, if cd_values points to the internal array |
1209 | | * _cd_values, the pointer will need to be updated when the |
1210 | | * filter struct is reallocated. Set these pointers to ~NULL |
1211 | | * so that we can reset them after reallocating the filters array. |
1212 | | */ |
1213 | 0 | for (n = 0; n < pline->nalloc; ++n) |
1214 | 0 | if (pline->filter[n].cd_values == pline->filter[n]._cd_values) |
1215 | 0 | pline->filter[n].cd_values = (unsigned *)((void *)~((size_t)NULL)); |
1216 | |
|
1217 | 0 | x.nalloc = MAX(H5Z_MAX_NFILTERS, 2 * pline->nalloc); |
1218 | 0 | x.filter = (H5Z_filter_info_t *)H5MM_realloc(pline->filter, x.nalloc * sizeof(x.filter[0])); |
1219 | 0 | if (NULL == x.filter) |
1220 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for filter pipeline"); |
1221 | | |
1222 | | /* Fix pointers in previous filters that need to point to their own |
1223 | | * internal data. |
1224 | | */ |
1225 | 0 | for (n = 0; n < pline->nalloc; ++n) |
1226 | 0 | if (x.filter[n].cd_values == (void *)~((size_t)NULL)) |
1227 | 0 | x.filter[n].cd_values = x.filter[n]._cd_values; |
1228 | | |
1229 | | /* Point to newly allocated buffer */ |
1230 | 0 | pline->nalloc = x.nalloc; |
1231 | 0 | pline->filter = x.filter; |
1232 | 0 | } /* end if */ |
1233 | | |
1234 | | /* Add the new filter to the pipeline */ |
1235 | 0 | idx = pline->nused; |
1236 | 0 | pline->filter[idx].id = filter; |
1237 | 0 | pline->filter[idx].flags = flags; |
1238 | 0 | pline->filter[idx].name = NULL; /*we'll pick it up later*/ |
1239 | 0 | pline->filter[idx].cd_nelmts = cd_nelmts; |
1240 | 0 | if (cd_nelmts > 0) { |
1241 | 0 | size_t i; /* Local index variable */ |
1242 | | |
1243 | | /* Allocate memory or point at internal buffer */ |
1244 | 0 | if (cd_nelmts > H5Z_COMMON_CD_VALUES) { |
1245 | 0 | pline->filter[idx].cd_values = (unsigned *)H5MM_malloc(cd_nelmts * sizeof(unsigned)); |
1246 | 0 | if (NULL == pline->filter[idx].cd_values) |
1247 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for filter"); |
1248 | 0 | } /* end if */ |
1249 | 0 | else |
1250 | 0 | pline->filter[idx].cd_values = pline->filter[idx]._cd_values; |
1251 | | |
1252 | | /* Copy client data values */ |
1253 | 0 | for (i = 0; i < cd_nelmts; i++) |
1254 | 0 | pline->filter[idx].cd_values[i] = cd_values[i]; |
1255 | 0 | } /* end if */ |
1256 | 0 | else |
1257 | 0 | pline->filter[idx].cd_values = NULL; |
1258 | | |
1259 | 0 | pline->nused++; |
1260 | |
|
1261 | 0 | done: |
1262 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1263 | 0 | } /* end H5Z_append() */ |
1264 | | |
1265 | | /*------------------------------------------------------------------------- |
1266 | | * Function: H5Z__find_idx |
1267 | | * |
1268 | | * Purpose: Given a filter ID return the offset in the global array |
1269 | | * that holds all the registered filters. |
1270 | | * |
1271 | | * Return: Success: Non-negative index of entry in global filter table. |
1272 | | * Failure: Negative |
1273 | | *------------------------------------------------------------------------- |
1274 | | */ |
1275 | | static int |
1276 | | H5Z__find_idx(H5Z_filter_t id) |
1277 | 0 | { |
1278 | 0 | size_t i; /* Local index variable */ |
1279 | 0 | int ret_value = FAIL; /* Return value */ |
1280 | |
|
1281 | 0 | FUNC_ENTER_PACKAGE_NOERR |
1282 | |
|
1283 | 0 | for (i = 0; i < H5Z_table_used_g; i++) |
1284 | 0 | if (H5Z_table_g[i].id == id) |
1285 | 0 | HGOTO_DONE((int)i); |
1286 | | |
1287 | 0 | done: |
1288 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1289 | 0 | } /* end H5Z__find_idx() */ |
1290 | | |
1291 | | /*------------------------------------------------------------------------- |
1292 | | * Function: H5Z_find |
1293 | | * |
1294 | | * Purpose: Given a filter ID return a pointer to a global struct that |
1295 | | * defines the filter. |
1296 | | * |
1297 | | * Return: Success: Ptr to entry in global filter table. |
1298 | | * Failure: NULL |
1299 | | *------------------------------------------------------------------------- |
1300 | | */ |
1301 | | H5Z_class2_t * |
1302 | | H5Z_find(H5Z_filter_t id) |
1303 | 0 | { |
1304 | 0 | int idx; /* Filter index in global table */ |
1305 | 0 | H5Z_class2_t *ret_value = NULL; /* Return value */ |
1306 | |
|
1307 | 0 | FUNC_ENTER_NOAPI(NULL) |
1308 | | |
1309 | | /* Get the index in the global table */ |
1310 | 0 | if ((idx = H5Z__find_idx(id)) < 0) |
1311 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_NOTFOUND, NULL, "required filter %d is not registered", id); |
1312 | | |
1313 | | /* Set return value */ |
1314 | 0 | ret_value = H5Z_table_g + idx; |
1315 | |
|
1316 | 0 | done: |
1317 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1318 | 0 | } /* H5Z_find() */ |
1319 | | |
1320 | | /*------------------------------------------------------------------------- |
1321 | | * Function: H5Z_pipeline |
1322 | | * |
1323 | | * Purpose: Process data through the filter pipeline. The FLAGS argument |
1324 | | * is the filter invocation flags (definition flags come from |
1325 | | * the PLINE->filter[].flags). The filters are processed in |
1326 | | * definition order unless the H5Z_FLAG_REVERSE is set. The |
1327 | | * FILTER_MASK is a bit-mask to indicate which filters to skip |
1328 | | * and on exit will indicate which filters failed. Each |
1329 | | * filter has an index number in the pipeline and that index |
1330 | | * number is the filter's bit in the FILTER_MASK. NBYTES is the |
1331 | | * number of bytes of data to filter and on exit should be the |
1332 | | * number of resulting bytes while BUF_SIZE holds the total |
1333 | | * allocated size of the buffer, which is pointed to BUF. |
1334 | | * |
1335 | | * If the buffer must grow during processing of the pipeline |
1336 | | * then the pipeline function should free the original buffer |
1337 | | * and return a fresh buffer, adjusting BUF_SIZE accordingly. |
1338 | | * |
1339 | | * Return: Non-negative on success |
1340 | | * Negative on failure |
1341 | | *------------------------------------------------------------------------- |
1342 | | */ |
1343 | | herr_t |
1344 | | H5Z_pipeline(const H5O_pline_t *pline, unsigned flags, unsigned *filter_mask /*in,out*/, H5Z_EDC_t edc_read, |
1345 | | H5Z_cb_t cb_struct, size_t *nbytes /*in,out*/, size_t *buf_size /*in,out*/, |
1346 | | void **buf /*in,out*/) |
1347 | 0 | { |
1348 | 0 | size_t idx; |
1349 | 0 | size_t new_nbytes; |
1350 | 0 | int fclass_idx; /* Index of filter class in global table */ |
1351 | 0 | H5Z_class2_t *fclass = NULL; /* Filter class pointer */ |
1352 | | #ifdef H5Z_DEBUG |
1353 | | H5Z_stats_t *fstats = NULL; /* Filter stats pointer */ |
1354 | | H5_timer_t timer; /* Timer for filter operations */ |
1355 | | H5_timevals_t times; /* Elapsed time for each operation */ |
1356 | | #endif |
1357 | 0 | unsigned failed = 0; |
1358 | 0 | unsigned tmp_flags; |
1359 | 0 | size_t i; |
1360 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1361 | |
|
1362 | 0 | FUNC_ENTER_NOAPI(FAIL) |
1363 | |
|
1364 | 0 | assert(0 == (flags & ~((unsigned)H5Z_FLAG_INVMASK))); |
1365 | 0 | assert(filter_mask); |
1366 | 0 | assert(nbytes && *nbytes > 0); |
1367 | 0 | assert(buf_size && *buf_size > 0); |
1368 | 0 | assert(buf && *buf); |
1369 | 0 | assert(!pline || pline->nused < H5Z_MAX_NFILTERS); |
1370 | |
|
1371 | | #ifdef H5Z_DEBUG |
1372 | | H5_timer_init(&timer); |
1373 | | #endif |
1374 | 0 | if (pline && (flags & H5Z_FLAG_REVERSE)) { /* Read */ |
1375 | 0 | for (i = pline->nused; i > 0; --i) { |
1376 | 0 | idx = i - 1; |
1377 | 0 | if (*filter_mask & ((unsigned)1 << idx)) { |
1378 | 0 | failed |= (unsigned)1 << idx; |
1379 | 0 | continue; /* filter excluded */ |
1380 | 0 | } |
1381 | | |
1382 | | /* If the filter isn't registered and the application doesn't |
1383 | | * indicate no plugin through HDF5_PRELOAD_PLUG (using the symbol "::"), |
1384 | | * try to load it dynamically and register it. Otherwise, return failure |
1385 | | */ |
1386 | 0 | if ((fclass_idx = H5Z__find_idx(pline->filter[idx].id)) < 0) { |
1387 | 0 | H5PL_key_t key; |
1388 | 0 | const H5Z_class2_t *filter_info; |
1389 | 0 | bool issue_error = false; |
1390 | | |
1391 | | /* Try loading the filter */ |
1392 | 0 | key.id = (int)(pline->filter[idx].id); |
1393 | 0 | if (NULL != (filter_info = (const H5Z_class2_t *)H5PL_load(H5PL_TYPE_FILTER, &key))) { |
1394 | | /* Register the filter we loaded */ |
1395 | 0 | if (H5Z_register(filter_info) < 0) |
1396 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to register filter"); |
1397 | | |
1398 | | /* Search in the table of registered filters again to find the dynamic filter just loaded |
1399 | | * and registered */ |
1400 | 0 | if ((fclass_idx = H5Z__find_idx(pline->filter[idx].id)) < 0) |
1401 | 0 | issue_error = true; |
1402 | 0 | } |
1403 | 0 | else |
1404 | 0 | issue_error = true; |
1405 | | |
1406 | | /* Check for error */ |
1407 | 0 | if (issue_error) { |
1408 | | /* Print out the filter name to give more info. But the name is optional for |
1409 | | * the filter */ |
1410 | 0 | if (pline->filter[idx].name) |
1411 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_READERROR, FAIL, "required filter '%s' is not registered", |
1412 | 0 | pline->filter[idx].name); |
1413 | 0 | else |
1414 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_READERROR, FAIL, |
1415 | 0 | "required filter (name unavailable) is not registered"); |
1416 | 0 | } |
1417 | 0 | } /* end if */ |
1418 | | |
1419 | 0 | fclass = &H5Z_table_g[fclass_idx]; |
1420 | |
|
1421 | | #ifdef H5Z_DEBUG |
1422 | | fstats = &H5Z_stat_table_g[fclass_idx]; |
1423 | | H5_timer_start(&timer); |
1424 | | #endif |
1425 | |
|
1426 | 0 | tmp_flags = flags | (pline->filter[idx].flags); |
1427 | 0 | tmp_flags |= (edc_read == H5Z_DISABLE_EDC) ? H5Z_FLAG_SKIP_EDC : 0; |
1428 | 0 | new_nbytes = (fclass->filter)(tmp_flags, pline->filter[idx].cd_nelmts, |
1429 | 0 | pline->filter[idx].cd_values, *nbytes, buf_size, buf); |
1430 | |
|
1431 | | #ifdef H5Z_DEBUG |
1432 | | H5_timer_stop(&timer); |
1433 | | H5_timer_get_times(timer, ×); |
1434 | | fstats->stats[1].times.elapsed += times.elapsed; |
1435 | | fstats->stats[1].times.system += times.system; |
1436 | | fstats->stats[1].times.user += times.user; |
1437 | | |
1438 | | fstats->stats[1].total += MAX(*nbytes, new_nbytes); |
1439 | | if (0 == new_nbytes) |
1440 | | fstats->stats[1].errors += *nbytes; |
1441 | | #endif |
1442 | |
|
1443 | 0 | if (0 == new_nbytes) { |
1444 | 0 | if ((cb_struct.func && (H5Z_CB_FAIL == cb_struct.func(pline->filter[idx].id, *buf, *buf_size, |
1445 | 0 | cb_struct.op_data))) || |
1446 | 0 | !cb_struct.func) |
1447 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_READERROR, FAIL, "filter returned failure during read"); |
1448 | | |
1449 | 0 | *nbytes = *buf_size; |
1450 | 0 | failed |= (unsigned)1 << idx; |
1451 | 0 | H5E_clear_stack(); |
1452 | 0 | } |
1453 | 0 | else |
1454 | 0 | *nbytes = new_nbytes; |
1455 | 0 | } |
1456 | 0 | } |
1457 | 0 | else if (pline) { /* Write */ |
1458 | 0 | for (idx = 0; idx < pline->nused; idx++) { |
1459 | 0 | if (*filter_mask & ((unsigned)1 << idx)) { |
1460 | 0 | failed |= (unsigned)1 << idx; |
1461 | 0 | continue; /* filter excluded */ |
1462 | 0 | } |
1463 | 0 | if ((fclass_idx = H5Z__find_idx(pline->filter[idx].id)) < 0) { |
1464 | | /* Check if filter is optional -- If it isn't, then error */ |
1465 | 0 | if ((pline->filter[idx].flags & H5Z_FLAG_OPTIONAL) == 0) |
1466 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_WRITEERROR, FAIL, "required filter is not registered"); |
1467 | 0 | failed |= (unsigned)1 << idx; |
1468 | 0 | H5E_clear_stack(); |
1469 | 0 | continue; /* filter excluded */ |
1470 | 0 | } /* end if */ |
1471 | | |
1472 | 0 | fclass = &H5Z_table_g[fclass_idx]; |
1473 | |
|
1474 | | #ifdef H5Z_DEBUG |
1475 | | fstats = &H5Z_stat_table_g[fclass_idx]; |
1476 | | H5_timer_start(&timer); |
1477 | | #endif |
1478 | |
|
1479 | 0 | new_nbytes = (fclass->filter)(flags | (pline->filter[idx].flags), pline->filter[idx].cd_nelmts, |
1480 | 0 | pline->filter[idx].cd_values, *nbytes, buf_size, buf); |
1481 | |
|
1482 | | #ifdef H5Z_DEBUG |
1483 | | H5_timer_stop(&timer); |
1484 | | H5_timer_get_times(timer, ×); |
1485 | | fstats->stats[0].times.elapsed += times.elapsed; |
1486 | | fstats->stats[0].times.system += times.system; |
1487 | | fstats->stats[0].times.user += times.user; |
1488 | | |
1489 | | fstats->stats[0].total += MAX(*nbytes, new_nbytes); |
1490 | | if (0 == new_nbytes) |
1491 | | fstats->stats[0].errors += *nbytes; |
1492 | | #endif |
1493 | |
|
1494 | 0 | if (0 == new_nbytes) { |
1495 | 0 | if (0 == (pline->filter[idx].flags & H5Z_FLAG_OPTIONAL)) { |
1496 | 0 | if ((cb_struct.func && (H5Z_CB_FAIL == cb_struct.func(pline->filter[idx].id, *buf, |
1497 | 0 | *nbytes, cb_struct.op_data))) || |
1498 | 0 | !cb_struct.func) |
1499 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_WRITEERROR, FAIL, "filter returned failure"); |
1500 | | |
1501 | 0 | *nbytes = *buf_size; |
1502 | 0 | } |
1503 | 0 | failed |= (unsigned)1 << idx; |
1504 | 0 | H5E_clear_stack(); |
1505 | 0 | } |
1506 | 0 | else |
1507 | 0 | *nbytes = new_nbytes; |
1508 | 0 | } /* end for */ |
1509 | 0 | } |
1510 | | |
1511 | 0 | *filter_mask = failed; |
1512 | |
|
1513 | 0 | done: |
1514 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1515 | 0 | } |
1516 | | |
1517 | | /*------------------------------------------------------------------------- |
1518 | | * Function: H5Z_filter_info |
1519 | | * |
1520 | | * Purpose: Get pointer to filter info for pipeline |
1521 | | * |
1522 | | * Return: Non-negative on success |
1523 | | * Negative on failure |
1524 | | *------------------------------------------------------------------------- |
1525 | | */ |
1526 | | H5Z_filter_info_t * |
1527 | | H5Z_filter_info(const H5O_pline_t *pline, H5Z_filter_t filter) |
1528 | 0 | { |
1529 | 0 | size_t idx; /* Index of filter in pipeline */ |
1530 | 0 | H5Z_filter_info_t *ret_value = NULL; /* Return value */ |
1531 | |
|
1532 | 0 | FUNC_ENTER_NOAPI(NULL) |
1533 | |
|
1534 | 0 | assert(pline); |
1535 | 0 | assert(filter >= 0 && filter <= H5Z_FILTER_MAX); |
1536 | | |
1537 | | /* Locate the filter in the pipeline */ |
1538 | 0 | for (idx = 0; idx < pline->nused; idx++) |
1539 | 0 | if (pline->filter[idx].id == filter) |
1540 | 0 | break; |
1541 | | |
1542 | | /* Check if the filter was not already in the pipeline */ |
1543 | 0 | if (idx >= pline->nused) |
1544 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_NOTFOUND, NULL, "filter not in pipeline"); |
1545 | | |
1546 | | /* Set return value */ |
1547 | 0 | ret_value = &pline->filter[idx]; |
1548 | |
|
1549 | 0 | done: |
1550 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1551 | 0 | } /* end H5Z_filter_info() */ |
1552 | | |
1553 | | /*------------------------------------------------------------------------- |
1554 | | * Function: H5Z_filter_in_pline |
1555 | | * |
1556 | | * Purpose: Check whether a filter is in the filter pipeline using the |
1557 | | * filter ID. This function is very similar to H5Z_filter_info |
1558 | | * |
1559 | | * Return: true - found filter |
1560 | | * false - not found |
1561 | | * FAIL - error |
1562 | | *------------------------------------------------------------------------- |
1563 | | */ |
1564 | | htri_t |
1565 | | H5Z_filter_in_pline(const H5O_pline_t *pline, H5Z_filter_t filter) |
1566 | 0 | { |
1567 | 0 | size_t idx; /* Index of filter in pipeline */ |
1568 | 0 | htri_t ret_value = true; /* Return value */ |
1569 | |
|
1570 | 0 | FUNC_ENTER_NOAPI_NOERR |
1571 | |
|
1572 | 0 | assert(pline); |
1573 | 0 | assert(filter >= 0 && filter <= H5Z_FILTER_MAX); |
1574 | | |
1575 | | /* Locate the filter in the pipeline */ |
1576 | 0 | for (idx = 0; idx < pline->nused; idx++) |
1577 | 0 | if (pline->filter[idx].id == filter) |
1578 | 0 | break; |
1579 | | |
1580 | | /* Check if the filter was not already in the pipeline */ |
1581 | 0 | if (idx >= pline->nused) |
1582 | 0 | ret_value = false; |
1583 | |
|
1584 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1585 | 0 | } /* end H5Z_filter_in_pline() */ |
1586 | | |
1587 | | /*------------------------------------------------------------------------- |
1588 | | * Function: H5Z_all_filters_avail |
1589 | | * |
1590 | | * Purpose: Verify that all the filters in a pipeline are currently |
1591 | | * available (i.e. registered) |
1592 | | * |
1593 | | * Return: Non-negative (true/false) on success |
1594 | | * Negative on failure |
1595 | | *------------------------------------------------------------------------- |
1596 | | */ |
1597 | | htri_t |
1598 | | H5Z_all_filters_avail(const H5O_pline_t *pline) |
1599 | 0 | { |
1600 | 0 | size_t i, j; /* Local index variable */ |
1601 | 0 | htri_t ret_value = true; /* Return value */ |
1602 | |
|
1603 | 0 | FUNC_ENTER_NOAPI_NOERR |
1604 | | |
1605 | | /* Check args */ |
1606 | 0 | assert(pline); |
1607 | | |
1608 | | /* Iterate through all the filters in pipeline */ |
1609 | 0 | for (i = 0; i < pline->nused; i++) { |
1610 | | /* Look for each filter in the list of registered filters */ |
1611 | 0 | for (j = 0; j < H5Z_table_used_g; j++) |
1612 | 0 | if (H5Z_table_g[j].id == pline->filter[i].id) |
1613 | 0 | break; |
1614 | | |
1615 | | /* Check if we didn't find the filter */ |
1616 | 0 | if (j == H5Z_table_used_g) |
1617 | 0 | HGOTO_DONE(false); |
1618 | 0 | } /* end for */ |
1619 | | |
1620 | 0 | done: |
1621 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1622 | 0 | } /* end H5Z_all_filters_avail() */ |
1623 | | |
1624 | | /*------------------------------------------------------------------------- |
1625 | | * Function: H5Z_delete |
1626 | | * |
1627 | | * Purpose: Delete filter FILTER from pipeline PLINE; |
1628 | | * deletes all filters if FILTER is H5Z_FILTER_ALL |
1629 | | * |
1630 | | * Return: Non-negative on success |
1631 | | * Negative on failure |
1632 | | *------------------------------------------------------------------------- |
1633 | | */ |
1634 | | herr_t |
1635 | | H5Z_delete(H5O_pline_t *pline, H5Z_filter_t filter) |
1636 | 0 | { |
1637 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1638 | |
|
1639 | 0 | FUNC_ENTER_NOAPI(FAIL) |
1640 | | |
1641 | | /* Check args */ |
1642 | 0 | assert(pline); |
1643 | 0 | assert(filter >= 0 && filter <= H5Z_FILTER_MAX); |
1644 | | |
1645 | | /* if the pipeline has no filters, just return */ |
1646 | 0 | if (pline->nused == 0) |
1647 | 0 | HGOTO_DONE(SUCCEED); |
1648 | | |
1649 | | /* Delete all filters */ |
1650 | 0 | if (H5Z_FILTER_ALL == filter) { |
1651 | 0 | if (H5O_msg_reset(H5O_PLINE_ID, pline) < 0) |
1652 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANTFREE, FAIL, "can't release pipeline info"); |
1653 | 0 | } |
1654 | | /* Delete filter */ |
1655 | 0 | else { |
1656 | 0 | size_t idx; /* Index of filter in pipeline */ |
1657 | 0 | bool found = false; /* Indicate filter was found in pipeline */ |
1658 | | |
1659 | | /* Locate the filter in the pipeline */ |
1660 | 0 | for (idx = 0; idx < pline->nused; idx++) |
1661 | 0 | if (pline->filter[idx].id == filter) { |
1662 | 0 | found = true; |
1663 | 0 | break; |
1664 | 0 | } |
1665 | | |
1666 | | /* filter was not found in the pipeline */ |
1667 | 0 | if (!found) |
1668 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_NOTFOUND, FAIL, "filter not in pipeline"); |
1669 | | |
1670 | | /* Free information for deleted filter */ |
1671 | 0 | if (pline->filter[idx].name && pline->filter[idx].name != pline->filter[idx]._name) |
1672 | 0 | assert((strlen(pline->filter[idx].name) + 1) > H5Z_COMMON_NAME_LEN); |
1673 | 0 | if (pline->filter[idx].name != pline->filter[idx]._name) |
1674 | 0 | pline->filter[idx].name = (char *)H5MM_xfree(pline->filter[idx].name); |
1675 | 0 | if (pline->filter[idx].cd_values && pline->filter[idx].cd_values != pline->filter[idx]._cd_values) |
1676 | 0 | assert(pline->filter[idx].cd_nelmts > H5Z_COMMON_CD_VALUES); |
1677 | 0 | if (pline->filter[idx].cd_values != pline->filter[idx]._cd_values) |
1678 | 0 | pline->filter[idx].cd_values = (unsigned *)H5MM_xfree(pline->filter[idx].cd_values); |
1679 | | |
1680 | | /* Remove filter from pipeline array */ |
1681 | 0 | if ((idx + 1) < pline->nused) { |
1682 | | /* Copy filters down & fix up any client data value arrays using internal storage */ |
1683 | 0 | for (; (idx + 1) < pline->nused; idx++) { |
1684 | 0 | pline->filter[idx] = pline->filter[idx + 1]; |
1685 | 0 | if (pline->filter[idx].name && (strlen(pline->filter[idx].name) + 1) <= H5Z_COMMON_NAME_LEN) |
1686 | 0 | pline->filter[idx].name = pline->filter[idx]._name; |
1687 | 0 | if (pline->filter[idx].cd_nelmts <= H5Z_COMMON_CD_VALUES) |
1688 | 0 | pline->filter[idx].cd_values = pline->filter[idx]._cd_values; |
1689 | 0 | } |
1690 | 0 | } |
1691 | | |
1692 | | /* Decrement number of used filters */ |
1693 | 0 | pline->nused--; |
1694 | | |
1695 | | /* Reset information for previous last filter in pipeline */ |
1696 | 0 | memset(&pline->filter[pline->nused], 0, sizeof(H5Z_filter_info_t)); |
1697 | 0 | } /* end else */ |
1698 | | |
1699 | 0 | done: |
1700 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1701 | 0 | } /* end H5Z_delete() */ |
1702 | | |
1703 | | /*------------------------------------------------------------------------- |
1704 | | * Function: H5Zget_filter_info |
1705 | | * |
1706 | | * Purpose: Gets information about a pipeline data filter and stores it |
1707 | | * in filter_config_flags. |
1708 | | * |
1709 | | * Return: zero on success |
1710 | | * negative on failure |
1711 | | *------------------------------------------------------------------------- |
1712 | | */ |
1713 | | herr_t |
1714 | | H5Zget_filter_info(H5Z_filter_t filter, unsigned *filter_config_flags /*out*/) |
1715 | 0 | { |
1716 | 0 | herr_t ret_value = SUCCEED; |
1717 | |
|
1718 | 0 | FUNC_ENTER_API(FAIL) |
1719 | | |
1720 | | /* Get the filter info */ |
1721 | 0 | if (H5Z_get_filter_info(filter, filter_config_flags) < 0) |
1722 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "Filter info not retrieved"); |
1723 | | |
1724 | 0 | done: |
1725 | 0 | FUNC_LEAVE_API(ret_value) |
1726 | 0 | } /* end H5Zget_filter_info() */ |
1727 | | |
1728 | | /*------------------------------------------------------------------------- |
1729 | | * Function: H5Z_get_filter_info |
1730 | | * |
1731 | | * Purpose: Gets information about a pipeline data filter and stores it |
1732 | | * in filter_config_flags. |
1733 | | * |
1734 | | * Return: zero on success |
1735 | | * negative on failure |
1736 | | *------------------------------------------------------------------------- |
1737 | | */ |
1738 | | herr_t |
1739 | | H5Z_get_filter_info(H5Z_filter_t filter, unsigned int *filter_config_flags) |
1740 | 0 | { |
1741 | 0 | H5Z_class2_t *fclass; |
1742 | 0 | herr_t ret_value = SUCCEED; |
1743 | |
|
1744 | 0 | FUNC_ENTER_NOAPI(FAIL) |
1745 | | |
1746 | | /* Look up the filter class info */ |
1747 | 0 | if (NULL == (fclass = H5Z_find(filter))) |
1748 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_BADVALUE, FAIL, "Filter not defined"); |
1749 | | |
1750 | | /* Set the filter config flags for the application */ |
1751 | 0 | if (filter_config_flags != NULL) { |
1752 | 0 | *filter_config_flags = 0; |
1753 | |
|
1754 | 0 | if (fclass->encoder_present) |
1755 | 0 | *filter_config_flags |= H5Z_FILTER_CONFIG_ENCODE_ENABLED; |
1756 | 0 | if (fclass->decoder_present) |
1757 | 0 | *filter_config_flags |= H5Z_FILTER_CONFIG_DECODE_ENABLED; |
1758 | 0 | } /* end if */ |
1759 | |
|
1760 | 0 | done: |
1761 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1762 | 0 | } /* end H5Z_get_filter_info() */ |