/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 */ |