Coverage Report

Created: 2024-06-18 06:29

/src/hdf5/src/H5SMmessage.c
Line
Count
Source (jump to first uncovered line)
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 COPYING 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
/* Module Setup */
15
/****************/
16
17
#define H5O_FRIEND      /*suppress error about including H5Opkg   */
18
#include "H5SMmodule.h" /* This source code file is part of the H5SM module */
19
20
/***********/
21
/* Headers */
22
/***********/
23
#include "H5private.h"   /* Generic Functions     */
24
#include "H5Eprivate.h"  /* Error handling        */
25
#include "H5MMprivate.h" /* Memory management     */
26
#include "H5Opkg.h"      /* Object Headers                       */
27
#include "H5SMpkg.h"     /* Shared object header messages        */
28
29
/****************/
30
/* Local Macros */
31
/****************/
32
33
/******************/
34
/* Local Typedefs */
35
/******************/
36
37
/* Udata struct for calls to H5SM__compare_cb and H5SM__compare_iter_op*/
38
typedef struct H5SM_compare_udata_t {
39
    const H5SM_mesg_key_t *key; /* Key; compare this against stored message */
40
    H5O_msg_crt_idx_t      idx; /* Index of the message in the OH, if applicable */
41
    herr_t                 ret; /* Return value; set this to result of memcmp */
42
} H5SM_compare_udata_t;
43
44
/********************/
45
/* Local Prototypes */
46
/********************/
47
static herr_t H5SM__compare_cb(const void *obj, size_t obj_len, void *udata);
48
static herr_t H5SM__compare_iter_op(H5O_t *oh, H5O_mesg_t *mesg, unsigned sequence, unsigned *oh_modified,
49
                                    void *udata);
50
51
/*********************/
52
/* Package Variables */
53
/*********************/
54
55
/*****************************/
56
/* Library Private Variables */
57
/*****************************/
58
59
/*******************/
60
/* Local Variables */
61
/*******************/
62
63
/*-------------------------------------------------------------------------
64
 * Function:  H5SM__compare_cb
65
 *
66
 * Purpose: Callback for H5HF_op, used in H5SM__message_compare below.
67
 *              Determines whether the search key passed in in _UDATA is
68
 *              equal to OBJ or not.
69
 *
70
 *              Passes back the result in _UDATA->RET
71
 *
72
 * Return:  Negative on error, non-negative on success
73
 *
74
 *-------------------------------------------------------------------------
75
 */
76
static herr_t
77
H5SM__compare_cb(const void *obj, size_t obj_len, void *_udata)
78
0
{
79
0
    H5SM_compare_udata_t *udata = (H5SM_compare_udata_t *)_udata;
80
81
0
    FUNC_ENTER_PACKAGE_NOERR
82
83
    /* If the encoding sizes are different, it's not the same object */
84
0
    if (udata->key->encoding_size > obj_len)
85
0
        udata->ret = 1;
86
0
    else if (udata->key->encoding_size < obj_len)
87
0
        udata->ret = -1;
88
0
    else
89
        /* Sizes are the same.  Return result of memcmp */
90
0
        udata->ret = memcmp(udata->key->encoding, obj, obj_len);
91
92
0
    FUNC_LEAVE_NOAPI(SUCCEED)
93
0
} /* end H5SM__compare_cb() */
94
95
/*-------------------------------------------------------------------------
96
 * Function:  H5SM__compare_iter_op
97
 *
98
 * Purpose: OH iteration callback to compare a key against a message in
99
 *              an OH
100
 *
101
 * Return:  0 if this is not the message we're searching for
102
 *              1 if this is the message we're searching for (with memcmp
103
 *                      result returned in udata)
104
 *              negative on error
105
 *
106
 *-------------------------------------------------------------------------
107
 */
108
static herr_t
109
H5SM__compare_iter_op(H5O_t *oh, H5O_mesg_t *mesg /*in,out*/, unsigned sequence,
110
                      unsigned H5_ATTR_UNUSED *oh_modified, void *_udata /*in,out*/)
