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: H5Faccum.c |
16 | | * |
17 | | * Purpose: File metadata "accumulator" routines. (Used to |
18 | | * cache small metadata I/Os and group them into a |
19 | | * single larger I/O) |
20 | | * |
21 | | *------------------------------------------------------------------------- |
22 | | */ |
23 | | |
24 | | /****************/ |
25 | | /* Module Setup */ |
26 | | /****************/ |
27 | | |
28 | | #include "H5Fmodule.h" /* This source code file is part of the H5F module */ |
29 | | |
30 | | /***********/ |
31 | | /* Headers */ |
32 | | /***********/ |
33 | | #include "H5private.h" /* Generic Functions */ |
34 | | #include "H5Eprivate.h" /* Error handling */ |
35 | | #include "H5Fpkg.h" /* File access */ |
36 | | #include "H5FLprivate.h" /* Free Lists */ |
37 | | #include "H5FDprivate.h" /* File drivers */ |
38 | | #include "H5MMprivate.h" /* Memory management */ |
39 | | #include "H5VMprivate.h" /* Vectors and arrays */ |
40 | | |
41 | | /****************/ |
42 | | /* Local Macros */ |
43 | | /****************/ |
44 | | |
45 | | /* Metadata accumulator controls */ |
46 | 14 | #define H5F_ACCUM_THROTTLE 8 |
47 | 4 | #define H5F_ACCUM_THRESHOLD 2048 |
48 | 176 | #define H5F_ACCUM_MAX_SIZE (1024 * 1024) /* Max. accum. buf size (max. I/Os will be 1/2 this size) */ |
49 | | |
50 | | /******************/ |
51 | | /* Local Typedefs */ |
52 | | /******************/ |
53 | | |
54 | | /* Enumerated type to indicate how data will be added to accumulator */ |
55 | | typedef enum { |
56 | | H5F_ACCUM_PREPEND, /* Data will be prepended to accumulator */ |
57 | | H5F_ACCUM_APPEND /* Data will be appended to accumulator */ |
58 | | } H5F_accum_adjust_t; |
59 | | |
60 | | /********************/ |
61 | | /* Package Typedefs */ |
62 | | /********************/ |
63 | | |
64 | | /********************/ |
65 | | /* Local Prototypes */ |
66 | | /********************/ |
67 | | |
68 | | /*********************/ |
69 | | /* Package Variables */ |
70 | | /*********************/ |
71 | | |
72 | | /*****************************/ |
73 | | /* Library Private Variables */ |
74 | | /*****************************/ |
75 | | |
76 | | /*******************/ |
77 | | /* Local Variables */ |
78 | | /*******************/ |
79 | | |
80 | | /* Declare a PQ free list to manage the metadata accumulator buffer */ |
81 | | H5FL_BLK_DEFINE_STATIC(meta_accum); |
82 | | |
83 | | /*------------------------------------------------------------------------- |
84 | | * Function: H5F__accum_read |
85 | | * |
86 | | * Purpose: Attempts to read some data from the metadata accumulator for |
87 | | * a file into a buffer. |
88 | | * |
89 | | * Note: We can't change (or add to) the metadata accumulator, because |
90 | | * this might be a speculative read and could possibly read raw |
91 | | * data into the metadata accumulator. |
92 | | * |
93 | | * Return: Non-negative on success/Negative on failure |
94 | | * |
95 | | *------------------------------------------------------------------------- |
96 | | */ |
97 | | herr_t |
98 | | H5F__accum_read(H5F_shared_t *f_sh, H5FD_mem_t map_type, haddr_t addr, size_t size, void *buf /*out*/) |
99 | 111 | { |
100 | 111 | H5FD_t *file; /* File driver pointer */ |
101 | 111 | herr_t ret_value = SUCCEED; /* Return value */ |
102 | | |
103 | 111 | FUNC_ENTER_PACKAGE |
104 | | |
105 | | /* Sanity checks */ |
106 | 111 | assert(f_sh); |
107 | 111 | assert(buf); |
108 | | |
109 | | /* Translate to file driver I/O info object */ |
110 | 111 | file = f_sh->lf; |
111 | | |
112 | | /* Check if this information is in the metadata accumulator */ |
113 | 111 | if ((f_sh->feature_flags & H5FD_FEAT_ACCUMULATE_METADATA) && map_type != H5FD_MEM_DRAW) { |
114 | 111 | H5F_meta_accum_t *accum; /* Alias for file's metadata accumulator */ |
115 | | |
116 | | /* Set up alias for file's metadata accumulator info */ |
117 | 111 | accum = &f_sh->accum; |
118 | | |
119 | 111 | if (size < H5F_ACCUM_MAX_SIZE) { |
120 | | /* Sanity check */ |
121 | 107 | assert(!accum->buf || (accum->alloc_size >= accum->size)); |
122 | | |
123 | | /* Current read adjoins or overlaps with metadata accumulator */ |
124 | 107 | if (H5_addr_defined(accum->loc) && |
125 | 0 | (H5_addr_overlap(addr, size, accum->loc, accum->size) || ((addr + size) == accum->loc) || |
126 | 0 | (accum->loc + accum->size) == addr)) { |
127 | 0 | size_t amount_before; /* Amount to read before current accumulator */ |
128 | 0 | haddr_t new_addr; /* New address of the accumulator buffer */ |
129 | 0 | size_t new_size; /* New size of the accumulator buffer */ |
130 | | |
131 | | /* Compute new values for accumulator */ |
132 | 0 | new_addr = MIN(addr, accum->loc); |
133 | 0 | new_size = (size_t)(MAX((addr + size), (accum->loc + accum->size)) - new_addr); |
134 | | |
135 | | /* Check if we need more buffer space */ |
136 | 0 | if (new_size > accum->alloc_size) { |
137 | 0 | size_t new_alloc_size; /* New size of accumulator */ |
138 | | |
139 | | /* Adjust the buffer size to be a power of 2 that is large enough to hold data */ |
140 | 0 | new_alloc_size = (size_t)1 << (1 + H5VM_log2_gen((uint64_t)(new_size - 1))); |
141 | | |
142 | | /* Reallocate the metadata accumulator buffer */ |
143 | 0 | if (NULL == (accum->buf = H5FL_BLK_REALLOC(meta_accum, accum->buf, new_alloc_size))) |
144 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, |
145 | 0 | "unable to allocate metadata accumulator buffer"); |
146 | | |
147 | | /* Note the new buffer size */ |
148 | 0 | accum->alloc_size = new_alloc_size; |
149 | | |
150 | | /* Clear the memory */ |
151 | 0 | memset(accum->buf + accum->size, 0, (accum->alloc_size - accum->size)); |
152 | 0 | } /* end if */ |
153 | | |
154 | | /* Read the part before the metadata accumulator */ |
155 | 0 | if (addr < accum->loc) { |
156 | | /* Set the amount to read */ |
157 | 0 | H5_CHECKED_ASSIGN(amount_before, size_t, (accum->loc - addr), hsize_t); |
158 | | |
159 | | /* Make room for the metadata to read in */ |
160 | 0 | memmove(accum->buf + amount_before, accum->buf, accum->size); |
161 | | |
162 | | /* Adjust dirty region tracking info, if present */ |
163 | 0 | if (accum->dirty) |
164 | 0 | accum->dirty_off += amount_before; |
165 | | |
166 | | /* Dispatch to driver */ |
167 | 0 | if (H5FD_read(file, map_type, addr, amount_before, accum->buf) < 0) |
168 | 0 | HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "driver read request failed"); |
169 | 0 | } /* end if */ |
170 | 0 | else |
171 | 0 | amount_before = 0; |
172 | | |
173 | | /* Read the part after the metadata accumulator */ |
174 | 0 | if ((addr + size) > (accum->loc + accum->size)) { |
175 | 0 | size_t amount_after; /* Amount to read at a time */ |
176 | | |
177 | | /* Set the amount to read */ |
178 | 0 | H5_CHECKED_ASSIGN(amount_after, size_t, ((addr + size) - (accum->loc + accum->size)), |
179 | 0 | hsize_t); |
180 | | |
181 | | /* Dispatch to driver */ |
182 | 0 | if (H5FD_read(file, map_type, (accum->loc + accum->size), amount_after, |
183 | 0 | (accum->buf + accum->size + amount_before)) < 0) |
184 | 0 | HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "driver read request failed"); |
185 | 0 | } /* end if */ |
186 | | |
187 | | /* Copy the data out of the buffer */ |
188 | 0 | H5MM_memcpy(buf, accum->buf + (addr - new_addr), size); |
189 | | |
190 | | /* Adjust the accumulator address & size */ |
191 | 0 | accum->loc = new_addr; |
192 | 0 | accum->size = new_size; |
193 | 0 | } /* end if */ |
194 | | /* Current read doesn't overlap with metadata accumulator, read it from file */ |
195 | 107 | else { |
196 | | /* Dispatch to driver */ |
197 | 107 | if (H5FD_read(file, map_type, addr, size, buf) < 0) |
198 | 3 | HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "driver read request failed"); |
199 | 107 | } /* end else */ |
200 | 107 | } /* end if */ |
201 | 4 | else { |
202 | | /* Read the data */ |
203 | 4 | if (H5FD_read(file, map_type, addr, size, buf) < 0) |
204 | 0 | HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "driver read request failed"); |
205 | | |
206 | | /* Check for overlap w/dirty accumulator */ |
207 | | /* (Note that this could be improved by updating the non-dirty |
208 | | * information in the accumulator with [some of] the information |
209 | | * just read in. -QAK) |
210 | | */ |
211 | 4 | if (accum->dirty && |
212 | 0 | H5_addr_overlap(addr, size, accum->loc + accum->dirty_off, accum->dirty_len)) { |
213 | 0 | haddr_t dirty_loc = accum->loc + accum->dirty_off; /* File offset of dirty information */ |
214 | 0 | size_t buf_off; /* Offset of dirty region in buffer */ |
215 | 0 | size_t dirty_off; /* Offset within dirty region */ |
216 | 0 | size_t overlap_size; /* Size of overlap with dirty region */ |
217 | | |
218 | | /* Check for read starting before beginning dirty region */ |
219 | 0 | if (H5_addr_le(addr, dirty_loc)) { |
220 | | /* Compute offset of dirty region within buffer */ |
221 | 0 | buf_off = (size_t)(dirty_loc - addr); |
222 | | |
223 | | /* Compute offset within dirty region */ |
224 | 0 | dirty_off = 0; |
225 | | |
226 | | /* Check for read ending within dirty region */ |
227 | 0 | if (H5_addr_lt(addr + size, dirty_loc + accum->dirty_len)) |
228 | 0 | overlap_size = (size_t)((addr + size) - buf_off); |
229 | 0 | else /* Access covers whole dirty region */ |
230 | 0 | overlap_size = accum->dirty_len; |
231 | 0 | } /* end if */ |
232 | 0 | else { /* Read starts after beginning of dirty region */ |
233 | | /* Compute dirty offset within buffer and overlap size */ |
234 | 0 | buf_off = 0; |
235 | 0 | dirty_off = (size_t)(addr - dirty_loc); |
236 | 0 | overlap_size = (size_t)((dirty_loc + accum->dirty_len) - addr); |
237 | 0 | } /* end else */ |
238 | | |
239 | | /* Copy the dirty region to buffer */ |
240 | 0 | H5MM_memcpy((unsigned char *)buf + buf_off, |
241 | 0 | (unsigned char *)accum->buf + accum->dirty_off + dirty_off, overlap_size); |
242 | 0 | } /* end if */ |
243 | 4 | } /* end else */ |
244 | 111 | } /* end if */ |
245 | 0 | else { |
246 | | /* Read the data */ |
247 | 0 | if (H5FD_read(file, map_type, addr, size, buf) < 0) |
248 | 0 | HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "driver read request failed"); |
249 | 0 | } /* end else */ |
250 | | |
251 | 111 | done: |
252 | 111 | FUNC_LEAVE_NOAPI(ret_value) |
253 | 111 | } /* end H5F__accum_read() */ |
254 | | |
255 | | /*------------------------------------------------------------------------- |
256 | | * Function: H5F__accum_adjust |
257 | | * |
258 | | * Purpose: Adjust accumulator size, if necessary |
259 | | * |
260 | | * Return: Non-negative on success/Negative on failure |
261 | | * |
262 | | *------------------------------------------------------------------------- |
263 | | */ |
264 | | static herr_t |
265 | | H5F__accum_adjust(H5F_meta_accum_t *accum, H5FD_t *file, H5F_accum_adjust_t adjust, size_t size) |
266 | 11 | { |
267 | 11 | herr_t ret_value = SUCCEED; /* Return value */ |
268 | | |
269 | 11 | FUNC_ENTER_PACKAGE |
270 | | |
271 | 11 | assert(accum); |
272 | 11 | assert(file); |
273 | 11 | assert(H5F_ACCUM_APPEND == adjust || H5F_ACCUM_PREPEND == adjust); |
274 | 11 | assert(size > 0); |
275 | 11 | assert(size <= H5F_ACCUM_MAX_SIZE); |
276 | | |
277 | | /* Check if we need more buffer space */ |
278 | 11 | if ((size + accum->size) > accum->alloc_size) { |
279 | 3 | size_t new_size; /* New size of accumulator */ |
280 | | |
281 | | /* Adjust the buffer size to be a power of 2 that is large enough to hold data */ |
282 | 3 | new_size = (size_t)1 << (1 + H5VM_log2_gen((uint64_t)((size + accum->size) - 1))); |
283 | | |
284 | | /* Check for accumulator getting too big */ |
285 | 3 | if (new_size > H5F_ACCUM_MAX_SIZE) { |
286 | 0 | size_t shrink_size; /* Amount to shrink accumulator by */ |
287 | 0 | size_t remnant_size; /* Amount left in accumulator */ |
288 | | |
289 | | /* Cap the accumulator's growth, leaving some room */ |
290 | | |
291 | | /* Determine the amounts to work with */ |
292 | 0 | if (size > (H5F_ACCUM_MAX_SIZE / 2)) { |
293 | 0 | new_size = H5F_ACCUM_MAX_SIZE; |
294 | 0 | shrink_size = accum->size; |
295 | 0 | remnant_size = 0; |
296 | 0 | } /* end if */ |
297 | 0 | else { |
298 | 0 | if (H5F_ACCUM_PREPEND == adjust) { |
299 | 0 | new_size = (H5F_ACCUM_MAX_SIZE / 2); |
300 | 0 | shrink_size = (H5F_ACCUM_MAX_SIZE / 2); |
301 | 0 | remnant_size = accum->size - shrink_size; |
302 | 0 | } /* end if */ |
303 | 0 | else { |
304 | 0 | size_t adjust_size = size + accum->dirty_len; |
305 | | |
306 | | /* Check if we can slide the dirty region down, to accommodate the request */ |
307 | 0 | if (accum->dirty && (adjust_size <= H5F_ACCUM_MAX_SIZE)) { |
308 | 0 | if ((ssize_t)(H5F_ACCUM_MAX_SIZE - (accum->dirty_off + adjust_size)) >= |
309 | 0 | (ssize_t)(2 * size)) |
310 | 0 | shrink_size = accum->dirty_off / 2; |
311 | 0 | else |
312 | 0 | shrink_size = accum->dirty_off; |
313 | 0 | remnant_size = accum->size - shrink_size; |
314 | 0 | new_size = remnant_size + size; |
315 | 0 | } /* end if */ |
316 | 0 | else { |
317 | 0 | new_size = (H5F_ACCUM_MAX_SIZE / 2); |
318 | 0 | shrink_size = (H5F_ACCUM_MAX_SIZE / 2); |
319 | 0 | remnant_size = accum->size - shrink_size; |
320 | 0 | } /* end else */ |
321 | 0 | } /* end else */ |
322 | 0 | } /* end else */ |
323 | | |
324 | | /* Check if we need to flush accumulator data to file */ |
325 | 0 | if (accum->dirty) { |
326 | | /* Check whether to accumulator will be prepended or appended */ |
327 | 0 | if (H5F_ACCUM_PREPEND == adjust) { |
328 | | /* Check if the dirty region overlaps the region to eliminate from the accumulator */ |
329 | 0 | if ((accum->size - shrink_size) < (accum->dirty_off + accum->dirty_len)) { |
330 | | /* Write out the dirty region from the metadata accumulator, with dispatch to driver |
331 | | */ |
332 | 0 | if (H5FD_write(file, H5FD_MEM_DEFAULT, (accum->loc + accum->dirty_off), |
333 | 0 | accum->dirty_len, (accum->buf + accum->dirty_off)) < 0) |
334 | 0 | HGOTO_ERROR(H5E_FILE, H5E_WRITEERROR, FAIL, "file write failed"); |
335 | | |
336 | | /* Reset accumulator dirty flag */ |
337 | 0 | accum->dirty = false; |
338 | 0 | } /* end if */ |
339 | 0 | } /* end if */ |
340 | 0 | else { |
341 | | /* Check if the dirty region overlaps the region to eliminate from the accumulator */ |
342 | 0 | if (shrink_size > accum->dirty_off) { |
343 | | /* Write out the dirty region from the metadata accumulator, with dispatch to driver |
344 | | */ |
345 | 0 | if (H5FD_write(file, H5FD_MEM_DEFAULT, (accum->loc + accum->dirty_off), |
346 | 0 | accum->dirty_len, (accum->buf + accum->dirty_off)) < 0) |
347 | 0 | HGOTO_ERROR(H5E_FILE, H5E_WRITEERROR, FAIL, "file write failed"); |
348 | | |
349 | | /* Reset accumulator dirty flag */ |
350 | 0 | accum->dirty = false; |
351 | 0 | } /* end if */ |
352 | | |
353 | | /* Adjust dirty region tracking info */ |
354 | 0 | accum->dirty_off -= shrink_size; |
355 | 0 | } /* end else */ |
356 | 0 | } /* end if */ |
357 | | |
358 | | /* Trim the accumulator's use of its buffer */ |
359 | 0 | accum->size = remnant_size; |
360 | | |
361 | | /* When appending, need to adjust location of accumulator */ |
362 | 0 | if (H5F_ACCUM_APPEND == adjust) { |
363 | | /* Move remnant of accumulator down */ |
364 | 0 | memmove(accum->buf, (accum->buf + shrink_size), remnant_size); |
365 | | |
366 | | /* Adjust accumulator's location */ |
367 | 0 | accum->loc += shrink_size; |
368 | 0 | } /* end if */ |
369 | 0 | } /* end if */ |
370 | | |
371 | | /* Check for accumulator needing to be reallocated */ |
372 | 3 | if (new_size > accum->alloc_size) { |
373 | 3 | unsigned char *new_buf; /* New buffer to hold the accumulated metadata */ |
374 | | |
375 | | /* Reallocate the metadata accumulator buffer */ |
376 | 3 | if (NULL == (new_buf = H5FL_BLK_REALLOC(meta_accum, accum->buf, new_size))) |
377 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "unable to allocate metadata accumulator buffer"); |
378 | | |
379 | | /* Update accumulator info */ |
380 | 3 | accum->buf = new_buf; |
381 | 3 | accum->alloc_size = new_size; |
382 | | |
383 | | /* Clear the memory */ |
384 | 3 | memset(accum->buf + accum->size, 0, (accum->alloc_size - (accum->size + size))); |
385 | 3 | } /* end if */ |
386 | 3 | } /* end if */ |
387 | | |
388 | 11 | done: |
389 | 11 | FUNC_LEAVE_NOAPI(ret_value) |
390 | 11 | } /* end H5F__accum_adjust() */ |
391 | | |
392 | | /*------------------------------------------------------------------------- |
393 | | * Function: H5F__accum_write |
394 | | * |
395 | | * Purpose: Attempts to write some data to the metadata accumulator for |
396 | | * a file from a buffer. |
397 | | * |
398 | | * Return: Non-negative on success/Negative on failure |
399 | | * |
400 | | *------------------------------------------------------------------------- |
401 | | */ |
402 | | herr_t |
403 | | H5F__accum_write(H5F_shared_t *f_sh, H5FD_mem_t map_type, haddr_t addr, size_t size, const void *buf) |
404 | 62 | { |
405 | 62 | H5FD_t *file; /* File driver pointer */ |
406 | 62 | herr_t ret_value = SUCCEED; /* Return value */ |
407 | | |
408 | 62 | FUNC_ENTER_PACKAGE |
409 | | |
410 | | /* Sanity checks */ |
411 | 62 | assert(f_sh); |
412 | 62 | assert(H5F_SHARED_INTENT(f_sh) & H5F_ACC_RDWR); |
413 | 62 | assert(buf); |
414 | | |
415 | | /* Translate to file driver pointer */ |
416 | 62 | file = f_sh->lf; |
417 | | |
418 | | /* Check for accumulating metadata */ |
419 | 62 | if ((f_sh->feature_flags & H5FD_FEAT_ACCUMULATE_METADATA) && map_type != H5FD_MEM_DRAW) { |
420 | 62 | H5F_meta_accum_t *accum; /* Alias for file's metadata accumulator */ |
421 | | |
422 | | /* Set up alias for file's metadata accumulator info */ |
423 | 62 | accum = &f_sh->accum; |
424 | | |
425 | 62 | if (size < H5F_ACCUM_MAX_SIZE) { |
426 | | /* Sanity check */ |
427 | 62 | assert(!accum->buf || (accum->alloc_size >= accum->size)); |
428 | | |
429 | | /* Check if there is already metadata in the accumulator */ |
430 | 62 | if (accum->size > 0) { |
431 | | /* Check if the new metadata adjoins the beginning of the current accumulator */ |
432 | 33 | if (H5_addr_defined(accum->loc) && (addr + size) == accum->loc) { |
433 | | /* Check if we need to adjust accumulator size */ |
434 | 0 | if (H5F__accum_adjust(accum, file, H5F_ACCUM_PREPEND, size) < 0) |
435 | 0 | HGOTO_ERROR(H5E_IO, H5E_CANTRESIZE, FAIL, "can't adjust metadata accumulator"); |
436 | | |
437 | | /* Move the existing metadata to the proper location */ |
438 | 0 | memmove(accum->buf + size, accum->buf, accum->size); |
439 | | |
440 | | /* Copy the new metadata at the front */ |
441 | 0 | H5MM_memcpy(accum->buf, buf, size); |
442 | | |
443 | | /* Set the new size & location of the metadata accumulator */ |
444 | 0 | accum->loc = addr; |
445 | 0 | accum->size += size; |
446 | | |
447 | | /* Adjust the dirty region and mark accumulator dirty */ |
448 | 0 | if (accum->dirty) |
449 | 0 | accum->dirty_len = size + accum->dirty_off + accum->dirty_len; |
450 | 0 | else { |
451 | 0 | accum->dirty_len = size; |
452 | 0 | accum->dirty = true; |
453 | 0 | } /* end else */ |
454 | 0 | accum->dirty_off = 0; |
455 | 0 | } /* end if */ |
456 | | /* Check if the new metadata adjoins the end of the current accumulator */ |
457 | 33 | else if (H5_addr_defined(accum->loc) && addr == (accum->loc + accum->size)) { |
458 | | /* Check if we need to adjust accumulator size */ |
459 | 11 | if (H5F__accum_adjust(accum, file, H5F_ACCUM_APPEND, size) < 0) |
460 | 0 | HGOTO_ERROR(H5E_IO, H5E_CANTRESIZE, FAIL, "can't adjust metadata accumulator"); |
461 | | |
462 | | /* Copy the new metadata to the end */ |
463 | 11 | H5MM_memcpy(accum->buf + accum->size, buf, size); |
464 | | |
465 | | /* Adjust the dirty region and mark accumulator dirty */ |
466 | 11 | if (accum->dirty) |
467 | 11 | accum->dirty_len = size + (accum->size - accum->dirty_off); |
468 | 0 | else { |
469 | 0 | accum->dirty_off = accum->size; |
470 | 0 | accum->dirty_len = size; |
471 | 0 | accum->dirty = true; |
472 | 0 | } /* end else */ |
473 | | |
474 | | /* Set the new size of the metadata accumulator */ |
475 | 11 | accum->size += size; |
476 | 11 | } /* end if */ |
477 | | /* Check if the piece of metadata being written overlaps the metadata accumulator */ |
478 | 22 | else if (H5_addr_defined(accum->loc) && |
479 | 22 | H5_addr_overlap(addr, size, accum->loc, accum->size)) { |
480 | 4 | size_t add_size; /* New size of the accumulator buffer */ |
481 | | |
482 | | /* Check if the new metadata is entirely within the current accumulator */ |
483 | 4 | if (addr >= accum->loc && (addr + size) <= (accum->loc + accum->size)) { |
484 | 4 | size_t dirty_off = (size_t)(addr - accum->loc); |
485 | | |
486 | | /* Copy the new metadata to the proper location within the accumulator */ |
487 | 4 | H5MM_memcpy(accum->buf + dirty_off, buf, size); |
488 | | |
489 | | /* Adjust the dirty region and mark accumulator dirty */ |
490 | 4 | if (accum->dirty) { |
491 | | /* Check for new metadata starting before current dirty region */ |
492 | 4 | if (dirty_off <= accum->dirty_off) { |
493 | 0 | if ((dirty_off + size) <= (accum->dirty_off + accum->dirty_len)) |
494 | 0 | accum->dirty_len = (accum->dirty_off + accum->dirty_len) - dirty_off; |
495 | 0 | else |
496 | 0 | accum->dirty_len = size; |
497 | 0 | accum->dirty_off = dirty_off; |
498 | 0 | } /* end if */ |
499 | 4 | else { |
500 | 4 | if ((dirty_off + size) <= (accum->dirty_off + accum->dirty_len)) |
501 | 4 | ; /* accum->dirty_len doesn't change */ |
502 | 0 | else |
503 | 0 | accum->dirty_len = (dirty_off + size) - accum->dirty_off; |
504 | 4 | } /* end else */ |
505 | 4 | } /* end if */ |
506 | 0 | else { |
507 | 0 | accum->dirty_off = dirty_off; |
508 | 0 | accum->dirty_len = size; |
509 | 0 | accum->dirty = true; |
510 | 0 | } /* end else */ |
511 | 4 | } /* end if */ |
512 | | /* Check if the new metadata overlaps the beginning of the current accumulator */ |
513 | 0 | else if (addr < accum->loc && (addr + size) <= (accum->loc + accum->size)) { |
514 | 0 | size_t old_offset; /* Offset of old data within the accumulator buffer */ |
515 | | |
516 | | /* Calculate the amount we will need to add to the accumulator size, based on the |
517 | | * amount of overlap */ |
518 | 0 | H5_CHECKED_ASSIGN(add_size, size_t, (accum->loc - addr), hsize_t); |
519 | | |
520 | | /* Check if we need to adjust accumulator size */ |
521 | 0 | if (H5F__accum_adjust(accum, file, H5F_ACCUM_PREPEND, add_size) < 0) |
522 | 0 | HGOTO_ERROR(H5E_IO, H5E_CANTRESIZE, FAIL, "can't adjust metadata accumulator"); |
523 | | |
524 | | /* Calculate the proper offset of the existing metadata */ |
525 | 0 | H5_CHECKED_ASSIGN(old_offset, size_t, (addr + size) - accum->loc, hsize_t); |
526 | | |
527 | | /* Move the existing metadata to the proper location */ |
528 | 0 | memmove(accum->buf + size, accum->buf + old_offset, (accum->size - old_offset)); |
529 | | |
530 | | /* Copy the new metadata at the front */ |
531 | 0 | H5MM_memcpy(accum->buf, buf, size); |
532 | | |
533 | | /* Set the new size & location of the metadata accumulator */ |
534 | 0 | accum->loc = addr; |
535 | 0 | accum->size += add_size; |
536 | | |
537 | | /* Adjust the dirty region and mark accumulator dirty */ |
538 | 0 | if (accum->dirty) { |
539 | 0 | size_t curr_dirty_end = add_size + accum->dirty_off + accum->dirty_len; |
540 | |
|
541 | 0 | accum->dirty_off = 0; |
542 | 0 | if (size <= curr_dirty_end) |
543 | 0 | accum->dirty_len = curr_dirty_end; |
544 | 0 | else |
545 | 0 | accum->dirty_len = size; |
546 | 0 | } /* end if */ |
547 | 0 | else { |
548 | 0 | accum->dirty_off = 0; |
549 | 0 | accum->dirty_len = size; |
550 | 0 | accum->dirty = true; |
551 | 0 | } /* end else */ |
552 | 0 | } /* end if */ |
553 | | /* Check if the new metadata overlaps the end of the current accumulator */ |
554 | 0 | else if (addr >= accum->loc && (addr + size) > (accum->loc + accum->size)) { |
555 | 0 | size_t dirty_off; /* Offset of dirty region */ |
556 | | |
557 | | /* Calculate the amount we will need to add to the accumulator size, based on the |
558 | | * amount of overlap */ |
559 | 0 | H5_CHECKED_ASSIGN(add_size, size_t, (addr + size) - (accum->loc + accum->size), |
560 | 0 | hsize_t); |
561 | | |
562 | | /* Check if we need to adjust accumulator size */ |
563 | 0 | if (H5F__accum_adjust(accum, file, H5F_ACCUM_APPEND, add_size) < 0) |
564 | 0 | HGOTO_ERROR(H5E_IO, H5E_CANTRESIZE, FAIL, "can't adjust metadata accumulator"); |
565 | | |
566 | | /* Compute offset of dirty region (after adjusting accumulator) */ |
567 | 0 | dirty_off = (size_t)(addr - accum->loc); |
568 | | |
569 | | /* Copy the new metadata to the end */ |
570 | 0 | H5MM_memcpy(accum->buf + dirty_off, buf, size); |
571 | | |
572 | | /* Set the new size of the metadata accumulator */ |
573 | 0 | accum->size += add_size; |
574 | | |
575 | | /* Adjust the dirty region and mark accumulator dirty */ |
576 | 0 | if (accum->dirty) { |
577 | | /* Check for new metadata starting before current dirty region */ |
578 | 0 | if (dirty_off <= accum->dirty_off) { |
579 | 0 | accum->dirty_off = dirty_off; |
580 | 0 | accum->dirty_len = size; |
581 | 0 | } /* end if */ |
582 | 0 | else { |
583 | 0 | accum->dirty_len = (dirty_off + size) - accum->dirty_off; |
584 | 0 | } /* end else */ |
585 | 0 | } /* end if */ |
586 | 0 | else { |
587 | 0 | accum->dirty_off = dirty_off; |
588 | 0 | accum->dirty_len = size; |
589 | 0 | accum->dirty = true; |
590 | 0 | } /* end else */ |
591 | 0 | } /* end if */ |
592 | | /* New metadata overlaps both ends of the current accumulator */ |
593 | 0 | else { |
594 | | /* Check if we need more buffer space */ |
595 | 0 | if (size > accum->alloc_size) { |
596 | 0 | size_t new_alloc_size; /* New size of accumulator */ |
597 | | |
598 | | /* Adjust the buffer size to be a power of 2 that is large enough to hold data */ |
599 | 0 | new_alloc_size = (size_t)1 << (1 + H5VM_log2_gen((uint64_t)(size - 1))); |
600 | | |
601 | | /* Reallocate the metadata accumulator buffer */ |
602 | 0 | if (NULL == |
603 | 0 | (accum->buf = H5FL_BLK_REALLOC(meta_accum, accum->buf, new_alloc_size))) |
604 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, |
605 | 0 | "unable to allocate metadata accumulator buffer"); |
606 | | |
607 | | /* Note the new buffer size */ |
608 | 0 | accum->alloc_size = new_alloc_size; |
609 | | |
610 | | /* Clear the memory */ |
611 | 0 | memset(accum->buf + size, 0, (accum->alloc_size - size)); |
612 | 0 | } /* end if */ |
613 | | |
614 | | /* Copy the new metadata to the buffer */ |
615 | 0 | H5MM_memcpy(accum->buf, buf, size); |
616 | | |
617 | | /* Set the new size & location of the metadata accumulator */ |
618 | 0 | accum->loc = addr; |
619 | 0 | accum->size = size; |
620 | | |
621 | | /* Adjust the dirty region and mark accumulator dirty */ |
622 | 0 | accum->dirty_off = 0; |
623 | 0 | accum->dirty_len = size; |
624 | 0 | accum->dirty = true; |
625 | 0 | } /* end else */ |
626 | 4 | } /* end if */ |
627 | | /* New piece of metadata doesn't adjoin or overlap the existing accumulator */ |
628 | 18 | else { |
629 | | /* Write out the existing metadata accumulator, with dispatch to driver */ |
630 | 18 | if (accum->dirty) { |
631 | 13 | if (H5FD_write(file, H5FD_MEM_DEFAULT, accum->loc + accum->dirty_off, |
632 | 13 | accum->dirty_len, accum->buf + accum->dirty_off) < 0) |
633 | 2 | HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed"); |
634 | | |
635 | | /* Reset accumulator dirty flag */ |
636 | 11 | accum->dirty = false; |
637 | 11 | } /* end if */ |
638 | | |
639 | | /* Cache the new piece of metadata */ |
640 | | /* Check if we need to resize the buffer */ |
641 | 16 | if (size > accum->alloc_size) { |
642 | 2 | size_t new_size; /* New size of accumulator */ |
643 | 2 | size_t clear_size; /* Size of memory that needs clearing */ |
644 | | |
645 | | /* Adjust the buffer size to be a power of 2 that is large enough to hold data */ |
646 | 2 | new_size = (size_t)1 << (1 + H5VM_log2_gen((uint64_t)(size - 1))); |
647 | | |
648 | | /* Grow the metadata accumulator buffer */ |
649 | 2 | if (NULL == (accum->buf = H5FL_BLK_REALLOC(meta_accum, accum->buf, new_size))) |
650 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, |
651 | 2 | "unable to allocate metadata accumulator buffer"); |
652 | | |
653 | | /* Note the new buffer size */ |
654 | 2 | accum->alloc_size = new_size; |
655 | | |
656 | | /* Clear the memory */ |
657 | 2 | clear_size = MAX(accum->size, size); |
658 | 2 | memset(accum->buf + clear_size, 0, (accum->alloc_size - clear_size)); |
659 | 2 | } /* end if */ |
660 | 14 | else { |
661 | | /* Check if we should shrink the accumulator buffer */ |
662 | 14 | if (size < (accum->alloc_size / H5F_ACCUM_THROTTLE) && |
663 | 4 | accum->alloc_size > H5F_ACCUM_THRESHOLD) { |
664 | 0 | size_t tmp_size = |
665 | 0 | (accum->alloc_size / H5F_ACCUM_THROTTLE); /* New size of accumulator buffer */ |
666 | | |
667 | | /* Shrink the accumulator buffer */ |
668 | 0 | if (NULL == (accum->buf = H5FL_BLK_REALLOC(meta_accum, accum->buf, tmp_size))) |
669 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, |
670 | 0 | "unable to allocate metadata accumulator buffer"); |
671 | | |
672 | | /* Note the new buffer size */ |
673 | 0 | accum->alloc_size = tmp_size; |
674 | 0 | } /* end if */ |
675 | 14 | } /* end else */ |
676 | | |
677 | | /* Update the metadata accumulator information */ |
678 | 16 | accum->loc = addr; |
679 | 16 | accum->size = size; |
680 | | |
681 | | /* Store the piece of metadata in the accumulator */ |
682 | 16 | H5MM_memcpy(accum->buf, buf, size); |
683 | | |
684 | | /* Adjust the dirty region and mark accumulator dirty */ |
685 | 16 | accum->dirty_off = 0; |
686 | 16 | accum->dirty_len = size; |
687 | 16 | accum->dirty = true; |
688 | 16 | } /* end else */ |
689 | 33 | } /* end if */ |
690 | | /* No metadata in the accumulator, grab this piece and keep it */ |
691 | 29 | else { |
692 | | /* Check if we need to reallocate the buffer */ |
693 | 29 | if (size > accum->alloc_size) { |
694 | 29 | size_t new_size; /* New size of accumulator */ |
695 | | |
696 | | /* Adjust the buffer size to be a power of 2 that is large enough to hold data */ |
697 | 29 | new_size = (size_t)1 << (1 + H5VM_log2_gen((uint64_t)(size - 1))); |
698 | | |
699 | | /* Reallocate the metadata accumulator buffer */ |
700 | 29 | if (NULL == (accum->buf = H5FL_BLK_REALLOC(meta_accum, accum->buf, new_size))) |
701 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, |
702 | 29 | "unable to allocate metadata accumulator buffer"); |
703 | | |
704 | | /* Note the new buffer size */ |
705 | 29 | accum->alloc_size = new_size; |
706 | | |
707 | | /* Clear the memory */ |
708 | 29 | memset(accum->buf + size, 0, (accum->alloc_size - size)); |
709 | 29 | } /* end if */ |
710 | | |
711 | | /* Update the metadata accumulator information */ |
712 | 29 | accum->loc = addr; |
713 | 29 | accum->size = size; |
714 | | |
715 | | /* Store the piece of metadata in the accumulator */ |
716 | 29 | H5MM_memcpy(accum->buf, buf, size); |
717 | | |
718 | | /* Adjust the dirty region and mark accumulator dirty */ |
719 | 29 | accum->dirty_off = 0; |
720 | 29 | accum->dirty_len = size; |
721 | 29 | accum->dirty = true; |
722 | 29 | } /* end else */ |
723 | 62 | } /* end if */ |
724 | 0 | else { |
725 | | /* Make certain that data in accumulator is visible before new write */ |
726 | 0 | if ((H5F_SHARED_INTENT(f_sh) & H5F_ACC_SWMR_WRITE) > 0) |
727 | | /* Flush if dirty and reset accumulator */ |
728 | 0 | if (H5F__accum_reset(f_sh, true, false) < 0) |
729 | 0 | HGOTO_ERROR(H5E_IO, H5E_CANTRESET, FAIL, "can't reset accumulator"); |
730 | | |
731 | | /* Write the data */ |
732 | 0 | if (H5FD_write(file, map_type, addr, size, buf) < 0) |
733 | 0 | HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed"); |
734 | | |
735 | | /* Check for overlap w/accumulator */ |
736 | | /* (Note that this could be improved by updating the accumulator |
737 | | * with [some of] the information just read in. -QAK) |
738 | | */ |
739 | 0 | if (H5_addr_defined(accum->loc) && H5_addr_overlap(addr, size, accum->loc, accum->size)) { |
740 | | /* Check for write starting before beginning of accumulator */ |
741 | 0 | if (H5_addr_le(addr, accum->loc)) { |
742 | | /* Check for write ending within accumulator */ |
743 | 0 | if (H5_addr_le(addr + size, accum->loc + accum->size)) { |
744 | 0 | size_t overlap_size; /* Size of overlapping region */ |
745 | | |
746 | | /* Compute overlap size */ |
747 | 0 | overlap_size = (size_t)((addr + size) - accum->loc); |
748 | | |
749 | | /* Check for dirty region */ |
750 | 0 | if (accum->dirty) { |
751 | 0 | haddr_t dirty_start = |
752 | 0 | accum->loc + accum->dirty_off; /* File address of start of dirty region */ |
753 | 0 | haddr_t dirty_end = |
754 | 0 | dirty_start + accum->dirty_len; /* File address of end of dirty region */ |
755 | | |
756 | | /* Check if entire dirty region is overwritten */ |
757 | 0 | if (H5_addr_le(dirty_end, addr + size)) { |
758 | 0 | accum->dirty = false; |
759 | 0 | accum->dirty_len = 0; |
760 | 0 | } /* end if */ |
761 | 0 | else { |
762 | | /* Check for dirty region falling after write */ |
763 | 0 | if (H5_addr_le(addr + size, dirty_start)) |
764 | 0 | accum->dirty_off = overlap_size; |
765 | 0 | else { /* Dirty region overlaps w/written region */ |
766 | 0 | accum->dirty_off = 0; |
767 | 0 | accum->dirty_len -= (size_t)((addr + size) - dirty_start); |
768 | 0 | } /* end else */ |
769 | 0 | } /* end if */ |
770 | 0 | } /* end if */ |
771 | | |
772 | | /* Trim bottom of accumulator off */ |
773 | 0 | accum->loc += overlap_size; |
774 | 0 | accum->size -= overlap_size; |
775 | 0 | memmove(accum->buf, accum->buf + overlap_size, accum->size); |
776 | 0 | } /* end if */ |
777 | 0 | else { /* Access covers whole accumulator */ |
778 | | /* Reset accumulator, but don't flush */ |
779 | 0 | if (H5F__accum_reset(f_sh, false, false) < 0) |
780 | 0 | HGOTO_ERROR(H5E_IO, H5E_CANTRESET, FAIL, "can't reset accumulator"); |
781 | 0 | } /* end else */ |
782 | 0 | } /* end if */ |
783 | 0 | else { /* Write starts after beginning of accumulator */ |
784 | 0 | size_t overlap_size; /* Size of overlapping region */ |
785 | | |
786 | | /* Sanity check */ |
787 | 0 | assert(H5_addr_gt(addr + size, accum->loc + accum->size)); |
788 | | |
789 | | /* Compute overlap size */ |
790 | 0 | overlap_size = (size_t)((accum->loc + accum->size) - addr); |
791 | | |
792 | | /* Check for dirty region */ |
793 | 0 | if (accum->dirty) { |
794 | 0 | haddr_t dirty_start = |
795 | 0 | accum->loc + accum->dirty_off; /* File address of start of dirty region */ |
796 | 0 | haddr_t dirty_end = |
797 | 0 | dirty_start + accum->dirty_len; /* File address of end of dirty region */ |
798 | | |
799 | | /* Check if entire dirty region is overwritten */ |
800 | 0 | if (H5_addr_ge(dirty_start, addr)) { |
801 | 0 | accum->dirty = false; |
802 | 0 | accum->dirty_len = 0; |
803 | 0 | } /* end if */ |
804 | 0 | else { |
805 | | /* Check for dirty region falling before write */ |
806 | 0 | if (H5_addr_le(dirty_end, addr)) |
807 | 0 | ; /* noop */ |
808 | 0 | else /* Dirty region overlaps w/written region */ |
809 | 0 | accum->dirty_len = (size_t)(addr - dirty_start); |
810 | 0 | } /* end if */ |
811 | 0 | } /* end if */ |
812 | | |
813 | | /* Trim top of accumulator off */ |
814 | 0 | accum->size -= overlap_size; |
815 | 0 | } /* end else */ |
816 | 0 | } /* end if */ |
817 | 0 | } /* end else */ |
818 | 62 | } /* end if */ |
819 | 0 | else { |
820 | | /* Write the data */ |
821 | 0 | if (H5FD_write(file, map_type, addr, size, buf) < 0) |
822 | 0 | HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed"); |
823 | 0 | } /* end else */ |
824 | | |
825 | 62 | done: |
826 | 62 | FUNC_LEAVE_NOAPI(ret_value) |
827 | 62 | } /* end H5F__accum_write() */ |
828 | | |
829 | | /*------------------------------------------------------------------------- |
830 | | * Function: H5F__accum_free |
831 | | * |
832 | | * Purpose: Check for free space invalidating [part of] a metadata |
833 | | * accumulator. |
834 | | * |
835 | | * Return: Non-negative on success/Negative on failure |
836 | | * |
837 | | *------------------------------------------------------------------------- |
838 | | */ |
839 | | herr_t |
840 | | H5F__accum_free(H5F_shared_t *f_sh, H5FD_mem_t H5_ATTR_UNUSED type, haddr_t addr, hsize_t size) |
841 | 5 | { |
842 | 5 | H5F_meta_accum_t *accum; /* Alias for file's metadata accumulator */ |
843 | 5 | H5FD_t *file; /* File driver pointer */ |
844 | 5 | herr_t ret_value = SUCCEED; /* Return value */ |
845 | | |
846 | 5 | FUNC_ENTER_PACKAGE |
847 | | |
848 | | /* check arguments */ |
849 | 5 | assert(f_sh); |
850 | | |
851 | | /* Set up alias for file's metadata accumulator info */ |
852 | 5 | accum = &f_sh->accum; |
853 | | |
854 | | /* Translate to file driver pointer */ |
855 | 5 | file = f_sh->lf; |
856 | | |
857 | | /* Adjust the metadata accumulator to remove the freed block, if it overlaps */ |
858 | 5 | if ((f_sh->feature_flags & H5FD_FEAT_ACCUMULATE_METADATA) && H5_addr_defined(accum->loc) && |
859 | 0 | H5_addr_overlap(addr, size, accum->loc, accum->size)) { |
860 | 0 | size_t overlap_size; /* Size of overlap with accumulator */ |
861 | | |
862 | | /* Sanity check */ |
863 | | /* (The metadata accumulator should not intersect w/raw data */ |
864 | 0 | assert(H5FD_MEM_DRAW != type); |
865 | 0 | assert(H5FD_MEM_GHEAP != type); /* (global heap data is being treated as raw data currently) */ |
866 | | |
867 | | /* Check for overlapping the beginning of the accumulator */ |
868 | 0 | if (H5_addr_le(addr, accum->loc)) { |
869 | | /* Check for completely overlapping the accumulator */ |
870 | 0 | if (H5_addr_ge(addr + size, accum->loc + accum->size)) { |
871 | | /* Reset the accumulator, but don't free buffer */ |
872 | 0 | accum->loc = HADDR_UNDEF; |
873 | 0 | accum->size = 0; |
874 | 0 | accum->dirty = false; |
875 | 0 | } /* end if */ |
876 | | /* Block to free must end within the accumulator */ |
877 | 0 | else { |
878 | 0 | size_t new_accum_size; /* Size of new accumulator buffer */ |
879 | | |
880 | | /* Calculate the size of the overlap with the accumulator, etc. */ |
881 | 0 | H5_CHECKED_ASSIGN(overlap_size, size_t, (addr + size) - accum->loc, haddr_t); |
882 | | /* Sanity check */ |
883 | | /* Overlap size should not result in "negative" value after subtraction */ |
884 | 0 | assert(overlap_size < accum->size); |
885 | 0 | new_accum_size = accum->size - overlap_size; |
886 | | |
887 | | /* Move the accumulator buffer information to eliminate the freed block */ |
888 | 0 | memmove(accum->buf, accum->buf + overlap_size, new_accum_size); |
889 | | |
890 | | /* Adjust the accumulator information */ |
891 | 0 | accum->loc += overlap_size; |
892 | 0 | accum->size = new_accum_size; |
893 | | |
894 | | /* Adjust the dirty region and possibly mark accumulator clean */ |
895 | 0 | if (accum->dirty) { |
896 | | /* Check if block freed is entirely before dirty region */ |
897 | 0 | if (overlap_size < accum->dirty_off) |
898 | 0 | accum->dirty_off -= overlap_size; |
899 | 0 | else { |
900 | | /* Check if block freed ends within dirty region */ |
901 | 0 | if (overlap_size < (accum->dirty_off + accum->dirty_len)) { |
902 | 0 | accum->dirty_len = (accum->dirty_off + accum->dirty_len) - overlap_size; |
903 | 0 | accum->dirty_off = 0; |
904 | 0 | } /* end if */ |
905 | | /* Block freed encompasses dirty region */ |
906 | 0 | else |
907 | 0 | accum->dirty = false; |
908 | 0 | } /* end else */ |
909 | 0 | } /* end if */ |
910 | 0 | } /* end else */ |
911 | 0 | } /* end if */ |
912 | | /* Block to free must start within the accumulator */ |
913 | 0 | else { |
914 | 0 | haddr_t dirty_end = accum->loc + accum->dirty_off + accum->dirty_len; |
915 | 0 | haddr_t dirty_start = accum->loc + accum->dirty_off; |
916 | | |
917 | | /* Calculate the size of the overlap with the accumulator */ |
918 | 0 | H5_CHECKED_ASSIGN(overlap_size, size_t, (accum->loc + accum->size) - addr, haddr_t); |
919 | | |
920 | | /* Check if block to free begins before end of dirty region */ |
921 | 0 | if (accum->dirty && H5_addr_lt(addr, dirty_end)) { |
922 | 0 | haddr_t tail_addr; |
923 | | |
924 | | /* Calculate the address of the tail to write */ |
925 | 0 | tail_addr = addr + size; |
926 | | |
927 | | /* Check if the block to free begins before dirty region */ |
928 | 0 | if (H5_addr_lt(addr, dirty_start)) { |
929 | | /* Check if block to free is entirely before dirty region */ |
930 | 0 | if (H5_addr_le(tail_addr, dirty_start)) { |
931 | | /* Write out the entire dirty region of the accumulator */ |
932 | 0 | if (H5FD_write(file, H5FD_MEM_DEFAULT, dirty_start, accum->dirty_len, |
933 | 0 | accum->buf + accum->dirty_off) < 0) |
934 | 0 | HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed"); |
935 | 0 | } /* end if */ |
936 | | /* Block to free overlaps with some/all of dirty region */ |
937 | | /* Check for unfreed dirty region to write */ |
938 | 0 | else if (H5_addr_lt(tail_addr, dirty_end)) { |
939 | 0 | size_t write_size; |
940 | 0 | size_t dirty_delta; |
941 | |
|
942 | 0 | write_size = (size_t)(dirty_end - tail_addr); |
943 | 0 | dirty_delta = accum->dirty_len - write_size; |
944 | |
|
945 | 0 | assert(write_size > 0); |
946 | | |
947 | | /* Write out the unfreed dirty region of the accumulator */ |
948 | 0 | if (H5FD_write(file, H5FD_MEM_DEFAULT, dirty_start + dirty_delta, write_size, |
949 | 0 | accum->buf + accum->dirty_off + dirty_delta) < 0) |
950 | 0 | HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed"); |
951 | 0 | } /* end if */ |
952 | | |
953 | | /* Reset dirty flag */ |
954 | 0 | accum->dirty = false; |
955 | 0 | } /* end if */ |
956 | | /* Block to free begins at beginning of or in middle of dirty region */ |
957 | 0 | else { |
958 | | /* Check if block to free ends before end of dirty region */ |
959 | 0 | if (H5_addr_lt(tail_addr, dirty_end)) { |
960 | 0 | size_t write_size; |
961 | 0 | size_t dirty_delta; |
962 | |
|
963 | 0 | write_size = (size_t)(dirty_end - tail_addr); |
964 | 0 | dirty_delta = accum->dirty_len - write_size; |
965 | |
|
966 | 0 | assert(write_size > 0); |
967 | | |
968 | | /* Write out the unfreed end of the dirty region of the accumulator */ |
969 | 0 | if (H5FD_write(file, H5FD_MEM_DEFAULT, dirty_start + dirty_delta, write_size, |
970 | 0 | accum->buf + accum->dirty_off + dirty_delta) < 0) |
971 | 0 | HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed"); |
972 | 0 | } /* end if */ |
973 | | |
974 | | /* Check for block to free beginning at same location as dirty region */ |
975 | 0 | if (H5_addr_eq(addr, dirty_start)) { |
976 | | /* Reset dirty flag */ |
977 | 0 | accum->dirty = false; |
978 | 0 | } /* end if */ |
979 | | /* Block to free eliminates end of dirty region */ |
980 | 0 | else { |
981 | 0 | accum->dirty_len = (size_t)(addr - dirty_start); |
982 | 0 | } /* end else */ |
983 | 0 | } /* end else */ |
984 | |
|
985 | 0 | } /* end if */ |
986 | | |
987 | | /* Adjust the accumulator information */ |
988 | 0 | accum->size = accum->size - overlap_size; |
989 | 0 | } /* end else */ |
990 | 0 | } /* end if */ |
991 | | |
992 | 5 | done: |
993 | 5 | FUNC_LEAVE_NOAPI(ret_value) |
994 | 5 | } /* end H5F__accum_free() */ |
995 | | |
996 | | /*------------------------------------------------------------------------- |
997 | | * Function: H5F__accum_flush |
998 | | * |
999 | | * Purpose: Flush the metadata accumulator to the file |
1000 | | * |
1001 | | * Return: Non-negative on success/Negative on failure |
1002 | | * |
1003 | | *------------------------------------------------------------------------- |
1004 | | */ |
1005 | | herr_t |
1006 | | H5F__accum_flush(H5F_shared_t *f_sh) |
1007 | 65 | { |
1008 | 65 | herr_t ret_value = SUCCEED; /* Return value */ |
1009 | | |
1010 | 65 | FUNC_ENTER_PACKAGE |
1011 | | |
1012 | | /* Sanity checks */ |
1013 | 65 | assert(f_sh); |
1014 | | |
1015 | | /* Check if we need to flush out the metadata accumulator */ |
1016 | 65 | if ((f_sh->feature_flags & H5FD_FEAT_ACCUMULATE_METADATA) && f_sh->accum.dirty) { |
1017 | 34 | H5FD_t *file; /* File driver pointer */ |
1018 | | |
1019 | | /* Translate to file driver pointer */ |
1020 | 34 | file = f_sh->lf; |
1021 | | |
1022 | | /* Flush the metadata contents */ |
1023 | 34 | if (H5FD_write(file, H5FD_MEM_DEFAULT, f_sh->accum.loc + f_sh->accum.dirty_off, f_sh->accum.dirty_len, |
1024 | 34 | f_sh->accum.buf + f_sh->accum.dirty_off) < 0) |
1025 | 2 | HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed"); |
1026 | | |
1027 | | /* Reset the dirty flag */ |
1028 | 32 | f_sh->accum.dirty = false; |
1029 | 32 | } /* end if */ |
1030 | | |
1031 | 65 | done: |
1032 | 65 | FUNC_LEAVE_NOAPI(ret_value) |
1033 | 65 | } /* end H5F__accum_flush() */ |
1034 | | |
1035 | | /*------------------------------------------------------------------------- |
1036 | | * Function: H5F__accum_reset |
1037 | | * |
1038 | | * Purpose: Reset the metadata accumulator for the file |
1039 | | * |
1040 | | * Return: Non-negative on success/Negative on failure |
1041 | | * |
1042 | | *------------------------------------------------------------------------- |
1043 | | */ |
1044 | | herr_t |
1045 | | H5F__accum_reset(H5F_shared_t *f_sh, bool flush, bool force) |
1046 | 55 | { |
1047 | 55 | herr_t ret_value = SUCCEED; /* Return value */ |
1048 | | |
1049 | 55 | FUNC_ENTER_PACKAGE |
1050 | | |
1051 | | /* Sanity checks */ |
1052 | 55 | assert(f_sh); |
1053 | | |
1054 | | /* Flush any dirty data in accumulator, if requested */ |
1055 | 55 | if (flush) |
1056 | 55 | if (H5F__accum_flush(f_sh) < 0) { |
1057 | 2 | HDONE_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "can't flush metadata accumulator"); |
1058 | 2 | if (!force) |
1059 | 0 | HGOTO_DONE(FAIL); |
1060 | 2 | } |
1061 | | |
1062 | | /* Check if we need to reset the metadata accumulator information */ |
1063 | 55 | if (f_sh->feature_flags & H5FD_FEAT_ACCUMULATE_METADATA) { |
1064 | | /* Free the buffer */ |
1065 | 55 | if (f_sh->accum.buf) |
1066 | 29 | f_sh->accum.buf = H5FL_BLK_FREE(meta_accum, f_sh->accum.buf); |
1067 | | |
1068 | | /* Reset the buffer sizes & location */ |
1069 | 55 | f_sh->accum.alloc_size = f_sh->accum.size = 0; |
1070 | 55 | f_sh->accum.loc = HADDR_UNDEF; |
1071 | 55 | f_sh->accum.dirty = false; |
1072 | 55 | f_sh->accum.dirty_len = 0; |
1073 | 55 | } /* end if */ |
1074 | | |
1075 | 55 | done: |
1076 | 55 | FUNC_LEAVE_NOAPI(ret_value) |
1077 | 55 | } /* end H5F__accum_reset() */ |