summaryrefslogtreecommitdiffstats
path: root/src/H5Fcwfs.c
blob: c946fa453e15caab1c88e104b53f45dc268f57fb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright by The HDF Group.                                               *
 * All rights reserved.                                                      *
 *                                                                           *
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
 * terms governing use, modification, and redistribution, is contained in    *
 * the COPYING file, which can be found at the root of the source code       *
 * distribution tree, or in https://www.hdfgroup.org/licenses.               *
 * If you do not have access to either file, you may request a copy from     *
 * help@hdfgroup.org.                                                        *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/*
 * Purpose:	Each file has a small cache of global heap collections called
 *		the CWFS list and recently accessed collections with free
 *		space appear on this list.  As collections are accessed the
 *		collection is moved toward the front of the list.  New
 *		collections are added to the front of the list while old
 *		collections are added to the end of the list.
 *
 *		The collection model reduces the overhead which would be
 *		incurred if the global heap were a single object, and the
 *		CWFS list allows the library to cheaply choose a collection
 *		for a new object based on object size, amount of free space
 *		in the collection, and temporal locality.
 */

/****************/
/* Module Setup */
/****************/

#include "H5Fmodule.h" /* This source code file is part of the H5F module */

/***********/
/* Headers */
/***********/
#include "H5private.h"   /* Generic Functions			*/
#include "H5Eprivate.h"  /* Error handling		  	*/
#include "H5Fpkg.h"      /* File access				*/
#include "H5HGprivate.h" /* Global heaps				*/
#include "H5MFprivate.h" /* File memory management		*/
#include "H5MMprivate.h" /* Memory management			*/

/****************/
/* Local Macros */
/****************/

/*
 * Maximum length of the CWFS list, the list of remembered collections that
 * have free space.
 */
#define H5F_NCWFS 16

/******************/
/* Local Typedefs */
/******************/

/********************/
/* Package Typedefs */
/********************/

/********************/
/* Local Prototypes */
/********************/

/*********************/
/* Package Variables */
/*********************/

/*****************************/
/* Library Private Variables */
/*****************************/

/*******************/
/* Local Variables */
/*******************/

/*-------------------------------------------------------------------------
 * Function:	H5F_cwfs_add
 *
 * Purpose:	Add a global heap collection to the CWFS for a file.
 *
 * Return:	Success:	Non-negative
 *		Failure:	Negative
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5F_cwfs_add(H5F_t *f, H5HG_heap_t *heap)
{
    herr_t ret_value = SUCCEED; /* Return value */

    FUNC_ENTER_NOAPI(FAIL)

    /* Check args */
    assert(f);
    assert(f->shared);
    assert(heap);

    /*
     * Add the new heap to the CWFS list, removing some other entry if
     * necessary to make room. We remove the right-most entry that has less
     * free space than this heap.
     */
    if (NULL == f->shared->cwfs) {
        if (NULL == (f->shared->cwfs = (H5HG_heap_t **)H5MM_malloc(H5F_NCWFS * sizeof(H5HG_heap_t *))))
            HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "can't allocate CWFS for file");
        f->shared->cwfs[0] = heap;
        f->shared->ncwfs   = 1;
    }
    else if (H5F_NCWFS == f->shared->ncwfs) {
        int i; /* Local index variable */

        for (i = H5F_NCWFS - 1; i >= 0; --i)
            if (H5HG_FREE_SIZE(f->shared->cwfs[i]) < H5HG_FREE_SIZE(heap)) {
                memmove(f->shared->cwfs + 1, f->shared->cwfs, (size_t)i * sizeof(H5HG_heap_t *));
                f->shared->cwfs[0] = heap;
                break;
            } /* end if */
    }
    else {
        memmove(f->shared->cwfs + 1, f->shared->cwfs, f->shared->ncwfs * sizeof(H5HG_heap_t *));
        f->shared->cwfs[0] = heap;
        f->shared->ncwfs += 1;
    } /* end else */

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* H5F_cwfs_add() */