111
0
{
112
0
    H5SM_compare_udata_t *udata     = (H5SM_compare_udata_t *)_udata;
113
0
    herr_t                ret_value = H5_ITER_CONT;
114
115
0
    FUNC_ENTER_PACKAGE
116
117
    /*
118
     * Check arguments.
119
     */
120
0
    assert(oh);
121
0
    assert(mesg);
122
0
    assert(udata && udata->key);
123
124
    /* Check the creation index for this message */
125
0
    if (sequence == udata->idx) {
126
0
        size_t aligned_encoded_size = H5O_ALIGN_OH(oh, udata->key->encoding_size);
127
128
        /* Sanity check the message's length */
129
0
        assert(mesg->raw_size > 0);
130
131
0
        if (aligned_encoded_size > mesg->raw_size)
132
0
            udata->ret = 1;
133
0
        else if (aligned_encoded_size < mesg->raw_size)
134
0
            udata->ret = -1;
135
0
        else {
136
            /* Check if the message is dirty & flush it to the object header if so */
137
0
            if (mesg->dirty)
138
0
                if (H5O_msg_flush(udata->key->file, oh, mesg) < 0)
139
0
                    HGOTO_ERROR(H5E_SOHM, H5E_CANTENCODE, H5_ITER_ERROR,
140
0
                                "unable to encode object header message");
141
142
0
            assert(udata->key->encoding_size <= mesg->raw_size);
143
0
            udata->ret = memcmp(udata->key->encoding, mesg->raw, udata->key->encoding_size);
144
0
        } /* end else */
145
146
        /* Indicate that we found the message we were looking for */
147
0
        ret_value = H5_ITER_STOP;
148
0
    } /* end if */
149
150
0
done:
151
0
    FUNC_LEAVE_NOAPI(ret_value)
152
0
} /* end H5SM__compare_iter_op() */
153
154
/*-------------------------------------------------------------------------
155
 * Function:  H5SM__message_compare
156
 *
157
 * Purpose: Determine whether the search key rec1 represents a shared
158
 *              message that is equal to rec2 or not, and if not, whether
159
 *              rec1 is "greater than" or "less than" rec2.
160
 *
161
 * Return:  0 if rec1 == rec2
162
 *              Negative if rec1 < rec2
163
 *              Positive if rec1 > rec2
164
 *
165
 *-------------------------------------------------------------------------
166
 */
167
herr_t
168
H5SM__message_compare(const void *rec1, const void *rec2, int *result)
169
0
{
170
0
    const H5SM_mesg_key_t *key       = (const H5SM_mesg_key_t *)rec1;
171
0
    const H5SM_sohm_t     *mesg      = (const H5SM_sohm_t *)rec2;
172
0
    herr_t                 ret_value = SUCCEED;
173
174
0
    FUNC_ENTER_PACKAGE
175
176
    /* If the key has an fheap ID, we're looking for a message that's
177
     * already in the index; if the fheap ID matches, we've found the message
178
     * and can stop immediately.
179
     * Likewise, if the message has an OH location that is matched by the
180
     * message in the index, we've found the message.
181
     */
182
0
    if (mesg->location == H5SM_IN_HEAP && key->message.location == H5SM_IN_HEAP) {
183
0
        if (key->message.u.heap_loc.fheap_id.val == mesg->u.heap_loc.fheap_id.val) {
184
0
            *result = 0;
185
0
            HGOTO_DONE(SUCCEED);
186
0
        }
187
0
    } /* end if */
188
0
    else if (mesg->location == H5SM_IN_OH && key->message.location == H5SM_IN_OH) {
189
0
        if (key->message.u.mesg_loc.oh_addr == mesg->u.mesg_loc.oh_addr &&
190
0
            key->message.u.mesg_loc.index == mesg->u.mesg_loc.index &&
191
0
            key->message.msg_type_id == mesg->msg_type_id) {
192
0
            *result = 0;
193
0
            HGOTO_DONE(SUCCEED);
194
0
        }
195
0
    } /* end if */
196
197
    /* Compare hash values */
198
0
    if (key->message.hash > mesg->hash)
199
0
        *result = 1;
200
0
    else if (key->message.hash < mesg->hash)
201
0
        *result = -1;
202
    /* If the hash values match, make sure the messages are really the same */
203
0
    else {
204
        /* Hash values match; compare the encoded message with the one in
205
         * the index.
206
         */
207
0
        H5SM_compare_udata_t udata;
208
209
0
        assert(key->message.hash == mesg->hash);
210
0
        assert(key->encoding_size > 0 && key->encoding);
211
212
        /* Set up user data for callback */
213
0
        udata.key = key;
214
215
        /* Compare the encoded message with either the message in the heap or
216
         * the message in an object header.
217
         */
218
0
        if (mesg->location == H5SM_IN_HEAP) {
219
            /* Call heap op routine with comparison callback */
220
0
            if (H5HF_op(key->fheap, &(mesg->u.heap_loc.fheap_id), H5SM__compare_cb, &udata) < 0)
221
0
                HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records");
222
0
        } /* end if */
223
0
        else {
224
0
            H5O_loc_t           oloc; /* Object owning the message */
225
0
            H5O_mesg_operator_t op;   /* Message operator */
226
227
            /* Sanity checks */
228
0
            assert(key->file);
229
0
            assert(mesg->location == H5SM_IN_OH);
230
231
            /* Reset the object location */
232
0
            if (H5O_loc_reset(&oloc) < 0)
233
0
                HGOTO_ERROR(H5E_SYM, H5E_CANTRESET, FAIL, "unable to initialize target location");
234
235
            /* Set up object location */
236
0
            oloc.file = key->file;
237
0
            oloc.addr = mesg->u.mesg_loc.oh_addr;
238
239
            /* Finish setting up user data for iterator */
240
0
            udata.idx = mesg->u.mesg_loc.index;
241
242
            /* Locate the right message and compare with it */
243
0
            op.op_type  = H5O_MESG_OP_LIB;
244
0
            op.u.lib_op = H5SM__compare_iter_op;
245
0
            if (H5O_msg_iterate(&oloc, mesg->msg_type_id, &op, &udata) < 0)
246
0
                HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "error iterating over links");
247
0
        } /* end else */
248
249
0
        *result = udata.ret;
250
0
    } /* end if */
