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