Coverage Report

Created: 2026-01-16 06:15

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