/src/hdf5/src/H5Oshared.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 | | * Purpose: Functions that operate on a shared message. The shared |
15 | | * message doesn't ever actually appear in the object header as |
16 | | * a normal message. Instead, if a message is shared, the |
17 | | * H5O_FLAG_SHARED bit is set and the message body is that |
18 | | * defined here for H5O_SHARED. The message ID is the ID of the |
19 | | * pointed-to message and the pointed-to message is stored in |
20 | | * the global heap. |
21 | | */ |
22 | | |
23 | | /****************/ |
24 | | /* Module Setup */ |
25 | | /****************/ |
26 | | |
27 | | #include "H5Omodule.h" /* This source code file is part of the H5O module */ |
28 | | |
29 | | /***********/ |
30 | | /* Headers */ |
31 | | /***********/ |
32 | | #include "H5private.h" /* Generic Functions */ |
33 | | #include "H5Eprivate.h" /* Error handling */ |
34 | | #include "H5Fprivate.h" /* File access */ |
35 | | #include "H5HFprivate.h" /* Fractal heap */ |
36 | | #include "H5MMprivate.h" /* Memory management */ |
37 | | #include "H5Opkg.h" /* Object headers */ |
38 | | #include "H5SMprivate.h" /* Shared object header messages */ |
39 | | #include "H5WBprivate.h" /* Wrapped Buffers */ |
40 | | |
41 | | /****************/ |
42 | | /* Local Macros */ |
43 | | /****************/ |
44 | | |
45 | | /* First version, with full symbol table entry as link for object header sharing */ |
46 | 0 | #define H5O_SHARED_VERSION_1 1 |
47 | | |
48 | | /* Older version, with just address of object as link for object header sharing */ |
49 | 0 | #define H5O_SHARED_VERSION_2 2 |
50 | | |
51 | | /* Newest version, which recognizes messages that are stored in the SOHM heap */ |
52 | 0 | #define H5O_SHARED_VERSION_3 3 |
53 | 0 | #define H5O_SHARED_VERSION_LATEST H5O_SHARED_VERSION_3 |
54 | | |
55 | | /* Size of stack buffer for serialized messages */ |
56 | | #define H5O_MESG_BUF_SIZE 128 |
57 | | |
58 | | /******************/ |
59 | | /* Local Typedefs */ |
60 | | /******************/ |
61 | | |
62 | | /********************/ |
63 | | /* Local Prototypes */ |
64 | | /********************/ |
65 | | static void *H5O__shared_read(H5F_t *f, H5O_t *open_oh, unsigned *ioflags, const H5O_shared_t *shared, |
66 | | const H5O_msg_class_t *type); |
67 | | static herr_t H5O__shared_link_adj(H5F_t *f, H5O_t *open_oh, const H5O_msg_class_t *type, |
68 | | H5O_shared_t *shared, int adjust); |
69 | | |
70 | | /*********************/ |
71 | | /* Package Variables */ |
72 | | /*********************/ |
73 | | |
74 | | /*****************************/ |
75 | | /* Library Private Variables */ |
76 | | /*****************************/ |
77 | | |
78 | | /*******************/ |
79 | | /* Local Variables */ |
80 | | /*******************/ |
81 | | |
82 | | /*------------------------------------------------------------------------- |
83 | | * Function: H5O__shared_read |
84 | | * |
85 | | * Purpose: Reads a message referred to by a shared message. |
86 | | * |
87 | | * Return: Success: Ptr to message in native format. The message |
88 | | * should be freed by calling H5O_msg_reset(). |
89 | | * |
90 | | * Failure: NULL |
91 | | * |
92 | | *------------------------------------------------------------------------- |
93 | | */ |
94 | | static void * |
95 | | H5O__shared_read(H5F_t *f, H5O_t *open_oh, unsigned *ioflags, const H5O_shared_t *shared, |
96 | | const H5O_msg_class_t *type) |
97 | 0 | { |
98 | 0 | H5HF_t *fheap = NULL; |
99 | 0 | H5WB_t *wb = NULL; /* Wrapped buffer for attribute data */ |
100 | 0 | uint8_t mesg_buf[H5O_MESG_BUF_SIZE]; /* Buffer for deserializing messages */ |
101 | 0 | void *ret_value = NULL; /* Return value */ |
102 | |
|
103 | 0 | FUNC_ENTER_PACKAGE |
104 | | |
105 | | /* check args */ |
106 | 0 | assert(f); |
107 | 0 | assert(shared); |
108 | 0 | assert(type); |
109 | 0 | assert(type->share_flags & H5O_SHARE_IS_SHARABLE); |
110 | | |
111 | | /* This message could have a heap ID (SOHM) or the address of an object |
112 | | * header on disk (named datatype) |
113 | | */ |
114 | 0 | assert(H5O_IS_STORED_SHARED(shared->type)); |
115 | | |
116 | | /* Check for implicit shared object header message */ |
117 | 0 | if (shared->type == H5O_SHARE_TYPE_SOHM) { |
118 | 0 | haddr_t fheap_addr; /* Address of SOHM heap */ |
119 | 0 | uint8_t *mesg_ptr; /* Pointer to raw message in heap */ |
120 | 0 | size_t mesg_size; /* Size of message */ |
121 | | |
122 | | /* Retrieve the fractal heap address for shared messages */ |
123 | 0 | if (H5SM_get_fheap_addr(f, type->id, &fheap_addr) < 0) |
124 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, NULL, "can't get fheap address for shared messages"); |
125 | | |
126 | | /* Open the fractal heap */ |
127 | 0 | if (NULL == (fheap = H5HF_open(f, fheap_addr))) |
128 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, NULL, "unable to open fractal heap"); |
129 | | |
130 | | /* Get the size of the message in the heap */ |
131 | 0 | if (H5HF_get_obj_len(fheap, &(shared->u.heap_id), &mesg_size) < 0) |
132 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, NULL, "can't get message size from fractal heap."); |
133 | | |
134 | | /* Wrap the local buffer for serialized message */ |
135 | 0 | if (NULL == (wb = H5WB_wrap(mesg_buf, sizeof(mesg_buf)))) |
136 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "can't wrap buffer"); |
137 | | |
138 | | /* Get a pointer to a buffer that's large enough for message */ |
139 | 0 | if (NULL == (mesg_ptr = (uint8_t *)H5WB_actual(wb, mesg_size))) |
140 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, NULL, "can't get actual buffer"); |
141 | | |
142 | | /* Retrieve the message from the heap */ |
143 | 0 | if (H5HF_read(fheap, &(shared->u.heap_id), mesg_ptr) < 0) |
144 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "can't read message from fractal heap."); |
145 | | |
146 | | /* Decode the message */ |
147 | 0 | if (NULL == (ret_value = (type->decode)(f, open_oh, 0, ioflags, mesg_size, mesg_ptr))) |
148 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, NULL, "can't decode shared message."); |
149 | 0 | } /* end if */ |
150 | 0 | else { |
151 | 0 | H5O_loc_t oloc; /* Location for object header where message is stored */ |
152 | |
|
153 | 0 | assert(shared->type == H5O_SHARE_TYPE_COMMITTED); |
154 | | |
155 | | /* Build the object location for the shared message's object header */ |
156 | 0 | oloc.file = f; |
157 | 0 | oloc.addr = shared->u.loc.oh_addr; |
158 | 0 | oloc.holding_file = false; |
159 | |
|
160 | 0 | if (open_oh && oloc.addr == H5O_OH_GET_ADDR(open_oh)) { |
161 | | /* The shared message is in the already opened object header. This |
162 | | * is possible, for example, if an attribute's datatype is shared in |
163 | | * the same object header the attribute is in. Read the message |
164 | | * directly. */ |
165 | 0 | if (NULL == (ret_value = H5O_msg_read_oh(f, open_oh, type->id, NULL))) |
166 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_READERROR, NULL, "unable to read message"); |
167 | 0 | } |
168 | 0 | else |
169 | | /* The shared message is in another object header */ |
170 | 0 | if (NULL == (ret_value = H5O_msg_read(&oloc, type->id, NULL))) |
171 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_READERROR, NULL, "unable to read message"); |
172 | 0 | } /* end else */ |
173 | | |
174 | | /* Mark the message as shared */ |
175 | 0 | if (H5O_msg_set_share(type->id, shared, ret_value) < 0) |
176 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "unable to set sharing information"); |
177 | | |
178 | 0 | done: |
179 | | /* Release resources */ |
180 | 0 | if (fheap && H5HF_close(fheap) < 0) |
181 | 0 | HDONE_ERROR(H5E_HEAP, H5E_CANTFREE, NULL, "can't close fractal heap"); |
182 | 0 | if (wb && H5WB_unwrap(wb) < 0) |
183 | 0 | HDONE_ERROR(H5E_OHDR, H5E_CLOSEERROR, NULL, "can't close wrapped buffer"); |
184 | |
|
185 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
186 | 0 | } /* end H5O__shared_read() */ |
187 | | |
188 | | /*------------------------------------------------------------------------- |
189 | | * Function: H5O__shared_link_adj |
190 | | * |
191 | | * Purpose: Changes the link count for the object referenced by a shared |
192 | | * message. |
193 | | * |
194 | | * This function changes the object header link count and is |
195 | | * only relevant for committed messages. Messages shared in |
196 | | * the heap are re-shared each time they're written, so their |
197 | | * reference count is stored in the file-wide shared message |
198 | | * index and is changed in a different place in the code. |
199 | | * |
200 | | * Return: SUCCEED/FAIL |
201 | | * |
202 | | *------------------------------------------------------------------------- |
203 | | */ |
204 | | static herr_t |
205 | | H5O__shared_link_adj(H5F_t *f, H5O_t *open_oh, const H5O_msg_class_t *type, H5O_shared_t *shared, int adjust) |
206 | 0 | { |
207 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
208 | |
|
209 | 0 | FUNC_ENTER_PACKAGE |
210 | | |
211 | | /* check args */ |
212 | 0 | assert(f); |
213 | 0 | assert(shared); |
214 | | |
215 | | /* Check for type of shared message */ |
216 | 0 | if (shared->type == H5O_SHARE_TYPE_COMMITTED) { |
217 | 0 | H5O_loc_t oloc; /* Location for object header where message is stored */ |
218 | | |
219 | | /* |
220 | | * The shared message is stored in some object header. |
221 | | * The other object header must be in the same file as the |
222 | | * new object header. Adjust the reference count on that |
223 | | * object header. |
224 | | */ |
225 | | /* Unfortunately, it is possible for the shared->file pointer to become |
226 | | * invalid if the oh is kept in cache (which is contained in |
227 | | * shared->file->shared while shared->file is closed. Just ignore |
228 | | * shared->file until the "top-level" file pointer is removed at some |
229 | | * point in the future. -NAF */ |
230 | | /* This is related to Jira issue #7638 and should be uncommented after |
231 | | * the library has been refactored to shift to using shared file |
232 | | * pointers for file operations, instead of using top file pointers. |
233 | | * -QAK */ |
234 | | /*if(shared->file->shared != f->shared) |
235 | | HGOTO_ERROR(H5E_LINK, H5E_CANTINIT, FAIL, "interfile hard links are not allowed")*/ |
236 | | |
237 | | /* Build the object location for the shared message's object header */ |
238 | 0 | oloc.file = f; |
239 | 0 | oloc.addr = shared->u.loc.oh_addr; |
240 | 0 | oloc.holding_file = false; |
241 | |
|
242 | 0 | if (open_oh && oloc.addr == H5O_OH_GET_ADDR(open_oh)) { |
243 | | /* The shared message is in the already opened object header. This |
244 | | * is possible, for example, if an attribute's datatype is shared in |
245 | | * the same object header the attribute is in. Adjust the link |
246 | | * count directly. */ |
247 | 0 | bool deleted = false; /* This is used only to satisfy H5O__link_oh */ |
248 | |
|
249 | 0 | if (H5O__link_oh(f, adjust, open_oh, &deleted) < 0) |
250 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_LINKCOUNT, FAIL, "unable to adjust shared object link count"); |
251 | | |
252 | 0 | assert(!deleted); |
253 | 0 | } |
254 | 0 | else |
255 | | /* The shared message is in another object header */ |
256 | 0 | if (H5O_link(&oloc, adjust) < 0) |
257 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_LINKCOUNT, FAIL, "unable to adjust shared object link count"); |
258 | 0 | } /* end if */ |
259 | 0 | else { |
260 | 0 | assert(shared->type == H5O_SHARE_TYPE_SOHM || shared->type == H5O_SHARE_TYPE_HERE); |
261 | | |
262 | | /* Check for decrementing reference count on shared message */ |
263 | 0 | if (adjust < 0) { |
264 | 0 | if (H5SM_delete(f, open_oh, shared) < 0) |
265 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_CANTDEC, FAIL, "unable to delete message from SOHM table"); |
266 | 0 | } /* end if */ |
267 | | /* Check for incrementing reference count on message */ |
268 | 0 | else if (adjust > 0) { |
269 | 0 | if (H5SM_try_share(f, open_oh, 0, type->id, shared, NULL) < 0) |
270 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_CANTINC, FAIL, "error trying to share message"); |
271 | 0 | } /* end if */ |
272 | 0 | } /* end else */ |
273 | | |
274 | 0 | done: |
275 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
276 | 0 | } /* end H5O__shared_link_adj() */ |
277 | | |
278 | | /*------------------------------------------------------------------------- |
279 | | * Function: H5O__shared_decode |
280 | | * |
281 | | * Purpose: Decodes a shared object message |
282 | | * |
283 | | * Return: Success: A buffer containing the decoded shared object |
284 | | * Failure: NULL |
285 | | * |
286 | | *------------------------------------------------------------------------- |
287 | | */ |
288 | | void * |
289 | | H5O__shared_decode(H5F_t *f, H5O_t *open_oh, unsigned *ioflags, size_t buf_size, const uint8_t *buf, |
290 | | const H5O_msg_class_t *type) |
291 | 0 | { |
292 | 0 | const uint8_t *buf_end = buf + buf_size - 1; /* End of the buffer */ |
293 | 0 | H5O_shared_t sh_mesg; /* Shared message info */ |
294 | 0 | unsigned version; /* Shared message version */ |
295 | 0 | void *ret_value = NULL; /* Return value */ |
296 | |
|
297 | 0 | FUNC_ENTER_PACKAGE |
298 | | |
299 | | /* Check args */ |
300 | 0 | assert(f); |
301 | 0 | assert(buf); |
302 | 0 | assert(type); |
303 | | |
304 | | /* Version */ |
305 | 0 | if (H5_IS_BUFFER_OVERFLOW(buf, 1, buf_end)) |
306 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding"); |
307 | 0 | version = *buf++; |
308 | 0 | if (version < H5O_SHARED_VERSION_1 || version > H5O_SHARED_VERSION_LATEST) |
309 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "bad version number for shared object message"); |
310 | | |
311 | | /* Get the shared information type |
312 | | * Flags are unused before version 3. |
313 | | */ |
314 | 0 | if (H5_IS_BUFFER_OVERFLOW(buf, 1, buf_end)) |
315 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding"); |
316 | 0 | if (version >= H5O_SHARED_VERSION_2) |
317 | 0 | sh_mesg.type = *buf++; |
318 | 0 | else { |
319 | 0 | sh_mesg.type = H5O_SHARE_TYPE_COMMITTED; |
320 | 0 | buf++; |
321 | 0 | } /* end else */ |
322 | | |
323 | | /* Skip reserved bytes (for version 1) */ |
324 | 0 | if (version == H5O_SHARED_VERSION_1) { |
325 | 0 | if (H5_IS_BUFFER_OVERFLOW(buf, 6, buf_end)) |
326 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding"); |
327 | 0 | buf += 6; |
328 | 0 | } |
329 | | |
330 | | /* Body */ |
331 | 0 | if (version == H5O_SHARED_VERSION_1) { |
332 | | /* Initialize other location fields */ |
333 | 0 | sh_mesg.u.loc.index = 0; |
334 | | |
335 | | /* Decode stored "symbol table entry" into message location */ |
336 | 0 | if (H5_IS_BUFFER_OVERFLOW(buf, H5F_SIZEOF_SIZE(f), buf_end)) |
337 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding"); |
338 | 0 | buf += H5F_SIZEOF_SIZE(f); /* Skip over local heap address */ |
339 | 0 | if (H5_IS_BUFFER_OVERFLOW(buf, H5F_sizeof_addr(f), buf_end)) |
340 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding"); |
341 | 0 | H5F_addr_decode(f, &buf, &(sh_mesg.u.loc.oh_addr)); |
342 | 0 | } /* end if */ |
343 | 0 | else if (version >= H5O_SHARED_VERSION_2) { |
344 | | /* If this message is in the heap, copy a heap ID. |
345 | | * Otherwise, it is a named datatype, so copy an H5O_loc_t. |
346 | | */ |
347 | 0 | if (sh_mesg.type == H5O_SHARE_TYPE_SOHM) { |
348 | 0 | assert(version >= H5O_SHARED_VERSION_3); |
349 | 0 | if (H5_IS_BUFFER_OVERFLOW(buf, sizeof(sh_mesg.u.heap_id), buf_end)) |
350 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding"); |
351 | 0 | H5MM_memcpy(&sh_mesg.u.heap_id, buf, sizeof(sh_mesg.u.heap_id)); |
352 | 0 | } /* end if */ |
353 | 0 | else { |
354 | | /* The H5O_COMMITTED_FLAG should be set if this message |
355 | | * is from an older version before the flag existed. |
356 | | */ |
357 | 0 | if (version < H5O_SHARED_VERSION_3) |
358 | 0 | sh_mesg.type = H5O_SHARE_TYPE_COMMITTED; |
359 | |
|
360 | 0 | sh_mesg.u.loc.index = 0; |
361 | 0 | if (H5_IS_BUFFER_OVERFLOW(buf, H5F_sizeof_addr(f), buf_end)) |
362 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_OVERFLOW, NULL, "ran off end of input buffer while decoding"); |
363 | 0 | H5F_addr_decode(f, &buf, &sh_mesg.u.loc.oh_addr); |
364 | 0 | } /* end else */ |
365 | 0 | } /* end else if */ |
366 | | |
367 | | /* Set file pointer & message type for all types of shared messages */ |
368 | 0 | sh_mesg.file = f; |
369 | 0 | sh_mesg.msg_type_id = type->id; |
370 | | |
371 | | /* Retrieve actual message, through decoded shared message info */ |
372 | 0 | if (NULL == (ret_value = H5O__shared_read(f, open_oh, ioflags, &sh_mesg, type))) |
373 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_READERROR, NULL, "unable to retrieve native message"); |
374 | | |
375 | 0 | done: |
376 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
377 | 0 | } /* end H5O__shared_decode() */ |
378 | | |
379 | | /*------------------------------------------------------------------------- |
380 | | * Function: H5O__shared_encode |
381 | | * |
382 | | * Purpose: Encodes message _MESG into buffer BUF. |
383 | | * |
384 | | * Return: SUCCEED/FAIL |
385 | | * |
386 | | *------------------------------------------------------------------------- |
387 | | */ |
388 | | herr_t |
389 | | H5O__shared_encode(const H5F_t *f, uint8_t *buf /*out*/, const H5O_shared_t *sh_mesg) |
390 | 0 | { |
391 | 0 | unsigned version; |
392 | |
|
393 | 0 | FUNC_ENTER_PACKAGE_NOERR |
394 | | |
395 | | /* Check args */ |
396 | 0 | assert(f); |
397 | 0 | assert(buf); |
398 | 0 | assert(sh_mesg); |
399 | | |
400 | | /* If this message is shared in the heap, we need to use version 3 of the |
401 | | * encoding and encode the SHARED_IN_HEAP flag. |
402 | | */ |
403 | 0 | if (sh_mesg->type == H5O_SHARE_TYPE_SOHM) |
404 | 0 | version = H5O_SHARED_VERSION_LATEST; |
405 | 0 | else { |
406 | 0 | assert(sh_mesg->type == H5O_SHARE_TYPE_COMMITTED); |
407 | 0 | version = H5O_SHARED_VERSION_2; /* version 1 is no longer used */ |
408 | 0 | } /* end else */ |
409 | |
|
410 | 0 | *buf++ = (uint8_t)version; |
411 | 0 | *buf++ = (uint8_t)sh_mesg->type; |
412 | | |
413 | | /* Encode either the heap ID of the message or the address of the |
414 | | * object header that holds it. |
415 | | */ |
416 | 0 | if (sh_mesg->type == H5O_SHARE_TYPE_SOHM) |
417 | 0 | H5MM_memcpy(buf, &(sh_mesg->u.heap_id), sizeof(sh_mesg->u.heap_id)); |
418 | 0 | else |
419 | 0 | H5F_addr_encode(f, &buf, sh_mesg->u.loc.oh_addr); |
420 | |
|
421 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
422 | 0 | } /* end H5O__shared_encode() */ |
423 | | |
424 | | /*------------------------------------------------------------------------- |
425 | | * Function: H5O_set_shared |
426 | | * |
427 | | * Purpose: Sets the shared component for a message. |
428 | | * |
429 | | * Return: SUCCEED/FAIL |
430 | | * |
431 | | *------------------------------------------------------------------------- |
432 | | */ |
433 | | herr_t |
434 | | H5O_set_shared(H5O_shared_t *dst, const H5O_shared_t *src) |
435 | 0 | { |
436 | 0 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
437 | | |
438 | | /* check args */ |
439 | 0 | assert(dst); |
440 | 0 | assert(src); |
441 | | |
442 | | /* copy */ |
443 | 0 | *dst = *src; |
444 | |
|
445 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
446 | 0 | } /* end H5O_set_shared() */ |
447 | | |
448 | | /*------------------------------------------------------------------------- |
449 | | * Function: H5O__shared_size |
450 | | * |
451 | | * Purpose: Returns the length of a shared object message. |
452 | | * |
453 | | * Return: Success: Length |
454 | | * Failure: 0 |
455 | | * |
456 | | *------------------------------------------------------------------------- |
457 | | */ |
458 | | size_t |
459 | | H5O__shared_size(const H5F_t *f, const H5O_shared_t *sh_mesg) |
460 | 0 | { |
461 | 0 | size_t ret_value = 0; /* Return value */ |
462 | |
|
463 | 0 | FUNC_ENTER_PACKAGE_NOERR |
464 | |
|
465 | 0 | if (sh_mesg->type == H5O_SHARE_TYPE_COMMITTED) { |
466 | 0 | ret_value = (size_t)1 + /* Version */ |
467 | 0 | (size_t)1 + /* Type field */ |
468 | 0 | (size_t)H5F_SIZEOF_ADDR(f); /* Sharing by another obj hdr */ |
469 | 0 | } /* end if */ |
470 | 0 | else { |
471 | 0 | assert(sh_mesg->type == H5O_SHARE_TYPE_SOHM); |
472 | 0 | ret_value = 1 + /* Version */ |
473 | 0 | 1 + /* Type field */ |
474 | 0 | H5O_FHEAP_ID_LEN; /* Shared in the heap */ |
475 | 0 | } /* end else */ |
476 | |
|
477 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
478 | 0 | } /* end H5O__shared_size() */ |
479 | | |
480 | | /*------------------------------------------------------------------------- |
481 | | * Function: H5O__shared_delete |
482 | | * |
483 | | * Purpose: Free file space referenced by message |
484 | | * |
485 | | * Return: SUCCEED/FAIL |
486 | | * |
487 | | *------------------------------------------------------------------------- |
488 | | */ |
489 | | herr_t |
490 | | H5O__shared_delete(H5F_t *f, H5O_t *open_oh, const H5O_msg_class_t *type, H5O_shared_t *sh_mesg) |
491 | 0 | { |
492 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
493 | |
|
494 | 0 | FUNC_ENTER_PACKAGE |
495 | | |
496 | | /* check args */ |
497 | 0 | assert(f); |
498 | 0 | assert(sh_mesg); |
499 | | |
500 | | /* |
501 | | * Committed datatypes increment the OH of the original message when they |
502 | | * are written (in H5O_shared_link) and decrement it here. |
503 | | * SOHMs in the heap behave differently; their refcount is incremented |
504 | | * during H5SM_share when they are going to be written (in H5O_msg_append |
505 | | * or H5O_msg_write). Their refcount in the SOHM indexes still needs to |
506 | | * be decremented when they're deleted (in H5O__shared_link_adj). |
507 | | */ |
508 | | |
509 | | /* Decrement the reference count on the shared object */ |
510 | 0 | if (H5O__shared_link_adj(f, open_oh, type, sh_mesg, -1) < 0) |
511 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_LINKCOUNT, FAIL, "unable to adjust shared object link count"); |
512 | | |
513 | 0 | done: |
514 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
515 | 0 | } /* end H5O__shared_delete() */ |
516 | | |
517 | | /*------------------------------------------------------------------------- |
518 | | * Function: H5O__shared_link |
519 | | * |
520 | | * Purpose: Increment reference count on any objects referenced by |
521 | | * message |
522 | | * |
523 | | * Return: SUCCEED/FAIL |
524 | | * |
525 | | *------------------------------------------------------------------------- |
526 | | */ |
527 | | herr_t |
528 | | H5O__shared_link(H5F_t *f, H5O_t *open_oh, const H5O_msg_class_t *type, H5O_shared_t *sh_mesg) |
529 | 0 | { |
530 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
531 | |
|
532 | 0 | FUNC_ENTER_PACKAGE |
533 | | |
534 | | /* Check args */ |
535 | 0 | assert(f); |
536 | 0 | assert(sh_mesg); |
537 | | |
538 | | /* Increment the reference count on the shared object */ |
539 | 0 | if (H5O__shared_link_adj(f, open_oh, type, sh_mesg, 1) < 0) |
540 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_LINKCOUNT, FAIL, "unable to adjust shared object link count"); |
541 | | |
542 | 0 | done: |
543 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
544 | 0 | } /* end H5O__shared_link() */ |
545 | | |
546 | | /*------------------------------------------------------------------------- |
547 | | * Function: H5O__shared_copy_file |
548 | | * |
549 | | * Purpose: Copies a message from _MESG to _DEST in file |
550 | | * |
551 | | * Return: SUCCEED/FAIL |
552 | | * |
553 | | *------------------------------------------------------------------------- |
554 | | */ |
555 | | herr_t |
556 | | H5O__shared_copy_file(H5F_t H5_ATTR_NDEBUG_UNUSED *file_src, H5F_t *file_dst, |
557 | | const H5O_msg_class_t *mesg_type, const void *_native_src, void *_native_dst, |
558 | | bool H5_ATTR_UNUSED *recompute_size, unsigned *mesg_flags, |
559 | | H5O_copy_t H5_ATTR_NDEBUG_UNUSED *cpy_info, void H5_ATTR_UNUSED *udata) |
560 | 0 | { |
561 | 0 | const H5O_shared_t *shared_src = |
562 | 0 | (const H5O_shared_t *)_native_src; /* Alias to shared info in native source */ |
563 | 0 | H5O_shared_t *shared_dst = |
564 | 0 | (H5O_shared_t *)_native_dst; /* Alias to shared info in native destination message */ |
565 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
566 | |
|
567 | 0 | FUNC_ENTER_PACKAGE |
568 | | |
569 | | /* check args */ |
570 | 0 | assert(file_src); |
571 | 0 | assert(file_dst); |
572 | 0 | assert(mesg_type); |
573 | 0 | assert(shared_src); |
574 | 0 | assert(shared_dst); |
575 | 0 | assert(recompute_size); |
576 | 0 | assert(cpy_info); |
577 | | |
578 | | /* Committed shared messages create a shared message at the destination |
579 | | * and also copy the committed object that they point to. |
580 | | * |
581 | | * Other messages simulate sharing the destination message to determine how |
582 | | * it will eventually be shared (if at all), but do not actually share the |
583 | | * message until "post copy". The "H5O_shared_t" part of the message will |
584 | | * be updated (to allow calculation of the final size) but the message is |
585 | | * not actually shared. |
586 | | */ |
587 | 0 | if (shared_src->type != H5O_SHARE_TYPE_COMMITTED) { |
588 | | /* Simulate trying to share new message in the destination file. */ |
589 | | /* Set copied metadata tag */ |
590 | 0 | H5_BEGIN_TAG(H5AC__COPIED_TAG) |
591 | |
|
592 | 0 | if (H5SM_try_share(file_dst, NULL, H5SM_DEFER, mesg_type->id, _native_dst, mesg_flags) < 0) |
593 | 0 | HGOTO_ERROR_TAG(H5E_OHDR, H5E_WRITEERROR, FAIL, |
594 | 0 | "unable to determine if message should be shared"); |
595 | | |
596 | | /* Reset metadata tag */ |
597 | 0 | H5_END_TAG |
598 | 0 | } /* end if */ |
599 | 0 | else { |
600 | | /* Mark the message as committed - as it will be committed in post copy |
601 | | */ |
602 | 0 | H5O_UPDATE_SHARED(shared_dst, H5O_SHARE_TYPE_COMMITTED, file_dst, mesg_type->id, 0, HADDR_UNDEF) |
603 | 0 | *mesg_flags |= H5O_MSG_FLAG_SHARED; |
604 | 0 | } /* end else */ |
605 | | |
606 | 0 | done: |
607 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
608 | 0 | } /* H5O__shared_copy_file() */ |
609 | | |
610 | | /*------------------------------------------------------------------------- |
611 | | * Function: H5O__shared_post_copy_file |
612 | | * |
613 | | * Purpose: Delete a shared message and replace with a new one. |
614 | | * The function is needed at cases such as copying a shared reg_ref attribute. |
615 | | * When a shared reg_ref attribute is copied from one file to |
616 | | * another, the values in file need to be replaced. The only way |
617 | | * to complish that is to delete the old message and write the |
618 | | * new message with the correct values. |
619 | | * |
620 | | * Return: SUCCEED/FAIL |
621 | | * |
622 | | *------------------------------------------------------------------------- |
623 | | */ |
624 | | herr_t |
625 | | H5O__shared_post_copy_file(H5F_t *f, const H5O_msg_class_t *mesg_type, const H5O_shared_t *shared_src, |
626 | | H5O_shared_t *shared_dst, unsigned *mesg_flags, H5O_copy_t *cpy_info) |
627 | 0 | { |
628 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
629 | |
|
630 | 0 | FUNC_ENTER_PACKAGE |
631 | | |
632 | | /* check args */ |
633 | 0 | assert(f); |
634 | 0 | assert(shared_src); |
635 | 0 | assert(shared_dst); |
636 | | |
637 | | /* Copy the target of committed messages, try to share others */ |
638 | 0 | if (shared_src->type == H5O_SHARE_TYPE_COMMITTED) { |
639 | 0 | H5O_loc_t dst_oloc; |
640 | 0 | H5O_loc_t src_oloc; |
641 | | |
642 | | /* Copy the shared object from source to destination */ |
643 | 0 | H5O_loc_reset(&dst_oloc); |
644 | 0 | dst_oloc.file = f; |
645 | 0 | src_oloc.file = shared_src->file; |
646 | 0 | src_oloc.addr = shared_src->u.loc.oh_addr; |
647 | 0 | if (H5O_copy_header_map(&src_oloc, &dst_oloc, cpy_info, false, NULL, NULL) < 0) |
648 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy object"); |
649 | | |
650 | | /* Set up destination message's shared info */ |
651 | 0 | H5O_UPDATE_SHARED(shared_dst, H5O_SHARE_TYPE_COMMITTED, f, mesg_type->id, 0, dst_oloc.addr) |
652 | 0 | } /* end if */ |
653 | 0 | else |
654 | | /* Share the message */ |
655 | 0 | if (H5SM_try_share(f, NULL, H5SM_WAS_DEFERRED, mesg_type->id, shared_dst, mesg_flags) < 0) |
656 | 0 | HGOTO_ERROR(H5E_OHDR, H5E_BADMESG, FAIL, "can't share message"); |
657 | | |
658 | 0 | done: |
659 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
660 | 0 | } /* end H5O__shared_post_copy_file() */ |
661 | | |
662 | | /*------------------------------------------------------------------------- |
663 | | * Function: H5O__shared_debug |
664 | | * |
665 | | * Purpose: Prints debugging info for the message |
666 | | * |
667 | | * Return: Non-negative on success/Negative on failure |
668 | | * |
669 | | *------------------------------------------------------------------------- |
670 | | */ |
671 | | herr_t |
672 | | H5O__shared_debug(const H5O_shared_t *mesg, FILE *stream, int indent, int fwidth) |
673 | 0 | { |
674 | 0 | FUNC_ENTER_PACKAGE_NOERR |
675 | | |
676 | | /* Check args */ |
677 | 0 | assert(mesg); |
678 | 0 | assert(stream); |
679 | 0 | assert(indent >= 0); |
680 | 0 | assert(fwidth >= 0); |
681 | |
|
682 | 0 | switch (mesg->type) { |
683 | 0 | case H5O_SHARE_TYPE_UNSHARED: |
684 | 0 | fprintf(stream, "%*s%-*s %s\n", indent, "", fwidth, "Shared Message type:", "Unshared"); |
685 | 0 | break; |
686 | | |
687 | 0 | case H5O_SHARE_TYPE_COMMITTED: |
688 | 0 | fprintf(stream, "%*s%-*s %s\n", indent, "", fwidth, "Shared Message type:", "Obj Hdr"); |
689 | 0 | fprintf(stream, "%*s%-*s %" PRIuHADDR "\n", indent, "", fwidth, |
690 | 0 | "Object address:", mesg->u.loc.oh_addr); |
691 | 0 | break; |
692 | | |
693 | 0 | case H5O_SHARE_TYPE_SOHM: |
694 | 0 | fprintf(stream, "%*s%-*s %s\n", indent, "", fwidth, "Shared Message type:", "SOHM"); |
695 | 0 | fprintf(stream, "%*s%-*s %016llx\n", indent, "", fwidth, |
696 | 0 | "Heap ID:", (unsigned long long)mesg->u.heap_id.val); |
697 | 0 | break; |
698 | | |
699 | 0 | case H5O_SHARE_TYPE_HERE: |
700 | 0 | fprintf(stream, "%*s%-*s %s\n", indent, "", fwidth, "Shared Message type:", "Here"); |
701 | 0 | break; |
702 | | |
703 | 0 | default: |
704 | 0 | fprintf(stream, "%*s%-*s %s (%u)\n", indent, "", fwidth, "Shared Message type:", "Unknown", |
705 | 0 | (unsigned)mesg->type); |
706 | 0 | } /* end switch */ |
707 | | |
708 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
709 | 0 | } /* end H5O__shared_debug() */ |