Coverage Report

Created: 2026-01-10 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5Faccum.c
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() */