251
252
0
done:
253
0
    FUNC_LEAVE_NOAPI(ret_value)
254
0
} /* end H5SM__message_compare */
255
256
/*-------------------------------------------------------------------------
257
 * Function:  H5SM__message_encode
258
 *
259
 * Purpose: Serialize a H5SM_sohm_t struct into a buffer RAW.
260
 *
261
 * Return:  Non-negative on success
262
 *              Negative on failure
263
 *
264
 *-------------------------------------------------------------------------
265
 */
266
herr_t
267
H5SM__message_encode(uint8_t *raw, const void *_nrecord, void *_ctx)
268
0
{
269
0
    H5SM_bt2_ctx_t    *ctx     = (H5SM_bt2_ctx_t *)_ctx; /* Callback context structure */
270
0
    const H5SM_sohm_t *message = (const H5SM_sohm_t *)_nrecord;
271
272
0
    FUNC_ENTER_PACKAGE_NOERR
273
274
    /* Sanity check */
275
0
    assert(ctx);
276
277
0
    *raw++ = (uint8_t)message->location;
278
0
    UINT32ENCODE(raw, message->hash);
279
280
0
    if (message->location == H5SM_IN_HEAP) {
281
0
        UINT32ENCODE(raw, message->u.heap_loc.ref_count);
282
0
        H5MM_memcpy(raw, message->u.heap_loc.fheap_id.id, (size_t)H5O_FHEAP_ID_LEN);
283
0
    } /* end if */
284
0
    else {
285
0
        assert(message->location == H5SM_IN_OH);
286
287
0
        *raw++ = 0; /* reserved (possible flags byte) */
288
0
        *raw++ = (uint8_t)message->msg_type_id;
289
0
        UINT16ENCODE(raw, message->u.mesg_loc.index);
290
0
        H5F_addr_encode_len((size_t)ctx->sizeof_addr, &raw, message->u.mesg_loc.oh_addr);
291
0
    } /* end else */
292
293
0
    FUNC_LEAVE_NOAPI(SUCCEED)
294
0
} /* end H5SM__message_encode */
295
296
/*-------------------------------------------------------------------------
297
 * Function:  H5SM__message_decode
298
 *
299
 * Purpose: Read an encoded SOHM message from RAW into an H5SM_sohm_t struct.
300
 *
301
 * Return:  Non-negative on success
302
 *              Negative on failure
303
 *
304
 *-------------------------------------------------------------------------
305
 */
306
herr_t
307
H5SM__message_decode(const uint8_t *raw, void *_nrecord, void *_ctx)
308
0
{
309
0
    H5SM_bt2_ctx_t *ctx     = (H5SM_bt2_ctx_t *)_ctx; /* Callback context structure */
310
0
    H5SM_sohm_t    *message = (H5SM_sohm_t *)_nrecord;
311
312
0
    FUNC_ENTER_PACKAGE_NOERR
313
314
0
    message->location = (H5SM_storage_loc_t)*raw++;
315
0
    UINT32DECODE(raw, message->hash);
316
317
0
    if (message->location == H5SM_IN_HEAP) {
318
0
        UINT32DECODE(raw, message->u.heap_loc.ref_count);
319
0
        H5MM_memcpy(message->u.heap_loc.fheap_id.id, raw, (size_t)H5O_FHEAP_ID_LEN);
320
0
    } /* end if */
321
0
    else {
322
0
        assert(message->location == H5SM_IN_OH);
323
324
0
        raw++; /* reserved */
325
0
        message->msg_type_id = *raw++;
326
0
        UINT16DECODE(raw, message->u.mesg_loc.index);
327
0
        H5F_addr_decode_len((size_t)ctx->sizeof_addr, &raw, &message->u.mesg_loc.oh_addr);
328
0
    } /* end else */
329
330
0
    FUNC_LEAVE_NOAPI(SUCCEED)
331
0
} /* end H5SM__message_decode */