/*-------------------------------------------------------------------------
 * Function:	H5F_cwfs_find_free_heap
 *
 * Purpose:	Find a global heap collection with free space for storing
 *		a new object.
 *
 * Return:	Success:	Non-negative
 *		Failure:	Negative
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5F_cwfs_find_free_heap(H5F_t *f, size_t need, haddr_t *addr)
{
    unsigned cwfsno;              /* Local index for iterating over collections */
    bool     found     = false;   /* Flag to indicate a heap with enough space was found */
    herr_t   ret_value = SUCCEED; /* Return value */

    FUNC_ENTER_NOAPI(FAIL)

    /* Check args */
    assert(f);
    assert(f->shared);
    assert(addr);

    /* Note that we don't have metadata cache locks on the entries in
     * f->shared->cwfs.
     *
     * In the current situation, this doesn't matter, as we are single
     * threaded, and as best I can tell, entries are added to and deleted
     * from f->shared->cwfs as they are added to and deleted from the
     * metadata cache.
     *
     * To be proper, we should either lock each entry in f->shared->cwfs
     * as we examine it, or lock the whole array.  However, at present
     * I don't see the point as there will be significant overhead,
     * and protecting and unprotecting all the collections in the global
     * heap on a regular basis will skew the replacement policy.
     *
     *                                        JRM - 5/24/04
     */
    for (cwfsno = 0; cwfsno < f->shared->ncwfs; cwfsno++)
        if (H5HG_FREE_SIZE(f->shared->cwfs[cwfsno]) >= need) {
            *addr = H5HG_ADDR(f->shared->cwfs[cwfsno]);
            found = true;
            break;
        } /* end if */

    /*
     * If we didn't find any collection with enough free space the check if
     * we can extend any of the collections to make enough room.
     */
    if (!found) {
        size_t new_need;

        for (cwfsno = 0; cwfsno < f->shared->ncwfs; cwfsno++) {
            new_need = need;
            new_need -= H5HG_FREE_SIZE(f->shared->cwfs[cwfsno]);
            new_need = MAX(H5HG_SIZE(f->shared->cwfs[cwfsno]), new_need);

            if ((H5HG_SIZE(f->shared->cwfs[cwfsno]) + new_need) <= H5HG_MAXSIZE) {
                htri_t was_extended; /* Whether the heap was extended */

                was_extended =
                    H5MF_try_extend(f, H5FD_MEM_GHEAP, H5HG_ADDR(f->shared->cwfs[cwfsno]),
                                    (hsize_t)H5HG_SIZE(f->shared->cwfs[cwfsno]), (hsize_t)new_need);
                if (was_extended < 0)
                    HGOTO_ERROR(H5E_HEAP, H5E_CANTEXTEND, FAIL, "error trying to extend heap");
                else if (was_extended == true) {
                    if (H5HG_extend(f, H5HG_ADDR(f->shared->cwfs[cwfsno]), new_need) < 0)
                        HGOTO_ERROR(H5E_HEAP, H5E_CANTRESIZE, FAIL,
                                    "unable to extend global heap collection");
                    *addr = H5HG_ADDR(f->shared->cwfs[cwfsno]);
                    found = true;
                    break;
                } /* end if */
            }     /* end if */
        }         /* end for */
    }             /* end if */

    if (found) {
        /* Move the collection forward in the CWFS list, if it's not
         * already at the front
         */
        if (cwfsno > 0) {
            H5HG_heap_t *tmp = f->shared->cwfs[cwfsno];

            f->shared->cwfs[cwfsno]     = f->shared->cwfs[cwfsno - 1];
            f->shared->cwfs[cwfsno - 1] = tmp;
        } /* end if */
    }     /* end if */

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* H5F_cwfs_find_free_heap() */

/*-------------------------------------------------------------------------
 * Function:	H5F_cwfs_advance_heap
 *
 * Purpose:	Advance a heap in the CWFS
 *
 * Return:	Success:	Non-negative
 *		Failure:	Negative
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5F_cwfs_advance_heap(H5F_t *f, H5HG_heap_t *heap, bool add_heap)
{
    unsigned u;                   /* Local index variable */
    herr_t   ret_value = SUCCEED; /* Return value */

    FUNC_ENTER_NOAPI_NOERR

    /* Check args */
    assert(f);
    assert(f->shared);
    assert(heap);

    for (u = 0; u < f->shared->ncwfs; u++)
        if (f->shared->cwfs[u] == heap) {
            if (u) {
                f->shared->cwfs[u]     = f->shared->cwfs[u - 1];
                f->shared->cwfs[u - 1] = heap;
            } /* end if */
            break;
        } /* end if */
    if (add_heap && u >= f->shared->ncwfs) {
        f->shared->ncwfs                      = MIN(f->shared->ncwfs + 1, H5F_NCWFS);
        f->shared->cwfs[f->shared->ncwfs - 1] = heap;
    } /* end if */

    FUNC_LEAVE_NOAPI(ret_value)
} /* H5F_cwfs_advance_heap() */

/*-------------------------------------------------------------------------
 * Function:	H5F_cwfs_remove_heap
 *
 * Purpose:	Remove a heap from the CWFS
 *
 * Return:	Success:	Non-negative
 *		Failure:	Negative
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5F_cwfs_remove_heap(H5F_shared_t *shared, H5HG_heap_t *heap)
{
    unsigned u;                   /* Local index variable */
    herr_t   ret_value = SUCCEED; /* Return value */

    FUNC_ENTER_NOAPI_NOERR

    /* Check args */
    assert(shared);
    assert(heap);

    /* Remove the heap from the CWFS list */
    for (u = 0; u < shared->ncwfs; u++) {
        if (shared->cwfs[u] == heap) {
            shared->ncwfs -= 1;
            memmove(shared->cwfs + u, shared->cwfs + u + 1, (shared->ncwfs - u) * sizeof(H5HG_heap_t *));
            break;
        } /* end if */
    }     /* end for */

    FUNC_LEAVE_NOAPI(ret_value)
} /* H5F_cwfs_remove_heap() */