Line | Count | Source |
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 LICENSE 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 | | /*------------------------------------------------------------------------- |
14 | | * |
15 | | * Created: H5C.c |
16 | | * |
17 | | * Purpose: Functions in this file implement a generic cache for |
18 | | * things which exist on disk, and which may be |
19 | | * unambiguously referenced by their disk addresses. |
20 | | * |
21 | | * For a detailed overview of the cache, please see the |
22 | | * header comment for H5C_t in H5Cpkg.h. |
23 | | * |
24 | | *------------------------------------------------------------------------- |
25 | | */ |
26 | | |
27 | | /************************************************************************** |
28 | | * |
29 | | * To Do: |
30 | | * |
31 | | * Code Changes: |
32 | | * |
33 | | * - Change protect/unprotect to lock/unlock. |
34 | | * |
35 | | * - Flush entries in increasing address order in |
36 | | * H5C__make_space_in_cache(). |
37 | | * |
38 | | * - Also in H5C__make_space_in_cache(), use high and low water marks |
39 | | * to reduce the number of I/O calls. |
40 | | * |
41 | | * - When flushing, attempt to combine contiguous entries to reduce |
42 | | * I/O overhead. Can't do this just yet as some entries are not |
43 | | * contiguous. Do this in parallel only or in serial as well? |
44 | | * |
45 | | * - Fix nodes in memory to point directly to the skip list node from |
46 | | * the LRU list, eliminating skip list lookups when evicting objects |
47 | | * from the cache. |
48 | | * |
49 | | **************************************************************************/ |
50 | | |
51 | | /****************/ |
52 | | /* Module Setup */ |
53 | | /****************/ |
54 | | |
55 | | #include "H5Cmodule.h" /* This source code file is part of the H5C module */ |
56 | | #define H5F_FRIEND /* suppress error about including H5Fpkg */ |
57 | | |
58 | | /***********/ |
59 | | /* Headers */ |
60 | | /***********/ |
61 | | #include "H5private.h" /* Generic Functions */ |
62 | | #include "H5ACprivate.h" /* Metadata cache */ |
63 | | #include "H5Cpkg.h" /* Cache */ |
64 | | #include "H5Eprivate.h" /* Error handling */ |
65 | | #include "H5Fpkg.h" /* Files */ |
66 | | #include "H5FLprivate.h" /* Free Lists */ |
67 | | #include "H5MFprivate.h" /* File memory management */ |
68 | | #include "H5MMprivate.h" /* Memory management */ |
69 | | #include "H5SLprivate.h" /* Skip Lists */ |
70 | | |
71 | | /****************/ |
72 | | /* Local Macros */ |
73 | | /****************/ |
74 | | |
75 | | /******************/ |
76 | | /* Local Typedefs */ |
77 | | /******************/ |
78 | | |
79 | | /********************/ |
80 | | /* Local Prototypes */ |
81 | | /********************/ |
82 | | |
83 | | /*********************/ |
84 | | /* Package Variables */ |
85 | | /*********************/ |
86 | | |
87 | | /* Package initialization variable */ |
88 | | bool H5_PKG_INIT_VAR = false; |
89 | | |
90 | | /* Declare a free list to manage the tag info struct */ |
91 | | H5FL_DEFINE(H5C_tag_info_t); |
92 | | |
93 | | /*****************************/ |
94 | | /* Library Private Variables */ |
95 | | /*****************************/ |
96 | | |
97 | | /*******************/ |
98 | | /* Local Variables */ |
99 | | /*******************/ |
100 | | |
101 | | /* Declare a free list to manage the H5C_t struct */ |
102 | | H5FL_DEFINE_STATIC(H5C_t); |
103 | | |
104 | | /*------------------------------------------------------------------------- |
105 | | * Function: H5C_create |
106 | | * |
107 | | * Purpose: Allocate, initialize, and return the address of a new |
108 | | * instance of H5C_t. |
109 | | * |
110 | | * In general, the max_cache_size parameter must be positive, |
111 | | * and the min_clean_size parameter must lie in the closed |
112 | | * interval [0, max_cache_size]. |
113 | | * |
114 | | * The check_write_permitted parameter must either be NULL, |
115 | | * or point to a function of type H5C_write_permitted_func_t. |
116 | | * If it is NULL, the cache will use the write_permitted |
117 | | * flag to determine whether writes are permitted. |
118 | | * |
119 | | * Return: Success: Pointer to the new instance. |
120 | | * Failure: NULL |
121 | | * |
122 | | *------------------------------------------------------------------------- |
123 | | */ |
124 | | H5C_t * |
125 | | H5C_create(size_t max_cache_size, size_t min_clean_size, int max_type_id, |
126 | | const H5C_class_t *const *class_table_ptr, H5C_write_permitted_func_t check_write_permitted, |
127 | | bool write_permitted, H5C_log_flush_func_t log_flush, void *aux_ptr) |
128 | 23 | { |
129 | 23 | int i; |
130 | 23 | H5C_t *cache_ptr = NULL; |
131 | 23 | H5C_t *ret_value = NULL; /* Return value */ |
132 | | |
133 | 23 | FUNC_ENTER_NOAPI(NULL) |
134 | | |
135 | 23 | assert(max_cache_size >= H5C__MIN_MAX_CACHE_SIZE); |
136 | 23 | assert(max_cache_size <= H5C__MAX_MAX_CACHE_SIZE); |
137 | 23 | assert(min_clean_size <= max_cache_size); |
138 | | |
139 | 23 | assert(max_type_id >= 0); |
140 | 23 | assert(max_type_id < H5C__MAX_NUM_TYPE_IDS); |
141 | 23 | assert(class_table_ptr); |
142 | | |
143 | 713 | for (i = 0; i <= max_type_id; i++) { |
144 | 690 | assert((class_table_ptr)[i]); |
145 | 690 | assert(strlen((class_table_ptr)[i]->name) > 0); |
146 | 690 | } /* end for */ |
147 | | |
148 | 23 | if (NULL == (cache_ptr = H5FL_CALLOC(H5C_t))) |
149 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed"); |
150 | | |
151 | 23 | if (NULL == (cache_ptr->slist_ptr = H5SL_create(H5SL_TYPE_HADDR, NULL))) |
152 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, NULL, "can't create skip list"); |
153 | | |
154 | 23 | cache_ptr->tag_list = NULL; |
155 | | |
156 | | /* If we get this far, we should succeed. Go ahead and initialize all |
157 | | * the fields. |
158 | | */ |
159 | | |
160 | 23 | cache_ptr->flush_in_progress = false; |
161 | | |
162 | 23 | if (NULL == (cache_ptr->log_info = (H5C_log_info_t *)H5MM_calloc(sizeof(H5C_log_info_t)))) |
163 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, NULL, "memory allocation failed"); |
164 | | |
165 | 23 | cache_ptr->aux_ptr = aux_ptr; |
166 | | |
167 | 23 | cache_ptr->max_type_id = max_type_id; |
168 | | |
169 | 23 | cache_ptr->class_table_ptr = class_table_ptr; |
170 | | |
171 | 23 | cache_ptr->max_cache_size = max_cache_size; |
172 | 23 | cache_ptr->min_clean_size = min_clean_size; |
173 | | |
174 | 23 | cache_ptr->check_write_permitted = check_write_permitted; |
175 | 23 | cache_ptr->write_permitted = write_permitted; |
176 | | |
177 | 23 | cache_ptr->log_flush = log_flush; |
178 | | |
179 | 23 | cache_ptr->evictions_enabled = true; |
180 | 23 | cache_ptr->close_warning_received = false; |
181 | | |
182 | 23 | cache_ptr->index_len = 0; |
183 | 23 | cache_ptr->index_size = (size_t)0; |
184 | 23 | cache_ptr->clean_index_size = (size_t)0; |
185 | 23 | cache_ptr->dirty_index_size = (size_t)0; |
186 | | |
187 | 161 | for (i = 0; i < H5C_RING_NTYPES; i++) { |
188 | 138 | cache_ptr->index_ring_len[i] = 0; |
189 | 138 | cache_ptr->index_ring_size[i] = (size_t)0; |
190 | 138 | cache_ptr->clean_index_ring_size[i] = (size_t)0; |
191 | 138 | cache_ptr->dirty_index_ring_size[i] = (size_t)0; |
192 | | |
193 | 138 | cache_ptr->slist_ring_len[i] = 0; |
194 | 138 | cache_ptr->slist_ring_size[i] = (size_t)0; |
195 | 138 | } /* end for */ |
196 | | |
197 | 1.50M | for (i = 0; i < H5C__HASH_TABLE_LEN; i++) |
198 | 1.50M | (cache_ptr->index)[i] = NULL; |
199 | | |
200 | 23 | cache_ptr->il_len = 0; |
201 | 23 | cache_ptr->il_size = (size_t)0; |
202 | 23 | cache_ptr->il_head = NULL; |
203 | 23 | cache_ptr->il_tail = NULL; |
204 | | |
205 | | /* Tagging Field Initializations */ |
206 | 23 | cache_ptr->ignore_tags = false; |
207 | 23 | cache_ptr->num_objs_corked = 0; |
208 | | |
209 | | /* slist field initializations */ |
210 | 23 | cache_ptr->slist_enabled = false; |
211 | 23 | cache_ptr->slist_changed = false; |
212 | 23 | cache_ptr->slist_len = 0; |
213 | 23 | cache_ptr->slist_size = (size_t)0; |
214 | | |
215 | | /* slist_ring_len, slist_ring_size, and |
216 | | * slist_ptr initialized above. |
217 | | */ |
218 | | |
219 | | #ifdef H5C_DO_SANITY_CHECKS |
220 | | cache_ptr->slist_len_increase = 0; |
221 | | cache_ptr->slist_size_increase = 0; |
222 | | #endif /* H5C_DO_SANITY_CHECKS */ |
223 | | |
224 | 23 | cache_ptr->entries_removed_counter = 0; |
225 | 23 | cache_ptr->last_entry_removed_ptr = NULL; |
226 | 23 | cache_ptr->entry_watched_for_removal = NULL; |
227 | | |
228 | 23 | cache_ptr->pl_len = 0; |
229 | 23 | cache_ptr->pl_size = (size_t)0; |
230 | 23 | cache_ptr->pl_head_ptr = NULL; |
231 | 23 | cache_ptr->pl_tail_ptr = NULL; |
232 | | |
233 | 23 | cache_ptr->pel_len = 0; |
234 | 23 | cache_ptr->pel_size = (size_t)0; |
235 | 23 | cache_ptr->pel_head_ptr = NULL; |
236 | 23 | cache_ptr->pel_tail_ptr = NULL; |
237 | | |
238 | 23 | cache_ptr->LRU_list_len = 0; |
239 | 23 | cache_ptr->LRU_list_size = (size_t)0; |
240 | 23 | cache_ptr->LRU_head_ptr = NULL; |
241 | 23 | cache_ptr->LRU_tail_ptr = NULL; |
242 | | |
243 | | #ifdef H5_HAVE_PARALLEL |
244 | | cache_ptr->coll_list_len = 0; |
245 | | cache_ptr->coll_list_size = (size_t)0; |
246 | | cache_ptr->coll_head_ptr = NULL; |
247 | | cache_ptr->coll_tail_ptr = NULL; |
248 | | cache_ptr->coll_write_list = NULL; |
249 | | #endif /* H5_HAVE_PARALLEL */ |
250 | | |
251 | | #if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS |
252 | | cache_ptr->cLRU_list_len = 0; |
253 | | cache_ptr->cLRU_list_size = (size_t)0; |
254 | | cache_ptr->cLRU_head_ptr = NULL; |
255 | | cache_ptr->cLRU_tail_ptr = NULL; |
256 | | |
257 | | cache_ptr->dLRU_list_len = 0; |
258 | | cache_ptr->dLRU_list_size = (size_t)0; |
259 | | cache_ptr->dLRU_head_ptr = NULL; |
260 | | cache_ptr->dLRU_tail_ptr = NULL; |
261 | | #endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ |
262 | | |
263 | 23 | cache_ptr->size_increase_possible = false; |
264 | 23 | cache_ptr->flash_size_increase_possible = false; |
265 | 23 | cache_ptr->flash_size_increase_threshold = 0; |
266 | 23 | cache_ptr->size_decrease_possible = false; |
267 | 23 | cache_ptr->resize_enabled = false; |
268 | 23 | cache_ptr->cache_full = false; |
269 | 23 | cache_ptr->size_decreased = false; |
270 | 23 | cache_ptr->resize_in_progress = false; |
271 | 23 | cache_ptr->msic_in_progress = false; |
272 | | |
273 | 23 | cache_ptr->resize_ctl.version = H5C__CURR_AUTO_SIZE_CTL_VER; |
274 | 23 | cache_ptr->resize_ctl.rpt_fcn = NULL; |
275 | 23 | cache_ptr->resize_ctl.set_initial_size = false; |
276 | 23 | cache_ptr->resize_ctl.initial_size = H5C__DEF_AR_INIT_SIZE; |
277 | 23 | cache_ptr->resize_ctl.min_clean_fraction = H5C__DEF_AR_MIN_CLEAN_FRAC; |
278 | 23 | cache_ptr->resize_ctl.max_size = H5C__DEF_AR_MAX_SIZE; |
279 | 23 | cache_ptr->resize_ctl.min_size = H5C__DEF_AR_MIN_SIZE; |
280 | 23 | cache_ptr->resize_ctl.epoch_length = H5C__DEF_AR_EPOCH_LENGTH; |
281 | | |
282 | 23 | cache_ptr->resize_ctl.incr_mode = H5C_incr__off; |
283 | 23 | cache_ptr->resize_ctl.lower_hr_threshold = H5C__DEF_AR_LOWER_THRESHHOLD; |
284 | 23 | cache_ptr->resize_ctl.increment = H5C__DEF_AR_INCREMENT; |
285 | 23 | cache_ptr->resize_ctl.apply_max_increment = true; |
286 | 23 | cache_ptr->resize_ctl.max_increment = H5C__DEF_AR_MAX_INCREMENT; |
287 | | |
288 | 23 | cache_ptr->resize_ctl.flash_incr_mode = H5C_flash_incr__off; |
289 | 23 | cache_ptr->resize_ctl.flash_multiple = 1.0; |
290 | 23 | cache_ptr->resize_ctl.flash_threshold = 0.25; |
291 | | |
292 | 23 | cache_ptr->resize_ctl.decr_mode = H5C_decr__off; |
293 | 23 | cache_ptr->resize_ctl.upper_hr_threshold = H5C__DEF_AR_UPPER_THRESHHOLD; |
294 | 23 | cache_ptr->resize_ctl.decrement = H5C__DEF_AR_DECREMENT; |
295 | 23 | cache_ptr->resize_ctl.apply_max_decrement = true; |
296 | 23 | cache_ptr->resize_ctl.max_decrement = H5C__DEF_AR_MAX_DECREMENT; |
297 | 23 | cache_ptr->resize_ctl.epochs_before_eviction = H5C__DEF_AR_EPCHS_B4_EVICT; |
298 | 23 | cache_ptr->resize_ctl.apply_empty_reserve = true; |
299 | 23 | cache_ptr->resize_ctl.empty_reserve = H5C__DEF_AR_EMPTY_RESERVE; |
300 | | |
301 | 23 | cache_ptr->epoch_markers_active = 0; |
302 | | |
303 | | /* no need to initialize the ring buffer itself */ |
304 | 23 | cache_ptr->epoch_marker_ringbuf_first = 1; |
305 | 23 | cache_ptr->epoch_marker_ringbuf_last = 0; |
306 | 23 | cache_ptr->epoch_marker_ringbuf_size = 0; |
307 | | |
308 | | /* Initialize all epoch marker entries' fields to zero/false/NULL */ |
309 | 23 | memset(cache_ptr->epoch_markers, 0, sizeof(cache_ptr->epoch_markers)); |
310 | | |
311 | | /* Set non-zero/false/NULL fields for epoch markers */ |
312 | 253 | for (i = 0; i < H5C__MAX_EPOCH_MARKERS; i++) { |
313 | 230 | ((cache_ptr->epoch_markers)[i]).addr = (haddr_t)i; |
314 | 230 | ((cache_ptr->epoch_markers)[i]).type = H5AC_EPOCH_MARKER; |
315 | 230 | } |
316 | | |
317 | | /* Initialize cache image generation on file close related fields. |
318 | | * Initial value of image_ctl must match H5C__DEFAULT_CACHE_IMAGE_CTL |
319 | | * in H5Cprivate.h. |
320 | | */ |
321 | 23 | cache_ptr->image_ctl.version = H5C__CURR_CACHE_IMAGE_CTL_VER; |
322 | 23 | cache_ptr->image_ctl.generate_image = false; |
323 | 23 | cache_ptr->image_ctl.save_resize_status = false; |
324 | 23 | cache_ptr->image_ctl.entry_ageout = -1; |
325 | 23 | cache_ptr->image_ctl.flags = H5C_CI__ALL_FLAGS; |
326 | | |
327 | 23 | cache_ptr->serialization_in_progress = false; |
328 | 23 | cache_ptr->load_image = false; |
329 | 23 | cache_ptr->image_loaded = false; |
330 | 23 | cache_ptr->delete_image = false; |
331 | 23 | cache_ptr->image_addr = HADDR_UNDEF; |
332 | 23 | cache_ptr->image_len = 0; |
333 | 23 | cache_ptr->image_data_len = 0; |
334 | | |
335 | 23 | cache_ptr->entries_loaded_counter = 0; |
336 | 23 | cache_ptr->entries_inserted_counter = 0; |
337 | 23 | cache_ptr->entries_relocated_counter = 0; |
338 | 23 | cache_ptr->entry_fd_height_change_counter = 0; |
339 | | |
340 | 23 | cache_ptr->num_entries_in_image = 0; |
341 | 23 | cache_ptr->image_entries = NULL; |
342 | 23 | cache_ptr->image_buffer = NULL; |
343 | | |
344 | | /* initialize free space manager related fields: */ |
345 | 23 | cache_ptr->rdfsm_settled = false; |
346 | 23 | cache_ptr->mdfsm_settled = false; |
347 | | |
348 | 23 | if (H5C_reset_cache_hit_rate_stats(cache_ptr) < 0) |
349 | | /* this should be impossible... */ |
350 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, NULL, "H5C_reset_cache_hit_rate_stats failed"); |
351 | | |
352 | 23 | H5C_stats__reset(cache_ptr); |
353 | | |
354 | 23 | cache_ptr->prefix[0] = '\0'; /* empty string */ |
355 | | |
356 | | #ifndef NDEBUG |
357 | | cache_ptr->get_entry_ptr_from_addr_counter = 0; |
358 | | #endif |
359 | | |
360 | | /* Set return value */ |
361 | 23 | ret_value = cache_ptr; |
362 | | |
363 | 23 | done: |
364 | 23 | if (NULL == ret_value) { |
365 | 0 | if (cache_ptr != NULL) { |
366 | 0 | if (cache_ptr->slist_ptr != NULL) |
367 | 0 | H5SL_close(cache_ptr->slist_ptr); |
368 | |
|
369 | 0 | HASH_CLEAR(hh, cache_ptr->tag_list); |
370 | 0 | cache_ptr->tag_list = NULL; |
371 | |
|
372 | 0 | if (cache_ptr->log_info != NULL) |
373 | 0 | H5MM_xfree(cache_ptr->log_info); |
374 | |
|
375 | 0 | cache_ptr = H5FL_FREE(H5C_t, cache_ptr); |
376 | 0 | } |
377 | 0 | } |
378 | | |
379 | 23 | FUNC_LEAVE_NOAPI(ret_value) |
380 | 23 | } /* H5C_create() */ |
381 | | |
382 | | /*------------------------------------------------------------------------- |
383 | | * Function: H5C_prep_for_file_close |
384 | | * |
385 | | * Purpose: This function should be called just prior to the cache |
386 | | * flushes at file close. There should be no protected |
387 | | * entries in the cache at this point. |
388 | | * |
389 | | * Return: Non-negative on success/Negative on failure |
390 | | * |
391 | | *------------------------------------------------------------------------- |
392 | | */ |
393 | | herr_t |
394 | | H5C_prep_for_file_close(H5F_t *f) |
395 | 23 | { |
396 | 23 | H5C_t *cache_ptr; |
397 | 23 | bool image_generated = false; /* Whether a cache image was generated */ |
398 | 23 | herr_t ret_value = SUCCEED; /* Return value */ |
399 | | |
400 | 23 | FUNC_ENTER_NOAPI(FAIL) |
401 | | |
402 | | /* Sanity checks */ |
403 | 23 | assert(f); |
404 | 23 | assert(f->shared); |
405 | 23 | assert(f->shared->cache); |
406 | 23 | cache_ptr = f->shared->cache; |
407 | 23 | assert(cache_ptr); |
408 | | |
409 | | /* It is possible to receive the close warning more than once */ |
410 | 23 | if (cache_ptr->close_warning_received) |
411 | 0 | HGOTO_DONE(SUCCEED); |
412 | 23 | cache_ptr->close_warning_received = true; |
413 | | |
414 | | /* Make certain there aren't any protected entries */ |
415 | 23 | assert(cache_ptr->pl_len == 0); |
416 | | |
417 | | /* Prepare cache image */ |
418 | 23 | if (H5C__prep_image_for_file_close(f, &image_generated) < 0) |
419 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, "can't create cache image"); |
420 | | |
421 | | #ifdef H5_HAVE_PARALLEL |
422 | | if ((H5F_INTENT(f) & H5F_ACC_RDWR) && !image_generated && cache_ptr->aux_ptr != NULL && |
423 | | f->shared->fs_persist) { |
424 | | /* If persistent free space managers are enabled, flushing the |
425 | | * metadata cache may result in the deletion, insertion, and/or |
426 | | * dirtying of entries. |
427 | | * |
428 | | * This is a problem in PHDF5, as it breaks two invariants of |
429 | | * our management of the metadata cache across all processes: |
430 | | * |
431 | | * 1) Entries will not be dirtied, deleted, inserted, or moved |
432 | | * during flush in the parallel case. |
433 | | * |
434 | | * 2) All processes contain the same set of dirty metadata |
435 | | * entries on entry to a sync point. |
436 | | * |
437 | | * To solve this problem for the persistent free space managers, |
438 | | * serialize the metadata cache on all processes prior to the |
439 | | * first sync point on file shutdown. The shutdown warning is |
440 | | * a convenient location for this call. |
441 | | * |
442 | | * This is sufficient since: |
443 | | * |
444 | | * 1) FSM settle routines are only invoked on file close. Since |
445 | | * serialization make the same settle calls as flush on file |
446 | | * close, and since the close warning is issued after all |
447 | | * non FSM related space allocations and just before the |
448 | | * first sync point on close, this call will leave the caches |
449 | | * in a consistent state across the processes if they were |
450 | | * consistent before. |
451 | | * |
452 | | * 2) Since the FSM settle routines are only invoked once during |
453 | | * file close, invoking them now will prevent their invocation |
454 | | * during a flush, and thus avoid any resulting entry dirties, |
455 | | * deletions, insertion, or moves during the flush. |
456 | | */ |
457 | | if (H5C__serialize_cache(f) < 0) |
458 | | HGOTO_ERROR(H5E_CACHE, H5E_CANTSERIALIZE, FAIL, "serialization of the cache failed"); |
459 | | } /* end if */ |
460 | | #endif /* H5_HAVE_PARALLEL */ |
461 | | |
462 | 23 | done: |
463 | 23 | FUNC_LEAVE_NOAPI(ret_value) |
464 | 23 | } /* H5C_prep_for_file_close() */ |
465 | | |
466 | | /*------------------------------------------------------------------------- |
467 | | * Function: H5C_dest |
468 | | * |
469 | | * Purpose: Flush all data to disk and destroy the cache. |
470 | | * |
471 | | * This function fails if any object are protected since the |
472 | | * resulting file might not be consistent. |
473 | | * |
474 | | * Note: *cache_ptr has been freed upon successful return. |
475 | | * |
476 | | * Return: Non-negative on success/Negative on failure |
477 | | * |
478 | | *------------------------------------------------------------------------- |
479 | | */ |
480 | | herr_t |
481 | | H5C_dest(H5F_t *f) |
482 | 23 | { |
483 | 23 | H5C_t *cache_ptr = f->shared->cache; |
484 | 23 | H5C_tag_info_t *item = NULL; |
485 | 23 | H5C_tag_info_t *tmp = NULL; |
486 | 23 | herr_t ret_value = SUCCEED; /* Return value */ |
487 | | |
488 | 23 | FUNC_ENTER_NOAPI(FAIL) |
489 | | |
490 | | /* Sanity check */ |
491 | 23 | assert(cache_ptr); |
492 | 23 | assert(cache_ptr->close_warning_received); |
493 | | |
494 | | #if H5AC_DUMP_IMAGE_STATS_ON_CLOSE |
495 | | if (H5C__image_stats(cache_ptr, true) < 0) |
496 | | HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't display cache image stats"); |
497 | | #endif /* H5AC_DUMP_IMAGE_STATS_ON_CLOSE */ |
498 | | |
499 | | /* Enable the slist, as it is needed in the flush */ |
500 | 23 | if (H5C_set_slist_enabled(f->shared->cache, true, true) < 0) |
501 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "set slist enabled failed"); |
502 | | |
503 | | /* Flush and invalidate all cache entries */ |
504 | 23 | if (H5C__flush_invalidate_cache(f, H5C__NO_FLAGS_SET) < 0) |
505 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush cache"); |
506 | | |
507 | | /* Generate & write cache image if requested */ |
508 | 23 | if (cache_ptr->image_ctl.generate_image) |
509 | 0 | if (H5C__generate_cache_image(f, cache_ptr) < 0) |
510 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, "Can't generate metadata cache image"); |
511 | | |
512 | | /* Question: Is it possible for cache_ptr->slist be non-null at this |
513 | | * point? If no, shouldn't this if statement be an assert? |
514 | | */ |
515 | 23 | if (cache_ptr->slist_ptr != NULL) { |
516 | 23 | assert(cache_ptr->slist_len == 0); |
517 | 23 | assert(cache_ptr->slist_size == 0); |
518 | | |
519 | 23 | H5SL_close(cache_ptr->slist_ptr); |
520 | 23 | cache_ptr->slist_ptr = NULL; |
521 | 23 | } |
522 | | |
523 | 23 | HASH_ITER(hh, cache_ptr->tag_list, item, tmp) |
524 | 0 | { |
525 | 0 | HASH_DELETE(hh, cache_ptr->tag_list, item); |
526 | 0 | item = H5FL_FREE(H5C_tag_info_t, item); |
527 | 0 | } |
528 | | |
529 | 23 | if (cache_ptr->log_info != NULL) |
530 | 23 | H5MM_xfree(cache_ptr->log_info); |
531 | | |
532 | | #ifdef H5C_DO_SANITY_CHECKS |
533 | | if (cache_ptr->get_entry_ptr_from_addr_counter > 0) |
534 | | fprintf(stdout, "*** %" PRId64 " calls to H5C_get_entry_ptr_from_add(). ***\n", |
535 | | cache_ptr->get_entry_ptr_from_addr_counter); |
536 | | #endif /* H5C_DO_SANITY_CHECKS */ |
537 | | |
538 | 23 | cache_ptr = H5FL_FREE(H5C_t, cache_ptr); |
539 | | |
540 | 23 | done: |
541 | 23 | if (ret_value < 0 && cache_ptr && cache_ptr->slist_ptr) |
542 | | /* Arguably, it shouldn't be necessary to re-enable the slist after |
543 | | * the call to H5C__flush_invalidate_cache(), as the metadata cache |
544 | | * should be discarded. However, in the test code, we make multiple |
545 | | * calls to H5C_dest(). Thus we re-enable the slist on failure if it |
546 | | * and the cache still exist. JRM -- 5/15/20 |
547 | | */ |
548 | 0 | if (H5C_set_slist_enabled(f->shared->cache, false, false) < 0) |
549 | 0 | HDONE_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "disable slist on flush dest failure failed"); |
550 | | |
551 | 23 | FUNC_LEAVE_NOAPI(ret_value) |
552 | 23 | } /* H5C_dest() */ |
553 | | |
554 | | /*------------------------------------------------------------------------- |
555 | | * Function: H5C_evict |
556 | | * |
557 | | * Purpose: Evict all except pinned entries in the cache |
558 | | * |
559 | | * Return: Non-negative on success/Negative on failure |
560 | | * |
561 | | *------------------------------------------------------------------------- |
562 | | */ |
563 | | herr_t |
564 | | H5C_evict(H5F_t *f) |
565 | 0 | { |
566 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
567 | |
|
568 | 0 | FUNC_ENTER_NOAPI(FAIL) |
569 | | |
570 | | /* Sanity check */ |
571 | 0 | assert(f); |
572 | | |
573 | | /* Enable the slist, as it is needed in the flush */ |
574 | 0 | if (H5C_set_slist_enabled(f->shared->cache, true, true) < 0) |
575 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "set slist enabled failed"); |
576 | | |
577 | | /* Flush and invalidate all cache entries except the pinned entries */ |
578 | 0 | if (H5C__flush_invalidate_cache(f, H5C__EVICT_ALLOW_LAST_PINS_FLAG) < 0) |
579 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to evict entries in the cache"); |
580 | | |
581 | | /* Disable the slist */ |
582 | 0 | if (H5C_set_slist_enabled(f->shared->cache, false, false) < 0) |
583 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "set slist disabled failed"); |
584 | | |
585 | 0 | done: |
586 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
587 | 0 | } /* H5C_evict() */ |
588 | | |
589 | | /*------------------------------------------------------------------------- |
590 | | * Function: H5C_flush_cache |
591 | | * |
592 | | * Purpose: Flush (and possibly destroy) the entries contained in the |
593 | | * specified cache. |
594 | | * |
595 | | * If the cache contains protected entries, the function will |
596 | | * fail, as protected entries cannot be flushed. However |
597 | | * all unprotected entries should be flushed before the |
598 | | * function returns failure. |
599 | | * |
600 | | * Return: Non-negative on success/Negative on failure or if there was |
601 | | * a request to flush all items and an entry was protected. |
602 | | * |
603 | | *------------------------------------------------------------------------- |
604 | | */ |
605 | | herr_t |
606 | | H5C_flush_cache(H5F_t *f, unsigned flags) |
607 | 4 | { |
608 | | #ifdef H5C_DO_SANITY_CHECKS |
609 | | int i; |
610 | | uint32_t index_len = 0; |
611 | | size_t index_size = (size_t)0; |
612 | | size_t clean_index_size = (size_t)0; |
613 | | size_t dirty_index_size = (size_t)0; |
614 | | size_t slist_size = (size_t)0; |
615 | | uint32_t slist_len = 0; |
616 | | #endif /* H5C_DO_SANITY_CHECKS */ |
617 | 4 | H5C_ring_t ring; |
618 | 4 | H5C_t *cache_ptr; |
619 | 4 | bool destroy; |
620 | 4 | herr_t ret_value = SUCCEED; |
621 | | |
622 | 4 | FUNC_ENTER_NOAPI(FAIL) |
623 | | |
624 | 4 | assert(f); |
625 | 4 | assert(f->shared); |
626 | 4 | cache_ptr = f->shared->cache; |
627 | 4 | assert(cache_ptr); |
628 | 4 | assert(cache_ptr->slist_ptr); |
629 | | |
630 | | #ifdef H5C_DO_SANITY_CHECKS |
631 | | assert(cache_ptr->index_ring_len[H5C_RING_UNDEFINED] == 0); |
632 | | assert(cache_ptr->index_ring_size[H5C_RING_UNDEFINED] == (size_t)0); |
633 | | assert(cache_ptr->clean_index_ring_size[H5C_RING_UNDEFINED] == (size_t)0); |
634 | | assert(cache_ptr->dirty_index_ring_size[H5C_RING_UNDEFINED] == (size_t)0); |
635 | | assert(cache_ptr->slist_ring_len[H5C_RING_UNDEFINED] == 0); |
636 | | assert(cache_ptr->slist_ring_size[H5C_RING_UNDEFINED] == (size_t)0); |
637 | | |
638 | | for (i = H5C_RING_USER; i < H5C_RING_NTYPES; i++) { |
639 | | index_len += cache_ptr->index_ring_len[i]; |
640 | | index_size += cache_ptr->index_ring_size[i]; |
641 | | clean_index_size += cache_ptr->clean_index_ring_size[i]; |
642 | | dirty_index_size += cache_ptr->dirty_index_ring_size[i]; |
643 | | |
644 | | slist_len += cache_ptr->slist_ring_len[i]; |
645 | | slist_size += cache_ptr->slist_ring_size[i]; |
646 | | } /* end for */ |
647 | | |
648 | | assert(cache_ptr->index_len == index_len); |
649 | | assert(cache_ptr->index_size == index_size); |
650 | | assert(cache_ptr->clean_index_size == clean_index_size); |
651 | | assert(cache_ptr->dirty_index_size == dirty_index_size); |
652 | | assert(cache_ptr->slist_len == slist_len); |
653 | | assert(cache_ptr->slist_size == slist_size); |
654 | | #endif /* H5C_DO_SANITY_CHECKS */ |
655 | | |
656 | | #ifdef H5C_DO_EXTREME_SANITY_CHECKS |
657 | | if (H5C__validate_protected_entry_list(cache_ptr) < 0 || H5C__validate_pinned_entry_list(cache_ptr) < 0 || |
658 | | H5C__validate_lru_list(cache_ptr) < 0) |
659 | | HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on entry"); |
660 | | #endif /* H5C_DO_EXTREME_SANITY_CHECKS */ |
661 | | |
662 | 4 | destroy = ((flags & H5C__FLUSH_INVALIDATE_FLAG) != 0); |
663 | 4 | assert(!(destroy && ((flags & H5C__FLUSH_IGNORE_PROTECTED_FLAG) != 0))); |
664 | 4 | assert(!(cache_ptr->flush_in_progress)); |
665 | | |
666 | 4 | cache_ptr->flush_in_progress = true; |
667 | | |
668 | 4 | if (destroy) { |
669 | 0 | if (H5C__flush_invalidate_cache(f, flags) < 0) |
670 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "flush invalidate failed"); |
671 | 0 | } /* end if */ |
672 | 4 | else { |
673 | | /* flush each ring, starting from the outermost ring and |
674 | | * working inward. |
675 | | */ |
676 | 4 | ring = H5C_RING_USER; |
677 | 24 | while (ring < H5C_RING_NTYPES) { |
678 | | /* Only call the free space manager settle routines when close |
679 | | * warning has been received. |
680 | | */ |
681 | 20 | if (cache_ptr->close_warning_received) { |
682 | 10 | switch (ring) { |
683 | 2 | case H5C_RING_USER: |
684 | 2 | break; |
685 | | |
686 | 2 | case H5C_RING_RDFSM: |
687 | | /* Settle raw data FSM */ |
688 | 2 | if (!cache_ptr->rdfsm_settled) |
689 | 2 | if (H5MF_settle_raw_data_fsm(f, &cache_ptr->rdfsm_settled) < 0) |
690 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "RD FSM settle failed"); |
691 | 2 | break; |
692 | | |
693 | 2 | case H5C_RING_MDFSM: |
694 | | /* Settle metadata FSM */ |
695 | 2 | if (!cache_ptr->mdfsm_settled) |
696 | 2 | if (H5MF_settle_meta_data_fsm(f, &cache_ptr->mdfsm_settled) < 0) |
697 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "MD FSM settle failed"); |
698 | 2 | break; |
699 | | |
700 | 2 | case H5C_RING_SBE: |
701 | 4 | case H5C_RING_SB: |
702 | 4 | break; |
703 | | |
704 | 0 | default: |
705 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Unknown ring?!?!"); |
706 | 0 | break; |
707 | 10 | } /* end switch */ |
708 | 10 | } /* end if */ |
709 | | |
710 | 20 | if (H5C__flush_ring(f, ring, flags) < 0) |
711 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "flush ring failed"); |
712 | 20 | ring++; |
713 | 20 | } /* end while */ |
714 | 4 | } /* end else */ |
715 | | |
716 | 4 | done: |
717 | 4 | cache_ptr->flush_in_progress = false; |
718 | | |
719 | 4 | FUNC_LEAVE_NOAPI(ret_value) |
720 | 4 | } /* H5C_flush_cache() */ |
721 | | |
722 | | /*------------------------------------------------------------------------- |
723 | | * Function: H5C_flush_to_min_clean |
724 | | * |
725 | | * Purpose: Flush dirty entries until the caches min clean size is |
726 | | * attained. |
727 | | * |
728 | | * This function is used in the implementation of the |
729 | | * metadata cache in PHDF5. To avoid "messages from the |
730 | | * future", the cache on process 0 can't be allowed to |
731 | | * flush entries until the other processes have reached |
732 | | * the same point in the calculation. If this constraint |
733 | | * is not met, it is possible that the other processes will |
734 | | * read metadata generated at a future point in the |
735 | | * computation. |
736 | | * |
737 | | * |
738 | | * Return: Non-negative on success/Negative on failure or if |
739 | | * write is not permitted. |
740 | | * |
741 | | *------------------------------------------------------------------------- |
742 | | */ |
743 | | herr_t |
744 | | H5C_flush_to_min_clean(H5F_t *f) |
745 | 0 | { |
746 | 0 | H5C_t *cache_ptr; |
747 | 0 | bool write_permitted; |
748 | 0 | herr_t ret_value = SUCCEED; |
749 | |
|
750 | 0 | FUNC_ENTER_NOAPI(FAIL) |
751 | |
|
752 | 0 | assert(f); |
753 | 0 | assert(f->shared); |
754 | 0 | cache_ptr = f->shared->cache; |
755 | 0 | assert(cache_ptr); |
756 | |
|
757 | 0 | if (cache_ptr->check_write_permitted != NULL) { |
758 | 0 | if ((cache_ptr->check_write_permitted)(f, &write_permitted) < 0) |
759 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "can't get write_permitted"); |
760 | 0 | } /* end if */ |
761 | 0 | else |
762 | 0 | write_permitted = cache_ptr->write_permitted; |
763 | | |
764 | 0 | if (!write_permitted) |
765 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "cache write is not permitted!?!"); |
766 | | |
767 | 0 | if (H5C__make_space_in_cache(f, (size_t)0, write_permitted) < 0) |
768 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C__make_space_in_cache failed"); |
769 | | |
770 | 0 | done: |
771 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
772 | 0 | } /* H5C_flush_to_min_clean() */ |
773 | | |
774 | | /*------------------------------------------------------------------------- |
775 | | * Function: H5C_reset_cache_hit_rate_stats() |
776 | | * |
777 | | * Purpose: Reset the cache hit rate computation fields. |
778 | | * |
779 | | * Return: SUCCEED on success, and FAIL on failure. |
780 | | * |
781 | | *------------------------------------------------------------------------- |
782 | | */ |
783 | | herr_t |
784 | | H5C_reset_cache_hit_rate_stats(H5C_t *cache_ptr) |
785 | 59 | { |
786 | 59 | herr_t ret_value = SUCCEED; /* Return value */ |
787 | | |
788 | 59 | FUNC_ENTER_NOAPI(FAIL) |
789 | | |
790 | 59 | if (cache_ptr == NULL) |
791 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "bad cache_ptr on entry"); |
792 | | |
793 | 59 | cache_ptr->cache_hits = 0; |
794 | 59 | cache_ptr->cache_accesses = 0; |
795 | | |
796 | 59 | done: |
797 | 59 | FUNC_LEAVE_NOAPI(ret_value) |
798 | 59 | } /* H5C_reset_cache_hit_rate_stats() */ |
799 | | |
800 | | /*------------------------------------------------------------------------- |
801 | | * Function: H5C_set_cache_auto_resize_config |
802 | | * |
803 | | * Purpose: Set the cache automatic resize configuration to the |
804 | | * provided values if they are in range, and fail if they |
805 | | * are not. |
806 | | * |
807 | | * If the new configuration enables automatic cache resizing, |
808 | | * coerce the cache max size and min clean size into agreement |
809 | | * with the new policy and re-set the full cache hit rate |
810 | | * stats. |
811 | | * |
812 | | * Return: SUCCEED on success, and FAIL on failure. |
813 | | * |
814 | | *------------------------------------------------------------------------- |
815 | | */ |
816 | | herr_t |
817 | | H5C_set_cache_auto_resize_config(H5C_t *cache_ptr, H5C_auto_size_ctl_t *config_ptr) |
818 | 23 | { |
819 | 23 | size_t new_max_cache_size; |
820 | 23 | size_t new_min_clean_size; |
821 | 23 | herr_t ret_value = SUCCEED; /* Return value */ |
822 | | |
823 | 23 | FUNC_ENTER_NOAPI(FAIL) |
824 | | |
825 | 23 | if (cache_ptr == NULL) |
826 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "bad cache_ptr on entry"); |
827 | 23 | if (config_ptr == NULL) |
828 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "NULL config_ptr on entry"); |
829 | 23 | if (config_ptr->version != H5C__CURR_AUTO_SIZE_CTL_VER) |
830 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "unknown config version"); |
831 | | |
832 | | /* check general configuration section of the config: */ |
833 | 23 | if (H5C_validate_resize_config(config_ptr, H5C_RESIZE_CFG__VALIDATE_GENERAL) < 0) |
834 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "error in general configuration fields of new config"); |
835 | | |
836 | | /* check size increase control fields of the config: */ |
837 | 23 | if (H5C_validate_resize_config(config_ptr, H5C_RESIZE_CFG__VALIDATE_INCREMENT) < 0) |
838 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "error in the size increase control fields of new config"); |
839 | | |
840 | | /* check size decrease control fields of the config: */ |
841 | 23 | if (H5C_validate_resize_config(config_ptr, H5C_RESIZE_CFG__VALIDATE_DECREMENT) < 0) |
842 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "error in the size decrease control fields of new config"); |
843 | | |
844 | | /* check for conflicts between size increase and size decrease controls: */ |
845 | 23 | if (H5C_validate_resize_config(config_ptr, H5C_RESIZE_CFG__VALIDATE_INTERACTIONS) < 0) |
846 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "conflicting threshold fields in new config"); |
847 | | |
848 | | /* will set the increase possible fields to false later if needed */ |
849 | 23 | cache_ptr->size_increase_possible = true; |
850 | 23 | cache_ptr->flash_size_increase_possible = true; |
851 | 23 | cache_ptr->size_decrease_possible = true; |
852 | | |
853 | 23 | switch (config_ptr->incr_mode) { |
854 | 0 | case H5C_incr__off: |
855 | 0 | cache_ptr->size_increase_possible = false; |
856 | 0 | break; |
857 | | |
858 | 23 | case H5C_incr__threshold: |
859 | 23 | if ((config_ptr->lower_hr_threshold <= 0.0) || (config_ptr->increment <= 1.0) || |
860 | 23 | ((config_ptr->apply_max_increment) && (config_ptr->max_increment <= 0))) |
861 | 0 | cache_ptr->size_increase_possible = false; |
862 | 23 | break; |
863 | | |
864 | 0 | default: /* should be unreachable */ |
865 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Unknown incr_mode?!?!?"); |
866 | 23 | } /* end switch */ |
867 | | |
868 | | /* logically, this is where configuration for flash cache size increases |
869 | | * should go. However, this configuration depends on max_cache_size, so |
870 | | * we wait until the end of the function, when this field is set. |
871 | | */ |
872 | | |
873 | 23 | switch (config_ptr->decr_mode) { |
874 | 0 | case H5C_decr__off: |
875 | 0 | cache_ptr->size_decrease_possible = false; |
876 | 0 | break; |
877 | | |
878 | 0 | case H5C_decr__threshold: |
879 | 0 | if (config_ptr->upper_hr_threshold >= 1.0 || config_ptr->decrement >= 1.0 || |
880 | 0 | (config_ptr->apply_max_decrement && config_ptr->max_decrement <= 0)) |
881 | 0 | cache_ptr->size_decrease_possible = false; |
882 | 0 | break; |
883 | | |
884 | 0 | case H5C_decr__age_out: |
885 | 0 | if ((config_ptr->apply_empty_reserve && config_ptr->empty_reserve >= 1.0) || |
886 | 0 | (config_ptr->apply_max_decrement && config_ptr->max_decrement <= 0)) |
887 | 0 | cache_ptr->size_decrease_possible = false; |
888 | 0 | break; |
889 | | |
890 | 23 | case H5C_decr__age_out_with_threshold: |
891 | 23 | if ((config_ptr->apply_empty_reserve && config_ptr->empty_reserve >= 1.0) || |
892 | 23 | (config_ptr->apply_max_decrement && config_ptr->max_decrement <= 0) || |
893 | 23 | config_ptr->upper_hr_threshold >= 1.0) |
894 | 0 | cache_ptr->size_decrease_possible = false; |
895 | 23 | break; |
896 | | |
897 | 0 | default: /* should be unreachable */ |
898 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Unknown decr_mode?!?!?"); |
899 | 23 | } /* end switch */ |
900 | | |
901 | 23 | if (config_ptr->max_size == config_ptr->min_size) { |
902 | 0 | cache_ptr->size_increase_possible = false; |
903 | 0 | cache_ptr->flash_size_increase_possible = false; |
904 | 0 | cache_ptr->size_decrease_possible = false; |
905 | 0 | } /* end if */ |
906 | | |
907 | | /* flash_size_increase_possible is intentionally omitted from the |
908 | | * following: |
909 | | */ |
910 | 23 | cache_ptr->resize_enabled = cache_ptr->size_increase_possible || cache_ptr->size_decrease_possible; |
911 | 23 | cache_ptr->resize_ctl = *config_ptr; |
912 | | |
913 | | /* Resize the cache to the supplied initial value if requested, or as |
914 | | * necessary to force it within the bounds of the current automatic |
915 | | * cache resizing configuration. |
916 | | * |
917 | | * Note that the min_clean_fraction may have changed, so we |
918 | | * go through the exercise even if the current size is within |
919 | | * range and an initial size has not been provided. |
920 | | */ |
921 | 23 | if (cache_ptr->resize_ctl.set_initial_size) |
922 | 23 | new_max_cache_size = cache_ptr->resize_ctl.initial_size; |
923 | 0 | else if (cache_ptr->max_cache_size > cache_ptr->resize_ctl.max_size) |
924 | 0 | new_max_cache_size = cache_ptr->resize_ctl.max_size; |
925 | 0 | else if (cache_ptr->max_cache_size < cache_ptr->resize_ctl.min_size) |
926 | 0 | new_max_cache_size = cache_ptr->resize_ctl.min_size; |
927 | 0 | else |
928 | 0 | new_max_cache_size = cache_ptr->max_cache_size; |
929 | | |
930 | 23 | new_min_clean_size = (size_t)((double)new_max_cache_size * (cache_ptr->resize_ctl.min_clean_fraction)); |
931 | | |
932 | | /* since new_min_clean_size is of type size_t, we have |
933 | | * |
934 | | * ( 0 <= new_min_clean_size ) |
935 | | * |
936 | | * by definition. |
937 | | */ |
938 | 23 | assert(new_min_clean_size <= new_max_cache_size); |
939 | 23 | assert(cache_ptr->resize_ctl.min_size <= new_max_cache_size); |
940 | 23 | assert(new_max_cache_size <= cache_ptr->resize_ctl.max_size); |
941 | | |
942 | 23 | if (new_max_cache_size < cache_ptr->max_cache_size) |
943 | 23 | cache_ptr->size_decreased = true; |
944 | | |
945 | 23 | cache_ptr->max_cache_size = new_max_cache_size; |
946 | 23 | cache_ptr->min_clean_size = new_min_clean_size; |
947 | | |
948 | 23 | if (H5C_reset_cache_hit_rate_stats(cache_ptr) < 0) |
949 | | /* this should be impossible... */ |
950 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_reset_cache_hit_rate_stats failed"); |
951 | | |
952 | | /* remove excess epoch markers if any */ |
953 | 23 | if ((config_ptr->decr_mode == H5C_decr__age_out_with_threshold) || |
954 | 23 | (config_ptr->decr_mode == H5C_decr__age_out)) { |
955 | 23 | if (cache_ptr->epoch_markers_active > cache_ptr->resize_ctl.epochs_before_eviction) |
956 | 0 | if (H5C__autoadjust__ageout__remove_excess_markers(cache_ptr) < 0) |
957 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "can't remove excess epoch markers"); |
958 | 23 | } /* end if */ |
959 | 0 | else if (cache_ptr->epoch_markers_active > 0) { |
960 | 0 | if (H5C__autoadjust__ageout__remove_all_markers(cache_ptr) < 0) |
961 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "error removing all epoch markers"); |
962 | 0 | } |
963 | | |
964 | | /* configure flash size increase facility. We wait until the |
965 | | * end of the function, as we need the max_cache_size set before |
966 | | * we start to keep things simple. |
967 | | * |
968 | | * If we haven't already ruled out flash cache size increases above, |
969 | | * go ahead and configure it. |
970 | | */ |
971 | 23 | if (cache_ptr->flash_size_increase_possible) { |
972 | 23 | switch (config_ptr->flash_incr_mode) { |
973 | 0 | case H5C_flash_incr__off: |
974 | 0 | cache_ptr->flash_size_increase_possible = false; |
975 | 0 | break; |
976 | | |
977 | 23 | case H5C_flash_incr__add_space: |
978 | 23 | cache_ptr->flash_size_increase_possible = true; |
979 | 23 | cache_ptr->flash_size_increase_threshold = |
980 | 23 | (size_t)(((double)(cache_ptr->max_cache_size)) * (cache_ptr->resize_ctl.flash_threshold)); |
981 | 23 | break; |
982 | | |
983 | 0 | default: /* should be unreachable */ |
984 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Unknown flash_incr_mode?!?!?"); |
985 | 0 | break; |
986 | 23 | } /* end switch */ |
987 | 23 | } /* end if */ |
988 | | |
989 | 23 | done: |
990 | 23 | FUNC_LEAVE_NOAPI(ret_value) |
991 | 23 | } /* H5C_set_cache_auto_resize_config() */ |
992 | | |
993 | | /*------------------------------------------------------------------------- |
994 | | * Function: H5C_set_evictions_enabled() |
995 | | * |
996 | | * Purpose: Set cache_ptr->evictions_enabled to the value of the |
997 | | * evictions enabled parameter. |
998 | | * |
999 | | * Return: SUCCEED on success, and FAIL on failure. |
1000 | | * |
1001 | | *------------------------------------------------------------------------- |
1002 | | */ |
1003 | | herr_t |
1004 | | H5C_set_evictions_enabled(H5C_t *cache_ptr, bool evictions_enabled) |
1005 | 23 | { |
1006 | 23 | herr_t ret_value = SUCCEED; /* Return value */ |
1007 | | |
1008 | 23 | FUNC_ENTER_NOAPI(FAIL) |
1009 | | |
1010 | 23 | if (cache_ptr == NULL) |
1011 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad cache_ptr on entry"); |
1012 | | |
1013 | | /* There is no fundamental reason why we should not permit |
1014 | | * evictions to be disabled while automatic resize is enabled. |
1015 | | * However, allowing it would greatly complicate testing |
1016 | | * the feature. Hence the following: |
1017 | | */ |
1018 | 23 | if ((evictions_enabled != true) && ((cache_ptr->resize_ctl.incr_mode != H5C_incr__off) || |
1019 | 0 | (cache_ptr->resize_ctl.decr_mode != H5C_decr__off))) |
1020 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't disable evictions when auto resize enabled"); |
1021 | | |
1022 | 23 | cache_ptr->evictions_enabled = evictions_enabled; |
1023 | | |
1024 | 23 | done: |
1025 | 23 | FUNC_LEAVE_NOAPI(ret_value) |
1026 | 23 | } /* H5C_set_evictions_enabled() */ |
1027 | | |
1028 | | /*------------------------------------------------------------------------- |
1029 | | * Function: H5C_set_slist_enabled() |
1030 | | * |
1031 | | * Purpose: Enable or disable the slist as directed. |
1032 | | * |
1033 | | * The slist (skip list) is an address ordered list of |
1034 | | * dirty entries in the metadata cache. However, this |
1035 | | * list is only needed during flush and close, where we |
1036 | | * use it to write entries in more or less increasing |
1037 | | * address order. |
1038 | | * |
1039 | | * This function sets up and enables further operations |
1040 | | * on the slist, or disable the slist. This in turn |
1041 | | * allows us to avoid the overhead of maintaining the |
1042 | | * slist when it is not needed. |
1043 | | * |
1044 | | * |
1045 | | * If the slist_enabled parameter is true, the function |
1046 | | * |
1047 | | * 1) Verifies that the slist is empty. |
1048 | | * |
1049 | | * 2) If the populate_slist parameter is true, scans the |
1050 | | * index list, and inserts all dirty entries into the |
1051 | | * slist. |
1052 | | * |
1053 | | * 3) Sets cache_ptr->slist_enabled = true. |
1054 | | * |
1055 | | * |
1056 | | * If the slist_enabled_parameter is false, the function |
1057 | | * shuts down the slist: |
1058 | | * |
1059 | | * 1) Test to see if the slist is empty. If it is, proceed |
1060 | | * to step 3. |
1061 | | * |
1062 | | * 2) Remove all entries from the slist. |
1063 | | * |
1064 | | * 3) set cache_ptr->slist_enabled = false. |
1065 | | * |
1066 | | * Note that the populate_slist parameter is ignored if |
1067 | | * the slist_enabed parameter is false. |
1068 | | * |
1069 | | * Return: SUCCEED on success, and FAIL on failure. |
1070 | | * |
1071 | | *------------------------------------------------------------------------- |
1072 | | */ |
1073 | | herr_t |
1074 | | H5C_set_slist_enabled(H5C_t *cache_ptr, bool slist_enabled, bool populate_slist) |
1075 | 29 | { |
1076 | 29 | H5C_cache_entry_t *entry_ptr; |
1077 | 29 | herr_t ret_value = SUCCEED; /* Return value */ |
1078 | | |
1079 | 29 | FUNC_ENTER_NOAPI(FAIL) |
1080 | | |
1081 | 29 | if (cache_ptr == NULL) |
1082 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad cache_ptr on entry"); |
1083 | | |
1084 | 29 | if (slist_enabled) { |
1085 | 26 | if (cache_ptr->slist_enabled) |
1086 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "slist already enabled?"); |
1087 | 26 | if ((cache_ptr->slist_len != 0) || (cache_ptr->slist_size != 0)) |
1088 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "slist not empty?"); |
1089 | | |
1090 | | /* set cache_ptr->slist_enabled to true so that the slist |
1091 | | * maintenance macros will be enabled. |
1092 | | */ |
1093 | 26 | cache_ptr->slist_enabled = true; |
1094 | | |
1095 | 26 | if (populate_slist) { |
1096 | | /* scan the index list and insert all dirty entries in the slist */ |
1097 | 24 | entry_ptr = cache_ptr->il_head; |
1098 | 63 | while (entry_ptr != NULL) { |
1099 | 39 | if (entry_ptr->is_dirty) |
1100 | 6 | H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, FAIL); |
1101 | 39 | entry_ptr = entry_ptr->il_next; |
1102 | 39 | } |
1103 | | |
1104 | | /* we don't maintain a dirty index len, so we can't do a cross |
1105 | | * check against it. Note that there is no point in cross checking |
1106 | | * against the dirty LRU size, as the dirty LRU may not be maintained, |
1107 | | * and in any case, there is no requirement that all dirty entries |
1108 | | * will reside on the dirty LRU. |
1109 | | */ |
1110 | 24 | assert(cache_ptr->dirty_index_size == cache_ptr->slist_size); |
1111 | 24 | } |
1112 | 26 | } |
1113 | 3 | else { /* take down the skip list */ |
1114 | 3 | if (!cache_ptr->slist_enabled) |
1115 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "slist already disabled?"); |
1116 | | |
1117 | 3 | if ((cache_ptr->slist_len != 0) || (cache_ptr->slist_size != 0)) |
1118 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "slist not empty?"); |
1119 | | |
1120 | 3 | cache_ptr->slist_enabled = false; |
1121 | | |
1122 | 3 | assert(0 == cache_ptr->slist_len); |
1123 | 3 | assert(0 == cache_ptr->slist_size); |
1124 | 3 | } |
1125 | | |
1126 | 29 | done: |
1127 | 29 | FUNC_LEAVE_NOAPI(ret_value) |
1128 | 29 | } /* H5C_set_slist_enabled() */ |
1129 | | |
1130 | | /*------------------------------------------------------------------------- |
1131 | | * Function: H5C_unsettle_ring() |
1132 | | * |
1133 | | * Purpose: Advise the metadata cache that the specified free space |
1134 | | * manager ring is no longer settled (if it was on entry). |
1135 | | * |
1136 | | * If the target free space manager ring is already |
1137 | | * unsettled, do nothing, and return SUCCEED. |
1138 | | * |
1139 | | * If the target free space manager ring is settled, and |
1140 | | * we are not in the process of a file shutdown, mark |
1141 | | * the ring as unsettled, and return SUCCEED. |
1142 | | * |
1143 | | * If the target free space manager is settled, and we |
1144 | | * are in the process of a file shutdown, post an error |
1145 | | * message, and return FAIL. |
1146 | | * |
1147 | | * Return: Non-negative on success/Negative on failure |
1148 | | * |
1149 | | *------------------------------------------------------------------------- |
1150 | | */ |
1151 | | herr_t |
1152 | | H5C_unsettle_ring(H5F_t *f, H5C_ring_t ring) |
1153 | 1 | { |
1154 | 1 | H5C_t *cache_ptr; |
1155 | 1 | herr_t ret_value = SUCCEED; /* Return value */ |
1156 | | |
1157 | 1 | FUNC_ENTER_NOAPI(FAIL) |
1158 | | |
1159 | | /* Sanity checks */ |
1160 | 1 | assert(f); |
1161 | 1 | assert(f->shared); |
1162 | 1 | assert(f->shared->cache); |
1163 | 1 | assert((H5C_RING_RDFSM == ring) || (H5C_RING_MDFSM == ring)); |
1164 | 1 | cache_ptr = f->shared->cache; |
1165 | | |
1166 | 1 | switch (ring) { |
1167 | 0 | case H5C_RING_RDFSM: |
1168 | 0 | if (cache_ptr->rdfsm_settled) { |
1169 | 0 | if (cache_ptr->close_warning_received) |
1170 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unexpected rdfsm ring unsettle"); |
1171 | 0 | cache_ptr->rdfsm_settled = false; |
1172 | 0 | } /* end if */ |
1173 | 0 | break; |
1174 | | |
1175 | 1 | case H5C_RING_MDFSM: |
1176 | 1 | if (cache_ptr->mdfsm_settled) { |
1177 | 0 | if (cache_ptr->close_warning_received) |
1178 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unexpected mdfsm ring unsettle"); |
1179 | 0 | cache_ptr->mdfsm_settled = false; |
1180 | 0 | } /* end if */ |
1181 | 1 | break; |
1182 | | |
1183 | 1 | default: |
1184 | 0 | assert(false); /* this should be un-reachable */ |
1185 | 0 | break; |
1186 | 1 | } /* end switch */ |
1187 | | |
1188 | 1 | done: |
1189 | 1 | FUNC_LEAVE_NOAPI(ret_value) |
1190 | 1 | } /* H5C_unsettle_ring() */ |
1191 | | |
1192 | | /*------------------------------------------------------------------------- |
1193 | | * Function: H5C_validate_resize_config() |
1194 | | * |
1195 | | * Purpose: Run a sanity check on the specified sections of the |
1196 | | * provided instance of struct H5C_auto_size_ctl_t. |
1197 | | * |
1198 | | * Do nothing and return SUCCEED if no errors are detected, |
1199 | | * and flag an error and return FAIL otherwise. |
1200 | | * |
1201 | | * Return: Non-negative on success/Negative on failure |
1202 | | * |
1203 | | *------------------------------------------------------------------------- |
1204 | | */ |
1205 | | herr_t |
1206 | | H5C_validate_resize_config(H5C_auto_size_ctl_t *config_ptr, unsigned int tests) |
1207 | 138 | { |
1208 | 138 | herr_t ret_value = SUCCEED; /* Return value */ |
1209 | | |
1210 | 138 | FUNC_ENTER_NOAPI(FAIL) |
1211 | | |
1212 | 138 | if (config_ptr == NULL) |
1213 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "NULL config_ptr on entry"); |
1214 | | |
1215 | 138 | if (config_ptr->version != H5C__CURR_AUTO_SIZE_CTL_VER) |
1216 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Unknown config version"); |
1217 | | |
1218 | 138 | if ((tests & H5C_RESIZE_CFG__VALIDATE_GENERAL) != 0) { |
1219 | 69 | if (config_ptr->max_size > H5C__MAX_MAX_CACHE_SIZE) |
1220 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "max_size too big"); |
1221 | 69 | if (config_ptr->min_size < H5C__MIN_MAX_CACHE_SIZE) |
1222 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "min_size too small"); |
1223 | 69 | if (config_ptr->min_size > config_ptr->max_size) |
1224 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "min_size > max_size"); |
1225 | 69 | if (config_ptr->set_initial_size && ((config_ptr->initial_size < config_ptr->min_size) || |
1226 | 69 | (config_ptr->initial_size > config_ptr->max_size))) |
1227 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, |
1228 | 69 | "initial_size must be in the interval [min_size, max_size]"); |
1229 | 69 | if ((config_ptr->min_clean_fraction < 0.0) || (config_ptr->min_clean_fraction > 1.0)) |
1230 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, |
1231 | 69 | "min_clean_fraction must be in the interval [0.0, 1.0]"); |
1232 | 69 | if (config_ptr->epoch_length < H5C__MIN_AR_EPOCH_LENGTH) |
1233 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "epoch_length too small"); |
1234 | 69 | if (config_ptr->epoch_length > H5C__MAX_AR_EPOCH_LENGTH) |
1235 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "epoch_length too big"); |
1236 | 69 | } /* H5C_RESIZE_CFG__VALIDATE_GENERAL */ |
1237 | | |
1238 | 138 | if ((tests & H5C_RESIZE_CFG__VALIDATE_INCREMENT) != 0) { |
1239 | 69 | if ((config_ptr->incr_mode != H5C_incr__off) && (config_ptr->incr_mode != H5C_incr__threshold)) |
1240 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Invalid incr_mode"); |
1241 | | |
1242 | 69 | if (config_ptr->incr_mode == H5C_incr__threshold) { |
1243 | 69 | if ((config_ptr->lower_hr_threshold < 0.0) || (config_ptr->lower_hr_threshold > 1.0)) |
1244 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, |
1245 | 69 | "lower_hr_threshold must be in the range [0.0, 1.0]"); |
1246 | 69 | if (config_ptr->increment < 1.0) |
1247 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "increment must be greater than or equal to 1.0"); |
1248 | | |
1249 | | /* no need to check max_increment, as it is a size_t, |
1250 | | * and thus must be non-negative. |
1251 | | */ |
1252 | 69 | } /* H5C_incr__threshold */ |
1253 | | |
1254 | 69 | switch (config_ptr->flash_incr_mode) { |
1255 | 0 | case H5C_flash_incr__off: |
1256 | | /* nothing to do here */ |
1257 | 0 | break; |
1258 | | |
1259 | 69 | case H5C_flash_incr__add_space: |
1260 | 69 | if ((config_ptr->flash_multiple < 0.1) || (config_ptr->flash_multiple > 10.0)) |
1261 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, |
1262 | 69 | "flash_multiple must be in the range [0.1, 10.0]"); |
1263 | 69 | if ((config_ptr->flash_threshold < 0.1) || (config_ptr->flash_threshold > 1.0)) |
1264 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, |
1265 | 69 | "flash_threshold must be in the range [0.1, 1.0]"); |
1266 | 69 | break; |
1267 | | |
1268 | 69 | default: |
1269 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Invalid flash_incr_mode"); |
1270 | 0 | break; |
1271 | 69 | } /* end switch */ |
1272 | 69 | } /* H5C_RESIZE_CFG__VALIDATE_INCREMENT */ |
1273 | | |
1274 | 138 | if ((tests & H5C_RESIZE_CFG__VALIDATE_DECREMENT) != 0) { |
1275 | 69 | if ((config_ptr->decr_mode != H5C_decr__off) && (config_ptr->decr_mode != H5C_decr__threshold) && |
1276 | 69 | (config_ptr->decr_mode != H5C_decr__age_out) && |
1277 | 69 | (config_ptr->decr_mode != H5C_decr__age_out_with_threshold)) |
1278 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Invalid decr_mode"); |
1279 | | |
1280 | 69 | if (config_ptr->decr_mode == H5C_decr__threshold) { |
1281 | 0 | if (config_ptr->upper_hr_threshold > 1.0) |
1282 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "upper_hr_threshold must be <= 1.0"); |
1283 | 0 | if ((config_ptr->decrement > 1.0) || (config_ptr->decrement < 0.0)) |
1284 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "decrement must be in the interval [0.0, 1.0]"); |
1285 | | |
1286 | | /* no need to check max_decrement as it is a size_t |
1287 | | * and thus must be non-negative. |
1288 | | */ |
1289 | 0 | } /* H5C_decr__threshold */ |
1290 | | |
1291 | 69 | if ((config_ptr->decr_mode == H5C_decr__age_out) || |
1292 | 69 | (config_ptr->decr_mode == H5C_decr__age_out_with_threshold)) { |
1293 | 69 | if (config_ptr->epochs_before_eviction < 1) |
1294 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "epochs_before_eviction must be positive"); |
1295 | 69 | if (config_ptr->epochs_before_eviction > H5C__MAX_EPOCH_MARKERS) |
1296 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "epochs_before_eviction too big"); |
1297 | 69 | if (config_ptr->apply_empty_reserve && |
1298 | 69 | (config_ptr->empty_reserve > 1.0 || config_ptr->empty_reserve < 0.0)) |
1299 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "empty_reserve must be in the interval [0.0, 1.0]"); |
1300 | | |
1301 | | /* no need to check max_decrement as it is a size_t |
1302 | | * and thus must be non-negative. |
1303 | | */ |
1304 | 69 | } /* H5C_decr__age_out || H5C_decr__age_out_with_threshold */ |
1305 | | |
1306 | 69 | if (config_ptr->decr_mode == H5C_decr__age_out_with_threshold) |
1307 | 69 | if ((config_ptr->upper_hr_threshold > 1.0) || (config_ptr->upper_hr_threshold < 0.0)) |
1308 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, |
1309 | 69 | "upper_hr_threshold must be in the interval [0.0, 1.0]"); |
1310 | 69 | } /* H5C_RESIZE_CFG__VALIDATE_DECREMENT */ |
1311 | | |
1312 | 138 | if ((tests & H5C_RESIZE_CFG__VALIDATE_INTERACTIONS) != 0) { |
1313 | 69 | if ((config_ptr->incr_mode == H5C_incr__threshold) && |
1314 | 69 | ((config_ptr->decr_mode == H5C_decr__threshold) || |
1315 | 69 | (config_ptr->decr_mode == H5C_decr__age_out_with_threshold)) && |
1316 | 69 | (config_ptr->lower_hr_threshold >= config_ptr->upper_hr_threshold)) |
1317 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "conflicting threshold fields in config"); |
1318 | 69 | } /* H5C_RESIZE_CFG__VALIDATE_INTERACTIONS */ |
1319 | | |
1320 | 138 | done: |
1321 | 138 | FUNC_LEAVE_NOAPI(ret_value) |
1322 | 138 | } /* H5C_validate_resize_config() */ |
1323 | | |
1324 | | /*------------------------------------------------------------------------- |
1325 | | * Function: H5C_cork |
1326 | | * |
1327 | | * Purpose: To cork/uncork/get cork status of an object depending on "action": |
1328 | | * H5C__SET_CORK: |
1329 | | * To cork the object |
1330 | | * Return error if the object is already corked |
1331 | | * H5C__UNCORK: |
1332 | | * To uncork the object |
1333 | | * Return error if the object is not corked |
1334 | | * H5C__GET_CORKED: |
1335 | | * To retrieve the cork status of an object in |
1336 | | * the parameter "corked" |
1337 | | * |
1338 | | * Return: Success: Non-negative |
1339 | | * Failure: Negative |
1340 | | * |
1341 | | *------------------------------------------------------------------------- |
1342 | | */ |
1343 | | herr_t |
1344 | | H5C_cork(H5C_t *cache_ptr, haddr_t obj_addr, unsigned action, bool *corked) |
1345 | 0 | { |
1346 | 0 | H5C_tag_info_t *tag_info = NULL; |
1347 | 0 | herr_t ret_value = SUCCEED; |
1348 | |
|
1349 | 0 | FUNC_ENTER_NOAPI_NOINIT |
1350 | | |
1351 | | /* Assertions */ |
1352 | 0 | assert(cache_ptr != NULL); |
1353 | 0 | assert(H5_addr_defined(obj_addr)); |
1354 | 0 | assert(action == H5C__SET_CORK || action == H5C__UNCORK || action == H5C__GET_CORKED); |
1355 | | |
1356 | | /* Search the list of corked object addresses in the cache */ |
1357 | 0 | HASH_FIND(hh, cache_ptr->tag_list, &obj_addr, sizeof(haddr_t), tag_info); |
1358 | |
|
1359 | 0 | if (H5C__GET_CORKED == action) { |
1360 | 0 | assert(corked); |
1361 | 0 | if (tag_info != NULL && tag_info->corked) |
1362 | 0 | *corked = true; |
1363 | 0 | else |
1364 | 0 | *corked = false; |
1365 | 0 | } |
1366 | 0 | else { |
1367 | | /* Sanity check */ |
1368 | 0 | assert(H5C__SET_CORK == action || H5C__UNCORK == action); |
1369 | | |
1370 | | /* Perform appropriate action */ |
1371 | 0 | if (H5C__SET_CORK == action) { |
1372 | | /* Check if this is the first entry for this tagged object */ |
1373 | 0 | if (NULL == tag_info) { |
1374 | | /* Allocate new tag info struct */ |
1375 | 0 | if (NULL == (tag_info = H5FL_CALLOC(H5C_tag_info_t))) |
1376 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "can't allocate tag info for cache entry"); |
1377 | | |
1378 | | /* Set the tag for all entries */ |
1379 | 0 | tag_info->tag = obj_addr; |
1380 | | |
1381 | | /* Insert tag info into hash table */ |
1382 | 0 | HASH_ADD(hh, cache_ptr->tag_list, tag, sizeof(haddr_t), tag_info); |
1383 | 0 | } |
1384 | 0 | else { |
1385 | | /* Check for object already corked */ |
1386 | 0 | if (tag_info->corked) |
1387 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_CANTCORK, FAIL, "object already corked"); |
1388 | 0 | assert(tag_info->entry_cnt > 0 && tag_info->head); |
1389 | 0 | } |
1390 | | |
1391 | | /* Set the corked status for the entire object */ |
1392 | 0 | tag_info->corked = true; |
1393 | 0 | cache_ptr->num_objs_corked++; |
1394 | 0 | } |
1395 | 0 | else { |
1396 | | /* Sanity check */ |
1397 | 0 | if (NULL == tag_info) |
1398 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_CANTUNCORK, FAIL, "tag info pointer is NULL"); |
1399 | | |
1400 | | /* Check for already uncorked */ |
1401 | 0 | if (!tag_info->corked) |
1402 | 0 | HGOTO_ERROR(H5E_CACHE, H5E_CANTUNCORK, FAIL, "object already uncorked"); |
1403 | | |
1404 | | /* Set the corked status for the entire object */ |
1405 | 0 | tag_info->corked = false; |
1406 | 0 | cache_ptr->num_objs_corked--; |
1407 | | |
1408 | | /* Remove the tag info from the tag list, if there's no more entries with this tag */ |
1409 | 0 | if (0 == tag_info->entry_cnt) { |
1410 | | /* Sanity check */ |
1411 | 0 | assert(NULL == tag_info->head); |
1412 | |
|
1413 | 0 | HASH_DELETE(hh, cache_ptr->tag_list, tag_info); |
1414 | | |
1415 | | /* Release the tag info */ |
1416 | 0 | tag_info = H5FL_FREE(H5C_tag_info_t, tag_info); |
1417 | 0 | } |
1418 | 0 | else |
1419 | 0 | assert(NULL != tag_info->head); |
1420 | 0 | } |
1421 | 0 | } |
1422 | | |
1423 | 0 | done: |
1424 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1425 | 0 | } /* H5C_cork() */ |