summaryrefslogtreecommitdiffstats
path: root/src/H5Omtime.c
blob: 1474c66968333647c030a8c7d349196a78a8b8ad (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
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 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:         The object modification time message
 */

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

#include "H5private.h"   /* Generic Functions			*/
#include "H5Eprivate.h"  /* Error handling		  	*/
#include "H5FLprivate.h" /* Free lists                           */
#include "H5MMprivate.h" /* Memory management			*/
#include "H5Opkg.h"      /* Object headers			*/

static void  *H5O__mtime_new_decode(H5F_t *f, H5O_t *open_oh, unsigned mesg_flags, unsigned *ioflags,
                                    size_t p_size, const uint8_t *p);
static herr_t H5O__mtime_new_encode(H5F_t *f, hbool_t disable_shared, uint8_t *p, const void *_mesg);
static size_t H5O__mtime_new_size(const H5F_t *f, hbool_t disable_shared, const void *_mesg);

static void  *H5O__mtime_decode(H5F_t *f, H5O_t *open_oh, unsigned mesg_flags, unsigned *ioflags,
                                size_t p_size, const uint8_t *p);
static herr_t H5O__mtime_encode(H5F_t *f, hbool_t disable_shared, uint8_t *p, const void *_mesg);
static void  *H5O__mtime_copy(const void *_mesg, void *_dest);
static size_t H5O__mtime_size(const H5F_t *f, hbool_t disable_shared, const void *_mesg);
static herr_t H5O__mtime_free(void *_mesg);
static herr_t H5O__mtime_debug(H5F_t *f, const void *_mesg, FILE *stream, int indent, int fwidth);

/* This message derives from H5O message class */
const H5O_msg_class_t H5O_MSG_MTIME[1] = {{
    H5O_MTIME_ID,      /*message id number		*/
    "mtime",           /*message name for debugging	*/
    sizeof(time_t),    /*native message size		*/
    0,                 /* messages are shareable?       */
    H5O__mtime_decode, /*decode message		*/
    H5O__mtime_encode, /*encode message		*/
    H5O__mtime_copy,   /*copy the native value		*/
    H5O__mtime_size,   /*raw message size		*/
    NULL,              /* reset method			*/
    H5O__mtime_free,   /* free method			*/
    NULL,              /* file delete method		*/
    NULL,              /* link method			*/
    NULL,              /*set share method		*/
    NULL,              /*can share method		*/
    NULL,              /* pre copy native value to file */
    NULL,              /* copy native value to file    */
    NULL,              /* post copy native value to file    */
    NULL,              /* get creation index		*/
    NULL,              /* set creation index		*/
    H5O__mtime_debug   /*debug the message		*/
}};

/* This message derives from H5O message class */
/* (Only encode, decode & size routines are different from old mtime routines) */
const H5O_msg_class_t H5O_MSG_MTIME_NEW[1] = {{
    H5O_MTIME_NEW_ID,      /*message id number		*/
    "mtime_new",           /*message name for debugging	*/
    sizeof(time_t),        /*native message size		*/
    0,                     /* messages are shareable?       */
    H5O__mtime_new_decode, /*decode message		*/
    H5O__mtime_new_encode, /*encode message		*/
    H5O__mtime_copy,       /*copy the native value		*/
    H5O__mtime_new_size,   /*raw message size		*/
    NULL,                  /* reset method			*/
    H5O__mtime_free,       /* free method			*/
    NULL,                  /* file delete method		*/
    NULL,                  /* link method			*/
    NULL,                  /*set share method		*/
    NULL,                  /*can share method		*/
    NULL,                  /* pre copy native value to file */
    NULL,                  /* copy native value to file    */
    NULL,                  /* post copy native value to file    */
    NULL,                  /* get creation index		*/
    NULL,                  /* set creation index		*/
    H5O__mtime_debug       /*debug the message		*/
}};

/* Current version of new mtime information */
#define H5O_MTIME_VERSION 1

/* Declare a free list to manage the time_t struct */
H5FL_DEFINE(time_t);

/*-------------------------------------------------------------------------
 * Function:    H5O__mtime_new_decode
 *
 * Purpose:     Decode a new modification time message and return a pointer to
 *              a new time_t value.
 *
 *              This version of the modification time was used in HDF5
 *              1.6.1 and later.
 *
 *              The new modification time message format was added due to the
 *              performance overhead of the old format.
 *
 * Return:      Success:    Pointer to new message in native struct
 *              Failure:    NULL
 *-------------------------------------------------------------------------
 */
static void *
H5O__mtime_new_decode(H5F_t H5_ATTR_NDEBUG_UNUSED *f, H5O_t H5_ATTR_UNUSED *open_oh,
                      unsigned H5_ATTR_UNUSED mesg_flags, unsigned H5_ATTR_UNUSED *ioflags, size_t p_size,
                      const uint8_t *p)
{
    const uint8_t *p_end = p + p_size - 1; /* End of input buffer */
    time_t        *mesg  = NULL;
    uint32_t       tmp_time;         /* Temporary copy of the time */
    void          *ret_value = NULL; /* Return value */

    FUNC_ENTER_PACKAGE

    assert(f);
    assert(p);

    if (H5_IS_BUFFER_OVERFLOW(p, 1, p_end))
        HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
    if (*p++ != H5O_MTIME_VERSION)
        HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad version number for mtime message");

    /* Skip reserved bytes */
    if (H5_IS_BUFFER_OVERFLOW(p, 3, p_end))
        HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
    p += 3;

    /* Get the time_t from the file */
    if (H5_IS_BUFFER_OVERFLOW(p, 4, p_end))
        HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
    UINT32DECODE(p, tmp_time);

    /* The return value */
    if (NULL == (mesg = H5FL_MALLOC(time_t)))
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
    *mesg = (time_t)tmp_time;

    /* Set return value */
    ret_value = mesg;

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5O__mtime_new_decode() */

/*-------------------------------------------------------------------------
 * Function:	H5O__mtime_decode
 *
 * Purpose:     Decode a modification time message and return a pointer to a
 *              new time_t value.
 *
 *              This version of the modification time was used in HDF5
 *              1.6.0 and earlier.
 *
 *              The new modification time message format was added due to the
 *              performance overhead of the old format.
 *
 * Return:      Success:    Pointer to new message in native struct
 *              Failure:    NULL
 *-------------------------------------------------------------------------
 */
static void *
H5O__mtime_decode(H5F_t H5_ATTR_NDEBUG_UNUSED *f, H5O_t H5_ATTR_UNUSED *open_oh,
                  unsigned H5_ATTR_UNUSED mesg_flags, unsigned H5_ATTR_UNUSED *ioflags, size_t p_size,
                  const uint8_t *p)
{
    const uint8_t *p_end = p + p_size - 1; /* End of input buffer */
    time_t        *mesg  = NULL;
    time_t         the_time;
    struct tm      tm;
    void          *ret_value = NULL;

    FUNC_ENTER_PACKAGE

    assert(f);
    assert(p);

    /* Buffer should have 14 message bytes and 2 reserved bytes */
    if (H5_IS_BUFFER_OVERFLOW(p, 16, p_end))
        HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding");
    for (int i = 0; i < 14; i++)
        if (!isdigit(p[i]))
            HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "badly formatted modification time message");

    /* Convert YYYYMMDDhhmmss UTC to a time_t. */
    memset(&tm, 0, sizeof tm);
    tm.tm_year  = (p[0] - '0') * 1000 + (p[1] - '0') * 100 + (p[2] - '0') * 10 + (p[3] - '0') - 1900;
    tm.tm_mon   = (p[4] - '0') * 10 + (p[5] - '0') - 1;
    tm.tm_mday  = (p[6] - '0') * 10 + (p[7] - '0');
    tm.tm_hour  = (p[8] - '0') * 10 + (p[9] - '0');
    tm.tm_min   = (p[10] - '0') * 10 + (p[11] - '0');
    tm.tm_sec   = (p[12] - '0') * 10 + (p[13] - '0');
    tm.tm_isdst = -1; /* (figure it out) */
    if ((time_t)-1 == (the_time = H5_make_time(&tm)))
        HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "can't construct time info");

    /* The return value */
    if (NULL == (mesg = H5FL_MALLOC(time_t)))
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
    *mesg = the_time;

    /* Set return value */
    ret_value = mesg;

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5O__mtime_decode() */

/*-------------------------------------------------------------------------
 * Function:	H5O__mtime_new_encode
 *
 * Purpose:	Encodes a new modification time message.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5O__mtime_new_encode(H5F_t H5_ATTR_UNUSED *f, hbool_t H5_ATTR_UNUSED disable_shared, uint8_t *p,
                      const void *_mesg)
{
    const time_t *mesg = (const time_t *)_mesg;

    FUNC_ENTER_PACKAGE_NOERR

    /* check args */
    assert(f);
    assert(p);
    assert(mesg);

    /* Version */
    *p++ = H5O_MTIME_VERSION;

    /* Reserved bytes */
    *p++ = 0;
    *p++ = 0;
    *p++ = 0;

    /* Encode time */
    UINT32ENCODE(p, *mesg);

    FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5O__mtime_new_encode() */

/*-------------------------------------------------------------------------
 * Function:	H5O__mtime_encode
 *
 * Purpose:	Encodes a modification time message.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5O__mtime_encode(H5F_t H5_ATTR_UNUSED *f, hbool_t H5_ATTR_UNUSED disable_shared, uint8_t *p,
                  const void *_mesg)
{
    const time_t *mesg = (const time_t *)_mesg;
    struct tm    *tm;

    FUNC_ENTER_PACKAGE_NOERR

    /* check args */
    assert(f);
    assert(p);
    assert(mesg);

    /* encode */
    tm = HDgmtime(mesg);
    HDsprintf((char *)p, "%04d%02d%02d%02d%02d%02d", 1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday,
              tm->tm_hour, tm->tm_min, tm->tm_sec);

    FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5O__mtime_encode() */

/*-------------------------------------------------------------------------
 * Function:	H5O__mtime_copy
 *
 * Purpose:	Copies a message from _MESG to _DEST, allocating _DEST if
 *		necessary.
 *
 * Return:	Success:	Ptr to _DEST
 *
 *		Failure:	NULL
 *
 *-------------------------------------------------------------------------
 */
static void *
H5O__mtime_copy(const void *_mesg, void *_dest)
{
    const time_t *mesg      = (const time_t *)_mesg;
    time_t       *dest      = (time_t *)_dest;
    void         *ret_value = NULL; /* Return value */

    FUNC_ENTER_PACKAGE

    /* check args */
    assert(mesg);
    if (!dest && NULL == (dest = H5FL_MALLOC(time_t)))
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");

    /* copy */
    *dest = *mesg;

    /* Set return value */
    ret_value = dest;

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5O__mtime_copy() */

/*-------------------------------------------------------------------------
 * Function:	H5O__mtime_new_size
 *
 * Purpose:	Returns the size of the raw message in bytes not
 *		counting the message type or size fields, but only the data
 *		fields.	 This function doesn't take into account
 *		alignment.
 *
 * Return:	Success:	Message data size in bytes w/o alignment.
 *
 *		Failure:	0
 *
 *-------------------------------------------------------------------------
 */
static size_t
H5O__mtime_new_size(const H5F_t H5_ATTR_UNUSED *f, hbool_t H5_ATTR_UNUSED disable_shared,
                    const void H5_ATTR_UNUSED *mesg)
{
    FUNC_ENTER_PACKAGE_NOERR

    /* check args */
    assert(f);
    assert(mesg);

    FUNC_LEAVE_NOAPI(8)
} /* end H5O__mtime_new_size() */

/*-------------------------------------------------------------------------
 * Function:	H5O__mtime_size
 *
 * Purpose:	Returns the size of the raw message in bytes not
 *		counting the message type or size fields, but only the data
 *		fields.	 This function doesn't take into account
 *		alignment.
 *
 * Return:	Success:	Message data size in bytes w/o alignment.
 *
 *		Failure:	0
 *
 *-------------------------------------------------------------------------
 */
static size_t
H5O__mtime_size(const H5F_t H5_ATTR_UNUSED *f, hbool_t H5_ATTR_UNUSED disable_shared,
                const void H5_ATTR_UNUSED *mesg)
{
    FUNC_ENTER_PACKAGE_NOERR

    /* check args */
    assert(f);
    assert(mesg);

    FUNC_LEAVE_NOAPI(16)
} /* end H5O__mtime_size() */

/*-------------------------------------------------------------------------
 * Function:	H5O__mtime_free
 *
 * Purpose:	Frees the message
 *
 * Return:	Non-negative on success/Negative on failure
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5O__mtime_free(void *mesg)
{
    FUNC_ENTER_PACKAGE_NOERR

    assert(mesg);

    mesg = H5FL_FREE(time_t, mesg);

    FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5O__mtime_free() */

/*-------------------------------------------------------------------------
 * Function:	H5O__mtime_debug
 *
 * Purpose:	Prints debugging info for the message.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5O__mtime_debug(H5F_t H5_ATTR_UNUSED *f, const void *_mesg, FILE *stream, int indent, int fwidth)
{
    const time_t *mesg = (const time_t *)_mesg;
    struct tm    *tm;
    char          buf[128];

    FUNC_ENTER_PACKAGE_NOERR

    /* check args */
    assert(f);
    assert(mesg);
    assert(stream);
    assert(indent >= 0);
    assert(fwidth >= 0);

    /* debug */
    tm = HDlocaltime(mesg);

    HDstrftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S %Z", tm);
    fprintf(stream, "%*s%-*s %s\n", indent, "", fwidth, "Time:", buf);

    FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5O__mtime_debug() */
ss="hl opt">, SUCCEED, -, H5EA_get_nelmts(const H5EA_t *ea, hsize_t *nelmts)) /* Local variables */ /* * Check arguments. */ HDassert(ea); HDassert(nelmts); /* Retrieve the max. index set */ *nelmts = ea->hdr->stats.stored.max_idx_set; END_FUNC(PRIV) /* end H5EA_get_nelmts() */ /*------------------------------------------------------------------------- * Function: H5EA_get_addr * * Purpose: Query the address of the array * * Return: SUCCEED/FAIL * * Programmer: Quincey Koziol * koziol@hdfgroup.org * Aug 21 2008 * *------------------------------------------------------------------------- */ BEGIN_FUNC(PRIV, NOERR, herr_t, SUCCEED, -, H5EA_get_addr(const H5EA_t *ea, haddr_t *addr)) /* Local variables */ /* * Check arguments. */ HDassert(ea); HDassert(ea->hdr); HDassert(addr); /* Retrieve the address of the extensible array's header */ *addr = ea->hdr->addr; END_FUNC(PRIV) /* end H5EA_get_addr() */ /*------------------------------------------------------------------------- * Function: H5EA__lookup_elmt * * Purpose: Retrieve the metadata object and the element buffer for a * given element in the array. * * Return: SUCCEED/FAIL * * Programmer: Quincey Koziol * koziol@hdfgroup.org * Sep 9 2008 * *------------------------------------------------------------------------- */ BEGIN_FUNC(STATIC, ERR, herr_t, SUCCEED, FAIL, H5EA__lookup_elmt(const H5EA_t *ea, hsize_t idx, hbool_t will_extend, unsigned thing_acc, void **thing, uint8_t **thing_elmt_buf, hsize_t *thing_elmt_idx, H5EA__unprotect_func_t *thing_unprot_func)) /* Local variables */ H5EA_hdr_t *hdr = ea->hdr; /* Header for EA */ H5EA_iblock_t *iblock = NULL; /* Pointer to index block for EA */ H5EA_sblock_t *sblock = NULL; /* Pointer to super block for EA */ H5EA_dblock_t *dblock = NULL; /* Pointer to data block for EA */ H5EA_dblk_page_t *dblk_page = NULL; /* Pointer to data block page for EA */ unsigned iblock_cache_flags = H5AC__NO_FLAGS_SET; /* Flags to unprotecting index block */ unsigned sblock_cache_flags = H5AC__NO_FLAGS_SET; /* Flags to unprotecting super block */ hbool_t stats_changed = FALSE; /* Whether array statistics changed */ hbool_t hdr_dirty = FALSE; /* Whether the array header changed */ /* * Check arguments. */ HDassert(ea); HDassert(hdr); HDassert(thing); HDassert(thing_elmt_buf); HDassert(thing_unprot_func); /* only the H5AC__READ_ONLY_FLAG may be set in thing_acc */ HDassert((thing_acc & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0); /* Set the shared array header's file context for this operation */ hdr->f = ea->f; /* Reset the pointers to the 'thing' info */ *thing = NULL; *thing_elmt_buf = NULL; *thing_elmt_idx = 0; *thing_unprot_func = (H5EA__unprotect_func_t)NULL; /* Check if we should create the index block */ if(!H5F_addr_defined(hdr->idx_blk_addr)) { /* Check if we are allowed to create the thing */ if(0 == (thing_acc & H5AC__READ_ONLY_FLAG)) { /* i.e. r/w access */ /* Create the index block */ hdr->idx_blk_addr = H5EA__iblock_create(hdr, &stats_changed); if(!H5F_addr_defined(hdr->idx_blk_addr)) H5E_THROW(H5E_CANTCREATE, "unable to create index block") hdr_dirty = TRUE; } /* end if */ else H5_LEAVE(SUCCEED) } /* end if */ /* Protect index block */ if(NULL == (iblock = H5EA__iblock_protect(hdr, thing_acc))) H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array index block, address = %llu", (unsigned long long)hdr->idx_blk_addr) /* Check if element is in index block */ if(idx < hdr->cparam.idx_blk_elmts) { /* Set 'thing' info to refer to the index block */ *thing = iblock; *thing_elmt_buf = (uint8_t *)iblock->elmts; *thing_elmt_idx = idx; *thing_unprot_func = (H5EA__unprotect_func_t)H5EA__iblock_unprotect; } /* end if */ else { unsigned sblk_idx; /* Which superblock does this index fall in? */ size_t dblk_idx; /* Data block index */ hsize_t elmt_idx; /* Offset of element in super block */ /* Get super block index where element is located */ sblk_idx = H5EA__dblock_sblk_idx(hdr, idx); /* Adjust index to offset in super block */ elmt_idx = idx - (hdr->cparam.idx_blk_elmts + hdr->sblk_info[sblk_idx].start_idx); /* Check for data block containing element address in the index block */ if(sblk_idx < iblock->nsblks) { /* Compute the data block index in index block */ dblk_idx = (size_t)(hdr->sblk_info[sblk_idx].start_dblk + (elmt_idx / hdr->sblk_info[sblk_idx].dblk_nelmts)); HDassert(dblk_idx < iblock->ndblk_addrs); /* Check if the data block has been allocated on disk yet */ if(!H5F_addr_defined(iblock->dblk_addrs[dblk_idx])) { /* Check if we are allowed to create the thing */ if(0 == (thing_acc & H5AC__READ_ONLY_FLAG)) { /* i.e. r/w access */ haddr_t dblk_addr; /* Address of data block created */ hsize_t dblk_off; /* Offset of data block in array */ /* Create data block */ dblk_off = hdr->sblk_info[sblk_idx].start_idx + (dblk_idx * hdr->sblk_info[sblk_idx].dblk_nelmts); dblk_addr = H5EA__dblock_create(hdr, iblock, &stats_changed, dblk_off, hdr->sblk_info[sblk_idx].dblk_nelmts); if(!H5F_addr_defined(dblk_addr)) H5E_THROW(H5E_CANTCREATE, "unable to create extensible array data block") /* Set data block address in index block */ iblock->dblk_addrs[dblk_idx] = dblk_addr; iblock_cache_flags |= H5AC__DIRTIED_FLAG; } /* end if */ else H5_LEAVE(SUCCEED) } /* end if */ /* Protect data block */ if(NULL == (dblock = H5EA__dblock_protect(hdr, iblock, iblock->dblk_addrs[dblk_idx], hdr->sblk_info[sblk_idx].dblk_nelmts, thing_acc))) H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array data block, address = %llu", (unsigned long long)iblock->dblk_addrs[dblk_idx]) /* Adjust index to offset in data block */ elmt_idx %= hdr->sblk_info[sblk_idx].dblk_nelmts; /* Check if there is already a dependency on the header */ if(will_extend && !dblock->has_hdr_depend) { if(H5EA__create_flush_depend((H5AC_info_t *)hdr, (H5AC_info_t *)dblock) < 0) H5E_THROW(H5E_CANTDEPEND, "unable to create flush dependency between data block and header, index = %llu", (unsigned long long)idx) dblock->has_hdr_depend = TRUE; } /* end if */ /* Set 'thing' info to refer to the data block */ *thing = dblock; *thing_elmt_buf = (uint8_t *)dblock->elmts; *thing_elmt_idx = elmt_idx; *thing_unprot_func = (H5EA__unprotect_func_t)H5EA__dblock_unprotect; } /* end if */ else { size_t sblk_off; /* Offset of super block in index block array of super blocks */ /* Calculate offset of super block in index block's array */ sblk_off = sblk_idx - iblock->nsblks; /* Check if the super block has been allocated on disk yet */ if(!H5F_addr_defined(iblock->sblk_addrs[sblk_off])) { /* Check if we are allowed to create the thing */ if(0 == (thing_acc & H5AC__READ_ONLY_FLAG)) { /* i.e. r/w access */ haddr_t sblk_addr; /* Address of data block created */ /* Create super block */ sblk_addr = H5EA__sblock_create(hdr, iblock, &stats_changed, sblk_idx); if(!H5F_addr_defined(sblk_addr)) H5E_THROW(H5E_CANTCREATE, "unable to create extensible array super block") /* Set super block address in index block */ iblock->sblk_addrs[sblk_off] = sblk_addr; iblock_cache_flags |= H5AC__DIRTIED_FLAG; } /* end if */ else H5_LEAVE(SUCCEED) } /* end if */ /* Protect super block */ if(NULL == (sblock = H5EA__sblock_protect(hdr, iblock, iblock->sblk_addrs[sblk_off], sblk_idx, thing_acc))) H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array super block, address = %llu", (unsigned long long)iblock->sblk_addrs[sblk_off]) /* Compute the data block index in super block */ dblk_idx = (size_t)(elmt_idx / sblock->dblk_nelmts); HDassert(dblk_idx < sblock->ndblks); /* Check if the data block has been allocated on disk yet */ if(!H5F_addr_defined(sblock->dblk_addrs[dblk_idx])) { /* Check if we are allowed to create the thing */ if(0 == (thing_acc & H5AC__READ_ONLY_FLAG)) { /* i.e. r/w access */ haddr_t dblk_addr; /* Address of data block created */ hsize_t dblk_off; /* Offset of data block in array */ /* Create data block */ dblk_off = hdr->sblk_info[sblk_idx].start_idx + (dblk_idx * hdr->sblk_info[sblk_idx].dblk_nelmts); dblk_addr = H5EA__dblock_create(hdr, sblock, &stats_changed, dblk_off, sblock->dblk_nelmts); if(!H5F_addr_defined(dblk_addr)) H5E_THROW(H5E_CANTCREATE, "unable to create extensible array data block") /* Set data block address in index block */ sblock->dblk_addrs[dblk_idx] = dblk_addr; sblock_cache_flags |= H5AC__DIRTIED_FLAG; /* Create flush dependency on header, if extending the array and one doesn't already exist */ if(will_extend && !sblock->has_hdr_depend) { if(H5EA__create_flush_depend((H5AC_info_t *)sblock->hdr, (H5AC_info_t *)sblock) < 0) H5E_THROW(H5E_CANTDEPEND, "unable to create flush dependency between super block and header, address = %llu", (unsigned long long)sblock->addr) sblock->has_hdr_depend = TRUE; } /* end if */ } /* end if */ else H5_LEAVE(SUCCEED) } /* end if */ /* Adjust index to offset in data block */ elmt_idx %= sblock->dblk_nelmts; /* Check if the data block is paged */ if(sblock->dblk_npages) { haddr_t dblk_page_addr; /* Address of data block page */ size_t page_idx; /* Index of page within data block */ size_t page_init_idx; /* Index of 'page init' bit */ /* Compute page index */ page_idx = (size_t)elmt_idx / hdr->dblk_page_nelmts; /* Compute 'page init' index */ page_init_idx = (dblk_idx * sblock->dblk_npages) + page_idx; /* Adjust index to offset in data block page */ elmt_idx %= hdr->dblk_page_nelmts; /* Compute data block page address */ dblk_page_addr = sblock->dblk_addrs[dblk_idx] + H5EA_DBLOCK_PREFIX_SIZE(sblock) + (page_idx * sblock->dblk_page_size); /* Check if page has been initialized yet */ if(!H5VM_bit_get(sblock->page_init, page_init_idx)) { /* Check if we are allowed to create the thing */ if(0 == (thing_acc & H5AC__READ_ONLY_FLAG)) { /* i.e. r/w access */ /* Create the data block page */ if(H5EA__dblk_page_create(hdr, sblock, dblk_page_addr) < 0) H5E_THROW(H5E_CANTCREATE, "unable to create data block page") /* Mark data block page as initialized in super block */ H5VM_bit_set(sblock->page_init, page_init_idx, TRUE); sblock_cache_flags |= H5AC__DIRTIED_FLAG; } /* end if */ else H5_LEAVE(SUCCEED) } /* end if */ /* Protect data block page */ if(NULL == (dblk_page = H5EA__dblk_page_protect(hdr, sblock, dblk_page_addr, thing_acc))) H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array data block page, address = %llu", (unsigned long long)dblk_page_addr) /* Check if there is already a dependency on the header */ if(will_extend && !dblk_page->has_hdr_depend) { if(H5EA__create_flush_depend((H5AC_info_t *)hdr, (H5AC_info_t *)dblk_page) < 0) H5E_THROW(H5E_CANTDEPEND, "unable to create flush dependency between data block page and header, index = %llu", (unsigned long long)idx) dblk_page->has_hdr_depend = TRUE; } /* end if */ /* Set 'thing' info to refer to the data block page */ *thing = dblk_page; *thing_elmt_buf = (uint8_t *)dblk_page->elmts; *thing_elmt_idx = elmt_idx; *thing_unprot_func = (H5EA__unprotect_func_t)H5EA__dblk_page_unprotect; } /* end if */ else { /* Protect data block */ if(NULL == (dblock = H5EA__dblock_protect(hdr, sblock, sblock->dblk_addrs[dblk_idx], sblock->dblk_nelmts, thing_acc))) H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array data block, address = %llu", (unsigned long long)sblock->dblk_addrs[dblk_idx]) /* Check if there is already a dependency on the header */ if(will_extend && !dblock->has_hdr_depend) { if(H5EA__create_flush_depend((H5AC_info_t *)hdr, (H5AC_info_t *)dblock) < 0) H5E_THROW(H5E_CANTDEPEND, "unable to create flush dependency between data block and header, index = %llu", (unsigned long long)idx) dblock->has_hdr_depend = TRUE; } /* end if */ /* Set 'thing' info to refer to the data block */ *thing = dblock; *thing_elmt_buf = (uint8_t *)dblock->elmts; *thing_elmt_idx = elmt_idx; *thing_unprot_func = (H5EA__unprotect_func_t)H5EA__dblock_unprotect; } /* end else */ } /* end else */ } /* end else */ /* Sanity checks */ HDassert(*thing != NULL); HDassert(*thing_unprot_func != NULL); CATCH /* Reset 'thing' info on error */ if(ret_value < 0) { *thing = NULL; *thing_elmt_buf = NULL; *thing_elmt_idx = 0; *thing_unprot_func = (H5EA__unprotect_func_t)NULL; } /* end if */ /* Check for updating array statistics */ if(stats_changed) hdr_dirty = TRUE; /* Check for header modified */ if(hdr_dirty) if(H5EA__hdr_modified(hdr) < 0) H5E_THROW(H5E_CANTMARKDIRTY, "unable to mark extensible array header as modified") /* Release resources */ if(iblock && *thing != iblock && H5EA__iblock_unprotect(iblock, iblock_cache_flags) < 0) H5E_THROW(H5E_CANTUNPROTECT, "unable to release extensible array index block") /* (Note: super blocks don't contain elements, so don't have a '*thing != sblock' check) */ if(sblock && H5EA__sblock_unprotect(sblock, sblock_cache_flags) < 0) H5E_THROW(H5E_CANTUNPROTECT, "unable to release extensible array super block") if(dblock && *thing != dblock && H5EA__dblock_unprotect(dblock, H5AC__NO_FLAGS_SET) < 0) H5E_THROW(H5E_CANTUNPROTECT, "unable to release extensible array data block") if(dblk_page && *thing != dblk_page && H5EA__dblk_page_unprotect(dblk_page, H5AC__NO_FLAGS_SET) < 0) H5E_THROW(H5E_CANTUNPROTECT, "unable to release extensible array data block page") END_FUNC(STATIC) /* end H5EA__lookup_elmt() */ /*------------------------------------------------------------------------- * Function: H5EA_set * * Purpose: Set an element of an extensible array * * Return: SUCCEED/FAIL * * Programmer: Quincey Koziol * koziol@hdfgroup.org * Sep 9 2008 * *------------------------------------------------------------------------- */ BEGIN_FUNC(PRIV, ERR, herr_t, SUCCEED, FAIL, H5EA_set(const H5EA_t *ea, hsize_t idx, const void *elmt)) /* Local variables */ H5EA_hdr_t *hdr = ea->hdr; /* Header for EA */ void *thing = NULL; /* Pointer to the array metadata containing the array index we are interested in */ uint8_t *thing_elmt_buf; /* Pointer to the element buffer for the array metadata */ hsize_t thing_elmt_idx; /* Index of the element in the element buffer for the array metadata */ H5EA__unprotect_func_t thing_unprot_func; /* Function pointer for unprotecting the array metadata */ hbool_t will_extend; /* Flag indicating if setting the element will extend the array */ unsigned thing_cache_flags = H5AC__NO_FLAGS_SET; /* Flags for unprotecting array metadata */ /* * Check arguments. */ HDassert(ea); HDassert(hdr); /* Set the shared array header's file context for this operation */ hdr->f = ea->f; /* Look up the array metadata containing the element we want to set */ will_extend = (idx >= hdr->stats.stored.max_idx_set); if(H5EA__lookup_elmt(ea, idx, will_extend, H5AC__NO_FLAGS_SET, &thing, &thing_elmt_buf, &thing_elmt_idx, &thing_unprot_func) < 0) H5E_THROW(H5E_CANTPROTECT, "unable to protect array metadata") /* Sanity check */ HDassert(thing); HDassert(thing_elmt_buf); HDassert(thing_unprot_func); /* Set element in thing's element buffer */ HDmemcpy(thing_elmt_buf + (hdr->cparam.cls->nat_elmt_size * thing_elmt_idx), elmt, hdr->cparam.cls->nat_elmt_size); thing_cache_flags |= H5AC__DIRTIED_FLAG; /* Update max. element set in array, if appropriate */ if(will_extend) { /* Update the max index for the array */ hdr->stats.stored.max_idx_set = idx + 1; if(H5EA__hdr_modified(hdr) < 0) H5E_THROW(H5E_CANTMARKDIRTY, "unable to mark extensible array header as modified") } /* end if */ CATCH /* Release resources */ if(thing && (thing_unprot_func)(thing, thing_cache_flags) < 0) H5E_THROW(H5E_CANTUNPROTECT, "unable to release extensible array metadata") END_FUNC(PRIV) /* end H5EA_set() */ /*------------------------------------------------------------------------- * Function: H5EA_get * * Purpose: Get an element of an extensible array * * Return: SUCCEED/FAIL * * Programmer: Quincey Koziol * koziol@hdfgroup.org * Sep 11 2008 * *------------------------------------------------------------------------- */ BEGIN_FUNC(PRIV, ERR, herr_t, SUCCEED, FAIL, H5EA_get(const H5EA_t *ea, hsize_t idx, void *elmt)) /* Local variables */ H5EA_hdr_t *hdr = ea->hdr; /* Header for EA */ void *thing = NULL; /* Pointer to the array metadata containing the array index we are interested in */ H5EA__unprotect_func_t thing_unprot_func; /* Function pointer for unprotecting the array metadata */ /* * Check arguments. */ HDassert(ea); HDassert(hdr); /* Check for element beyond max. element in array */ if(idx >= hdr->stats.stored.max_idx_set) { /* Call the class's 'fill' callback */ if((hdr->cparam.cls->fill)(elmt, (size_t)1) < 0) H5E_THROW(H5E_CANTSET, "can't set element to class's fill value") } /* end if */ else { uint8_t *thing_elmt_buf; /* Pointer to the element buffer for the array metadata */ hsize_t thing_elmt_idx; /* Index of the element in the element buffer for the array metadata */ /* Set the shared array header's file context for this operation */ hdr->f = ea->f; /* Look up the array metadata containing the element we want to set */ if(H5EA__lookup_elmt(ea, idx, FALSE, H5AC__READ_ONLY_FLAG, &thing, &thing_elmt_buf, &thing_elmt_idx, &thing_unprot_func) < 0) H5E_THROW(H5E_CANTPROTECT, "unable to protect array metadata") /* Check if the thing holding the element has been created yet */ if(NULL == thing) { /* Call the class's 'fill' callback */ if((hdr->cparam.cls->fill)(elmt, (size_t)1) < 0) H5E_THROW(H5E_CANTSET, "can't set element to class's fill value") } /* end if */ else /* Get element from thing's element buffer */ HDmemcpy(elmt, thing_elmt_buf + (hdr->cparam.cls->nat_elmt_size * thing_elmt_idx), hdr->cparam.cls->nat_elmt_size); } /* end else */ CATCH /* Release thing */ if(thing && (thing_unprot_func)(thing, H5AC__NO_FLAGS_SET) < 0) H5E_THROW(H5E_CANTUNPROTECT, "unable to release extensible array metadata") END_FUNC(PRIV) /* end H5EA_get() */ /*------------------------------------------------------------------------- * Function: H5EA_depend * * Purpose: Make a child flush dependency between the extensible array * and another piece of metadata in the file. * * Return: SUCCEED/FAIL * * Programmer: Quincey Koziol * koziol@hdfgroup.org * May 27 2009 * *------------------------------------------------------------------------- */ BEGIN_FUNC(PRIV, ERR, herr_t, SUCCEED, FAIL, H5EA_depend(H5EA_t *ea, H5AC_proxy_entry_t *parent)) /* Local variables */ H5EA_hdr_t *hdr = ea->hdr; /* Header for EA */ /* * Check arguments. */ HDassert(ea); HDassert(hdr); HDassert(parent); /* * Check to see if a flush dependency between the extensible array * and another data structure in the file has already been set up. * If it hasn't, do so now. */ if(NULL == hdr->parent) { /* Sanity check */ HDassert(hdr->top_proxy); /* Set the shared array header's file context for this operation */ hdr->f = ea->f; /* Add the extensible array as a child of the parent (proxy) */ if(H5AC_proxy_entry_add_child(parent, hdr->f, hdr->top_proxy) < 0) H5E_THROW(H5E_CANTSET, "unable to add extensible array as child of proxy") hdr->parent = parent; } /* end if */ CATCH END_FUNC(PRIV) /* end H5EA_depend() */ /*------------------------------------------------------------------------- * Function: H5EA_close * * Purpose: Close an extensible array * * Return: SUCCEED/FAIL * * Programmer: Quincey Koziol * koziol@hdfgroup.org * Aug 21 2008 * *------------------------------------------------------------------------- */ BEGIN_FUNC(PRIV, ERR, herr_t, SUCCEED, FAIL, H5EA_close(H5EA_t *ea)) /* Local variables */ hbool_t pending_delete = FALSE; /* Whether the array is pending deletion */ haddr_t ea_addr = HADDR_UNDEF; /* Address of array (for deletion) */ /* * Check arguments. */ HDassert(ea); /* Close the header, if it was set */ if(ea->hdr) { /* Decrement file reference & check if this is the last open extensible array using the shared array header */ if(0 == H5EA__hdr_fuse_decr(ea->hdr)) { /* Set the shared array header's file context for this operation */ ea->hdr->f = ea->f; /* Shut down anything that can't be put in the header's 'flush' callback */ /* Check for pending array deletion */ if(ea->hdr->pending_delete) { /* Set local info, so array deletion can occur after decrementing the * header's ref count */ pending_delete = TRUE; ea_addr = ea->hdr->addr; } /* end if */ } /* end if */ /* Check for pending array deletion */ if(pending_delete) { H5EA_hdr_t *hdr; /* Another pointer to extensible array header */ #ifndef NDEBUG { unsigned hdr_status = 0; /* Header's status in the metadata cache */ /* Check the header's status in the metadata cache */ if(H5AC_get_entry_status(ea->f, ea_addr, &hdr_status) < 0) H5E_THROW(H5E_CANTGET, "unable to check metadata cache status for extensible array header") /* Sanity checks on header */ HDassert(hdr_status & H5AC_ES__IN_CACHE); HDassert(hdr_status & H5AC_ES__IS_PINNED); HDassert(!(hdr_status & H5AC_ES__IS_PROTECTED)); } #endif /* NDEBUG */ /* Lock the array header into memory */ /* (OK to pass in NULL for callback context, since we know the header must be in the cache) */ if(NULL == (hdr = H5EA__hdr_protect(ea->f, ea_addr, NULL, H5AC__NO_FLAGS_SET))) H5E_THROW(H5E_CANTLOAD, "unable to load extensible array header") /* Set the shared array header's file context for this operation */ hdr->f = ea->f; /* Decrement the reference count on the array header */ /* (don't put in H5EA_hdr_fuse_decr() as the array header may be evicted * immediately -QAK) */ if(H5EA__hdr_decr(ea->hdr) < 0) H5E_THROW(H5E_CANTDEC, "can't decrement reference count on shared array header") /* Delete array, starting with header (unprotects header) */ if(H5EA__hdr_delete(hdr) < 0) H5E_THROW(H5E_CANTDELETE, "unable to delete extensible array") } /* end if */ else { /* Decrement the reference count on the array header */ /* (don't put in H5EA_hdr_fuse_decr() as the array header may be evicted * immediately -QAK) */ if(H5EA__hdr_decr(ea->hdr) < 0) H5E_THROW(H5E_CANTDEC, "can't decrement reference count on shared array header") } /* end else */ } /* end if */ /* Release the extensible array wrapper */ ea = (H5EA_t *)H5FL_FREE(H5EA_t, ea); CATCH END_FUNC(PRIV) /* end H5EA_close() */ /*------------------------------------------------------------------------- * Function: H5EA_delete * * Purpose: Delete an extensible array * * Return: SUCCEED/FAIL * * Programmer: Quincey Koziol * koziol@hdfgroup.org * Aug 28 2008 * *------------------------------------------------------------------------- */ BEGIN_FUNC(PRIV, ERR, herr_t, SUCCEED, FAIL, H5EA_delete(H5F_t *f, haddr_t ea_addr, void *ctx_udata)) /* Local variables */ H5EA_hdr_t *hdr = NULL; /* The fractal heap header information */ /* * Check arguments. */ HDassert(f); HDassert(H5F_addr_defined(ea_addr)); /* Lock the array header into memory */ if(NULL == (hdr = H5EA__hdr_protect(f, ea_addr, ctx_udata, H5AC__NO_FLAGS_SET))) H5E_THROW(H5E_CANTPROTECT, "unable to protect extensible array header, address = %llu", (unsigned long long)ea_addr) /* Check for files using shared array header */ if(hdr->file_rc) hdr->pending_delete = TRUE; else { /* Set the shared array header's file context for this operation */ hdr->f = f; /* Delete array now, starting with header (unprotects header) */ if(H5EA__hdr_delete(hdr) < 0) H5E_THROW(H5E_CANTDELETE, "unable to delete extensible array") hdr = NULL; } /* end if */ CATCH /* Unprotect the header, if an error occurred */ if(hdr && H5EA__hdr_unprotect(hdr, H5AC__NO_FLAGS_SET) < 0) H5E_THROW(H5E_CANTUNPROTECT, "unable to release extensible array header") END_FUNC(PRIV) /* end H5EA_delete() */ /*------------------------------------------------------------------------- * Function: H5EA_iterate * * Purpose: Iterate over the elements of an extensible array * (copied and modified from FA_iterate() in H5FA.c) * * Return: SUCCEED/FAIL * * Programmer: Vailin Choi; Feb 2015 * *------------------------------------------------------------------------- */ BEGIN_FUNC(PRIV, ERR, herr_t, SUCCEED, FAIL, H5EA_iterate(H5EA_t *ea, H5EA_operator_t op, void *udata)) /* Local variables */ uint8_t *elmt = NULL; hsize_t u; /* * Check arguments. */ HDassert(ea); HDassert(op); HDassert(udata); /* Allocate space for a native array element */ if(NULL == (elmt = H5FL_BLK_MALLOC(ea_native_elmt, ea->hdr->cparam.cls->nat_elmt_size))) H5E_THROW(H5E_CANTALLOC, "memory allocation failed for extensible array element") /* Iterate over all elements in array */ for(u = 0; u < ea->hdr->stats.stored.max_idx_set; u++) { int cb_ret; /* Return value from callback */ /* Get array element */ if(H5EA_get(ea, u, elmt) < 0) H5E_THROW(H5E_CANTGET, "unable to delete fixed array") /* Make callback */ if((cb_ret = (*op)(u, elmt, udata)) < 0) { H5E_PRINTF(H5E_BADITER, "iterator function failed"); H5_LEAVE(cb_ret) } /* end if */ } /* end for */ CATCH if(elmt) elmt = H5FL_BLK_FREE(ea_native_elmt, elmt); END_FUNC(PRIV) /* end H5EA_iterate() */ /*------------------------------------------------------------------------- * Function: H5EA_patch_file * * Purpose: Patch the top-level file pointer contained in ea * to point to idx_info->f if they are different. * This is possible because the file pointer in ea can be * closed out if ea remains open. * * Return: SUCCEED * *------------------------------------------------------------------------- */ BEGIN_FUNC(PRIV, NOERR, herr_t, SUCCEED, -, H5EA_patch_file(H5EA_t *ea, H5F_t *f)) /* Local variables */ /* * Check arguments. */ HDassert(ea); HDassert(f); if(ea->f != f || ea->hdr->f != f) ea->f = ea->hdr->f = f; END_FUNC(PRIV) /* end H5EA_patch_file() */