Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document VOL object wrapping context #4611

Merged
merged 3 commits into from
Jun 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 30 additions & 9 deletions doxygen/dox/VOLConnGuide.dox
Original file line number Diff line number Diff line change
Expand Up @@ -664,7 +664,11 @@ structure. It is the opposite of the <em>to_str</em> callback.

\subsection subsecVOLRefWrap Object Wrap Callbacks
The object wrap callbacks are used by passthrough connectors to wrap/unwrap objects and contexts when
passing them up and down the VOL chain.
passing them up and down the VOL chain. Each passthrough VOL must define an object wrapping structure and a wrap context.
The object wrapping structure should contain the information necessary to recursively unwrap the object - at a minimum, this is the object provided from and the ID of the next connector in the stack.
The wrap context should contain the information necessary to recursively wrap the object - at a minimum, this is the ID and the wrap context of the next VOL connector in the stack.

Each callback should use <em>H5VL&lt;callback&gt;</em> to recursively invoke the same callback in all lower passthrough VOl connectors.

<em>Wrap class for object wrapping routines, H5VLconnector.h</em>
\code
Expand All @@ -678,7 +682,13 @@ typedef struct H5VL_wrap_class_t {
\endcode

\subsubsection subsubsecVOLRefWrapobj wrap: get_object
Retrieves an underlying object.
Retrieves the underlying object from a wrapped object. Should return a pointer to the underlying object belonging to the terminal VOL connector.

This will generally be done by unwrapping this VOL's object wrapping structure, before recursively calling <em>H5VLget_object</em> to invoke the <em>get_object</em>
callback for all lower VOL connectors which define it. <em>H5VLget_object</em> requires the object returned by the next VOL and the next VOL's ID. Both of
these fields should be stored by the VOL somehow, generally on the wrapped object structure.

This callback should not cleanup or modify the provided object wrapping structure.
<table>
<tr>
<th>Signature:</th>
Expand All @@ -696,14 +706,17 @@ Retrieves an underlying object.
<tr>
<td>
\code
obj (IN): Object being unwrapped.
obj (IN): The object to be unwrapped.
\endcode
</td>
</tr>
</table>

\subsubsection subsubsecVOLRefWrapctx wrap: get_wrap_ctx
Get a VOL connector's object wrapping context.

The context should be returned in dynamically allocated memory under <em>*wrap_ctx</em>.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@qkoziol When trying to help with documenting the VOL wrap class, I couldn't quite figure out what the wrap context object was necessary for. Do you happen to remember why a passthrough VOL needs to return a wrapping context object for the library to keep around?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The wrapping context object is saved on the API Context, which is where H5VL__wrap_obj retrieves it from to provide it to the wrap object callback

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrapping objects is necessary for the library to return objects from user callbacks and other scenarios where the library has an object from a terminal VOL connector and needs to eventually pass back an ID to an application. The library has to wrap the terminal object using pass-throughs 'wrap' callbacks, so that the resulting ID refers to an object that can later be unwrapped by the connector stack and reach the terminal connector again.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I was asking more about the wrapping context object in particular and why a connector needs to allocate one and pass it back to the library.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The wrapping context is what the library gives back to a VOL connector to say "wrap this object for me". Without the wrapping context, the pass-through connector wouldn't know which connector stack it was supposed to be wrapping an object for.

Any resources this callback allocates should be freed within <em>free_wrap_ctx</em>.
<table>
<tr>
<th>Signature:</th>
Expand All @@ -721,15 +734,19 @@ Get a VOL connector's object wrapping context.
<tr>
<td>
\code
obj (IN): Object for which we need a context.
obj (IN): Object wrapped by this VOL connector, for which we need a context.
wrap_ctx (OUT): Context.
\endcode
</td>
</tr>
</table>

\subsubsection subsubsecVOLRefWrapwrap wrap: wrap_object
Asks a connector to wrap an underlying object.
Asks a connector to wrap an underlying object. This callback should use <em>H5VLwrap_object</em>
to recursively have the object wrapped by all lower VOL connectors before performing its own wrapping.

The wrapped object should provide the information necessary for <em>unwrap_object</em> to recursively
unwrap it - at a minimum, the object provided from and the ID of the next VOL connector.
<table>
<tr>
<th>Signature:</th>
Expand All @@ -747,7 +764,7 @@ Asks a connector to wrap an underlying object.
<tr>
<td>
\code
obj (IN): Object being wrapped.
obj (IN): The object to be wrapped.
obj_type (IN): Object type (see H5Ipublic.h).
wrap_ctx (IN): Context.
\endcode
Expand All @@ -756,7 +773,10 @@ Asks a connector to wrap an underlying object.
</table>

\subsubsection subsubsecVOLRefWrapunwrap wrap: unwrap_object
Unwrap an object from connector.
Unwrap an object from connector. Any resources allocated during <em>wrap_object</em> should be released and cleaned up here.

This callback should clean up this VOL's object wrapping structure before recursively invoking <em>H5VLunwrap_object</em>.

<table>
<tr>
<th>Signature:</th>
Expand All @@ -774,14 +794,15 @@ Unwrap an object from connector.
<tr>
<td>
\code
obj (IN): Object being unwrapped.
obj (IN): Object to be unwrapped.
\endcode
</td>
</tr>
</table>

\subsubsection subsubsecVOLRefWrapfree wrap: free_wrap_ctx
Release a VOL connector's object wrapping context.
Release a VOL connector's object wrapping context. This should free any resources allocated during <em>get_wrap_ctx</em>, and recursively invoke <em>H5VLfree_wrap_ctx</em>
to execute the free callback for the lower VOL connectors in the stack.
<table>
<tr>
<th>Signature:</th>
Expand Down
5 changes: 4 additions & 1 deletion src/H5VLcallback.c
Original file line number Diff line number Diff line change
Expand Up @@ -739,7 +739,10 @@ H5VL_get_wrap_ctx(const H5VL_class_t *connector, void *obj, void **wrap_ctx)
/*---------------------------------------------------------------------------
* Function: H5VLget_wrap_ctx
*
* Purpose: Get a VOL connector's object wrapping context
* Purpose: Get a VOL connector's object wrapping context. The output
* wrap context is stored in memory allocated by the VOL callback
* under *wrap_ctx and must be freed by the caller through
* H5VLfree_wrap_ctx().
*
* Return: Success: Non-negative
* Failure: Negative
Expand Down
3 changes: 2 additions & 1 deletion src/H5VLconnector.h
Original file line number Diff line number Diff line change
Expand Up @@ -845,7 +845,8 @@ typedef struct H5VL_info_class_t {
} H5VL_info_class_t;

/* VOL object wrap / retrieval callbacks */
/* (These only need to be implemented by "pass through" VOL connectors) */
/* (These must be implemented by "pass through" VOL connectors, and should not be implemented by terminal VOL
* connectors) */
typedef struct H5VL_wrap_class_t {
void *(*get_object)(const void *obj); /* Callback to retrieve underlying object */
herr_t (*get_wrap_ctx)(
Expand Down
11 changes: 10 additions & 1 deletion src/H5VLint.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,16 @@
/* Local Typedefs */
/******************/

/* Object wrapping context info */
/* Object wrapping context info for passthrough VOL connectors.
* Passthrough VOL connectors must wrap objects returned from lower level(s) of the VOL connector stack
* so that they may be passed back up the stack to the library, and must unwrap objects
* passed down the stack before providing them to the next lower VOL connector.
* This is generally done individually within each VOL object callback. However, the library sometimes
* needs to wrap objects from places that don't pass through the VOL layer.
* In this case, the wrap callbacks defined in H5VL_wrap_class_t are used, and the VOL-defined wrap context
* (obj_wrap_ctx) provides necessary information - at a minimum, the object originally returned by the lower
* VOL connector, and the ID of the next VOL connector.
*/
typedef struct H5VL_wrap_ctx_t {
unsigned rc; /* Ref. count for the # of times the context was set / reset */
H5VL_t *connector; /* VOL connector for "outermost" class to start wrap */
Expand Down
Loading