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 | | * Purpose: Each file has a small cache of global heap collections called |
15 | | * the CWFS list and recently accessed collections with free |
16 | | * space appear on this list. As collections are accessed the |
17 | | * collection is moved toward the front of the list. New |
18 | | * collections are added to the front of the list while old |
19 | | * collections are added to the end of the list. |
20 | | * |
21 | | * The collection model reduces the overhead which would be |
22 | | * incurred if the global heap were a single object, and the |
23 | | * CWFS list allows the library to cheaply choose a collection |
24 | | * for a new object based on object size, amount of free space |
25 | | * in the collection, and temporal locality. |
26 | | */ |
27 | | |
28 | | /****************/ |
29 | | /* Module Setup */ |
30 | | /****************/ |
31 | | |
32 | | #include "H5Fmodule.h" /* This source code file is part of the H5F module */ |
33 | | |
34 | | /***********/ |
35 | | /* Headers */ |
36 | | /***********/ |
37 | | #include "H5private.h" /* Generic Functions */ |
38 | | #include "H5Eprivate.h" /* Error handling */ |
39 | | #include "H5Fpkg.h" /* File access */ |
40 | | #include "H5HGprivate.h" /* Global heaps */ |
41 | | #include "H5MFprivate.h" /* File memory management */ |
42 | | #include "H5MMprivate.h" /* Memory management */ |
43 | | |
44 | | /****************/ |
45 | | /* Local Macros */ |
46 | | /****************/ |
47 | | |
48 | | /* |
49 | | * Maximum length of the CWFS list, the list of remembered collections that |
50 | | * have free space. |
51 | | */ |
52 | 0 | #define H5F_NCWFS 16 |
53 | | |
54 | | /******************/ |
55 | | /* Local Typedefs */ |
56 | | /******************/ |
57 | | |
58 | | /********************/ |
59 | | /* Package Typedefs */ |
60 | | /********************/ |
61 | | |
62 | | /********************/ |
63 | | /* Local Prototypes */ |
64 | | /********************/ |
65 | | |
66 | | /*********************/ |
67 | | /* Package Variables */ |
68 | | /*********************/ |
69 | | |
70 | | /*****************************/ |
71 | | /* Library Private Variables */ |
72 | | /*****************************/ |
73 | | |
74 | | /*******************/ |
75 | | /* Local Variables */ |
76 | | /*******************/ |
77 | | |
78 | | /*------------------------------------------------------------------------- |
79 | | * Function: H5F_cwfs_add |
80 | | * |
81 | | * Purpose: Add a global heap collection to the CWFS for a file. |
82 | | * |
83 | | * Return: Success: Non-negative |
84 | | * Failure: Negative |
85 | | * |
86 | | *------------------------------------------------------------------------- |
87 | | */ |
88 | | herr_t |
89 | | H5F_cwfs_add(H5F_t *f, H5HG_heap_t *heap) |
90 | 0 | { |
91 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
92 | |
|
93 | 0 | FUNC_ENTER_NOAPI(FAIL) |
94 | | |
95 | | /* Check args */ |
96 | 0 | assert(f); |
97 | 0 | assert(f->shared); |
98 | 0 | assert(heap); |
99 | | |
100 | | /* |
101 | | * Add the new heap to the CWFS list, removing some other entry if |
102 | | * necessary to make room. We remove the right-most entry that has less |
103 | | * free space than this heap. |
104 | | */ |
105 | 0 | if (NULL == f->shared->cwfs) { |
106 | 0 | if (NULL == (f->shared->cwfs = (H5HG_heap_t **)H5MM_malloc(H5F_NCWFS * sizeof(H5HG_heap_t *)))) |
107 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "can't allocate CWFS for file"); |
108 | 0 | f->shared->cwfs[0] = heap; |
109 | 0 | f->shared->ncwfs = 1; |
110 | 0 | } |
111 | 0 | else if (H5F_NCWFS == f->shared->ncwfs) { |
112 | 0 | int i; /* Local index variable */ |
113 | |
|
114 | 0 | for (i = H5F_NCWFS - 1; i >= 0; --i) |
115 | 0 | if (H5HG_FREE_SIZE(f->shared->cwfs[i]) < H5HG_FREE_SIZE(heap)) { |
116 | 0 | memmove(f->shared->cwfs + 1, f->shared->cwfs, (size_t)i * sizeof(H5HG_heap_t *)); |
117 | 0 | f->shared->cwfs[0] = heap; |
118 | 0 | break; |
119 | 0 | } /* end if */ |
120 | 0 | } |
121 | 0 | else { |
122 | 0 | memmove(f->shared->cwfs + 1, f->shared->cwfs, f->shared->ncwfs * sizeof(H5HG_heap_t *)); |
123 | 0 | f->shared->cwfs[0] = heap; |
124 | 0 | f->shared->ncwfs += 1; |
125 | 0 | } /* end else */ |
126 | | |
127 | 0 | done: |
128 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
129 | 0 | } /* H5F_cwfs_add() */ |
130 | | |
131 | | /*------------------------------------------------------------------------- |
132 | | * Function: H5F_cwfs_find_free_heap |
133 | | * |
134 | | * Purpose: Find a global heap collection with free space for storing |
135 | | * a new object. |
136 | | * |
137 | | * Return: Success: Non-negative |
138 | | * Failure: Negative |
139 | | * |
140 | | *------------------------------------------------------------------------- |
141 | | */ |
142 | | herr_t |
143 | | H5F_cwfs_find_free_heap(H5F_t *f, size_t need, haddr_t *addr) |
144 | 0 | { |
145 | 0 | unsigned cwfsno; /* Local index for iterating over collections */ |
146 | 0 | bool found = false; /* Flag to indicate a heap with enough space was found */ |
147 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
148 | |
|
149 | 0 | FUNC_ENTER_NOAPI(FAIL) |
150 | | |
151 | | /* Check args */ |
152 | 0 | assert(f); |
153 | 0 | assert(f->shared); |
154 | 0 | assert(addr); |
155 | | |
156 | | /* Note that we don't have metadata cache locks on the entries in |
157 | | * f->shared->cwfs. |
158 | | * |
159 | | * In the current situation, this doesn't matter, as we are single |
160 | | * threaded, and as best I can tell, entries are added to and deleted |
161 | | * from f->shared->cwfs as they are added to and deleted from the |
162 | | * metadata cache. |
163 | | * |
164 | | * To be proper, we should either lock each entry in f->shared->cwfs |
165 | | * as we examine it, or lock the whole array. However, at present |
166 | | * I don't see the point as there will be significant overhead, |
167 | | * and protecting and unprotecting all the collections in the global |
168 | | * heap on a regular basis will skew the replacement policy. |
169 | | * |
170 | | * JRM - 5/24/04 |
171 | | */ |
172 | 0 | for (cwfsno = 0; cwfsno < f->shared->ncwfs; cwfsno++) |
173 | 0 | if (H5HG_FREE_SIZE(f->shared->cwfs[cwfsno]) >= need) { |
174 | 0 | *addr = H5HG_ADDR(f->shared->cwfs[cwfsno]); |
175 | 0 | found = true; |
176 | 0 | break; |
177 | 0 | } /* end if */ |
178 | | |
179 | | /* |
180 | | * If we didn't find any collection with enough free space the check if |
181 | | * we can extend any of the collections to make enough room. |
182 | | */ |
183 | 0 | if (!found) { |
184 | 0 | size_t new_need; |
185 | |
|
186 | 0 | for (cwfsno = 0; cwfsno < f->shared->ncwfs; cwfsno++) { |
187 | 0 | new_need = need; |
188 | 0 | new_need -= H5HG_FREE_SIZE(f->shared->cwfs[cwfsno]); |
189 | 0 | new_need = MAX(H5HG_SIZE(f->shared->cwfs[cwfsno]), new_need); |
190 | |
|
191 | 0 | if ((H5HG_SIZE(f->shared->cwfs[cwfsno]) + new_need) <= H5HG_MAXSIZE) { |
192 | 0 | htri_t was_extended; /* Whether the heap was extended */ |
193 | |
|
194 | 0 | was_extended = |
195 | 0 | H5MF_try_extend(f, H5FD_MEM_GHEAP, H5HG_ADDR(f->shared->cwfs[cwfsno]), |
196 | 0 | (hsize_t)H5HG_SIZE(f->shared->cwfs[cwfsno]), (hsize_t)new_need); |
197 | 0 | if (was_extended < 0) |
198 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTEXTEND, FAIL, "error trying to extend heap"); |
199 | 0 | else if (was_extended == true) { |
200 | 0 | if (H5HG_extend(f, H5HG_ADDR(f->shared->cwfs[cwfsno]), new_need) < 0) |
201 | 0 | HGOTO_ERROR(H5E_HEAP, H5E_CANTRESIZE, FAIL, |
202 | 0 | "unable to extend global heap collection"); |
203 | 0 | *addr = H5HG_ADDR(f->shared->cwfs[cwfsno]); |
204 | 0 | found = true; |
205 | 0 | break; |
206 | 0 | } /* end if */ |
207 | 0 | } /* end if */ |
208 | 0 | } /* end for */ |
209 | 0 | } /* end if */ |
210 | | |
211 | 0 | if (found) { |
212 | | /* Move the collection forward in the CWFS list, if it's not |
213 | | * already at the front |
214 | | */ |
215 | 0 | if (cwfsno > 0) { |
216 | 0 | H5HG_heap_t *tmp = f->shared->cwfs[cwfsno]; |
217 | |
|
218 | 0 | f->shared->cwfs[cwfsno] = f->shared->cwfs[cwfsno - 1]; |
219 | 0 | f->shared->cwfs[cwfsno - 1] = tmp; |
220 | 0 | } /* end if */ |
221 | 0 | } /* end if */ |
222 | |
|
223 | 0 | done: |
224 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
225 | 0 | } /* H5F_cwfs_find_free_heap() */ |
226 | | |
227 | | /*------------------------------------------------------------------------- |
228 | | * Function: H5F_cwfs_advance_heap |
229 | | * |
230 | | * Purpose: Advance a heap in the CWFS |
231 | | * |
232 | | * Return: Success: Non-negative |
233 | | * Failure: Negative |
234 | | * |
235 | | *------------------------------------------------------------------------- |
236 | | */ |
237 | | herr_t |
238 | | H5F_cwfs_advance_heap(H5F_t *f, H5HG_heap_t *heap, bool add_heap) |
239 | 0 | { |
240 | 0 | unsigned u; /* Local index variable */ |
241 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
242 | |
|
243 | 0 | FUNC_ENTER_NOAPI(FAIL) |
244 | | |
245 | | /* Check args */ |
246 | 0 | assert(f); |
247 | 0 | assert(f->shared); |
248 | 0 | assert(heap); |
249 | |
|
250 | 0 | for (u = 0; u < f->shared->ncwfs; u++) |
251 | 0 | if (f->shared->cwfs[u] == heap) { |
252 | 0 | if (u) { |
253 | 0 | f->shared->cwfs[u] = f->shared->cwfs[u - 1]; |
254 | 0 | f->shared->cwfs[u - 1] = heap; |
255 | 0 | } /* end if */ |
256 | 0 | break; |
257 | 0 | } /* end if */ |
258 | 0 | if (add_heap && u >= f->shared->ncwfs) { |
259 | 0 | f->shared->ncwfs = MIN(f->shared->ncwfs + 1, H5F_NCWFS); |
260 | 0 | f->shared->cwfs[f->shared->ncwfs - 1] = heap; |
261 | 0 | } /* end if */ |
262 | |
|
263 | 0 | done: |
264 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
265 | 0 | } /* H5F_cwfs_advance_heap() */ |
266 | | |
267 | | /*------------------------------------------------------------------------- |
268 | | * Function: H5F_cwfs_remove_heap |
269 | | * |
270 | | * Purpose: Remove a heap from the CWFS |
271 | | * |
272 | | * Return: Success: Non-negative |
273 | | * Failure: Negative |
274 | | * |
275 | | *------------------------------------------------------------------------- |
276 | | */ |
277 | | herr_t |
278 | | H5F_cwfs_remove_heap(H5F_shared_t *shared, H5HG_heap_t *heap) |
279 | 0 | { |
280 | 0 | unsigned u; /* Local index variable */ |
281 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
282 | |
|
283 | 0 | FUNC_ENTER_NOAPI(FAIL) |
284 | | |
285 | | /* Check args */ |
286 | 0 | assert(shared); |
287 | 0 | assert(heap); |
288 | | |
289 | | /* Remove the heap from the CWFS list */ |
290 | 0 | for (u = 0; u < shared->ncwfs; u++) { |
291 | 0 | if (shared->cwfs[u] == heap) { |
292 | 0 | shared->ncwfs -= 1; |
293 | 0 | memmove(shared->cwfs + u, shared->cwfs + u + 1, (shared->ncwfs - u) * sizeof(H5HG_heap_t *)); |
294 | 0 | break; |
295 | 0 | } /* end if */ |
296 | 0 | } /* end for */ |
297 | |
|
298 | 0 | done: |
299 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
300 | 0 | } /* H5F_cwfs_remove_heap() */ |